aGrUM 3.1.1
a C++ library for (probabilistic) graphical models
LpInterface_tpl.h
Go to the documentation of this file.
1/****************************************************************************
2 * This file is part of the aGrUM/pyAgrum library. *
3 * *
4 * Copyright (c) 2005-2026 by *
5 * - Pierre-Henri WUILLEMIN(_at_LIP6) *
6 * - Christophe GONZALES(_at_AMU) *
7 * *
8 * The aGrUM/pyAgrum library is free software; you can redistribute it *
9 * and/or modify it under the terms of either : *
10 * *
11 * - the GNU Lesser General Public License as published by *
12 * the Free Software Foundation, either version 3 of the License, *
13 * or (at your option) any later version, *
14 * - the MIT license (MIT), *
15 * - or both in dual license, as here. *
16 * *
17 * (see https://agrum.gitlab.io/articles/dual-licenses-lgplv3mit.html) *
18 * *
19 * This aGrUM/pyAgrum library is distributed in the hope that it will be *
20 * useful, but WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
21 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES MERCHANTABILITY or FITNESS *
22 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
25 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
26 * OTHER DEALINGS IN THE SOFTWARE. *
27 * *
28 * See LICENCES for more details. *
29 * *
30 * SPDX-FileCopyrightText: Copyright 2005-2026 *
31 * - Pierre-Henri WUILLEMIN(_at_LIP6) *
32 * - Christophe GONZALES(_at_AMU) *
33 * SPDX-License-Identifier: LGPL-3.0-or-later OR MIT *
34 * *
35 * Contact : info_at_agrum_dot_org *
36 * homepage : http://agrum.gitlab.io *
37 * gitlab : https://gitlab.com/agrumery/agrum *
38 * *
39 ****************************************************************************/
40
41#pragma once
42
43
44#include <agrum/CN/polytope/LpInterface.h> // to ease IDE parser
45
46#include "LpInterface.h"
47
48namespace gum {
49 namespace credal {
50 namespace lp {
51
55 template < typename SCALAR >
56 LpExpr& LpExpr::operator=(const SCALAR& rhs) {
57 clear();
58
59 _mValue_ = rhs;
60 _imiddle_ = true;
61
62 return *this;
63 }
64
65 template < typename T >
66 LpExpr& LpExpr::operator+=(const T& rhs) {
67 if (_ileft_ || _iright_)
68 GUM_ERROR(OperationNotAllowed, "expr::operator+= (expr) : <= present on one side of expr")
69
70 if (!_imiddle_) _imiddle_ = true;
71
72 _mValue_ += rhs;
73
74 return *this;
75 }
76
77 template < typename T >
78 LpExpr& LpExpr::operator-=(const T& rhs) {
79 if (_ileft_ || _iright_)
80 GUM_ERROR(OperationNotAllowed, "expr::operator-= (rhs) : <= present in one of expr")
81
82 if (!_imiddle_) _imiddle_ = true;
83
84 _mValue_ -= rhs;
85
86 return *this;
87 }
88
89 template < typename SCALAR >
90 void LpExpr::_addSide_(const SCALAR& from) {
91 if (!_ileft_) {
92 _lValue_ = from;
93 _ileft_ = true;
94 } else if (!_imiddle_) {
95 _mValue_ = from;
96 _imiddle_ = true;
97 } else if (!_iright_) {
98 _rValue_ = from;
99 _iright_ = true;
100 } else
102 "LpExpr::setSide ( const LpCol & from "
103 ") : too many <= ; no free side");
104 }
105
109 template < GUM_Numeric GUM_SCALAR >
111 _positivity_ = false;
112 _sumIsOne_ = false;
113 GUM_CONSTRUCTOR(LpInterface);
114 }
115
116 template < GUM_Numeric GUM_SCALAR >
119 _rows_.resize(from._rows_.size());
120
121 for (unsigned int i = 0, end = from._rows_.size(); i < end; i++)
122 _rows_[i] = new LpRow(*from._rows_[i]);
123
124 GUM_CONS_CPY(LpInterface);
125 }
126
127 template < GUM_Numeric GUM_SCALAR >
130 _rows_.swap(from._rows_);
131 _cols_.swap(from._cols_);
132 GUM_CONS_CPY(LpInterface);
133 }
134
135 template < GUM_Numeric GUM_SCALAR >
137 for (const auto row: _rows_)
138 delete row;
139
140 GUM_DESTRUCTOR(LpInterface);
141 }
142
143 template < GUM_Numeric GUM_SCALAR >
147 for (const auto& row: _rows_)
148 delete row;
149
150 _rows_.clear();
151 _rows_.shrink_to_fit();
152
153 _rows_.resize(from._rows_.size());
154
155 for (unsigned int i = 0, end = from._rows_.size(); i < end; i++)
156 _rows_[i] = new LpRow(*from._rows_[i]);
157
158 _cols_ = from._cols_;
160 _sumIsOne_ = from._sumIsOne_;
161
162 return *this;
163 }
164
165 template < GUM_Numeric GUM_SCALAR >
168 _rows_.swap(from._rows_);
169 _cols_.swap(from._cols_);
170
171 _positivity_ = from._positivity_;
172 _sumIsOne_ = from._sumIsOne_;
173
174 return *this;
175 }
176
177 template < typename T >
178 std::ostream& operator<<(std::ostream& out, const LpInterface< T >& lpi) {
179 out << lpi.toString();
180 return out;
181 }
182
183 template < GUM_Numeric GUM_SCALAR >
185 LpCol col((unsigned int)_cols_.size());
186
187 _cols_.push_back(col);
188
189 return col;
190 }
191
192 template < GUM_Numeric GUM_SCALAR >
193 std::vector< LpCol > LpInterface< GUM_SCALAR >::addCols(const unsigned int& cols) {
194 if (cols < 1)
196 "LpInterface::addCols ( cols ) : cols "
197 "needs must be equal or greater than 1 : "
198 << cols << " < 1");
199
200 for (unsigned int i = 0; i < cols; i++) {
201 _cols_.push_back(LpCol((unsigned int)_cols_.size()));
202 }
203
204 return _cols_;
205 }
206
207 template < GUM_Numeric GUM_SCALAR >
209 if (!expr._ileft_ && !expr._iright_)
211 "addRow ( const LpExpr & expr ) : expr : " << expr.toString()
212 << "is not an inequality.");
213
214 if ((expr._ileft_ && !expr._iright_) || (!expr._ileft_ && expr._iright_)) {
215 _rows_.push_back(new LpRow(expr, _cols_));
216 } else {
217 LpExpr lexpr(expr, true, true, false);
218 LpExpr rexpr(expr, false, true, true);
219
220 _rows_.push_back(new LpRow(std::move(lexpr),
221 _cols_));
222 _rows_.push_back(new LpRow(std::move(rexpr),
223 _cols_));
224 }
225 }
226
227 template < GUM_Numeric GUM_SCALAR >
229 if (!expr._ileft_ && !expr._iright_)
231 "addRow ( const LpExpr & expr ) : expr : " << expr.toString()
232 << "is not an inequality.");
233
234 if ((expr._ileft_ && !expr._iright_) || (!expr._ileft_ && expr._iright_)) {
235 _rows_.push_back(new LpRow(std::move(expr), _cols_));
236 } else {
237 LpExpr lexpr(std::move(expr), true, true, false);
238
240 LpExpr rexpr(std::move(expr), false, false, true);
241
243
244 *rexpr._mCoeffs_ = *lexpr._mCoeffs_;
245 rexpr._mValue_ = lexpr._mValue_;
246 rexpr._imiddle_ = true;
247
248 _rows_.push_back(new LpRow(std::move(lexpr),
249 _cols_));
250 _rows_.push_back(new LpRow(std::move(rexpr),
251 _cols_));
252 }
253 }
254
255 template < GUM_Numeric GUM_SCALAR >
257 if (_positivity_) return;
258
259 for (const auto& col: _cols_)
260 addRow(0 <= col);
261
262 _positivity_ = true;
263 }
264
265 template < GUM_Numeric GUM_SCALAR >
267 if (_sumIsOne_) return;
268
269 LpExpr expr;
270
271 for (const auto& col: _cols_)
272 expr += col;
273
274 addRow(1 <= std::move(expr) <= 1);
275
276 _sumIsOne_ = true;
277 }
278
279 template < GUM_Numeric GUM_SCALAR >
281 if (_positivity_ && _sumIsOne_) {
282 return;
283 } else if (_positivity_ && !_sumIsOne_) {
284 addSumIsOne();
285 return;
286 } else if (!_positivity_ && _sumIsOne_) {
288 return;
289 }
290
291 // we can do both with one loop, don't call the above functions.
292 // addPositivity();
293 // addSumIsOne();
294 LpExpr expr;
295
296 for (const auto& col: _cols_) {
297 addRow(0 <= col);
298 expr += col;
299 }
300
301 addRow(1 <= std::move(expr) <= 1);
302
303 _sumIsOne_ = true;
304 _positivity_ = true;
305 }
306
307 template < GUM_Numeric GUM_SCALAR >
308 std::vector< std::vector< GUM_SCALAR > > LpInterface< GUM_SCALAR >::solve() {
310
311 lrs.setUpH((unsigned int)_cols_.size());
312
313 std::vector< std::vector< GUM_SCALAR > > lrsMatrix;
314
315 for (const auto& row: _rows_) {
316 std::vector< GUM_SCALAR > expandedRow(_cols_.size() + 1, 0);
317
318 expandedRow[0] = row->_cste_;
319
320 for (const auto& elt: *row->_coeffs_)
321 expandedRow[elt.first.id() + 1] = elt.second;
322
323 lrsMatrix.push_back(expandedRow);
324 }
325
326 lrs.fillMatrix(lrsMatrix);
327
328 lrs.H2V();
329
330 return lrs.getOutput();
331 }
332
333 template < GUM_Numeric GUM_SCALAR >
334 std::vector< LpCol > LpInterface< GUM_SCALAR >::getCols() const {
335 return _cols_;
336 }
337
338 template < GUM_Numeric GUM_SCALAR >
340 std::ostringstream s;
341
342 s << std::endl << std::endl << "Variables : " << std::endl;
343
344 for (const auto& col: _cols_)
345 s << " " << col.toString();
346
347 s << std::endl;
348
349 for (const auto& row: _rows_)
350 s << std::endl << row->toString();
351
352 s << std::endl << std::endl;
353
354 return s.str();
355 }
356
357 template < GUM_Numeric GUM_SCALAR >
359 for (const auto& row: _rows_)
360 delete row;
361
362 _rows_.clear();
363 _rows_.shrink_to_fit();
367
368 _cols_.clear();
369 _cols_.shrink_to_fit();
370
371 _positivity_ = false;
372 _sumIsOne_ = false;
373 }
374
375 template < GUM_Numeric GUM_SCALAR >
377 for (const auto& row: _rows_)
378 delete row;
379
380 _rows_.clear();
381 _rows_.shrink_to_fit();
382
383 _positivity_ = false;
384 _sumIsOne_ = false;
385 }
386
388 template < typename T2 >
389 LpExpr operator+(LpExpr&& lhs, const T2& rhs) {
390 LpExpr expr = std::move(lhs);
391 expr += rhs;
392
393 return expr;
394 }
395
396 template < typename T2 >
397 LpExpr operator+(const LpExpr& lhs, const T2& rhs) {
398 LpExpr expr(lhs);
399 expr += rhs;
400
401 return expr;
402 }
403
404 template < typename T1, forbidden_type< T1, LpExpr > >
405 LpExpr operator+(const T1& lhs, LpExpr&& rhs) {
406 LpExpr expr = std::move(rhs);
407 ;
408 expr += lhs;
409
410 return expr;
411 }
412
413 template < typename T1, forbidden_type< T1, LpExpr > >
414 LpExpr operator+(const T1& lhs, LpExpr& rhs) {
415 LpExpr expr(rhs);
416 expr += lhs;
417
418 return expr;
419 }
420
421 template < typename T2, forbidden_type< T2, LpExpr > >
422 LpExpr operator+(const LpCol& lhs, const T2& rhs) {
423 LpExpr expr;
424 expr += lhs;
425 expr += rhs;
426
427 return expr;
428 }
429
430 template < typename T1, forbidden_type< T1, LpExpr >, forbidden_type< T1, LpCol > >
431 LpExpr operator+(const T1& lhs, const LpCol& rhs) {
432 LpExpr expr;
433 expr += rhs;
434 expr += lhs;
435
436 return expr;
437 }
438
440 template < typename T2 >
441 LpExpr operator-(LpExpr&& lhs, const T2& rhs) {
442 LpExpr expr = std::move(lhs);
443 expr -= rhs;
444
445 return expr;
446 }
447
448 template < typename T2 >
449 LpExpr operator-(const LpExpr& lhs, const T2& rhs) {
450 LpExpr expr(lhs);
451 expr -= rhs;
452
453 return expr;
454 }
455
456 template < typename T1, forbidden_type< T1, LpExpr > >
457 LpExpr operator-(const T1& lhs, LpExpr&& rhs) {
458 LpExpr expr;
459 expr += std::move(rhs);
460 ;
461 expr -= lhs;
462
463 return expr;
464 }
465
466 template < typename T1, forbidden_type< T1, LpExpr > >
467 LpExpr operator-(const T1& lhs, LpExpr& rhs) {
468 LpExpr expr;
469 expr += rhs;
470 expr -= lhs;
471
472 return expr;
473 }
474
475 template < typename T2, forbidden_type< T2, LpExpr > >
476 LpExpr operator-(const LpCol& lhs, const T2& rhs) {
477 LpExpr expr;
478 expr += lhs;
479 expr -= rhs;
480
481 return expr;
482 }
483
484 template < typename T1, forbidden_type< T1, LpExpr >, forbidden_type< T1, LpCol > >
485 LpExpr operator-(const T1& lhs, const LpCol& rhs) {
486 LpExpr expr;
487 expr += rhs;
488 expr -= lhs;
489
490 return expr;
491 }
492
494 template < typename SCALAR >
495 LpExpr LpExpr::multiply(const SCALAR& lhs, const LpCol& rhs) {
496 LpExpr expr;
497 expr._mCoeffs_->insert(rhs, lhs);
498 expr._imiddle_ = true;
499 return expr;
500 }
501
502 template < typename SCALAR >
503 LpExpr operator*(const SCALAR& lhs, const LpCol& rhs) {
504 return LpExpr::multiply(lhs, rhs);
505 }
506
507 template < typename SCALAR >
508 LpExpr operator*(const LpCol& lhs, const SCALAR& rhs) {
509 return LpExpr::multiply(rhs, lhs);
510 }
511
513 template < typename T1, typename T2 >
514 LpExpr LpExpr::lessThan(T1&& lhs, T2&& rhs) {
515 LpExpr expr;
516 expr._addSide_(std::forward< T1 >(lhs));
517 expr._addSide_(std::forward< T2 >(rhs));
518 return expr;
519 }
520
521 // const lvalue
522 template < typename T2 >
523 LpExpr operator<=(const LpExpr& lhs, T2&& rhs) {
524 return LpExpr::lessThan(lhs, std::forward< T2 >(rhs));
525 }
526
527 template < typename T2 >
528 LpExpr operator<=(const LpCol& lhs, T2&& rhs) {
529 return LpExpr::lessThan(lhs, std::forward< T2 >(rhs));
530 }
531
532 template < typename T1, forbidden_type< T1, LpExpr& >, forbidden_type< T1, LpCol& > >
533 LpExpr operator<=(T1&& lhs, const LpExpr& rhs) {
534 return LpExpr::lessThan(std::forward< T1 >(lhs), rhs);
535 }
536
537 template < typename T1, forbidden_type< T1, LpExpr& >, forbidden_type< T1, LpCol& > >
538 LpExpr operator<=(T1&& lhs, const LpCol& rhs) {
539 return LpExpr::lessThan(std::forward< T1 >(lhs), rhs);
540 }
541
542 // rvaue
543 template < typename T2 >
544 LpExpr operator<=(LpExpr&& lhs, T2&& rhs) {
545 return LpExpr::lessThan(std::move(lhs), std::forward< T2 >(rhs));
546 }
547
548 template < typename T2 >
549 LpExpr operator<=(LpCol&& lhs, T2&& rhs) {
550 return LpExpr::lessThan(std::move(lhs), std::forward< T2 >(rhs));
551 }
552
553 template < typename T1, forbidden_type< T1, LpExpr >, forbidden_type< T1, LpCol > >
554 LpExpr operator<=(T1&& lhs, LpExpr&& rhs) {
555 return LpExpr::lessThan(std::forward< T1 >(lhs), std::move(rhs));
556 }
557
558 template < typename T1, forbidden_type< T1, LpExpr >, forbidden_type< T1, LpCol > >
559 LpExpr operator<=(T1&& lhs, LpCol&& rhs) {
560 return LpExpr::lessThan(std::forward< T1 >(lhs), std::move(rhs));
561 }
562 } // namespace lp
563
564 } // namespace credal
565
566} // namespace gum
Class representing a polytope ( credal set ) by a set of linear constraints.
Exception : operation not allowed.
Class template acting as a wrapper for Lexicographic Reverse Search by David Avis.
Definition LrsWrapper.h:121
const matrix & getOutput() const
Get the output matrix solution of the problem.
void H2V()
H-representation to V-representation.
void fillMatrix(const std::vector< std::vector< GUM_SCALAR > > &matrix)
Fill the H-representation from the matrix given in argument.
void setUpH(const Size &card)
Sets up an H-representation.
Class representing a variable ( a column ) of a linear program, i.e.
Definition LpInterface.h:80
Class representing a linear expression.
LpExpr & operator+=(const LpCol &rhs)
Compound assignment operator += with a variable.
double _rValue_
The constant on the right side L : L <= M <= R.
bool _ileft_
True if this expression has a non-empty left side L : L <= M <= R .
bool _imiddle_
True if this expression has a non-empty middle side M ( the default ) : L <= M <= R .
LpExpr & operator-=(const LpCol &rhs)
Compound assignment operator -= with a variable.
LpExpr()
Default constructor.
std::string toString() const
Get the string representation of a calling expression.
void clear()
Clear all data of the calling expression as if it was constructed.
static LpExpr multiply(const SCALAR &lhs, const LpCol &rhs)
bool _iright_
True if this expression has a non-empty right side R : L <= M <= R .
HashTable< LpCol, double > * _mCoeffs_
The coefficients of each variable on the middle side L : L <= M <= R.
static LpExpr lessThan(T1 &&lhs, T2 &&rhs)
double _mValue_
The constant on the middle side L : L <= M <= R.
double _lValue_
The constant on the left side L : L <= M <= R.
LpExpr & operator=(const LpCol &rhs)
Assignment operator = with a variable.
void _addSide_(const LpCol &from)
Set the side of the calling expression, from LEFT TO RIGHT : L <= M <= R.
Class representing a linear program.
bool _sumIsOne_
true if addSumIsOne() has been called, false otherwise.
std::string toString() const
Get the string representation of a calling linear program.
void addSumIsOne()
Add sum of variables is 1 constraints.
void clear()
Reset the rows (inequalities) and columns (variables) of the LP as if it was created.
std::vector< LpCol > getCols() const
Get the variables of the LP.
void clearRows()
Reset the rows (inequalities) of the LP but not the columns (variables are kept).
std::vector< LpCol > _cols_
Variables of the problem.
std::vector< LpRow * > _rows_
Rows of the problem.
LpInterface< GUM_SCALAR > & operator=(const LpInterface< GUM_SCALAR > &from)
Copy compound assignment.
LpInterface()
Default constructor, empty problem.
void addPositivity()
Add positivity constraints for all variables.
std::vector< std::vector< GUM_SCALAR > > solve()
Solve the linear program (H-representation of the polytope) by enumeration (of the polytope vertices)...
std::vector< LpCol > addCols(const unsigned int &cols)
Insert new columns, i.e.
LpCol addCol()
Insert a new column, i.e.
void addProba()
Add positivity constraints and sum of variables is 1 ( probability constraints ).
void addRow(const LpExpr &expr)
Add rows to the linear program according to a given expression ( which must be at least an inequality...
~LpInterface()
Default destructor.
bool _positivity_
true if addPositivity() has been called, false otherwise.
Class representing a row of the linear program, i.e.
#define GUM_ERROR(type, msg)
Definition exceptions.h:76
namespace for constraint-based description of credal sets
Definition agrum.h:64
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 LpExpr &lhs, T2 &&rhs)
Overload of operator <= between anything and anything.
LpExpr operator-(LpExpr &&lhs, const T2 &rhs)
Overload of operator - between anything ( a scalar, a variable or an expression ) and anything except...
std::ostream & operator<<(std::ostream &out, const LpRow &row)
namespace for all credal networks entities
Definition agrum.h:61
gum is the global namespace for all aGrUM entities
Definition agrum.h:46
value_type & operator*()
Returns the value pointed to by the iterator.