aGrUM  0.20.2
a C++ library for (probabilistic) graphical models
PRMScalarAttribute_tpl.h
Go to the documentation of this file.
1 /**
2  *
3  * Copyright 2005-2020 Pierre-Henri WUILLEMIN(@LIP6) & Christophe GONZALES(@AMU)
4  * info_at_agrum_dot_org
5  *
6  * This library is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this library. If not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20 
21 
22 /**
23  * @file
24  * @brief Inline implementation of gum::PRMScalarAttribute
25  *
26  * @author Lionel TORTI and Pierre-Henri WUILLEMIN(@LIP6)
27  */
28 
29 #include <sstream>
30 
31 #include <agrum/PRM/utils_prm.h>
32 
33 #include <agrum/PRM/elements/PRMAttribute.h>
34 #include <agrum/PRM/elements/PRMType.h>
35 
36 namespace gum {
37  namespace prm {
38 
39  template < typename GUM_SCALAR >
40  PRMScalarAttribute< GUM_SCALAR >::PRMScalarAttribute(
41  const std::string& name,
42  const PRMType& type,
43  MultiDimImplementation< GUM_SCALAR >* impl) :
44  PRMAttribute< GUM_SCALAR >(name),
45  type__(new PRMType(type)), cpf__(new Potential< GUM_SCALAR >(impl)) {
46  GUM_CONSTRUCTOR(PRMScalarAttribute);
47  cpf__->add(type__->variable());
48 
49  this->safeName_ = PRMObject::LEFT_CAST() + type__->name()
50  + PRMObject::RIGHT_CAST() + name;
51  }
52 
53  template < typename GUM_SCALAR >
54  PRMScalarAttribute< GUM_SCALAR >::PRMScalarAttribute(
55  const PRMScalarAttribute< GUM_SCALAR >& source) :
56  PRMAttribute< GUM_SCALAR >(source),
57  type__(0), cpf__(0) {
58  GUM_CONS_CPY(PRMScalarAttribute);
59  GUM_ERROR(FatalError,
60  "Illegal call to the copy constructor of gum::ScalarAttribute");
61  }
62 
63  template < typename GUM_SCALAR >
64  PRMScalarAttribute< GUM_SCALAR >::~PRMScalarAttribute() {
65  GUM_DESTRUCTOR(PRMScalarAttribute);
66  delete cpf__;
67  delete type__;
68  }
69 
70  template < typename GUM_SCALAR >
71  PRMAttribute< GUM_SCALAR >* PRMScalarAttribute< GUM_SCALAR >::newFactory(
72  const PRMClass< GUM_SCALAR >& c) const {
73  auto impl = static_cast< MultiDimImplementation< GUM_SCALAR >* >(
74  this->cpf().content()->newFactory());
75  return new PRMScalarAttribute< GUM_SCALAR >(this->name(),
76  this->type(),
77  impl);
78  }
79 
80  template < typename GUM_SCALAR >
81  PRMAttribute< GUM_SCALAR >* PRMScalarAttribute< GUM_SCALAR >::copy(
82  Bijection< const DiscreteVariable*, const DiscreteVariable* > bij) const {
83  auto copy = new PRMScalarAttribute< GUM_SCALAR >(this->name(), this->type());
84 
85  if (!bij.existsFirst(&(type().variable()))) {
86  bij.insert(&(type().variable()), &(copy->type().variable()));
87  }
88 
89  delete copy->cpf__;
90  copy->cpf__ = copyPotential(bij, cpf());
91 
92  return copy;
93  }
94 
95  template < typename GUM_SCALAR >
96  void PRMScalarAttribute< GUM_SCALAR >::copyCpf(
97  const Bijection< const DiscreteVariable*, const DiscreteVariable* >& bij,
98  const PRMAttribute< GUM_SCALAR >& source) {
99  delete cpf__;
100  cpf__ = new Potential< GUM_SCALAR >();
101 
102  for (auto var: source.cpf().variablesSequence()) {
103  cpf__->add(*(bij.second(var)));
104  }
105 
106  Instantiation inst(*cpf__), jnst(source.cpf());
107 
108  for (inst.setFirst(), jnst.setFirst(); !(inst.end() || jnst.end());
109  inst.inc(), jnst.inc()) {
110  cpf__->set(inst, source.cpf().get(jnst));
111  }
112 
113  GUM_ASSERT(inst.end() && jnst.end());
114  GUM_ASSERT(cpf__->contains(type__->variable()));
115  GUM_ASSERT(!cpf__->contains(source.type().variable()));
116  }
117 
118  template < typename GUM_SCALAR >
119  PRMScalarAttribute< GUM_SCALAR >& PRMScalarAttribute< GUM_SCALAR >::operator=(
120  const PRMScalarAttribute< GUM_SCALAR >& from) {
121  GUM_ERROR(FatalError,
122  "Illegal call to the copy operator of gum::ScalarAttribute");
123  }
124 
125  template < typename GUM_SCALAR >
126  INLINE typename PRMClassElement< GUM_SCALAR >::ClassElementType
127  PRMScalarAttribute< GUM_SCALAR >::elt_type() const {
128  return this->prm_attribute;
129  }
130 
131  template < typename GUM_SCALAR >
132  INLINE PRMType& PRMScalarAttribute< GUM_SCALAR >::type() {
133  return *type__;
134  }
135 
136  template < typename GUM_SCALAR >
137  INLINE const PRMType& PRMScalarAttribute< GUM_SCALAR >::type() const {
138  return *type__;
139  }
140 
141  template < typename GUM_SCALAR >
142  INLINE const Potential< GUM_SCALAR >&
143  PRMScalarAttribute< GUM_SCALAR >::cpf() const {
144  return *cpf__;
145  }
146 
147  template < typename GUM_SCALAR >
148  INLINE void PRMScalarAttribute< GUM_SCALAR >::addParent(
149  const PRMClassElement< GUM_SCALAR >& elt) {
150  try {
151  cpf__->add(elt.type().variable());
152  } catch (DuplicateElement&) {
153  GUM_ERROR(DuplicateElement,
154  elt.name() << " as parent of " << this->name());
155  } catch (OperationNotAllowed&) {
156  GUM_ERROR(OperationNotAllowed,
157  elt.name() << " of wrong type as parent of " << this->name());
158  }
159  }
160 
161  // See gum::PRMClassElement<GUM_SCALAR>::addChild_().
162  template < typename GUM_SCALAR >
163  INLINE void PRMScalarAttribute< GUM_SCALAR >::addChild(
164  const PRMClassElement< GUM_SCALAR >& elt) {}
165 
166  template < typename GUM_SCALAR >
167  PRMAttribute< GUM_SCALAR >*
168  PRMScalarAttribute< GUM_SCALAR >::getCastDescendant() const {
169  PRMScalarAttribute< GUM_SCALAR >* cast = 0;
170 
171  try {
172  cast = new PRMScalarAttribute< GUM_SCALAR >(this->name(),
173  type().superType());
174  } catch (NotFound&) {
175  GUM_ERROR(OperationNotAllowed,
176  "this ScalarAttribute can not have cast descendant");
177  }
178 
179  cast->addParent(*this);
180  const DiscreteVariable& my_var = type().variable();
181  DiscreteVariable& cast_var = cast->type().variable();
182  Instantiation inst(cast->cpf());
183 
184  for (inst.setFirst(); !inst.end(); inst.inc()) {
185  if (type().label_map()[inst.val(my_var)] == inst.val(cast_var)) {
186  cast->cpf().set(inst, 1);
187  } else {
188  cast->cpf().set(inst, 0);
189  }
190  }
191 
192  return cast;
193  }
194 
195  template < typename GUM_SCALAR >
196  void PRMScalarAttribute< GUM_SCALAR >::setAsCastDescendant(
197  PRMAttribute< GUM_SCALAR >* cast) {
198  try {
199  type().setSuper(cast->type());
200  } catch (OperationNotAllowed&) {
201  GUM_ERROR(OperationNotAllowed,
202  "this ScalarAttribute can not have cast descendant");
203  } catch (TypeError&) {
204  std::stringstream msg;
205  msg << type().name() << " is not a subtype of " << cast->type().name();
206  GUM_ERROR(TypeError, msg.str());
207  }
208  cast->becomeCastDescendant(type());
209  }
210 
211  template < typename GUM_SCALAR >
212  void PRMScalarAttribute< GUM_SCALAR >::becomeCastDescendant(PRMType& subtype) {
213  delete cpf__;
214  cpf__ = new Potential< GUM_SCALAR >();
215  cpf__->add(type().variable());
216  cpf__->add(subtype.variable());
217 
218  Instantiation inst(*cpf__);
219 
220  for (inst.setFirst(); !inst.end(); inst.inc()) {
221  auto my_pos = inst.pos(subtype.variable());
222  if (subtype.label_map()[my_pos] == inst.pos(type().variable())) {
223  cpf__->set(inst, 1);
224  } else {
225  cpf__->set(inst, 0);
226  }
227  }
228  }
229 
230  template < typename GUM_SCALAR >
231  void PRMScalarAttribute< GUM_SCALAR >::swap(const PRMType& old_type,
232  const PRMType& new_type) {
233  if (&(old_type) == type__) {
234  GUM_ERROR(OperationNotAllowed, "Cannot replace attribute own type");
235  }
236  if (old_type->domainSize() != new_type->domainSize()) {
237  GUM_ERROR(OperationNotAllowed,
238  "Cannot replace types with difference domain size");
239  }
240  if (!cpf__->contains(old_type.variable())) {
241  GUM_ERROR(NotFound, "could not find variable " + old_type.name());
242  }
243 
244  auto old = cpf__;
245 
246  cpf__ = new Potential< GUM_SCALAR >();
247 
248  for (auto var: old->variablesSequence()) {
249  if (var != &(old_type.variable())) {
250  cpf__->add(*var);
251  } else {
252  cpf__->add(new_type.variable());
253  }
254  }
255 
256  Instantiation inst(cpf__), jnst(old);
257 
258  for (inst.setFirst(), jnst.setFirst(); !(inst.end() || jnst.end());
259  inst.inc(), jnst.inc()) {
260  cpf__->set(inst, old->get(jnst));
261  }
262 
263  delete old;
264 
265  GUM_ASSERT(inst.end() && jnst.end());
266  GUM_ASSERT(cpf__->contains(type__->variable()));
267  GUM_ASSERT(cpf__->contains(new_type.variable()));
268  GUM_ASSERT(!cpf__->contains(old_type.variable()));
269  }
270 
271  template < typename GUM_SCALAR >
272  PRMType* PRMScalarAttribute< GUM_SCALAR >::type_() {
273  return type__;
274  }
275 
276  template < typename GUM_SCALAR >
277  void PRMScalarAttribute< GUM_SCALAR >::type_(PRMType* t) {
278  if (type__->variable().domainSize() != t->variable().domainSize()) {
279  GUM_ERROR(OperationNotAllowed,
280  "Cannot replace types with difference domain size");
281  }
282  auto old = cpf__;
283 
284  cpf__ = new Potential< GUM_SCALAR >();
285 
286  for (auto var: old->variablesSequence()) {
287  if (var != &(type__->variable())) {
288  cpf__->add(*var);
289  } else {
290  cpf__->add(t->variable());
291  }
292  }
293 
294  Instantiation inst(cpf__), jnst(old);
295 
296  for (inst.setFirst(), jnst.setFirst(); !(inst.end() || jnst.end());
297  inst.inc(), jnst.inc()) {
298  cpf__->set(inst, old->get(jnst));
299  }
300 
301  delete old;
302 
303  type__ = t;
304 
305  GUM_ASSERT(cpf__->contains(type__->variable()));
306  GUM_ASSERT(inst.end() && jnst.end());
307  }
308 
309  } /* namespace prm */
310 } /* namespace gum */