1 /**
2  *
3  *   Copyright (c) 2005-2021 by Pierre-Henri WUILLEMIN(_at_LIP6) & Christophe GONZALES(_at_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 >
LRSWrapper()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 >
~LRSWrapper()47     LRSWrapper< GUM_SCALAR >::~LRSWrapper() {
48       GUM_DESTRUCTOR(LRSWrapper);
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 >
getVerticesNumber()62     const unsigned int& LRSWrapper< GUM_SCALAR >::getVerticesNumber() const {
63       return _vertices_;
64     }
65 
66     template < typename GUM_SCALAR >
getVolume()67     const GUM_SCALAR& LRSWrapper< GUM_SCALAR >::getVolume() const {
68       if (_volume_ != 0)
69         return _volume_;
70       else
71         GUM_ERROR(OperationNotAllowed,
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 >
setUpH(const Size & card)79     void LRSWrapper< GUM_SCALAR >::setUpH(const Size& card) {
80       if (card < 2)
81         GUM_ERROR(OperationNotAllowed,
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 
98       _vertex_ = std::vector< GUM_SCALAR >(card);
99 
100       _state_ = _states_::Hup;
101 
102       _card_ = (unsigned int)card;
103     }
104 
105     template < typename GUM_SCALAR >
setUpV(const Size & card,const Size & vertices)106     void LRSWrapper< GUM_SCALAR >::setUpV(const Size& card, const Size& vertices) {
107       if (card < 2)
108         GUM_ERROR(OperationNotAllowed,
109                   "LRSWrapper< GUM_SCALAR >::setUpV : "
110                   "cardinality must be at least 2");
111 
112       if (vertices < 2)
113         GUM_ERROR(OperationNotAllowed,
114                   "LRSWrapper< GUM_SCALAR >::setUpV : vertices "
115                   "must be at least 2 to build a polytope");
116 
117       tearDown();
118 
119       _input_ = std::vector< std::vector< GUM_SCALAR > >(vertices,
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 >
tearDown()131     void LRSWrapper< GUM_SCALAR >::tearDown() {
132       _input_.clear();
133       _output_.clear();
134       _vertex_.clear();
135       _insertedModals_.clear();
136 
137       _insertedVertices_.clear();
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 >
nextHInput()151     void LRSWrapper< GUM_SCALAR >::nextHInput() {
152       _insertedModals_.clear();
153       _insertedVertices_.clear();
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;
169         GUM_ERROR(OperationNotAllowed,
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 >
fillH(const GUM_SCALAR & min,const GUM_SCALAR & max,const Size & modal)182     void LRSWrapper< GUM_SCALAR >::fillH(const GUM_SCALAR& min,
183                                          const GUM_SCALAR& max,
184                                          const Size&       modal) {
185       if (_state_ != _states_::Hup)
186         GUM_ERROR(OperationNotAllowed,
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_)
192         GUM_ERROR(OutOfBounds,
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 
205       _insertedModals_.insert(int(modal));
206 
207       if (_insertedModals_.size() == _card_) _state_ = _states_::H2Vready;
208     }
209 
210     template < typename GUM_SCALAR >
fillMatrix(const std::vector<std::vector<GUM_SCALAR>> & matrix)211     void LRSWrapper< GUM_SCALAR >::fillMatrix(
212        const std::vector< std::vector< GUM_SCALAR > >& matrix) {
213       if (_state_ != _states_::Hup)
214         GUM_ERROR(OperationNotAllowed,
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_)
220         GUM_ERROR(OutOfBounds,
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++) {
228         _insertedModals_.insert(modal);
229       }
230 
231       _state_ = _states_::H2Vready;
232     }
233 
234     template < typename GUM_SCALAR >
fillV(const std::vector<GUM_SCALAR> & vertex)235     void LRSWrapper< GUM_SCALAR >::fillV(const std::vector< GUM_SCALAR >& vertex) {
236       if (_state_ != _states_::Vup)
237         GUM_ERROR(OperationNotAllowed,
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 
242       if (_insertedVertices_.size() == _vertices_)
243         GUM_ERROR(OutOfBounds,
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 
272       _insertedVertices_.push_back(vertex);
273 
274       if (_insertedVertices_.size() == _vertices_) _state_ = _states_::V2Hready;
275     }
276 
277     template < typename GUM_SCALAR >
H2V()278     void LRSWrapper< GUM_SCALAR >::H2V() {
279       if (_state_ != _states_::H2Vready)
280         GUM_ERROR(OperationNotAllowed,
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) {
294         _output_ = std::vector< std::vector< GUM_SCALAR > >(1, _vertex_);
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++)
317           if (lrs_getsolution(_dic_, _dat_, _lrsOutput_, 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]);*/
327               GUM_ERROR(FatalError,
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++)
332                 _getLRSWrapperOutput_(_lrsOutput_[i], _lrsOutput_[0], Num, Den);
333           }
334       } while (lrs_getnextbasis(&_dic_, _dat_, 0L));
335 
336       auto                      vtx = Num.size();
337       std::vector< GUM_SCALAR > vertex(_card_);
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) {
343           _output_.push_back(vertex);
344           _vertices_++;
345         }
346       }
347 
348       _freeLrs_();
349 
350       //  _coutOn_();
351     }
352 
353     template < typename GUM_SCALAR >
V2H()354     void LRSWrapper< GUM_SCALAR >::V2H() {
355       if (!_state_ == _states_::V2Hready)
356         GUM_ERROR(OperationNotAllowed,
357                   "LRSWrapper< GUM_SCALAR >::V2H : fillV has "
358                   "not been called with all vertices, current "
359                   "state is still : "
360                      << _setUpStateNames_[_state_]);
361     }
362 
363     template < typename GUM_SCALAR >
computeVolume()364     void LRSWrapper< GUM_SCALAR >::computeVolume() {
365       if (!_state_ == _states_::V2Hready)
366         GUM_ERROR(OperationNotAllowed,
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 : "
371                      << _setUpStateNames_[_state_]);
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++)
381           lrs_getsolution(_dic_, _dat_, _lrsOutput_, 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 >
elimRedundVrep()416     void LRSWrapper< GUM_SCALAR >::elimRedundVrep() {
417       if (_state_ != _states_::V2Hready)
418         GUM_ERROR(OperationNotAllowed,
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 
456         redineq[ineq] = checkindex(_dic_, _dat_, index);
457       }
458 
459       /* linearities */
460       if (nlinearity > 0)
461         GUM_ERROR(FatalError,
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)
480           _output_.push_back(std::vector< GUM_SCALAR >(++_input_[std::size_t(i - 1)].begin(),
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 >
_getLRSWrapperOutput_(lrs_mp Nin,lrs_mp Din,std::vector<int64_t> & Num,std::vector<int64_t> & Den)491     void LRSWrapper< GUM_SCALAR >::_getLRSWrapperOutput_(lrs_mp                  Nin,
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 >
_fill_()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 
556       int64_t rows = int64_t(_input_.size());
557 
558       int64_t numerator, denominator;
559 
560       for (int64_t row = 0; row < rows; row++) {
561         for (std::size_t col = 0; col < cols; col++) {
562           Rational< GUM_SCALAR >::continuedFracFirst(numerator,
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 */
572         lrs_set_row(_dic_,
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 >
_initLrs_()585     void LRSWrapper< GUM_SCALAR >::_initLrs_() {
586       if (_state_ != _states_::H2Vready && _state_ != _states_::V2Hready)
587         GUM_ERROR(OperationNotAllowed,
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 
620       _lrsOutput_ = lrs_alloc_mp_vector(_dat_->n);
621 
622       _dic_ = lrs_alloc_dic(_dat_);
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++)
651             lrs_printoutput(_dat_, _Lin_[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 >
_freeLrs_()674     void LRSWrapper< GUM_SCALAR >::_freeLrs_() {
675       /* free space : do not change order of next lines! */
676 
677       lrs_clear_mp_vector(_lrsOutput_, _dat_->n);
678 
679       if (_dat_->nredundcol > 0) lrs_clear_mp_matrix(_Lin_, _dat_->nredundcol, _dat_->n);
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;
691       lrs_free_dat(_dat_);
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 >
_coutOff_()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 >
_coutOn_()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
728