aGrUM  0.17.2
a C++ library for (probabilistic) graphical models
MarkovNet_tpl.h
Go to the documentation of this file.
1 
30 #include <limits>
31 #include <set>
32 
33 #include <agrum/MN/MarkovNet.h>
34 
38 
48 
52 
54 
57 
58 namespace gum {
59  template < typename GUM_SCALAR >
60  NodeId build_node(gum::MarkovNet< GUM_SCALAR >& mn,
61  std::string node,
62  gum::Size default_domain_size) {
63  std::string name = node;
64  auto ds = default_domain_size;
65  long range_min = 0;
66  long range_max = long(ds) - 1;
67  std::vector< std::string > labels;
68  std::vector< GUM_SCALAR > ticks;
69 
70  if (*(node.rbegin()) == ']') {
71  auto posBrack = node.find('[');
72  if (posBrack != std::string::npos) {
73  name = node.substr(0, posBrack);
74  const auto& s_args = node.substr(posBrack + 1, node.size() - posBrack - 2);
75  const auto& args = split(s_args, ",");
76  if (args.size() == 0) { // n[]
77  GUM_ERROR(InvalidArgument, "Empty range for variable " << node)
78  } else if (args.size() == 1) { // n[4]
79  ds = static_cast< Size >(std::stoi(args[0]));
80  range_min = 0;
81  range_max = long(ds) - 1;
82  } else if (args.size() == 2) { // n[5,10]
83  range_min = std::stol(args[0]);
84  range_max = std::stol(args[1]);
85  if (1 + range_max - range_min < 2) {
86  GUM_ERROR(InvalidArgument, "Invalid range for variable " << node);
87  }
88  ds = static_cast< Size >(1 + range_max - range_min);
89  } else { // n[3.14,5,10,12]
90  for (const auto& tick: args) {
91  ticks.push_back(static_cast< GUM_SCALAR >(std::atof(tick.c_str())));
92  }
93  ds = static_cast< Size >(args.size() - 1);
94  }
95  }
96  } else if (*(node.rbegin()) == '}') { // node like "n{one|two|three}"
97  auto posBrack = node.find('{');
98  if (posBrack != std::string::npos) {
99  name = node.substr(0, posBrack);
100  labels = split(node.substr(posBrack + 1, node.size() - posBrack - 2), "|");
101  if (labels.size() < 2) {
102  GUM_ERROR(InvalidArgument, "Not enough labels in node " << node);
103  }
104  if (!hasUniqueElts(labels)) {
105  GUM_ERROR(InvalidArgument, "Duplicate labels in node " << node);
106  }
107  ds = static_cast< Size >(labels.size());
108  }
109  }
110 
111  if (ds == 0) {
112  GUM_ERROR(InvalidArgument, "No value for variable " << name << ".");
113  } else if (ds == 1) {
115  "Only one value for variable " << name
116  << " (2 at least are needed).");
117  }
118 
119  // now we add the node in the BN
120  NodeId idVar;
121  try {
122  idVar = mn.idFromName(name);
123  } catch (gum::NotFound&) {
124  if (!labels.empty()) {
125  idVar = mn.add(LabelizedVariable(name, name, labels));
126  } else if (!ticks.empty()) {
127  idVar = mn.add(DiscretizedVariable< GUM_SCALAR >(name, name, ticks));
128  } else {
129  idVar = mn.add(RangeVariable(name, name, range_min, range_max));
130  }
131  }
132 
133  return idVar;
134  }
135 
136  template < typename GUM_SCALAR >
137  MarkovNet< GUM_SCALAR >
138  MarkovNet< GUM_SCALAR >::fastPrototype(const std::string& dotlike,
139  Size domainSize) {
140  GUM_ERROR(FatalError, "Not Implemented Yet");
141  /*
142  gum::MarkovNet< GUM_SCALAR > mn;
143 
144 
145  for (const auto& chaine: split(dotlike, ";")) {
146  NodeId lastId = 0;
147  bool notfirst = false;
148  for (const auto& souschaine: split(chaine, "->")) {
149  bool forward = true;
150  for (const auto& node: split(souschaine, "<-")) {
151  auto idVar = build_node(mn, node, domainSize);
152  if (notfirst) {
153  if (forward) {
154  mn.addArc(lastId, idVar);
155  forward = false;
156  } else {
157  mn.addArc(idVar, lastId);
158  }
159  } else {
160  notfirst = true;
161  forward = false;
162  }
163  lastId = idVar;
164  }
165  }
166  }
167  mn.generateFactors();
168  mn.setProperty("name", "fastPrototype");
169  return mn;
170  */
171  }
172 
173  template < typename GUM_SCALAR >
174  INLINE MarkovNet< GUM_SCALAR >::MarkovNet() : IMarkovNet< GUM_SCALAR >() {
175  GUM_CONSTRUCTOR(MarkovNet);
176  }
177 
178  template < typename GUM_SCALAR >
179  INLINE MarkovNet< GUM_SCALAR >::MarkovNet(std::string name) :
181  GUM_CONSTRUCTOR(MarkovNet);
182  }
183 
184  template < typename GUM_SCALAR >
185  MarkovNet< GUM_SCALAR >::MarkovNet(const MarkovNet< GUM_SCALAR >& source) :
186  IMarkovNet< GUM_SCALAR >(source), __varMap(source.__varMap) {
187  GUM_CONS_CPY(MarkovNet);
188 
189  __copyFactors(source);
190  }
191 
192  template < typename GUM_SCALAR >
193  MarkovNet< GUM_SCALAR >&
194  MarkovNet< GUM_SCALAR >::operator=(const MarkovNet< GUM_SCALAR >& source) {
195  if (this != &source) {
197  __varMap = source.__varMap;
198  __copyFactors(source);
199  }
200 
201  return *this;
202  }
203 
204  template < typename GUM_SCALAR >
205  MarkovNet< GUM_SCALAR >::~MarkovNet() {
206  __clearFactors();
207  GUM_DESTRUCTOR(MarkovNet);
208  }
209 
210  template < typename GUM_SCALAR >
211  INLINE const DiscreteVariable&
212  MarkovNet< GUM_SCALAR >::variable(NodeId id) const {
213  return __varMap.get(id);
214  }
215 
216  template < typename GUM_SCALAR >
217  INLINE void
218  MarkovNet< GUM_SCALAR >::changeVariableName(NodeId id,
219  const std::string& new_name) {
220  __varMap.changeName(id, new_name);
221  }
222 
223  template < typename GUM_SCALAR >
224  INLINE void MarkovNet< GUM_SCALAR >::changeVariableLabel(
225  NodeId id, const std::string& old_label, const std::string& new_label) {
226  if (variable(id).varType() != VarType::Labelized) {
227  GUM_ERROR(NotFound, "Variable " << id << " is not a LabelizedVariable.");
228  }
229  LabelizedVariable* var = dynamic_cast< LabelizedVariable* >(
230  const_cast< DiscreteVariable* >(&variable(id)));
231 
232  var->changeLabel(var->posLabel(old_label), new_label);
233  }
234 
235  template < typename GUM_SCALAR >
236  INLINE NodeId
237  MarkovNet< GUM_SCALAR >::nodeId(const DiscreteVariable& var) const {
238  return __varMap.get(var);
239  }
240 
241  template < typename GUM_SCALAR >
243  MarkovNet< GUM_SCALAR >::factor(const NodeSet& varIds) const {
244  return *__factors[varIds];
245  }
246 
247  template < typename GUM_SCALAR >
248  const FactorTable< GUM_SCALAR >& MarkovNet< GUM_SCALAR >::factors() const {
249  return __factors;
250  }
251 
252  template < typename GUM_SCALAR >
253  INLINE NodeId MarkovNet< GUM_SCALAR >::add(const std::string& name,
254  unsigned int nbrmod) {
255  if (nbrmod < 2) {
257  "Variable " << name << "needs more than " << nbrmod
258  << " modalities");
259  }
260 
261  RangeVariable v(name, name, 0, nbrmod - 1);
262  return add(v);
263  }
264 
265  template < typename GUM_SCALAR >
266  INLINE NodeId MarkovNet< GUM_SCALAR >::add(const DiscreteVariable& var) {
267  return add(var, graph().nextNodeId());
268  }
269 
270  template < typename GUM_SCALAR >
271  INLINE NodeId MarkovNet< GUM_SCALAR >::add(const DiscreteVariable& var,
272  NodeId id) {
273  __varMap.insert(id, var);
274  this->_graph.addNodeWithId(id);
275  return id;
276  }
277 
278  template < typename GUM_SCALAR >
279  INLINE NodeId
280  MarkovNet< GUM_SCALAR >::idFromName(const std::string& name) const {
281  return __varMap.idFromName(name);
282  }
283 
284  template < typename GUM_SCALAR >
285  INLINE const DiscreteVariable&
286  MarkovNet< GUM_SCALAR >::variableFromName(const std::string& name) const {
287  return __varMap.variableFromName(name);
288  }
289 
290  template < typename GUM_SCALAR >
291  INLINE const VariableNodeMap& MarkovNet< GUM_SCALAR >::variableNodeMap() const {
292  return __varMap;
293  }
294 
295  template < typename GUM_SCALAR >
296  INLINE void MarkovNet< GUM_SCALAR >::erase(const DiscreteVariable& var) {
297  erase(__varMap.get(var));
298  }
299 
300  template < typename GUM_SCALAR >
301  void MarkovNet< GUM_SCALAR >::erase(NodeId varId) {
302  GUM_ERROR(FatalError, "Not implemented yet");
303  /*
304  if (__varMap.exists(varId)) {
305  // Reduce the variable child's CPT
306  const NodeSet& children = this->children(varId);
307 
308  for (const auto c: children) {
309  __probaMap[c]->erase(variable(varId));
310  }
311 
312  delete __probaMap[varId];
313 
314  __probaMap.erase(varId);
315  __varMap.erase(varId);
316  this->_dag.eraseNode(varId);
317  }*/
318  }
319 
320  template < typename GUM_SCALAR >
321  void MarkovNet< GUM_SCALAR >::clear() {
322  if (!this->empty()) {
323  auto l = this->nodes();
324  for (const auto no: l) {
325  this->erase(no);
326  }
327  }
328  }
329 
330 
331  template < typename GUM_SCALAR >
332  INLINE std::ostream& operator<<(std::ostream& output,
333  const MarkovNet< GUM_SCALAR >& mn) {
334  output << mn.toString();
335  return output;
336  }
337 
338  template < typename GUM_SCALAR >
339  INLINE const Potential< GUM_SCALAR >&
340  MarkovNet< GUM_SCALAR >::addFactor(const gum::NodeSet& vars) {
341  if (vars.size() == 0) {
342  GUM_ERROR(InvalidArgument, "Empty factor cannot be added.")
343  }
344 
345  if (__factors.exists(vars)) {
346  GUM_ERROR(InvalidArgument, "A factor for (" << vars << ") already exists.")
347  }
348  auto factor = new Potential< GUM_SCALAR >();
349  for (const auto v: vars) {
350  factor->add(variable(v));
351  }
352  __factors.insert(vars, factor);
353 
354  for (const auto var1: vars)
355  for (const auto var2: vars)
356  if (var1 != var2) this->_graph.addEdge(var1, var2);
357 
358  return *factor;
359  }
360 
361  template < typename GUM_SCALAR >
362  INLINE const Potential< GUM_SCALAR >& MarkovNet< GUM_SCALAR >::addFactor(
363  const std::vector< std::string >& varnames) {
364  NodeSet vars;
365  for (const auto name: varnames) {
366  vars.insert(idFromName(name));
367  }
368  return addFactor(vars);
369  }
370 
371  template < typename GUM_SCALAR >
372  INLINE const Potential< GUM_SCALAR >&
373  MarkovNet< GUM_SCALAR >::addFactor(const Potential< GUM_SCALAR >& factor) {
374  if (factor.nbrDim() == 0) {
375  GUM_ERROR(InvalidArgument, "Empty factor cannot be added.");
376  }
377 
378  NodeSet key;
379  for (Idx i = 0; i < factor.nbrDim(); i++) {
380  key.insert(idFromName(factor.variable(i).name()));
381  }
382  if (__factors.exists(key)) {
383  GUM_ERROR(InvalidArgument, "A factor for (" << key << ") already exists.");
384  }
385  auto* p = new Potential< GUM_SCALAR >(factor);
386  __factors.insert(key, p);
387  return *p;
388  }
389 
390 
391  template < typename GUM_SCALAR >
392  INLINE void MarkovNet< GUM_SCALAR >::generateFactors() const {
393  GUM_ERROR(FatalError, "Not implemented yet");
394  }
395 
396  template < typename GUM_SCALAR >
397  INLINE void MarkovNet< GUM_SCALAR >::generateFactor(const NodeSet& vars) const {
398  GUM_ERROR(FatalError, "Not implemented yet");
399  /*
400  SimpleCPTGenerator< GUM_SCALAR > generator;
401 
402  generator.generateCPT(cpt(node).pos(variable(node)), cpt(node));*/
403  }
404 
405  template < typename GUM_SCALAR >
406  void MarkovNet< GUM_SCALAR >::changeFactor(const NodeSet& vars,
407  Potential< GUM_SCALAR >* newPot) {
408  GUM_ERROR(FatalError, "Not implemented yet");
409  /*
410  if (cpt(id).nbrDim() != newPot->nbrDim()) {
411  GUM_ERROR(OperationNotAllowed,
412  "cannot exchange potentials with different "
413  "dimensions for variable with id "
414  << id);
415  }
416 
417  for (Idx i = 0; i < cpt(id).nbrDim(); i++) {
418  if (&cpt(id).variable(i) != &(newPot->variable(i))) {
419  GUM_ERROR(OperationNotAllowed,
420  "cannot exchange potentials because, for variable with id "
421  << id << ", dimension " << i << " differs. ");
422  }
423  }
424 
425  _unsafeChangePotential(id, newPot);
426  */
427  }
428 
429  template < typename GUM_SCALAR >
430  void MarkovNet< GUM_SCALAR >::__clearFactors() {
431  for (const auto& c: __factors) {
432  delete c.second;
433  }
434  __factors.clear();
435  }
436 
437  template < typename GUM_SCALAR >
438  void MarkovNet< GUM_SCALAR >::__copyFactors(
439  const MarkovNet< GUM_SCALAR >& source) {
440  __clearFactors();
441  for (const auto& factor: source.factors()) {
442  addFactor(*factor.second);
443  }
444  }
445 } /* namespace gum */
aGrUM&#39;s Potential is a multi-dimensional array with tensor operators.
Definition: potential.h:60
virtual Idx nbrDim() const final
Returns the number of vars in the multidimensional container.
Copyright 2005-2020 Pierre-Henri WUILLEMIN () et Christophe GONZALES () info_at_agrum_dot_org.
void changeLabel(Idx pos, const std::string &aLabel) const
change a label for this index
bool hasUniqueElts(std::vector< T > const &x)
class LabelizedVariable
Copyright 2005-2020 Pierre-Henri WUILLEMIN () et Christophe GONZALES () info_at_agrum_dot_org.
Class for discretized random variable.
Copyright 2005-2020 Pierre-Henri WUILLEMIN () et Christophe GONZALES () info_at_agrum_dot_org.
Container used to map discrete variables with nodes.
Copyright 2005-2020 Pierre-Henri WUILLEMIN () et Christophe GONZALES () info_at_agrum_dot_org.
Copyright 2005-2020 Pierre-Henri WUILLEMIN () et Christophe GONZALES () info_at_agrum_dot_org.
NodeId build_node(gum::BayesNet< GUM_SCALAR > &bn, std::string node, gum::Size default_domain_size)
Definition: BayesNet_tpl.h:60
Copyright 2005-2020 Pierre-Henri WUILLEMIN () et Christophe GONZALES () info_at_agrum_dot_org.
Base class for discrete random variable.
Copyright 2005-2020 Pierre-Henri WUILLEMIN () et Christophe GONZALES () info_at_agrum_dot_org.
Definition: agrum.h:25
std::vector< std::string > split(const std::string &str, const std::string &delim)
Split str using the delimiter.
Copyright 2005-2020 Pierre-Henri WUILLEMIN () et Christophe GONZALES () info_at_agrum_dot_org.
The class for generic Hash Tables.
Definition: hashTable.h:679
Representation of a setA Set is a structure that contains arbitrary elements.
Definition: set.h:165
std::ostream & operator<<(std::ostream &output, const BayesNet< GUM_SCALAR > &bn)
Prints map&#39;s DAG in output using the Graphviz-dot format.
Definition: BayesNet_tpl.h:626
Copyright 2005-2020 Pierre-Henri WUILLEMIN () et Christophe GONZALES () info_at_agrum_dot_org.
Copyright 2005-2020 Pierre-Henri WUILLEMIN () et Christophe GONZALES () info_at_agrum_dot_org.
Copyright 2005-2020 Pierre-Henri WUILLEMIN () et Christophe GONZALES () info_at_agrum_dot_org.
virtual const DiscreteVariable & variable(Idx) const final
Returns a const ref to the ith var.
Idx posLabel(const std::string &label) const
return the pos from label
IMarkovNet< GUM_SCALAR > & operator=(const IMarkovNet< GUM_SCALAR > &source)
Copy operator.
Defines a discrete random variable over an integer interval.
Definition: rangeVariable.h:54
Copyright 2005-2020 Pierre-Henri WUILLEMIN () et Christophe GONZALES () info_at_agrum_dot_org.
NodeId nextNodeId()
Returns the next value of an unique counter for PRM&#39;s node id.
Definition: utils_prm.cpp:65
virtual void add(const DiscreteVariable &v) final
Adds a new var to the variables of the multidimensional matrix.
Copyright 2005-2020 Pierre-Henri WUILLEMIN () et Christophe GONZALES () info_at_agrum_dot_org.
Copyright 2005-2020 Pierre-Henri WUILLEMIN () et Christophe GONZALES () info_at_agrum_dot_org.
Copyright 2005-2020 Pierre-Henri WUILLEMIN () et Christophe GONZALES () info_at_agrum_dot_org.
Copyright 2005-2020 Pierre-Henri WUILLEMIN () et Christophe GONZALES () info_at_agrum_dot_org.
Size Idx
Type for indexes.
Definition: types.h:53
Copyright 2005-2020 Pierre-Henri WUILLEMIN () et Christophe GONZALES () info_at_agrum_dot_org.
Copyright 2005-2020 Pierre-Henri WUILLEMIN () et Christophe GONZALES () info_at_agrum_dot_org.
Class representing the minimal interface for Bayesian Network.
Definition: IMarkovNet.h:64
std::size_t Size
In aGrUM, hashed values are unsigned long int.
Definition: types.h:48
Size size() const noexcept
Returns the number of elements in the set.
Definition: set_tpl.h:703
const std::string & name() const
returns the name of the variable
Copyright 2005-2020 Pierre-Henri WUILLEMIN () et Christophe GONZALES () info_at_agrum_dot_org.
Size NodeId
Type for node ids.
Definition: graphElements.h:98
void insert(const Key &k)
Inserts a new element into the set.
Definition: set_tpl.h:615
#define GUM_ERROR(type, msg)
Definition: exceptions.h:55