aGrUM  0.18.1
a C++ library for (probabilistic) graphical models
LpInterface_tpl.h
Go to the documentation of this file.
1 
23 #include "LpInterface.h"
24 
25 namespace gum {
26  namespace credal {
27  namespace lp {
32  LpCol::LpCol(unsigned int id) : id__(id) { GUM_CONSTRUCTOR(LpCol); }
33 
34  LpCol::LpCol(const LpCol& col) : id__(col.id__) { GUM_CONS_CPY(LpCol); }
35 
36  LpCol::~LpCol() { GUM_DESTRUCTOR(LpCol); }
37 
38  unsigned int LpCol::id() const { return id__; }
39 
40  bool LpCol::operator<(const LpCol& col) const { return (id__ < col.id()); }
41 
42  bool LpCol::operator==(const LpCol& col) const { return (id__ == col.id()); }
43 
44  bool LpCol::operator!=(const LpCol& col) const { return (id__ != col.id()); }
45 
46  LpCol& LpCol::operator=(const LpCol& col) {
47  id__ = col.id__;
48 
49  return *this;
50  }
51 
52  std::ostream& operator<<(std::ostream& out, const LpCol& col) {
53  out << col.toString();
54  return out;
55  }
56 
57  std::string LpCol::toString() const { return "V" + std::to_string(id__); }
58  } // namespace lp
59 
60  } // namespace credal
61 
62 
63  namespace credal {
64  namespace lp {
65 
71  ileft__(false), imiddle__(false), iright__(false), lValue__(0.),
72  mValue__(0.), rValue__(0.), lCoeffs__(new HashTable< LpCol, double >()),
73  mCoeffs__(new HashTable< LpCol, double >()),
74  rCoeffs__(new HashTable< LpCol, double >()) {
75  GUM_CONSTRUCTOR(LpExpr);
76  }
77 
78  LpExpr::LpExpr(const LpExpr& expr) :
79  ileft__(expr.ileft__), imiddle__(expr.imiddle__),
80  iright__(expr.iright__), lValue__(expr.lValue__),
81  mValue__(expr.mValue__), rValue__(expr.rValue__),
82  lCoeffs__(new HashTable< LpCol, double >(*expr.lCoeffs__)),
83  mCoeffs__(new HashTable< LpCol, double >(*expr.mCoeffs__)),
84  rCoeffs__(new HashTable< LpCol, double >(*expr.rCoeffs__)) {
85  GUM_CONS_CPY(LpExpr);
86  }
87 
88  LpExpr::LpExpr(const LpExpr& expr,
89  bool copyLeft,
90  bool copyMiddle,
91  bool copyRight) :
92  ileft__(false),
93  imiddle__(false), iright__(false), lValue__(0.), mValue__(0.),
94  rValue__(0.), lCoeffs__(nullptr), mCoeffs__(nullptr),
95  rCoeffs__(nullptr) {
96  if (copyLeft) {
98  lValue__ = expr.lValue__;
99  ileft__ = true;
100  } else
102 
103  if (copyMiddle) {
105  mValue__ = expr.mValue__;
106  imiddle__ = true;
107  } else
109 
110  if (copyRight) {
112  rValue__ = expr.rValue__;
113  iright__ = true;
114  } else
116 
117  GUM_CONS_CPY(LpExpr);
118  }
119 
121  ileft__(expr.ileft__), imiddle__(expr.imiddle__),
122  iright__(expr.iright__), lValue__(expr.lValue__),
123  mValue__(expr.mValue__), rValue__(expr.rValue__),
124  lCoeffs__(expr.lCoeffs__), mCoeffs__(expr.mCoeffs__),
125  rCoeffs__(expr.rCoeffs__) {
126  expr.lCoeffs__ = nullptr;
127  expr.mCoeffs__ = nullptr;
128  expr.rCoeffs__ = nullptr;
129 
130  GUM_CONS_CPY(LpExpr);
131  }
132 
134  bool copyLeft,
135  bool copyMiddle,
136  bool copyRight) :
137  ileft__(false),
138  imiddle__(false), iright__(false), lValue__(0.), mValue__(0.),
139  rValue__(0.), lCoeffs__(nullptr), mCoeffs__(nullptr),
140  rCoeffs__(nullptr) {
141  if (copyLeft) {
142  swap(lCoeffs__, expr.lCoeffs__);
143  lValue__ = expr.lValue__;
144  ileft__ = true;
145  } else
147 
148  if (copyMiddle) {
149  swap(mCoeffs__, expr.mCoeffs__);
150  mValue__ = expr.mValue__;
151  imiddle__ = true;
152  } else
154 
155  if (copyRight) {
156  swap(rCoeffs__, expr.rCoeffs__);
157  rValue__ = expr.rValue__;
158  iright__ = true;
159  } else
161 
162  GUM_CONS_CPY(LpExpr);
163  }
164 
166  delete lCoeffs__;
167  delete mCoeffs__;
168  delete rCoeffs__;
169 
170  GUM_DESTRUCTOR(LpExpr);
171  }
172 
174  clear();
175 
176  mCoeffs__->insert(rhs, 1.);
177  imiddle__ = true;
178 
179  return *this;
180  }
181 
184  if (this == &rhs) return *this;
185 
186  *lCoeffs__ = *rhs.lCoeffs__;
187  *mCoeffs__ = *rhs.mCoeffs__;
188  *rCoeffs__ = *rhs.rCoeffs__;
189 
190  lValue__ = rhs.lValue__;
191  mValue__ = rhs.mValue__;
192  rValue__ = rhs.rValue__;
193 
194  ileft__ = rhs.ileft__;
195  imiddle__ = rhs.imiddle__;
196  iright__ = rhs.iright__;
197 
198  return *this;
199  }
200 
203  if (this == &rhs) return *this;
204 
205  swap(lCoeffs__, rhs.lCoeffs__);
206  swap(mCoeffs__, rhs.mCoeffs__);
207  swap(rCoeffs__, rhs.rCoeffs__);
208 
209  lValue__ = rhs.lValue__;
210  mValue__ = rhs.mValue__;
211  rValue__ = rhs.rValue__;
212 
213  ileft__ = rhs.ileft__;
214  imiddle__ = rhs.imiddle__;
215  iright__ = rhs.iright__;
216 
217  return *this;
218  }
219 
220  template < typename SCALAR >
221  LpExpr& LpExpr::operator=(const SCALAR& rhs) {
222  clear();
223 
224  mValue__ = rhs;
225  imiddle__ = true;
226 
227  return *this;
228  }
229 
231  if (ileft__ || iright__)
233  "expr::operator+= (expr) : <= present on one side of expr");
234 
235  if (!imiddle__) imiddle__ = true;
236 
237  mCoeffs__->getWithDefault(rhs, 0.) += 1.;
238 
239  return *this;
240  }
241 
243  if (ileft__ || iright__ || rhs.ileft__ || rhs.iright__)
245  "expr::operator+= (rhs) : <= present "
246  "on one side of rhs and/or expr");
247 
248  if (!imiddle__) imiddle__ = true;
249 
250  for (const auto& elt: *rhs.mCoeffs__)
251  mCoeffs__->getWithDefault(elt.first, 0.) += elt.second;
252 
253  mValue__ += rhs.mValue__;
254 
255  return *this;
256  }
257 
259  if (ileft__ || iright__ || rhs.ileft__ || rhs.iright__)
261  "expr::operator+= (rhs) : <= present "
262  "on one side of rhs and/or expr");
263 
264  if (!imiddle__) {
265  imiddle__ = true;
266 
267  mValue__ = rhs.mValue__;
268 
269  swap(mCoeffs__, rhs.mCoeffs__);
270 
271  return *this;
272  }
273 
274  for (const auto& elt: *rhs.mCoeffs__)
275  mCoeffs__->getWithDefault(elt.first, 0.) += elt.second;
276 
277  mValue__ += rhs.mValue__;
278 
279  return *this;
280  }
281 
282  template < typename T >
283  LpExpr& LpExpr::operator+=(const T& rhs) {
284  if (ileft__ || iright__)
286  "expr::operator+= (expr) : <= present on one side of expr");
287 
288  if (!imiddle__) imiddle__ = true;
289 
290  mValue__ += rhs;
291 
292  return *this;
293  }
294 
296  if (ileft__ || iright__)
298  "expr::operator-= (rhs) : <= present in one of expr");
299 
300  if (!imiddle__) imiddle__ = true;
301 
302  mCoeffs__->getWithDefault(rhs, 0.) -= 1.;
303 
304  return *this;
305  }
306 
308  if (ileft__ || iright__ || rhs.ileft__ || rhs.iright__)
309  GUM_ERROR(
311  "expr::operator-= (rhs) : <= present in one of rhs and/or expr");
312 
313  if (!imiddle__) imiddle__ = true;
314 
315  for (const auto& elt: *rhs.mCoeffs__)
316  mCoeffs__->getWithDefault(elt.first, 0.) -= elt.second;
317 
318  mValue__ -= rhs.mValue__;
319 
320  return *this;
321  }
322 
323  template < typename T >
324  LpExpr& LpExpr::operator-=(const T& rhs) {
325  if (ileft__ || iright__)
327  "expr::operator-= (rhs) : <= present in one of expr");
328 
329  if (!imiddle__) imiddle__ = true;
330 
331  mValue__ -= rhs;
332 
333  return *this;
334  }
335 
336  std::ostream& operator<<(std::ostream& out, const LpExpr& expr) {
337  out << expr.toString();
338  return out;
339  }
340 
341  void LpExpr::addSide__(const LpCol& from) {
342  if (!ileft__) {
343  lCoeffs__->insert(from, 1.);
344  ileft__ = true;
345  } else if (!imiddle__) {
346  mCoeffs__->insert(from, 1.);
347  imiddle__ = true;
348  } else if (!iright__) {
349  rCoeffs__->insert(from, 1.);
350  iright__ = true;
351  } else
353  "LpExpr::setSide ( const LpCol & from "
354  ") : too many <= ; no free side");
355  }
356 
357  void LpExpr::addSide__(const LpExpr& from) {
358  if (ileft__ && iright__ && from.imiddle__)
360  "LpExpr::setSide ( const LpCol & from "
361  ") : too many <= ; no free side");
362 
364  if (!from.imiddle__) return;
365 
369  if (!from.ileft__ && !from.iright__) {
370  if (!ileft__) {
371  *lCoeffs__ = *from.mCoeffs__;
372  lValue__ = from.mValue__;
373  ileft__ = true;
374 
375  return;
376  } else if (!imiddle__) {
377  *mCoeffs__ = *from.mCoeffs__;
378  mValue__ = from.mValue__;
379  imiddle__ = true;
380 
381  return;
382  } else if (!iright__) {
383  *rCoeffs__ = *from.mCoeffs__;
384  rValue__ = from.mValue__;
385  iright__ = true;
386 
387  return;
388  } else
390  "LpExpr::setSide ( const LpCol & from ) "
391  ": too many <= ; no free side");
392  }
395  else if (from.ileft__ && !from.iright__) {
396  if (!ileft__) {
397  *lCoeffs__ = *from.lCoeffs__;
398  lValue__ = from.lValue__;
399  ileft__ = true;
400 
401  *mCoeffs__ = *from.mCoeffs__;
402  mValue__ = from.mValue__;
403  imiddle__ = true;
404 
405  return;
406  } else if (!imiddle__ && !iright__) {
407  *mCoeffs__ = *from.lCoeffs__;
408  mValue__ = from.lValue__;
409  imiddle__ = true;
410 
411  *rCoeffs__ = *from.mCoeffs__;
412  rValue__ = from.mValue__;
413  iright__ = true;
414 
415  return;
416  } else
418  "LpExpr::setSide ( const LpCol & from ) "
419  ": too many <= ; no free side");
420  }
423  else if (from.ileft__ && from.iright__) {
424  if (ileft__ || imiddle__ || iright__)
426  "LpExpr::setSide ( const LpCol & from ) "
427  ": too many <= ; no free side");
428 
429  *this = from;
430 
431  return;
432  } else
434  "LpExpr::setSide ( const LpCol & from "
435  ") : too many <= ; no free side");
436  }
437 
438  void LpExpr::addSide__(LpExpr&& from) {
440  if (ileft__ && iright__ && from.imiddle__)
442  "LpExpr::setSide ( const LpCol & from "
443  ") : too many <= ; no free side");
444 
446  if (!from.imiddle__) return;
447 
451  if (!from.ileft__ && !from.iright__) {
452  if (!ileft__) {
454  swap(lCoeffs__, from.mCoeffs__);
455  lValue__ = from.mValue__;
456  ileft__ = true;
457 
458  return;
459  } else if (!imiddle__) {
461  swap(mCoeffs__, from.mCoeffs__);
462  mValue__ = from.mValue__;
463  imiddle__ = true;
464 
465  return;
466  } else if (!iright__) {
468  swap(rCoeffs__, from.mCoeffs__);
469  rValue__ = from.mValue__;
470  iright__ = true;
471 
472  return;
473  } else
475  "LpExpr::setSide ( const LpCol & from ) "
476  ": too many <= ; no free side");
477  }
480  else if (from.ileft__ && !from.iright__) {
481  if (!ileft__) {
483  swap(lCoeffs__, from.lCoeffs__);
484  lValue__ = from.lValue__;
485  ileft__ = true;
486 
488  swap(mCoeffs__, from.mCoeffs__);
489  mValue__ = from.mValue__;
490  imiddle__ = true;
491 
492  return;
493  } else if (!imiddle__ && !iright__) {
495  swap(mCoeffs__, from.lCoeffs__);
496  mValue__ = from.lValue__;
497  imiddle__ = true;
498 
500  swap(rCoeffs__, from.mCoeffs__);
501  rValue__ = from.mValue__;
502  iright__ = true;
503 
504  return;
505  } else
507  "LpExpr::setSide ( const LpCol & from ) "
508  ": too many <= ; no free side");
509  }
512  else if (from.ileft__ && from.iright__) {
513  if (ileft__ || imiddle__ || iright__)
515  "LpExpr::setSide ( const LpCol & from ) "
516  ": too many <= ; no free side");
517 
518  *this = std::move(from);
519 
520  return;
521  } else
523  "LpExpr::setSide ( const LpCol & from "
524  ") : too many <= ; no free side");
525  }
526 
527  template < typename SCALAR >
528  void LpExpr::addSide__(const SCALAR& from) {
529  if (!ileft__) {
530  lValue__ = from;
531  ileft__ = true;
532  } else if (!imiddle__) {
533  mValue__ = from;
534  imiddle__ = true;
535  } else if (!iright__) {
536  rValue__ = from;
537  iright__ = true;
538  } else
540  "LpExpr::setSide ( const LpCol & from "
541  ") : too many <= ; no free side");
542  }
543 
544  void LpExpr::clear() {
545  lCoeffs__->clear();
546  mCoeffs__->clear();
547  rCoeffs__->clear();
548 
549  lValue__ = 0.;
550  mValue__ = 0.;
551  rValue__ = 0.;
552 
553  ileft__ = false;
554  imiddle__ = false;
555  iright__ = false;
556  }
557 
558  std::string LpExpr::toString() const {
559  std::ostringstream s;
560 
561  s << std::endl << "left side : " << std::endl;
562 
563  if (lCoeffs__ != nullptr)
564  for (const auto& elt: *lCoeffs__)
565  s << elt.first.toString() << " " << elt.second << " | ";
566 
567  s << std::endl << "middle side : " << std::endl;
568 
569  if (mCoeffs__ != nullptr)
570  for (const auto& elt: *mCoeffs__)
571  s << elt.first.toString() << " " << elt.second << " | ";
572 
573  s << std::endl << "right side : " << std::endl;
574 
575  if (rCoeffs__ != nullptr)
576  for (const auto& elt: *rCoeffs__)
577  s << elt.first.toString() << " " << elt.second << " | ";
578 
579  s << std::endl
580  << "lvalue : " << lValue__ << std::endl
581  << "mvalue : " << mValue__ << std::endl
582  << "rvalue : " << rValue__ << std::endl;
583 
584  s << std::endl;
585 
586  return s.str();
587  }
588 
593  LpRow::LpRow(const LpExpr& expr, const std::vector< LpCol >& cols) :
594  coeffs__(nullptr) {
595  // we write 0 <= Ax + b from Ex + f <= Cx + d
596  if (expr.ileft__ && !expr.iright__) {
598 
599  for (const auto& col: cols) {
600  double col_coeff = 0.;
601 
602  // from left side to middle side : 0 <= middle - left
603  if (expr.lCoeffs__->exists(col))
604  col_coeff = expr.lCoeffs__->operator[](col);
605 
606  coeffs__->getWithDefault(col, 0.) -= col_coeff;
607  }
608 
609  cste__ = expr.mValue__ - expr.lValue__;
610  } else if (expr.iright__ && !expr.ileft__) {
612 
613  for (const auto& col: cols) {
614  double col_coeff = 0;
615 
616  // from middle side to right side : 0 <= right - middle
617  if (expr.mCoeffs__->exists(col))
618  col_coeff = expr.mCoeffs__->operator[](col);
619 
620  coeffs__->getWithDefault(col, 0.) -= col_coeff;
621  }
622 
623  cste__ = expr.rValue__ - expr.mValue__;
624  } else
626  "expr : " << expr.toString()
627  << "is not a valid inequality; no <= detected");
628 
629  if (coeffs__->size() == 0)
631  "expr : " << expr.toString()
632  << "is not a valid inequality; "
633  "no variable in inequality, "
634  "only constants");
635 
636  GUM_CONSTRUCTOR(LpRow);
637  }
638 
639  LpRow::LpRow(LpExpr&& expr, const std::vector< LpCol >& cols) :
640  coeffs__(nullptr) {
642  if (expr.ileft__ && !expr.iright__) {
643  swap(coeffs__, expr.mCoeffs__);
644 
645  for (const auto& col: cols) {
646  double col_coeff = 0;
647 
648  if (expr.lCoeffs__->exists(col))
649  col_coeff = expr.lCoeffs__->operator[](col);
650 
651  coeffs__->getWithDefault(col, 0.) -= col_coeff;
652  }
653 
654  cste__ = expr.mValue__ - expr.lValue__;
655  } else if (expr.iright__ && !expr.ileft__) {
656  swap(coeffs__, expr.rCoeffs__);
657 
658  for (const auto& col: cols) {
659  double col_coeff = 0;
660 
661  if (expr.mCoeffs__->exists(col))
662  col_coeff = expr.mCoeffs__->operator[](col);
663 
664  coeffs__->getWithDefault(col, 0.) -= col_coeff;
665  }
666 
667  cste__ = expr.rValue__ - expr.mValue__;
668  } else
670  "expr : " << expr.toString()
671  << "is not a valid inequality; no <= detected");
672 
673  if (coeffs__->size() == 0)
675  "expr : " << expr.toString()
676  << "is not a valid inequality; "
677  "no variable in inequality, "
678  "only constants");
679 
680  GUM_CONSTRUCTOR(LpRow);
681  }
682 
683  LpRow::LpRow(const LpRow& row) :
684  cste__(row.cste__),
685  coeffs__(new HashTable< LpCol, double >(*row.coeffs__)) {
686  GUM_CONS_CPY(LpRow);
687  }
688 
690  row.coeffs__ = nullptr;
691 
692  GUM_CONS_CPY(LpRow);
693  }
694 
696  delete coeffs__;
697 
698  GUM_DESTRUCTOR(LpRow);
699  }
700 
701  LpRow& LpRow::operator=(const LpRow& row) {
702  cste__ = row.cste__;
703  *coeffs__ = *row.coeffs__;
704  return *this;
705  }
706 
708  cste__ = row.cste__;
709  swap(coeffs__, row.coeffs__);
710  return *this;
711  }
712 
713  std::ostream& operator<<(std::ostream& out, const LpRow& row) {
714  out << row.toString();
715  return out;
716  }
717 
718  std::string LpRow::toString() const {
719  std::ostringstream s;
720 
721  s << "0 <= " << cste__;
722 
723  if (coeffs__ != nullptr) {
724  for (const auto& elt: *coeffs__) {
725  if (elt.second > 0) {
726  if (elt.second != 1) {
727  s << " +" << elt.second << "*" << elt.first.toString();
728  } else {
729  s << " +" << elt.first.toString();
730  }
731  } else {
732  if (elt.second < 0) {
733  if (elt.second != -1) {
734  s << " " << elt.second << "*" << elt.first.toString();
735  } else {
736  s << " -" << elt.first.toString();
737  }
738  }
739  }
740  }
741  }
742 
743  return s.str();
744  }
745 
749  template < typename GUM_SCALAR >
751  positivity__ = false;
752  sumIsOne__ = false;
753  GUM_CONSTRUCTOR(LpInterface);
754  }
755 
756  template < typename GUM_SCALAR >
758  const LpInterface< GUM_SCALAR >& from) :
759  cols__(from.cols__),
760  positivity__(from.positivity__), sumIsOne__(from.sumIsOne__) {
761  rows__.resize(from.rows__.size());
762 
763  for (unsigned int i = 0, end = from.rows__.size(); i < end; i++)
764  rows__[i] = new LpRow(*from.rows__[i]);
765 
766  GUM_CONS_CPY(LpInterface);
767  }
768 
769  template < typename GUM_SCALAR >
772  rows__.swap(from.rows__);
773  cols__.swap(from.cols__);
774  GUM_CONS_CPY(LpInterface);
775  }
776 
777  template < typename GUM_SCALAR >
779  for (const auto row: rows__)
780  delete row;
781 
782  GUM_DESTRUCTOR(LpInterface);
783  }
784 
785  template < typename GUM_SCALAR >
787  const LpInterface< GUM_SCALAR >& from) {
789  for (const auto& row: rows__)
790  delete row;
791 
792  rows__.clear();
793  rows__.shrink_to_fit();
794 
795  rows__.resize(from.rows__.size());
796 
797  for (unsigned int i = 0, end = from.rows__.size(); i < end; i++)
798  rows__[i] = new LpRow(*from.rows__[i]);
799 
800  cols__ = from.cols__;
801  positivity__ = from.positivity__;
802  sumIsOne__ = from.sumIsOne__;
803 
804  return *this;
805  }
806 
807  template < typename GUM_SCALAR >
810  rows__.swap(from.rows__);
811  cols__.swap(from.cols__);
812 
813  positivity__ = from.positivity__;
814  sumIsOne__ = from.sumIsOne__;
815 
816  return *this;
817  }
818 
819  template < typename T >
820  std::ostream& operator<<(std::ostream& out, const LpInterface< T >& lpi) {
821  out << lpi.toString();
822  return out;
823  }
824 
825  template < typename GUM_SCALAR >
827  LpCol col((unsigned int)cols__.size());
828 
829  cols__.push_back(col);
830 
831  return col;
832  }
833 
834  template < typename GUM_SCALAR >
835  std::vector< LpCol >
836  LpInterface< GUM_SCALAR >::addCols(const unsigned int& cols) {
837  if (cols < 1)
839  "LpInterface::addCols ( cols ) : cols "
840  "needs must be equal or greater than 1 : "
841  << cols << " < 1");
842 
843  for (unsigned int i = 0; i < cols; i++) {
844  cols__.push_back(LpCol((unsigned int)cols__.size()));
845  }
846 
847  return cols__;
848  }
849 
850  template < typename GUM_SCALAR >
852  if (!expr.ileft__ && !expr.iright__)
854  "addRow ( const LpExpr & expr ) : expr : "
855  << expr.toString() << "is not an inequality.");
856 
857  if ((expr.ileft__ && !expr.iright__) || (!expr.ileft__ && expr.iright__)) {
858  rows__.push_back(new LpRow(expr, cols__));
859  } else {
860  LpExpr lexpr(expr, true, true, false);
861  LpExpr rexpr(expr, false, true, true);
862 
863  rows__.push_back(
864  new LpRow(std::move(lexpr),
865  cols__));
866  rows__.push_back(
867  new LpRow(std::move(rexpr),
868  cols__));
869  }
870  }
871 
872  template < typename GUM_SCALAR >
874  if (!expr.ileft__ && !expr.iright__)
876  "addRow ( const LpExpr & expr ) : expr : "
877  << expr.toString() << "is not an inequality.");
878 
879  if ((expr.ileft__ && !expr.iright__) || (!expr.ileft__ && expr.iright__)) {
880  rows__.push_back(new LpRow(std::move(expr), cols__));
881  } else {
882  LpExpr lexpr(std::move(expr), true, true, false);
883 
885  LpExpr rexpr(std::move(expr), false, false, true);
886 
888 
889  *rexpr.mCoeffs__ = *lexpr.mCoeffs__;
890  rexpr.mValue__ = lexpr.mValue__;
891  rexpr.imiddle__ = true;
892 
893  rows__.push_back(
894  new LpRow(std::move(lexpr),
895  cols__));
896  rows__.push_back(
897  new LpRow(std::move(rexpr),
898  cols__));
899  }
900  }
901 
902  template < typename GUM_SCALAR >
904  if (positivity__) return;
905 
906  for (const auto& col: cols__)
907  addRow(0 <= col);
908 
909  positivity__ = true;
910  }
911 
912  template < typename GUM_SCALAR >
914  if (sumIsOne__) return;
915 
916  LpExpr expr;
917 
918  for (const auto& col: cols__)
919  expr += col;
920 
921  addRow(1 <= std::move(expr) <= 1);
922 
923  sumIsOne__ = true;
924  }
925 
926  template < typename GUM_SCALAR >
928  if (positivity__ && sumIsOne__) {
929  return;
930  } else if (positivity__ && !sumIsOne__) {
931  addSumIsOne();
932  return;
933  } else if (!positivity__ && sumIsOne__) {
934  addPositivity();
935  return;
936  }
937 
938  // we can do both with one loop, don't call the above functions.
939  // addPositivity();
940  // addSumIsOne();
941  LpExpr expr;
942 
943  for (const auto& col: cols__) {
944  addRow(0 <= col);
945  expr += col;
946  }
947 
948  addRow(1 <= std::move(expr) <= 1);
949 
950  sumIsOne__ = true;
951  positivity__ = true;
952  }
953 
954  template < typename GUM_SCALAR >
955  std::vector< std::vector< GUM_SCALAR > > LpInterface< GUM_SCALAR >::solve() {
957 
958  lrs.setUpH((unsigned int)cols__.size());
959 
960  std::vector< std::vector< GUM_SCALAR > > lrsMatrix;
961 
962  for (const auto& row: rows__) {
963  std::vector< GUM_SCALAR > expandedRow(cols__.size() + 1, 0);
964 
965  expandedRow[0] = row->cste__;
966 
967  for (const auto& elt: *row->coeffs__)
968  expandedRow[elt.first.id() + 1] = elt.second;
969 
970  lrsMatrix.push_back(expandedRow);
971  }
972 
973  lrs.fillMatrix(lrsMatrix);
974 
975  lrs.H2V();
976 
977  return lrs.getOutput();
978  }
979 
980  template < typename GUM_SCALAR >
981  std::vector< LpCol > LpInterface< GUM_SCALAR >::getCols() const {
982  return cols__;
983  }
984 
985  template < typename GUM_SCALAR >
987  std::ostringstream s;
988 
989  s << std::endl << std::endl << "Variables : " << std::endl;
990 
991  for (const auto& col: cols__)
992  s << " " << col.toString();
993 
994  s << std::endl;
995 
996  for (const auto& row: rows__)
997  s << std::endl << row->toString();
998 
999  s << std::endl << std::endl;
1000 
1001  return s.str();
1002  }
1003 
1004  template < typename GUM_SCALAR >
1006  for (const auto& row: rows__)
1007  delete row;
1008 
1009  rows__.clear();
1010  rows__.shrink_to_fit();
1011 
1015  cols__.clear();
1016  cols__.shrink_to_fit();
1017 
1018  positivity__ = false;
1019  sumIsOne__ = false;
1020  }
1021 
1022  template < typename GUM_SCALAR >
1024  for (const auto& row: rows__)
1025  delete row;
1026 
1027  rows__.clear();
1028  rows__.shrink_to_fit();
1029 
1030  positivity__ = false;
1031  sumIsOne__ = false;
1032  }
1033 
1037  a = b;
1038  b = tmp;
1039  }
1040 
1042  template < typename T2 >
1043  LpExpr operator+(LpExpr&& lhs, const T2& rhs) {
1044  LpExpr expr = std::move(lhs);
1045  expr += rhs;
1046 
1047  return expr;
1048  }
1049 
1050  template < typename T2 >
1051  LpExpr operator+(const LpExpr& lhs, const T2& rhs) {
1052  LpExpr expr(lhs);
1053  expr += rhs;
1054 
1055  return expr;
1056  }
1057 
1058  template < typename T1, forbidden_type< T1, LpExpr > >
1059  LpExpr operator+(const T1& lhs, LpExpr&& rhs) {
1060  LpExpr expr = std::move(rhs);
1061  ;
1062  expr += lhs;
1063 
1064  return expr;
1065  }
1066 
1067  template < typename T1, forbidden_type< T1, LpExpr > >
1068  LpExpr operator+(const T1& lhs, LpExpr& rhs) {
1069  LpExpr expr(rhs);
1070  expr += lhs;
1071 
1072  return expr;
1073  }
1074 
1075  template < typename T2, forbidden_type< T2, LpExpr > >
1076  LpExpr operator+(const LpCol& lhs, const T2& rhs) {
1077  LpExpr expr;
1078  expr += lhs;
1079  expr += rhs;
1080 
1081  return expr;
1082  }
1083 
1084  template < typename T1,
1087  LpExpr operator+(const T1& lhs, const LpCol& rhs) {
1088  LpExpr expr;
1089  expr += rhs;
1090  expr += lhs;
1091 
1092  return expr;
1093  }
1094 
1096  template < typename T2 >
1097  LpExpr operator-(LpExpr&& lhs, const T2& rhs) {
1098  LpExpr expr = std::move(lhs);
1099  expr -= rhs;
1100 
1101  return expr;
1102  }
1103 
1104  template < typename T2 >
1105  LpExpr operator-(const LpExpr& lhs, const T2& rhs) {
1106  LpExpr expr(lhs);
1107  expr -= rhs;
1108 
1109  return expr;
1110  }
1111 
1112  template < typename T1, forbidden_type< T1, LpExpr > >
1113  LpExpr operator-(const T1& lhs, LpExpr&& rhs) {
1114  LpExpr expr;
1115  expr += std::move(rhs);
1116  ;
1117  expr -= lhs;
1118 
1119  return expr;
1120  }
1121 
1122  template < typename T1, forbidden_type< T1, LpExpr > >
1123  LpExpr operator-(const T1& lhs, LpExpr& rhs) {
1124  LpExpr expr;
1125  expr += rhs;
1126  expr -= lhs;
1127 
1128  return expr;
1129  }
1130 
1131  template < typename T2, forbidden_type< T2, LpExpr > >
1132  LpExpr operator-(const LpCol& lhs, const T2& rhs) {
1133  LpExpr expr;
1134  expr += lhs;
1135  expr -= rhs;
1136 
1137  return expr;
1138  }
1139 
1140  template < typename T1,
1141  forbidden_type< T1, LpExpr >,
1143  LpExpr operator-(const T1& lhs, const LpCol& rhs) {
1144  LpExpr expr;
1145  expr += rhs;
1146  expr -= lhs;
1147 
1148  return expr;
1149  }
1150 
1152  template < typename SCALAR >
1153  INLINE LpExpr LpExpr::multiply(const SCALAR& lhs, const LpCol& rhs) {
1154  LpExpr expr;
1155  expr.mCoeffs__->insert(rhs, lhs);
1156  expr.imiddle__ = true;
1157  return expr;
1158  }
1159 
1160  template < typename SCALAR >
1161  LpExpr operator*(const SCALAR& lhs, const LpCol& rhs) {
1162  return LpExpr::multiply(lhs, rhs);
1163  }
1164 
1165  template < typename SCALAR >
1166  LpExpr operator*(const LpCol& lhs, const SCALAR& rhs) {
1167  return LpExpr::multiply(rhs, lhs);
1168  }
1169 
1171  template < typename T1, typename T2 >
1172  INLINE LpExpr LpExpr::lessThan(T1&& lhs, T2&& rhs) {
1173  LpExpr expr;
1174  expr.addSide__(std::forward< T1 >(lhs));
1175  expr.addSide__(std::forward< T2 >(rhs));
1176  return expr;
1177  }
1178 
1179  // const lvalue
1180  template < typename T2 >
1181  LpExpr operator<=(const LpExpr& lhs, T2&& rhs) {
1182  return LpExpr::lessThan(lhs, std::forward< T2 >(rhs));
1183  }
1184 
1185  template < typename T2 >
1186  LpExpr operator<=(const LpCol& lhs, T2&& rhs) {
1187  return LpExpr::lessThan(lhs, std::forward< T2 >(rhs));
1188  }
1189 
1190  template < typename T1,
1193  LpExpr operator<=(T1&& lhs, const LpExpr& rhs) {
1194  return LpExpr::lessThan(std::forward< T1 >(lhs), rhs);
1195  }
1196 
1197  template < typename T1,
1198  forbidden_type< T1, LpExpr& >,
1200  LpExpr operator<=(T1&& lhs, const LpCol& rhs) {
1201  return LpExpr::lessThan(std::forward< T1 >(lhs), rhs);
1202  }
1203 
1204  // rvaue
1205  template < typename T2 >
1206  LpExpr operator<=(LpExpr&& lhs, T2&& rhs) {
1207  return LpExpr::lessThan(std::move(lhs), std::forward< T2 >(rhs));
1208  }
1209 
1210  template < typename T2 >
1211  LpExpr operator<=(LpCol&& lhs, T2&& rhs) {
1212  return LpExpr::lessThan(std::move(lhs), std::forward< T2 >(rhs));
1213  }
1214 
1215  template < typename T1,
1216  forbidden_type< T1, LpExpr >,
1218  LpExpr operator<=(T1&& lhs, LpExpr&& rhs) {
1219  return LpExpr::lessThan(std::forward< T1 >(lhs), std::move(rhs));
1220  }
1221 
1222  template < typename T1,
1223  forbidden_type< T1, LpExpr >,
1225  LpExpr operator<=(T1&& lhs, LpCol&& rhs) {
1226  return LpExpr::lessThan(std::forward< T1 >(lhs), std::move(rhs));
1227  }
1228  } // namespace lp
1229 
1230  } // namespace credal
1231 
1232 } // namespace gum
~LpRow()
Default destructor.
std::vector< std::vector< GUM_SCALAR > > solve()
Solve the linear program (H-representation of the polytope) by enumeration (of the polytope vertices)...
void addProba()
Add positivity constraints and sum of variables is 1 ( probability constraints )
static LpExpr lessThan(T1 &&lhs, T2 &&rhs)
double mValue__
The constant on the middle side L : L <= M <= R.
Definition: LpInterface.h:428
std::string toString() const
Get the string representation of a calling variable.
bool operator==(const LpCol &col) const
Test of equality == between two variables.
void fillMatrix(const std::vector< std::vector< GUM_SCALAR > > &matrix)
Fill the H-representation from the matrix given in argument.
HashTable< LpCol, double > * mCoeffs__
The coefficients of each variable on the middle side L : L <= M <= R.
Definition: LpInterface.h:439
friend std::ostream & operator<<(std::ostream &out, const LpRow &row)
Overload of << to use with output streams ( such as std::cout << ).
void addRow(const LpExpr &expr)
Add rows to the linear program according to a given expression ( which must be at least an inequality...
void swap(HashTable< LpCol, double > *&a, HashTable< LpCol, double > *&b)
Swap the addresses of two pointers to hashTables.
LpCol(unsigned int id)
Default constructor.
Copyright 2005-2020 Pierre-Henri WUILLEMIN() & Christophe GONZALES() info_at_agrum_dot_org.
LpExpr operator<=(const LpExpr &lhs, T2 &&rhs)
Overload of operator <= between anything and anything.
LpRow & operator=(const LpRow &row)
void addPositivity()
Add positivity constraints for all variables.
Copyright 2005-2020 Pierre-Henri WUILLEMIN() & Christophe GONZALES() info_at_agrum_dot_org.
Definition: agrum.h:25
void addSumIsOne()
Add sum of variables is 1 constraints.
unsigned int id__
Variable id.
Definition: LpInterface.h:163
The class for generic Hash Tables.
Definition: hashTable.h:679
HashTable< LpCol, double > * coeffs__
The coefficients of the variables of the linear inequality.
Definition: LpInterface.h:593
void clear()
Reset the rows (inequalities) and columns (variables) of the LP as if it was created.
bool sumIsOne__
true if addSumIsOne() has been called, false otherwise.
Definition: LpInterface.h:761
Class representing a variable ( a column ) of a linear program, i.e.
Definition: LpInterface.h:61
LpInterface()
Default constructor, empty problem.
bool iright__
True if this expression has a non-empty right side R : L <= M <= R .
Definition: LpInterface.h:423
void clear()
Clear all data of the calling expression as if it was constructed.
Class template acting as a wrapper for Lexicographic Reverse Search by David Avis.
Definition: LrsWrapper.h:107
void setUpH(const Size &card)
Sets up an H-representation.
Class representing a linear expression.
Definition: LpInterface.h:210
LpExpr()
Default constructor.
Class representing a row of the linear program, i.e.
Definition: LpInterface.h:501
LpExpr & operator-=(const LpCol &rhs)
Compound assignment operator -= with a variable.
std::ostream & operator<<(std::ostream &out, const LpCol &col)
std::string to_string(const Formula &f)
Definition: formula_inl.h:499
Class representing a linear program.
Definition: LpInterface.h:49
~LpCol()
Default destructor.
LpExpr operator+(LpExpr &&lhs, const T2 &rhs)
Overload of operator + between anything ( a scalar, a variable or an expression ) and anything except...
LpExpr & operator=(const LpCol &rhs)
Assignment operator = with a variable.
LpRow(const LpExpr &expr, const std::vector< LpCol > &cols)
Constructor from an expression and the address of the vector of variables of the problem.
friend std::ostream & operator<<(std::ostream &out, const LpCol &col)
Overload of << to use with output streams ( such as std::cout << ).
typename std::enable_if< !std::is_same< T1, T2 >::value, int >::type forbidden_type
Forbidden_type<T1,T2> return the "int" type if T1 and T2 are of the same type, else nothing...
Definition: utils_misc.h:125
void clearRows()
Reset the rows (inequalities) of the LP but not the columns (variables are kept). ...
std::vector< LpCol > getCols() const
Get the variables of the LP.
LpExpr operator*(const SCALAR &lhs, const LpCol &rhs)
Overload of operator * between a scalar and a variable.
double rValue__
The constant on the right side L : L <= M <= R.
Definition: LpInterface.h:430
std::vector< LpCol > cols__
Variables of the problem.
Definition: LpInterface.h:754
std::vector< LpCol > addCols(const unsigned int &cols)
Insert new columns, i.e.
HashTable< LpCol, double > * lCoeffs__
The coefficients of each variable on the left side L : L <= M <= R.
Definition: LpInterface.h:435
HashTable< LpCol, double > * rCoeffs__
The coefficients of each variable on the right side L : L <= M <= R.
Definition: LpInterface.h:443
~LpInterface()
Default destructor.
void H2V()
H-representation to V-representation.
void addSide__(const LpCol &from)
Set the side of the calling expression, from LEFT TO RIGHT : L <= M <= R.
double lValue__
The constant on the left side L : L <= M <= R.
Definition: LpInterface.h:426
static LpExpr multiply(const SCALAR &lhs, const LpCol &rhs)
LpInterface< GUM_SCALAR > & operator=(const LpInterface< GUM_SCALAR > &from)
Copy compound assignment.
~LpExpr()
Default destructor.
LpCol addCol()
Insert a new column, i.e.
bool positivity__
true if addPositivity() has been called, false otherwise.
Definition: LpInterface.h:758
const matrix & getOutput() const
Get the output matrix solution of the problem.
double cste__
The constant of the linear inequality.
Definition: LpInterface.h:589
std::string toString() const
Get the string representation of a calling expression.
std::vector< LpRow *> rows__
Rows of the problem.
Definition: LpInterface.h:752
std::string toString() const
Get the string representation of a calling linear program.
bool operator!=(const LpCol &col) const
Opposite of equality != test between two variables.
bool ileft__
True if this expression has a non-empty left side L : L <= M <= R .
Definition: LpInterface.h:415
LpExpr & operator+=(const LpCol &rhs)
Compound assignment operator += with a variable.
LpCol & operator=(const LpCol &col)
Assignment operator = by copy.
LpExpr operator-(LpExpr &&lhs, const T2 &rhs)
Overload of operator - between anything ( a scalar, a variable or an expression ) and anything except...
bool imiddle__
True if this expression has a non-empty middle side M ( the default ) : L <= M <= R ...
Definition: LpInterface.h:419
unsigned int id() const
Variable id accessor.
#define GUM_ERROR(type, msg)
Definition: exceptions.h:55
bool operator<(const LpCol &col) const
Test of ordering < between two variables.
std::string toString() const
Get the string representation of a calling row.