aGrUM  0.20.3
a C++ library for (probabilistic) graphical models
LpInterface.cpp
Go to the documentation of this file.
1 /**
2  *
3  * Copyright (c) 2005-2021 by 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 Class to include at least once this header
25  *
26  * @author Pierre-Henri WUILLEMIN(@LIP6) & Christophe GONZALES(@AMU)
27  */
28 
29 #include <agrum/CN/polytope/LpInterface.h>
30 
31 #ifdef GUM_NO_INLINE
32 # include <agrum/CN/polytope/LpInterface_inl.h>
33 #endif /* GUM_NO_INLINE */
34 
35 
36 namespace gum {
37  namespace credal {
38  namespace lp {
39 
40  /**
41  * class LpCol
42  */
43 
44  LpCol::LpCol(unsigned int id) : _id_(id) {
46  ;
47  }
48 
49  LpCol::LpCol(const LpCol& col) : _id_(col._id_) {
51  ;
52  }
53 
54  LpCol::~LpCol() {
56  ;
57  }
58 
59  /**
60  * class LpExpr
61  */
62 
64  _ileft_(false), _imiddle_(false), _iright_(false), _lValue_(0.), _mValue_(0.),
65  _rValue_(0.), _lCoeffs_(new HashTable< LpCol, double >()),
66  _mCoeffs_(new HashTable< LpCol, double >()), _rCoeffs_(new HashTable< LpCol, double >()) {
68  }
69 
70  LpExpr::LpExpr(const LpExpr& expr) :
73  _lCoeffs_(new HashTable< LpCol, double >(*expr._lCoeffs_)),
74  _mCoeffs_(new HashTable< LpCol, double >(*expr._mCoeffs_)),
75  _rCoeffs_(new HashTable< LpCol, double >(*expr._rCoeffs_)) {
77  }
78 
79  LpExpr::LpExpr(const LpExpr& expr, bool copyLeft, bool copyMiddle, bool copyRight) :
80  _ileft_(false), _imiddle_(false), _iright_(false), _lValue_(0.), _mValue_(0.),
81  _rValue_(0.), _lCoeffs_(nullptr), _mCoeffs_(nullptr), _rCoeffs_(nullptr) {
82  if (copyLeft) {
83  _lCoeffs_ = new HashTable< LpCol, double >(*expr._lCoeffs_);
85  _ileft_ = true;
86  } else
87  _lCoeffs_ = new HashTable< LpCol, double >();
88 
89  if (copyMiddle) {
90  _mCoeffs_ = new HashTable< LpCol, double >(*expr._mCoeffs_);
92  _imiddle_ = true;
93  } else
94  _mCoeffs_ = new HashTable< LpCol, double >();
95 
96  if (copyRight) {
97  _rCoeffs_ = new HashTable< LpCol, double >(*expr._rCoeffs_);
99  _iright_ = true;
100  } else
101  _rCoeffs_ = new HashTable< LpCol, double >();
102 
104  }
105 
110  expr._lCoeffs_ = nullptr;
111  expr._mCoeffs_ = nullptr;
112  expr._rCoeffs_ = nullptr;
113 
115  }
116 
118  _ileft_(false), _imiddle_(false), _iright_(false), _lValue_(0.), _mValue_(0.),
119  _rValue_(0.), _lCoeffs_(nullptr), _mCoeffs_(nullptr), _rCoeffs_(nullptr) {
120  if (copyLeft) {
123  _ileft_ = true;
124  } else
125  _lCoeffs_ = new HashTable< LpCol, double >();
126 
127  if (copyMiddle) {
130  _imiddle_ = true;
131  } else
132  _mCoeffs_ = new HashTable< LpCol, double >();
133 
134  if (copyRight) {
137  _iright_ = true;
138  } else
139  _rCoeffs_ = new HashTable< LpCol, double >();
140 
142  }
143 
145  delete _lCoeffs_;
146  delete _mCoeffs_;
147  delete _rCoeffs_;
148 
150  }
151 
153  clear();
154 
155  _mCoeffs_->insert(rhs, 1.);
156  _imiddle_ = true;
157 
158  return *this;
159  }
160 
162  /// self assignment check to avoid hashTable copies
163  if (this == &rhs) return *this;
164 
165  *_lCoeffs_ = *rhs._lCoeffs_;
166  *_mCoeffs_ = *rhs._mCoeffs_;
167  *_rCoeffs_ = *rhs._rCoeffs_;
168 
172 
173  _ileft_ = rhs._ileft_;
176 
177  return *this;
178  }
179 
181  /// self assignment check to avoid hashTable copies
182  if (this == &rhs) return *this;
183 
187 
191 
192  _ileft_ = rhs._ileft_;
195 
196  return *this;
197  }
198 
199 
201  if (_ileft_ || _iright_)
202  GUM_ERROR(OperationNotAllowed, "expr::operator+= (expr) : <= present on one side of expr")
203 
204  if (!_imiddle_) _imiddle_ = true;
205 
206  _mCoeffs_->getWithDefault(rhs, 0.) += 1.;
207 
208  return *this;
209  }
210 
212  if (_ileft_ || _iright_ || rhs._ileft_ || rhs._iright_)
214  "expr::operator+= (rhs) : <= present "
215  "on one side of rhs and/or expr");
216 
217  if (!_imiddle_) _imiddle_ = true;
218 
219  for (const auto& elt: *rhs._mCoeffs_)
221 
222  _mValue_ += rhs._mValue_;
223 
224  return *this;
225  }
226 
228  if (_ileft_ || _iright_ || rhs._ileft_ || rhs._iright_)
230  "expr::operator+= (rhs) : <= present "
231  "on one side of rhs and/or expr");
232 
233  if (!_imiddle_) {
234  _imiddle_ = true;
237 
238  return *this;
239  }
240 
241  for (const auto& elt: *rhs._mCoeffs_)
243  _mValue_ += rhs._mValue_;
244 
245  return *this;
246  }
247 
249  if (_ileft_ || _iright_)
250  GUM_ERROR(OperationNotAllowed, "expr::operator-= (rhs) : <= present in one of expr")
251 
252  if (!_imiddle_) _imiddle_ = true;
253 
254  _mCoeffs_->getWithDefault(rhs, 0.) -= 1.;
255 
256  return *this;
257  }
258 
260  if (_ileft_ || _iright_ || rhs._ileft_ || rhs._iright_)
262  "expr::operator-= (rhs) : <= present in one of rhs and/or expr");
263 
264  if (!_imiddle_) _imiddle_ = true;
265 
266  for (const auto& elt: *rhs._mCoeffs_)
268 
269  _mValue_ -= rhs._mValue_;
270 
271  return *this;
272  }
273 
274 
275  void LpExpr::_addSide_(const LpCol& from) {
276  if (!_ileft_) {
277  _lCoeffs_->insert(from, 1.);
278  _ileft_ = true;
279  } else if (!_imiddle_) {
280  _mCoeffs_->insert(from, 1.);
281  _imiddle_ = true;
282  } else if (!_iright_) {
283  _rCoeffs_->insert(from, 1.);
284  _iright_ = true;
285  } else
287  "LpExpr::setSide ( const LpCol & from "
288  ") : too many <= ; no free side");
289  }
290 
291  void LpExpr::_addSide_(const LpExpr& from) {
292  if (_ileft_ && _iright_ && from._imiddle_)
294  "LpExpr::setSide ( const LpCol & from "
295  ") : too many <= ; no free side");
296 
297  /// nothing to do, from is an empty LpExpr
298  if (!from._imiddle_) return;
299 
300  /// from only has middle side : this should be empty or has left side,
301  /// or has
302  /// left and middle side
303  if (!from._ileft_ && !from._iright_) {
304  if (!_ileft_) {
307  _ileft_ = true;
308 
309  return;
310  } else if (!_imiddle_) {
313  _imiddle_ = true;
314 
315  return;
316  } else if (!_iright_) {
319  _iright_ = true;
320 
321  return;
322  } else
324  "LpExpr::setSide ( const LpCol & from ) "
325  ": too many <= ; no free side");
326  }
327  /// from has left and middle side : this should be empty or has left
328  /// side
329  else if (from._ileft_ && !from._iright_) {
330  if (!_ileft_) {
333  _ileft_ = true;
334 
337  _imiddle_ = true;
338 
339  return;
340  } else if (!_imiddle_ && !_iright_) {
343  _imiddle_ = true;
344 
347  _iright_ = true;
348 
349  return;
350  } else
352  "LpExpr::setSide ( const LpCol & from ) "
353  ": too many <= ; no free side");
354  }
355  /// from has left, middle and right side : this should be empty
356  /// to be exhaustive
357  else if (from._ileft_ && from._iright_) {
358  if (_ileft_ || _imiddle_ || _iright_)
360  "LpExpr::setSide ( const LpCol & from ) "
361  ": too many <= ; no free side");
362 
363  *this = from;
364 
365  return;
366  } else
368  "LpExpr::setSide ( const LpCol & from "
369  ") : too many <= ; no free side");
370  }
371 
373  /// std::cout << from;
374  if (_ileft_ && _iright_ && from._imiddle_)
376  "LpExpr::setSide ( const LpCol & from "
377  ") : too many <= ; no free side");
378 
379  /// nothing to do, from is an empty LpExpr
380  if (!from._imiddle_) return;
381 
382  /// from only has middle side : this should be empty or has left side,
383  /// or has
384  /// left and middle side
385  if (!from._ileft_ && !from._iright_) {
386  if (!_ileft_) {
387  ///* _lCoeffs_ = * from. _mCoeffs_;
390  _ileft_ = true;
391 
392  return;
393  } else if (!_imiddle_) {
394  ///* _mCoeffs_ = * from. _mCoeffs_;
397  _imiddle_ = true;
398 
399  return;
400  } else if (!_iright_) {
401  ///* _rCoeffs_ = * from. _mCoeffs_;
404  _iright_ = true;
405 
406  return;
407  } else
409  "LpExpr::setSide ( const LpCol & from ) "
410  ": too many <= ; no free side");
411  }
412  /// from has left and middle side : this should be empty or has left
413  /// side
414  else if (from._ileft_ && !from._iright_) {
415  if (!_ileft_) {
416  ///* _lCoeffs_ = * from. _lCoeffs_;
419  _ileft_ = true;
420 
421  ///* _mCoeffs_ = * from. _mCoeffs_;
424  _imiddle_ = true;
425 
426  return;
427  } else if (!_imiddle_ && !_iright_) {
428  ///* _mCoeffs_ = * from. _lCoeffs_;
431  _imiddle_ = true;
432 
433  ///* _rCoeffs_ = * from. _mCoeffs_;
436  _iright_ = true;
437 
438  return;
439  } else
441  "LpExpr::setSide ( const LpCol & from ) "
442  ": too many <= ; no free side");
443  }
444  /// from has left, middle and right side : this should be empty
445  /// to be exhaustive
446  else if (from._ileft_ && from._iright_) {
447  if (_ileft_ || _imiddle_ || _iright_)
449  "LpExpr::setSide ( const LpCol & from ) "
450  ": too many <= ; no free side");
451 
452  *this = std::move(from);
453 
454  return;
455  } else
457  "LpExpr::setSide ( const LpCol & from "
458  ") : too many <= ; no free side");
459  }
460 
461 
462  void LpExpr::clear() {
463  _lCoeffs_->clear();
464  _mCoeffs_->clear();
465  _rCoeffs_->clear();
466 
467  _lValue_ = 0.;
468  _mValue_ = 0.;
469  _rValue_ = 0.;
470 
471  _ileft_ = false;
472  _imiddle_ = false;
473  _iright_ = false;
474  }
475 
476  std::string LpExpr::toString() const {
478 
479  s << std::endl << "left side : " << std::endl;
480 
481  if (_lCoeffs_ != nullptr)
482  for (const auto& elt: *_lCoeffs_)
483  s << elt.first.toString() << " " << elt.second << " | ";
484 
485  s << std::endl << "middle side : " << std::endl;
486 
487  if (_mCoeffs_ != nullptr)
488  for (const auto& elt: *_mCoeffs_)
489  s << elt.first.toString() << " " << elt.second << " | ";
490 
491  s << std::endl << "right side : " << std::endl;
492 
493  if (_rCoeffs_ != nullptr)
494  for (const auto& elt: *_rCoeffs_)
495  s << elt.first.toString() << " " << elt.second << " | ";
496 
497  s << std::endl
498  << "lvalue : " << _lValue_ << std::endl
499  << "mvalue : " << _mValue_ << std::endl
500  << "rvalue : " << _rValue_ << std::endl;
501 
502  s << std::endl;
503 
504  return s.str();
505  }
506 
507 
508  /**
509  * class LpRow
510  */
511 
512 
513  LpRow::LpRow(const LpExpr& expr, const std::vector< LpCol >& cols) : _coeffs_(nullptr) {
514  // we write 0 <= Ax + b from Ex + f <= Cx + d
515  if (expr._ileft_ && !expr._iright_) {
516  _coeffs_ = new HashTable< LpCol, double >(*expr._mCoeffs_);
517 
518  for (const auto& col: cols) {
519  double col_coeff = 0.;
520 
521  // from left side to middle side : 0 <= middle - left
523 
525  }
526 
528  } else if (expr._iright_ && !expr._ileft_) {
529  _coeffs_ = new HashTable< LpCol, double >(*expr._rCoeffs_);
530 
531  for (const auto& col: cols) {
532  double col_coeff = 0;
533 
534  // from middle side to right side : 0 <= right - middle
536 
538  }
539 
541  } else
543  "expr : " << expr.toString() << "is not a valid inequality; no <= detected");
544 
545  if (_coeffs_->size() == 0)
547  "expr : " << expr.toString()
548  << "is not a valid inequality; "
549  "no variable in inequality, "
550  "only constants");
551 
553  }
554 
555  LpRow::LpRow(LpExpr&& expr, const std::vector< LpCol >& cols) : _coeffs_(nullptr) {
556  /// we write 0 <= Ax + b from Ex + f <= Cx + d
557  if (expr._ileft_ && !expr._iright_) {
559 
560  for (const auto& col: cols) {
561  double col_coeff = 0;
562 
564 
566  }
567 
569  } else if (expr._iright_ && !expr._ileft_) {
571 
572  for (const auto& col: cols) {
573  double col_coeff = 0;
574 
576 
578  }
579 
581  } else
583  "expr : " << expr.toString() << "is not a valid inequality; no <= detected");
584 
585  if (_coeffs_->size() == 0)
587  "expr : " << expr.toString()
588  << "is not a valid inequality; "
589  "no variable in inequality, "
590  "only constants");
591 
593  }
594 
595  LpRow::LpRow(const LpRow& row) :
596  _cste_(row._cste_), _coeffs_(new HashTable< LpCol, double >(*row._coeffs_)) {
598  }
599 
601  row._coeffs_ = nullptr;
602 
604  }
605 
606  LpRow::~LpRow() {
607  delete _coeffs_;
608 
610  }
611 
612  LpRow& LpRow::operator=(const LpRow& row) {
613  _cste_ = row._cste_;
614  *_coeffs_ = *row._coeffs_;
615  return *this;
616  }
617 
619  _cste_ = row._cste_;
621  return *this;
622  }
623 
625  out << row.toString();
626  return out;
627  }
628 
629  std::string LpRow::toString() const {
631 
632  s << "0 <= " << _cste_;
633 
634  if (_coeffs_ != nullptr) {
635  for (const auto& elt: *_coeffs_) {
636  if (elt.second > 0) {
637  if (elt.second != 1) {
638  s << " +" << elt.second << "*" << elt.first.toString();
639  } else {
640  s << " +" << elt.first.toString();
641  }
642  } else {
643  if (elt.second < 0) {
644  if (elt.second != -1) {
645  s << " " << elt.second << "*" << elt.first.toString();
646  } else {
647  s << " -" << elt.first.toString();
648  }
649  }
650  }
651  }
652  }
653 
654  return s.str();
655  }
656 
657  } // namespace lp
658  } // namespace credal
659 } // namespace gum
INLINE void emplace(Args &&... args)
Definition: set_tpl.h:643
std::ostream & operator<<(std::ostream &out, const LpRow &row)
namespace for constraint-based description of credal sets
Definition: LpInterface.cpp:38
namespace for all credal networks entities
Definition: LpInterface.cpp:37