aGrUM  0.20.2
a C++ library for (probabilistic) graphical models
LrsWrapper_tpl.h
Go to the documentation of this file.
1 /**
2  *
3  * Copyright 2005-2020 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 
88  card * 2 + 2,
89  std::vector< GUM_SCALAR >(card + 1, 0));
90 
91  input__[card * 2] = std::vector< GUM_SCALAR >(card + 1, -1);
92  input__[card * 2][0] = 1;
93 
94  input__[card * 2 + 1] = std::vector< GUM_SCALAR >(card + 1, 1);
95  input__[card * 2 + 1][0] = -1;
96 
97  output__ = std::vector< std::vector< GUM_SCALAR > >();
98 
100 
101  state__ = states__::Hup;
102 
103  card__ = (unsigned int)card;
104  }
105 
106  template < typename GUM_SCALAR >
107  void LRSWrapper< GUM_SCALAR >::setUpV(const Size& card, const Size& vertices) {
108  if (card < 2)
110  "LRSWrapper< GUM_SCALAR >::setUpV : "
111  "cardinality must be at least 2");
112 
113  if (vertices < 2)
115  "LRSWrapper< GUM_SCALAR >::setUpV : vertices "
116  "must be at least 2 to build a polytope");
117 
118  tearDown();
119 
121  vertices,
122  std::vector< GUM_SCALAR >(card + 1, 1));
123 
124  output__ = std::vector< std::vector< GUM_SCALAR > >();
125 
126  state__ = states__::Vup;
127 
128  card__ = (unsigned int)card;
129  vertices__ = (unsigned int)vertices;
130  }
131 
132  template < typename GUM_SCALAR >
134  input__.clear();
135  output__.clear();
136  vertex__.clear();
138 
140  vertices__ = 0;
141 
142  volume__ = 0;
143 
144  state__ = states__::none;
145  card__ = 0;
146 
147  getVolume__ = false;
148  hull__ = false;
149  polytope__ = false;
150  }
151 
152  template < typename GUM_SCALAR >
156  output__.clear();
157  vertex__.clear();
158  vertex__.resize(card__, 0);
159 
160  volume__ = 0;
161  vertices__ = 0;
162 
163  getVolume__ = false;
164  hull__ = false;
165  polytope__ = false;
166 
167  if (state__ == states__::H2Vready)
168  state__ = states__::Hup;
169  else if (state__ == states__::V2Hready) {
170  state__ = states__::Vup;
171  GUM_ERROR(
173  "LRSWrapper< GUM_SCALAR >::nextHInput : only for H-representation "
174  "as input. Previous state was : "
175  << setUpStateNames__[static_cast< int >(state__)]);
176  } else {
177  input__.clear();
178  state__ = states__::none;
179  card__ = 0;
180  vertex__.clear();
181  }
182  }
183 
184  template < typename GUM_SCALAR >
186  const GUM_SCALAR& max,
187  const Size& modal) {
188  if (state__ != states__::Hup)
189  GUM_ERROR(
191  "LRSWrapper< GUM_SCALAR >::fillH : setUpH or nextInput has not "
192  "been called or H-representation is complete, current state is : "
193  << setUpStateNames__[static_cast< int >(state__)]);
194 
195  if (modal >= card__)
197  "LRSWrapper< GUM_SCALAR >::fillH : modality is "
198  "greater or equal than cardinality : "
199  << modal << " >= " << card__);
200 
201  input__[modal * 2][0] = -min;
202  input__[modal * 2][modal + 1] = 1;
203 
204  input__[modal * 2 + 1][0] = max;
205  input__[modal * 2 + 1][modal + 1] = -1;
206 
207  vertex__[modal] = max;
208 
210 
212  }
213 
214  template < typename GUM_SCALAR >
216  const std::vector< std::vector< GUM_SCALAR > >& matrix) {
217  if (state__ != states__::Hup)
218  GUM_ERROR(
220  "LRSWrapper< GUM_SCALAR >::fillH : setUpH or nextInput has not "
221  "been called or H-representation is complete, current state is : "
222  << setUpStateNames__[static_cast< int >(state__)]);
223 
224  if (matrix[0].size() - 1 != card__)
226  "LRSWrapper< GUM_SCALAR >::fillMatrix : size is "
227  "different than cardinality : "
228  << (matrix[0].size() - 1) << " != " << card__);
229 
230  input__ = matrix;
231 
232  for (unsigned int modal = 0; modal < card__; modal++) {
234  }
235 
237  }
238 
239  template < typename GUM_SCALAR >
241  if (state__ != states__::Vup)
242  GUM_ERROR(
244  "LRSWrapper< GUM_SCALAR >::fillV : setUpV or nextInput has not "
245  "been called or V-representation is complete, current state is : "
246  << setUpStateNames__[static_cast< int >(state__)]);
247 
250  "LRSWrapper< GUM_SCALAR >::fillV : input is already full with "
251  << vertices__ << " vertices.");
252 
253  bool eq = true;
254 
255  for (const auto& v: insertedVertices__) {
256  eq = true;
257 
258  for (decltype(card__) mod = 0; mod < card__; mod++)
259  if (std::fabs(v[mod] - vertex[mod]) > 1e-6) {
260  eq = false;
261  break;
262  }
263 
264  if (eq) {
265  vertices__--;
266  return;
267  // GUM_ERROR ( DuplicateElement, "LRSWrapper< GUM_SCALAR >::fillV :
268  // vertex
269  // already present : " << vertex );
270  }
271  }
272 
273  auto row = insertedVertices__.size();
274 
275  for (decltype(card__) mod = 0; mod < card__; mod++)
276  input__[row][mod + 1] = vertex[mod];
277 
279 
281  }
282 
283  template < typename GUM_SCALAR >
284  void LRSWrapper< GUM_SCALAR >::H2V() {
285  if (state__ != states__::H2Vready)
287  "LRSWrapper< GUM_SCALAR >::H2V : fillH has not been called with "
288  "all modalities, current state is still : "
289  << setUpStateNames__[static_cast< int >(state__)]);
290 
291  // check that we have a credal set and not a precise point probability,
292  // i.e.
293  // sum of vertex elements is close to one ( floating type precision )
294  GUM_SCALAR sum = 0;
295 
296  for (const auto elem: vertex__)
297  sum += elem;
298 
299  if (std::fabs(sum - 1) < 1e-6) {
301  return;
302  }
303 
304  // not precise point probability, initialize lrs
305 
306  // coutOff__();
307 
308  initLrs__();
309 
310  /* We initiate reverse search from this dictionary */
311  /* getting new dictionaries until the search is complete */
312  /* User can access each output line from output which is */
313  /* vertex/ray/facet from the lrs_mp_vector output */
314  /* prune is TRUE if tree should be pruned at current node */
315 
316  // pruning is not used
317 
318  std::vector< int64_t > Num; /* numerators of all vertices */
319  std::vector< int64_t > Den; /* denominators of all vertices */
320 
321  do {
322  for (decltype(dic__->d) col = 0, end = dic__->d; col <= end; col++)
324  // iszero macro could be used here for the test on right
325  if (dat__->hull
326  || ((((lrsOutput__[0])[0] == 2 || (lrsOutput__[0])[0] == -2)
327  && (lrsOutput__[0])[1] == 0)
328  ? 1L
329  : 0L)) {
330  // coutOn__();
331  /*for ( decltype(Q->n) i = 0; i < Q->n; i++ )
332  pmp ("", output[i]);*/
334  "LRSWrapper< GUM_SCALAR >::H2V : asked for "
335  "Q-hull computation or not reading a vertex !");
336  } else
337  for (decltype(dat__->n) i = 1, end = dat__->n; i < end; i++)
339  }
340  } while (lrs_getnextbasis(&dic__, dat__, 0L));
341 
342  auto vtx = Num.size();
344 
345  for (decltype(vtx) i = 1; i <= vtx; i++) {
346  vertex[(i - 1) % card__] = GUM_SCALAR(Num[i - 1] * 1.0 / Den[i - 1]);
347 
348  if (i % card__ == 0) {
350  vertices__++;
351  }
352  }
353 
354  freeLrs__();
355 
356  // coutOn__();
357  }
358 
359  template < typename GUM_SCALAR >
360  void LRSWrapper< GUM_SCALAR >::V2H() {
361  if (!state__ == states__::V2Hready)
363  "LRSWrapper< GUM_SCALAR >::V2H : fillV has "
364  "not been called with all vertices, current "
365  "state is still : "
367  }
368 
369  template < typename GUM_SCALAR >
371  if (!state__ == states__::V2Hready)
373  "LRSWrapper< GUM_SCALAR >::computeVolume : "
374  "volume is only for V-representation or "
375  "fillV has not been called with all "
376  "vertices, current state is still : "
378 
379  // coutOff__();
380 
381  getVolume__ = true;
382 
383  initLrs__();
384 
385  do {
386  for (decltype(dic__->d) col = 0, end = dic__->d; col <= end; col++)
388  } while (lrs_getnextbasis(&dic__, dat__, 0L));
389 
390  int64_t Nsize
391  = (dat__->Nvolume[0] > 0) ? dat__->Nvolume[0] : -dat__->Nvolume[0];
392  int64_t Dsize
393  = (dat__->Dvolume[0] > 0) ? dat__->Dvolume[0] : -dat__->Dvolume[0];
394 
395  int64_t num = 0L, den = 0L;
396  int64_t tmp;
397 
398  for (decltype(Nsize) i = Nsize - 1; i > 0; i--) {
399  tmp = dat__->Nvolume[i];
400 
401  for (decltype(i) j = 1; j < i; j++)
402  tmp *= BASE;
403 
404  num += tmp;
405  }
406 
407  for (decltype(Dsize) i = Dsize - 1; i > 0; i--) {
408  tmp = dat__->Dvolume[i];
409 
410  for (decltype(i) j = 1; j < i; j++)
411  tmp *= BASE;
412 
413  den += tmp;
414  }
415 
416  volume__ = num * 1.0 / den;
417 
418  freeLrs__();
419 
420  // coutOn__();
421  }
422 
423  template < typename GUM_SCALAR >
425  if (state__ != states__::V2Hready)
426  GUM_ERROR(
428  "LRSWrapper< GUM_SCALAR >::elimRedundVrep : only for "
429  "V-representation or fillV has not been called with all vertices, "
430  "current state is still : "
431  << setUpStateNames__[static_cast< int >(state__)]);
432 
433  // coutOff__();
434 
435  initLrs__();
436 
437  int64_t* redineq; /* redineq[i]=0 if ineq i non-red,1 if red,2 linearity */
438 
439  /*********************************************************************************/
440  /* Test each row of the dictionary to see if it is redundant */
441  /*********************************************************************************/
442 
443  /* note some of these may have been changed in getting initial dictionary
444  */
445  auto m = dic__->m_A;
446  auto d = dic__->d;
447  /* number of linearities in input */ /* should be 0 ! */
448  auto nlinearity = dat__->nlinearity;
449  auto lastdv = dat__->lastdv;
450 
451  /* linearities are not considered for redundancy */
452  redineq = (int64_t*)calloc(std::size_t(m + 1), sizeof(int64_t));
453 
454  for (decltype(nlinearity) i = 0; i < nlinearity; i++)
455  redineq[dat__->linearity[i]] = 2L;
456 
457  /* rows 0..lastdv are cost, decision variables, or linearities */
458  /* other rows need to be tested */
459 
460  for (decltype(m + d) index = lastdv + 1, end = m + d; index <= end;
461  index++) {
462  /* input inequality number of current index */
463  auto ineq
464  = dat__->inequality[index - lastdv]; /* the input inequality number
465  corr. to this index */
466 
468  }
469 
470  /* linearities */
471  if (nlinearity > 0)
473  "LRSWrapper< GUM_SCALAR >::elimRedundVrep : not "
474  "reading a vertex but a linearity !");
475 
476  /* count number of non-redundant inequalities */
477  /*
478  auto nredund = nlinearity;
479  for ( decltype ( m ) i = 1; i <= m; i++ )
480  if ( redineq[ i ] == 0 )
481  nredund++;
482  */
483 
484  //__vertices = nredund;
485  //__output = std::vector< std::vector< GUM_SCALAR > > ( nredund,
486  // std::vector<
487  // GUM_SCALAR > ( dat__->n - 1 ) );
488 
489  for (decltype(m) i = 1; i <= m; i++)
490  if (redineq[i] == 0)
492  std::vector< GUM_SCALAR >(++input__[std::size_t(i - 1)].begin(),
493  input__[std::size_t(i - 1)].end()));
494 
495  vertices__ = (unsigned int)output__.size();
496 
497  freeLrs__();
498 
499  // coutOn__();
500  }
501 
502  template < typename GUM_SCALAR >
504  lrs_mp Nin,
505  lrs_mp Din,
506  std::vector< int64_t >& Num,
507  std::vector< int64_t >& Den) const {
508  int64_t Nsize = (Nin[0] > 0) ? Nin[0] : -Nin[0];
509  int64_t Dsize = (Din[0] > 0) ? Din[0] : -Din[0];
510 
511  int64_t num = 0L;
512  int64_t den = 0L;
513 
514  int64_t tmp;
515 
516  for (decltype(Nsize) i = Nsize - 1; i > 0; i--) {
517  tmp = Nin[i];
518 
519  for (decltype(i) j = 1; j < i; j++)
520  tmp *= BASE;
521 
522  num += tmp;
523  }
524 
525  if (!(Din[0] == 2L && Din[1] == 1L)) { /* rational */
526  for (decltype(Dsize) i = Dsize - 1; i > 0; i--) {
527  tmp = Din[i];
528 
529  for (decltype(i) j = 1; j < i; j++)
530  tmp *= BASE;
531 
532  den += tmp;
533  }
534  } else {
535  den = 1L;
536  }
537 
538  int64_t Nsign = ((Nin[0] < 0) ? -1L : 1L);
539  int64_t Dsign = ((Din[0] < 0) ? -1L : 1L);
540 
541  if ((Nsign * Dsign) == -1L) num = -num;
542 
543  Num.push_back(num);
544  Den.push_back(den);
545  }
546 
547  /*
548  void pmp (char name[], lrs_mp a) {
549  int64_t i;
550  fprintf (lrs_ofp, "%s", name);
551  if (sign (a) == NEG)
552  fprintf (lrs_ofp, "-");
553  else
554  fprintf (lrs_ofp, " ");
555  fprintf (lrs_ofp, "%lu", a[length (a) - 1]);
556  for (i = length (a) - 2; i >= 1; i--)
557  fprintf (lrs_ofp, FORMAT, a[i]);
558  fprintf (lrs_ofp, " ");
559  }*/
560 
561  template < typename GUM_SCALAR >
562  void LRSWrapper< GUM_SCALAR >::fill__() const {
563  std::size_t cols = input__[0].size();
564 
565  int64_t* num = new int64_t[cols]; // ISO C++ forbids variable length array,
566  // we need to do this instead
567  int64_t* den = new int64_t[cols];
568 
570 
572 
573  for (int64_t row = 0; row < rows; row++) {
574  for (std::size_t col = 0; col < cols; col++) {
576  numerator,
577  denominator,
578  input__[std::size_t(row)][col]);
579 
580  num[col] = numerator;
581  den[col] = denominator;
582  }
583 
584  /* GE is inequality, EQ is equation */
585  /* 1L, 0L respectively */
587  dat__,
588  int64_t(row + 1),
589  num,
590  den,
591  1L); // do NOT forget this + 1 on row
592  }
593 
594  delete[] num;
595  delete[] den;
596  }
597 
598  template < typename GUM_SCALAR >
602  "LRSWrapper< GUM_SCALAR >::initLrs__ : not ready, current state "
603  "is still : "
604  << setUpStateNames__[static_cast< int >(state__)]);
605 
606  //__coutOff();
607 
608  std::string name = "\n*LrsWrapper:";
609  std::vector< char > chars(name.c_str(), name.c_str() + name.size() + 1u);
610  // use &chars[0] as a char*
611 
612  if (!lrs_init(&chars[0])) {
613  // coutOn__();
615  "LRSWrapper< GUM_SCALAR >::initLrs__ : failed lrs_init");
616  }
617 
618  name = "LRSWrapper globals";
619  chars = std::vector< char >(name.c_str(), name.c_str() + name.size() + 1u);
620 
621  dat__ = lrs_alloc_dat(&chars[0]);
622 
623  if (dat__ == nullptr) {
624  // coutOn__();
626  "LRSWrapper< GUM_SCALAR >::initLrs__ : failed lrs_alloc_dat");
627  }
628 
629  dat__->n = Size(input__[0].size());
630  dat__->m = Size(input__.size());
631 
632  dat__->getvolume = (getVolume__) ? 1L : 0L;
633  dat__->hull = (hull__) ? 1L : 0L;
634  dat__->polytope = (polytope__) ? 1L : 0L;
635 
637 
639 
640  if (dic__ == nullptr) {
641  // coutOn__();
643  "LRSWrapper< GUM_SCALAR >::initLrs__ : failed lrs_alloc_dic");
644  }
645 
646  fill__();
647 
648  /* Pivot to a starting dictionary */
649  if (!lrs_getfirstbasis(&dic__, dat__, &Lin__, 0L)) {
650  // coutOn__();
651  GUM_ERROR(
652  FatalError,
653  "LRSWrapper< GUM_SCALAR >::initLrs__ : failed lrs_getfirstbasis");
654  }
655 
656  /* There may have been column redundancy */
657  /* If so the linearity space is obtained and redundant */
658  /* columns are removed. User can access linearity space */
659  /* from lrs_mp_matrix Lin dimensions nredundcol x d+1 */
660 
661  decltype(dat__->nredundcol) startcol = 0;
662 
663  if (dat__->homogeneous && dat__->hull) {
664  startcol++; /* col zero not treated as redundant */
665 
666  if (!dat__->restart) {
667  // coutOn__();
668 
669  for (decltype(dat__->nredundcol) col = startcol; col < dat__->nredundcol;
670  col++)
672 
674  "LRSWrapper< GUM_SCALAR >::initLrs__ : redundant columns !");
675  }
676  }
677  /*
678  if ( dat__->nredundcol > 0 ) {
679  coutOn__();
680 
681  for ( decltype( dat__->nredundcol ) col = 0, end =
682  dat__->nredundcol;
683  col < end;
684  col++ )
685  lrs_printoutput( dat__, Lin__[col] );
686 
687  GUM_ERROR(
688  FatalError,
689  "LRSWrapper< GUM_SCALAR >::initLrs__ : redundant columns !" );
690  }
691  */
692  }
693 
694  template < typename GUM_SCALAR >
696  /* free space : do not change order of next lines! */
697 
699 
700  if (dat__->nredundcol > 0)
702 
703  if (dat__->runs > 0) {
704  free(dat__->isave);
705  free(dat__->jsave);
706  }
707 
708  auto savem = dic__->m; /* need this to clear dat__*/
709 
710  lrs_free_dic(dic__, dat__); /* deallocate lrs_dic */
711 
712  dat__->m = savem;
714 
715  std::string name = "LrsWrapper:";
716  std::vector< char > chars(name.c_str(), name.c_str() + name.size() + 1u);
717 
718  lrs_close(&chars[0]);
719 
720  // coutOn__();
721  }
722 
723  template < typename GUM_SCALAR >
724  void LRSWrapper< GUM_SCALAR >::coutOff__() const {
725  fflush(stdout);
726 #ifdef _MSC_VER
727  freopen("NUL", "w", stdout);
728 #else // _MSC_VER
729  oldCout__ = dup(1);
730 
731  int new_cout = open("/dev/null", O_WRONLY);
732  dup2(new_cout, 1);
733  close(new_cout);
734 #endif // _MSC_VER
735  }
736 
737  template < typename GUM_SCALAR >
738  void LRSWrapper< GUM_SCALAR >::coutOn__() const {
739  fflush(stdout);
740 #ifdef _MSC_VER
741  freopen("CON", "w", stdout);
742 #else // _MSC_VER
743  dup2(oldCout__, 1);
744  close(oldCout__);
745 #endif // _MSC_VER
746  }
747 
748  } // namespace credal
749 } // namespace gum
INLINE void emplace(Args &&... args)
Definition: set_tpl.h:669
namespace for all credal networks entities
Definition: LpInterface.cpp:37