aGrUM  0.20.3
a C++ library for (probabilistic) graphical models
LrsWrapper_tpl.h
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 #include <string.h>
23 
24 #include <agrum/CN/polytope/LrsWrapper.h>
25 #include <agrum/agrum.h>
26 
27 namespace gum {
28  namespace credal {
29 
30  template < typename GUM_SCALAR >
31  LRSWrapper< GUM_SCALAR >::LRSWrapper() {
32  _state_ = _states_::none;
33 
34  _vertices_ = 0;
35  _card_ = 0;
36 
37  _volume_ = 0;
38 
39  _getVolume_ = false;
40  _hull_ = false;
41  _polytope_ = false;
42 
43  GUM_CONSTRUCTOR(LRSWrapper);
44  }
45 
46  template < typename GUM_SCALAR >
49  }
50 
51  template < typename GUM_SCALAR >
52  auto LRSWrapper< GUM_SCALAR >::getInput() const -> const matrix& {
53  return _input_;
54  }
55 
56  template < typename GUM_SCALAR >
57  auto LRSWrapper< GUM_SCALAR >::getOutput() const -> const matrix& {
58  return _output_;
59  }
60 
61  template < typename GUM_SCALAR >
62  const unsigned int& LRSWrapper< GUM_SCALAR >::getVerticesNumber() const {
63  return _vertices_;
64  }
65 
66  template < typename GUM_SCALAR >
68  if (_volume_ != 0)
69  return _volume_;
70  else
72  "LRSWrapper< GUM_SCALAR >::getVolume () : "
73  "volume computation was not asked for this "
74  "credal set, call computeVolume() from a "
75  "V-representation.");
76  }
77 
78  template < typename GUM_SCALAR >
79  void LRSWrapper< GUM_SCALAR >::setUpH(const Size& card) {
80  if (card < 2)
82  "LRSWrapper< GUM_SCALAR >::setUpH : "
83  "cardinality must be at least 2");
84 
85  tearDown();
86 
87  _input_ = std::vector< std::vector< GUM_SCALAR > >(card * 2 + 2,
88  std::vector< GUM_SCALAR >(card + 1, 0));
89 
90  _input_[card * 2] = std::vector< GUM_SCALAR >(card + 1, -1);
91  _input_[card * 2][0] = 1;
92 
93  _input_[card * 2 + 1] = std::vector< GUM_SCALAR >(card + 1, 1);
94  _input_[card * 2 + 1][0] = -1;
95 
96  _output_ = std::vector< std::vector< GUM_SCALAR > >();
97 
99 
100  _state_ = _states_::Hup;
101 
102  _card_ = (unsigned int)card;
103  }
104 
105  template < typename GUM_SCALAR >
106  void LRSWrapper< GUM_SCALAR >::setUpV(const Size& card, const Size& vertices) {
107  if (card < 2)
109  "LRSWrapper< GUM_SCALAR >::setUpV : "
110  "cardinality must be at least 2");
111 
112  if (vertices < 2)
114  "LRSWrapper< GUM_SCALAR >::setUpV : vertices "
115  "must be at least 2 to build a polytope");
116 
117  tearDown();
118 
120  std::vector< GUM_SCALAR >(card + 1, 1));
121 
122  _output_ = std::vector< std::vector< GUM_SCALAR > >();
123 
124  _state_ = _states_::Vup;
125 
126  _card_ = (unsigned int)card;
127  _vertices_ = (unsigned int)vertices;
128  }
129 
130  template < typename GUM_SCALAR >
132  _input_.clear();
133  _output_.clear();
134  _vertex_.clear();
136 
138  _vertices_ = 0;
139 
140  _volume_ = 0;
141 
142  _state_ = _states_::none;
143  _card_ = 0;
144 
145  _getVolume_ = false;
146  _hull_ = false;
147  _polytope_ = false;
148  }
149 
150  template < typename GUM_SCALAR >
154  _output_.clear();
155  _vertex_.clear();
156  _vertex_.resize(_card_, 0);
157 
158  _volume_ = 0;
159  _vertices_ = 0;
160 
161  _getVolume_ = false;
162  _hull_ = false;
163  _polytope_ = false;
164 
165  if (_state_ == _states_::H2Vready)
166  _state_ = _states_::Hup;
167  else if (_state_ == _states_::V2Hready) {
168  _state_ = _states_::Vup;
170  "LRSWrapper< GUM_SCALAR >::nextHInput : only for H-representation "
171  "as input. Previous state was : "
172  << _setUpStateNames_[static_cast< int >(_state_)]);
173  } else {
174  _input_.clear();
175  _state_ = _states_::none;
176  _card_ = 0;
177  _vertex_.clear();
178  }
179  }
180 
181  template < typename GUM_SCALAR >
183  const GUM_SCALAR& max,
184  const Size& modal) {
185  if (_state_ != _states_::Hup)
187  "LRSWrapper< GUM_SCALAR >::fillH : setUpH or nextInput has not "
188  "been called or H-representation is complete, current state is : "
189  << _setUpStateNames_[static_cast< int >(_state_)]);
190 
191  if (modal >= _card_)
193  "LRSWrapper< GUM_SCALAR >::fillH : modality is "
194  "greater or equal than cardinality : "
195  << modal << " >= " << _card_);
196 
197  _input_[modal * 2][0] = -min;
198  _input_[modal * 2][modal + 1] = 1;
199 
200  _input_[modal * 2 + 1][0] = max;
201  _input_[modal * 2 + 1][modal + 1] = -1;
202 
203  _vertex_[modal] = max;
204 
206 
208  }
209 
210  template < typename GUM_SCALAR >
212  const std::vector< std::vector< GUM_SCALAR > >& matrix) {
213  if (_state_ != _states_::Hup)
215  "LRSWrapper< GUM_SCALAR >::fillH : setUpH or nextInput has not "
216  "been called or H-representation is complete, current state is : "
217  << _setUpStateNames_[static_cast< int >(_state_)]);
218 
219  if (matrix[0].size() - 1 != _card_)
221  "LRSWrapper< GUM_SCALAR >::fillMatrix : size is "
222  "different than cardinality : "
223  << (matrix[0].size() - 1) << " != " << _card_);
224 
225  _input_ = matrix;
226 
227  for (unsigned int modal = 0; modal < _card_; modal++) {
229  }
230 
232  }
233 
234  template < typename GUM_SCALAR >
236  if (_state_ != _states_::Vup)
238  "LRSWrapper< GUM_SCALAR >::fillV : setUpV or nextInput has not "
239  "been called or V-representation is complete, current state is : "
240  << _setUpStateNames_[static_cast< int >(_state_)]);
241 
244  "LRSWrapper< GUM_SCALAR >::fillV : input is already full with " << _vertices_
245  << " vertices.");
246 
247  bool eq = true;
248 
249  for (const auto& v: _insertedVertices_) {
250  eq = true;
251 
252  for (decltype(_card_) mod = 0; mod < _card_; mod++)
253  if (std::fabs(v[mod] - vertex[mod]) > 1e-6) {
254  eq = false;
255  break;
256  }
257 
258  if (eq) {
259  _vertices_--;
260  return;
261  // GUM_ERROR ( DuplicateElement, "LRSWrapper< GUM_SCALAR >::fillV :
262  // vertex
263  // already present : " << vertex );
264  }
265  }
266 
267  auto row = _insertedVertices_.size();
268 
269  for (decltype(_card_) mod = 0; mod < _card_; mod++)
270  _input_[row][mod + 1] = vertex[mod];
271 
273 
275  }
276 
277  template < typename GUM_SCALAR >
278  void LRSWrapper< GUM_SCALAR >::H2V() {
279  if (_state_ != _states_::H2Vready)
281  "LRSWrapper< GUM_SCALAR >::H2V : fillH has not been called with "
282  "all modalities, current state is still : "
283  << _setUpStateNames_[static_cast< int >(_state_)]);
284 
285  // check that we have a credal set and not a precise point probability,
286  // i.e.
287  // sum of vertex elements is close to one ( floating type precision )
288  GUM_SCALAR sum = 0;
289 
290  for (const auto elem: _vertex_)
291  sum += elem;
292 
293  if (std::fabs(sum - 1) < 1e-6) {
295  return;
296  }
297 
298  // not precise point probability, initialize lrs
299 
300  // _coutOff_();
301 
302  _initLrs_();
303 
304  /* We initiate reverse search from this dictionary */
305  /* getting new dictionaries until the search is complete */
306  /* User can access each output line from output which is */
307  /* vertex/ray/facet from the lrs_mp_vector output */
308  /* prune is TRUE if tree should be pruned at current node */
309 
310  // pruning is not used
311 
312  std::vector< int64_t > Num; /* numerators of all vertices */
313  std::vector< int64_t > Den; /* denominators of all vertices */
314 
315  do {
316  for (decltype(_dic_->d) col = 0, end = _dic_->d; col <= end; col++)
318  // iszero macro could be used here for the test on right
319  if (_dat_->hull
320  || ((((_lrsOutput_[0])[0] == 2 || (_lrsOutput_[0])[0] == -2)
321  && (_lrsOutput_[0])[1] == 0)
322  ? 1L
323  : 0L)) {
324  // _coutOn_();
325  /*for ( decltype(Q->n) i = 0; i < Q->n; i++ )
326  pmp ("", output[i]);*/
328  "LRSWrapper< GUM_SCALAR >::H2V : asked for "
329  "Q-hull computation or not reading a vertex !");
330  } else
331  for (decltype(_dat_->n) i = 1, end = _dat_->n; i < end; i++)
333  }
334  } while (lrs_getnextbasis(&_dic_, _dat_, 0L));
335 
336  auto vtx = Num.size();
338 
339  for (decltype(vtx) i = 1; i <= vtx; i++) {
340  vertex[(i - 1) % _card_] = GUM_SCALAR(Num[i - 1] * 1.0 / Den[i - 1]);
341 
342  if (i % _card_ == 0) {
344  _vertices_++;
345  }
346  }
347 
348  _freeLrs_();
349 
350  // _coutOn_();
351  }
352 
353  template < typename GUM_SCALAR >
354  void LRSWrapper< GUM_SCALAR >::V2H() {
355  if (!_state_ == _states_::V2Hready)
357  "LRSWrapper< GUM_SCALAR >::V2H : fillV has "
358  "not been called with all vertices, current "
359  "state is still : "
361  }
362 
363  template < typename GUM_SCALAR >
365  if (!_state_ == _states_::V2Hready)
367  "LRSWrapper< GUM_SCALAR >::computeVolume : "
368  "volume is only for V-representation or "
369  "fillV has not been called with all "
370  "vertices, current state is still : "
372 
373  // _coutOff_();
374 
375  _getVolume_ = true;
376 
377  _initLrs_();
378 
379  do {
380  for (decltype(_dic_->d) col = 0, end = _dic_->d; col <= end; col++)
382  } while (lrs_getnextbasis(&_dic_, _dat_, 0L));
383 
384  int64_t Nsize = (_dat_->Nvolume[0] > 0) ? _dat_->Nvolume[0] : -_dat_->Nvolume[0];
385  int64_t Dsize = (_dat_->Dvolume[0] > 0) ? _dat_->Dvolume[0] : -_dat_->Dvolume[0];
386 
387  int64_t num = 0L, den = 0L;
388  int64_t tmp;
389 
390  for (decltype(Nsize) i = Nsize - 1; i > 0; i--) {
391  tmp = _dat_->Nvolume[i];
392 
393  for (decltype(i) j = 1; j < i; j++)
394  tmp *= BASE;
395 
396  num += tmp;
397  }
398 
399  for (decltype(Dsize) i = Dsize - 1; i > 0; i--) {
400  tmp = _dat_->Dvolume[i];
401 
402  for (decltype(i) j = 1; j < i; j++)
403  tmp *= BASE;
404 
405  den += tmp;
406  }
407 
408  _volume_ = num * 1.0 / den;
409 
410  _freeLrs_();
411 
412  // _coutOn_();
413  }
414 
415  template < typename GUM_SCALAR >
417  if (_state_ != _states_::V2Hready)
419  "LRSWrapper< GUM_SCALAR >::elimRedundVrep : only for "
420  "V-representation or fillV has not been called with all vertices, "
421  "current state is still : "
422  << _setUpStateNames_[static_cast< int >(_state_)]);
423 
424  // _coutOff_();
425 
426  _initLrs_();
427 
428  int64_t* redineq; /* redineq[i]=0 if ineq i non-red,1 if red,2 linearity */
429 
430  /*********************************************************************************/
431  /* Test each row of the dictionary to see if it is redundant */
432  /*********************************************************************************/
433 
434  /* note some of these may have been changed in getting initial dictionary
435  */
436  auto m = _dic_->m_A;
437  auto d = _dic_->d;
438  /* number of linearities in input */ /* should be 0 ! */
439  auto nlinearity = _dat_->nlinearity;
440  auto lastdv = _dat_->lastdv;
441 
442  /* linearities are not considered for redundancy */
443  redineq = (int64_t*)calloc(std::size_t(m + 1), sizeof(int64_t));
444 
445  for (decltype(nlinearity) i = 0; i < nlinearity; i++)
446  redineq[_dat_->linearity[i]] = 2L;
447 
448  /* rows 0..lastdv are cost, decision variables, or linearities */
449  /* other rows need to be tested */
450 
451  for (decltype(m + d) index = lastdv + 1, end = m + d; index <= end; index++) {
452  /* input inequality number of current index */
453  auto ineq = _dat_->inequality[index - lastdv]; /* the input inequality number
454  corr. to this index */
455 
457  }
458 
459  /* linearities */
460  if (nlinearity > 0)
462  "LRSWrapper< GUM_SCALAR >::elimRedundVrep : not "
463  "reading a vertex but a linearity !");
464 
465  /* count number of non-redundant inequalities */
466  /*
467  auto nredund = nlinearity;
468  for ( decltype ( m ) i = 1; i <= m; i++ )
469  if ( redineq[ i ] == 0 )
470  nredund++;
471  */
472 
473  // __vertices = nredund;
474  // __output = std::vector< std::vector< GUM_SCALAR > > ( nredund,
475  // std::vector<
476  // GUM_SCALAR > ( _dat_->n - 1 ) );
477 
478  for (decltype(m) i = 1; i <= m; i++)
479  if (redineq[i] == 0)
481  _input_[std::size_t(i - 1)].end()));
482 
483  _vertices_ = (unsigned int)_output_.size();
484 
485  _freeLrs_();
486 
487  // _coutOn_();
488  }
489 
490  template < typename GUM_SCALAR >
492  lrs_mp Din,
493  std::vector< int64_t >& Num,
494  std::vector< int64_t >& Den) const {
495  int64_t Nsize = (Nin[0] > 0) ? Nin[0] : -Nin[0];
496  int64_t Dsize = (Din[0] > 0) ? Din[0] : -Din[0];
497 
498  int64_t num = 0L;
499  int64_t den = 0L;
500 
501  int64_t tmp;
502 
503  for (decltype(Nsize) i = Nsize - 1; i > 0; i--) {
504  tmp = Nin[i];
505 
506  for (decltype(i) j = 1; j < i; j++)
507  tmp *= BASE;
508 
509  num += tmp;
510  }
511 
512  if (!(Din[0] == 2L && Din[1] == 1L)) { /* rational */
513  for (decltype(Dsize) i = Dsize - 1; i > 0; i--) {
514  tmp = Din[i];
515 
516  for (decltype(i) j = 1; j < i; j++)
517  tmp *= BASE;
518 
519  den += tmp;
520  }
521  } else {
522  den = 1L;
523  }
524 
525  int64_t Nsign = ((Nin[0] < 0) ? -1L : 1L);
526  int64_t Dsign = ((Din[0] < 0) ? -1L : 1L);
527 
528  if ((Nsign * Dsign) == -1L) num = -num;
529 
530  Num.push_back(num);
531  Den.push_back(den);
532  }
533 
534  /*
535  void pmp (char name[], lrs_mp a) {
536  int64_t i;
537  fprintf (lrs_ofp, "%s", name);
538  if (sign (a) == NEG)
539  fprintf (lrs_ofp, "-");
540  else
541  fprintf (lrs_ofp, " ");
542  fprintf (lrs_ofp, "%lu", a[length (a) - 1]);
543  for (i = length (a) - 2; i >= 1; i--)
544  fprintf (lrs_ofp, FORMAT, a[i]);
545  fprintf (lrs_ofp, " ");
546  }*/
547 
548  template < typename GUM_SCALAR >
549  void LRSWrapper< GUM_SCALAR >::_fill_() const {
550  std::size_t cols = _input_[0].size();
551 
552  int64_t* num = new int64_t[cols]; // ISO C++ forbids variable length array,
553  // we need to do this instead
554  int64_t* den = new int64_t[cols];
555 
557 
559 
560  for (int64_t row = 0; row < rows; row++) {
561  for (std::size_t col = 0; col < cols; col++) {
563  denominator,
564  _input_[std::size_t(row)][col]);
565 
566  num[col] = numerator;
567  den[col] = denominator;
568  }
569 
570  /* GE is inequality, EQ is equation */
571  /* 1L, 0L respectively */
573  _dat_,
574  int64_t(row + 1),
575  num,
576  den,
577  1L); // do NOT forget this + 1 on row
578  }
579 
580  delete[] num;
581  delete[] den;
582  }
583 
584  template < typename GUM_SCALAR >
588  "LRSWrapper< GUM_SCALAR >:: _initLrs_ : not ready, current state "
589  "is still : "
590  << _setUpStateNames_[static_cast< int >(_state_)]);
591 
592  // __coutOff();
593 
594  std::string name = "\n*LrsWrapper:";
595  std::vector< char > chars(name.c_str(), name.c_str() + name.size() + 1u);
596  // use &chars[0] as a char*
597 
598  if (!lrs_init(&chars[0])) {
599  // _coutOn_();
600  GUM_ERROR(FatalError, "LRSWrapper< GUM_SCALAR >:: _initLrs_ : failed lrs_init")
601  }
602 
603  name = "LRSWrapper globals";
604  chars = std::vector< char >(name.c_str(), name.c_str() + name.size() + 1u);
605 
606  _dat_ = lrs_alloc_dat(&chars[0]);
607 
608  if (_dat_ == nullptr) {
609  // _coutOn_();
610  GUM_ERROR(FatalError, "LRSWrapper< GUM_SCALAR >:: _initLrs_ : failed lrs_alloc_dat")
611  }
612 
613  _dat_->n = Size(_input_[0].size());
614  _dat_->m = Size(_input_.size());
615 
616  _dat_->getvolume = (_getVolume_) ? 1L : 0L;
617  _dat_->hull = (_hull_) ? 1L : 0L;
618  _dat_->polytope = (_polytope_) ? 1L : 0L;
619 
621 
623 
624  if (_dic_ == nullptr) {
625  // _coutOn_();
626  GUM_ERROR(FatalError, "LRSWrapper< GUM_SCALAR >:: _initLrs_ : failed lrs_alloc_dic")
627  }
628 
629  _fill_();
630 
631  /* Pivot to a starting dictionary */
632  if (!lrs_getfirstbasis(&_dic_, _dat_, &_Lin_, 0L)) {
633  // _coutOn_();
634  GUM_ERROR(FatalError, "LRSWrapper< GUM_SCALAR >:: _initLrs_ : failed lrs_getfirstbasis");
635  }
636 
637  /* There may have been column redundancy */
638  /* If so the linearity space is obtained and redundant */
639  /* columns are removed. User can access linearity space */
640  /* from lrs_mp_matrix Lin dimensions nredundcol x d+1 */
641 
642  decltype(_dat_->nredundcol) startcol = 0;
643 
644  if (_dat_->homogeneous && _dat_->hull) {
645  startcol++; /* col zero not treated as redundant */
646 
647  if (!_dat_->restart) {
648  // _coutOn_();
649 
650  for (decltype(_dat_->nredundcol) col = startcol; col < _dat_->nredundcol; col++)
652 
653  GUM_ERROR(FatalError, "LRSWrapper< GUM_SCALAR >:: _initLrs_ : redundant columns !")
654  }
655  }
656  /*
657  if ( _dat_->nredundcol > 0 ) {
658  _coutOn_();
659 
660  for ( decltype( _dat_->nredundcol ) col = 0, end =
661  _dat_->nredundcol;
662  col < end;
663  col++ )
664  lrs_printoutput( _dat_, _Lin_[col] );
665 
666  GUM_ERROR(
667  FatalError,
668  "LRSWrapper< GUM_SCALAR >:: _initLrs_ : redundant columns !" );
669  }
670  */
671  }
672 
673  template < typename GUM_SCALAR >
675  /* free space : do not change order of next lines! */
676 
678 
680 
681  if (_dat_->runs > 0) {
682  free(_dat_->isave);
683  free(_dat_->jsave);
684  }
685 
686  auto savem = _dic_->m; /* need this to clear _dat_*/
687 
688  lrs_free_dic(_dic_, _dat_); /* deallocate lrs_dic */
689 
690  _dat_->m = savem;
692 
693  std::string name = "LrsWrapper:";
694  std::vector< char > chars(name.c_str(), name.c_str() + name.size() + 1u);
695 
696  lrs_close(&chars[0]);
697 
698  // _coutOn_();
699  }
700 
701  template < typename GUM_SCALAR >
702  void LRSWrapper< GUM_SCALAR >::_coutOff_() const {
703  fflush(stdout);
704 #ifdef _MSC_VER
705  freopen("NUL", "w", stdout);
706 #else // _MSC_VER
707  _oldCout_ = dup(1);
708 
709  int new_cout = open("/dev/null", O_WRONLY);
710  dup2(new_cout, 1);
711  close(new_cout);
712 #endif // _MSC_VER
713  }
714 
715  template < typename GUM_SCALAR >
716  void LRSWrapper< GUM_SCALAR >::_coutOn_() const {
717  fflush(stdout);
718 #ifdef _MSC_VER
719  freopen("CON", "w", stdout);
720 #else // _MSC_VER
721  dup2(_oldCout_, 1);
722  close(_oldCout_);
723 #endif // _MSC_VER
724  }
725 
726  } // namespace credal
727 } // namespace gum
INLINE void emplace(Args &&... args)
Definition: set_tpl.h:643
namespace for all credal networks entities
Definition: LpInterface.cpp:37