aGrUM  0.20.3
a C++ library for (probabilistic) graphical models
LrsWrapper.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 /**
23  * @file
24  * @brief Lrs wrapper
25  * @author Matthieu HOURBRACQ and Pierre-Henri WUILLEMIN(@LIP6)
26  *
27  * easy use of lrs lib
28  */
29 
30 #ifndef __LRSWrapper_WRAPPER__H__
31 #define __LRSWrapper_WRAPPER__H__
32 
33 #include <agrum/agrum.h>
34 #include <agrum/tools/core/math/math_utils.h>
35 
36 
37 #ifdef HAVE_UNISTD_H
38 # include <unistd.h>
39 #else
40 # include <agrum/tools/core/mvsc/unistd.h>
41 #endif
42 
43 #include <chrono>
44 #include <cstdio>
45 #include <fcntl.h>
46 #include <fstream>
47 #include <unordered_set>
48 #include <vector>
49 
50 #include <agrum/tools/core/math/rational.h>
51 
52 // we force MP (not long or GMP)
53 #undef LONG
54 #undef LRSLONG
55 #undef GMP
56 #define MP
57 // lrs stuff
58 extern "C" {
59 #include <agrum/tools/external/lrslib/lrslib.h>
60 }
61 /* *** from lrs, we need to know BASE to read multiple precision integers *** */
62 #ifdef B32
63 /*32 bit machines */
64 # define FORMAT "%4.4lu"
65 # define MAXD 2147483647L
66 # define BASE 10000L
67 # define BASE_DIG 4
68 # define INTSIZE 8L
69 # define BIT "32bit"
70 #else
71 /* 64 bit machines */
72 # define MAXD 9223372036854775807L
73 # define BASE 1000000000L
74 # define FORMAT "%9.9lu"
75 # define BASE_DIG 9
76 # define INTSIZE 16L
77 # define BIT "64bit"
78 #endif
79 
80 // 64 bits for windows (long is 32 bits)
81 #ifdef _MSC_VER
82 typedef __int64 int64_t;
83 typedef unsigned __int64 uint64_t;
84 #else
85 # include <stdint.h>
86 #endif
87 
88 /* ************ */
89 
90 #define enumStringify(name) #name
91 
92 namespace gum {
93  namespace credal {
94 
95  /**
96  * @class LRSWrapper
97  * @headerfile LrsWrapper.h <agrum/CN/LrsWrapper.h>
98  * @brief Class template acting as a wrapper for Lexicographic Reverse
99  * Search by
100  * David Avis.
101  * @ingroup cn_group
102  * @tparam GUM_SCALAR A floating type ( float, double, long double ... ).
103  * @author Matthieu HOURBRACQ and Pierre-Henri WUILLEMIN(@LIP6)
104  */
105  template < typename GUM_SCALAR >
106  class LRSWrapper {
107  private:
108  /** @brief Shortcut for dynamic matrix using vectors. */
109  using matrix = typename std::vector< std::vector< GUM_SCALAR > >;
110 
111  /** @brief Input matrix - either a V-representation or an
112  * H-representation. */
113  matrix _input_;
114 
115  /** @brief Output matrix - either a V-representation or an
116  * H-representation. */
117  matrix _output_;
118 
119  /** @brief Cardinality of the variable. */
120  unsigned int _card_;
121 
122  /** @brief To keep track of which constraints over modalities have been
123  * inserted. When the set is full, the state changes from up to ready. */
124  std::unordered_set< int > _insertedModals_;
125 
126  /** @brief The number of vertices of the polytope. */
127  unsigned int _vertices_;
128 
129  /** @brief To keep track of inserted vertices and total. When set is full,
130  * the
131  * state changes from up to ready. */
132  std::vector< std::vector< GUM_SCALAR > > _insertedVertices_;
133 
134  /** @brief In case we have lower = upper for all modalities, a point
135  * probability, there is no need to use lrs. */
136  std::vector< GUM_SCALAR > _vertex_;
137 
138  /** @enum _states_ The possible states of the LrsWrapper. Some functions
139  * will
140  * throw an exception if the state is not correct. It allows the user to
141  * avoid
142  * making - invisible - mistakes. */
143  enum class _states_ : char
144  {
145  none = char(0),
146  Hup = char(1),
147  Vup = char(2),
148  H2Vready = char(3),
149  V2Hready = char(4),
150  };
151 
152  /** @brief The current state of the LrsWrapper. */
153  _states_ _state_;
154 
155  /** @brief The volume of the polytope, if computed, 0 otherwise. */
156  GUM_SCALAR _volume_;
157 
158  /** @brief To print an enum field name instead of it's value. Used with
159  * GUM_ERROR. */
160  const char* _setUpStateNames_[5] = {
161  enumStringify(_states_::none),
162  enumStringify(_states_::nHup),
163  enumStringify(_states_::nVup),
164  enumStringify(_states_::nH2Vready),
165  enumStringify(_states_::nV2Hready),
166  };
167 
168  /**
169  * @brief File descriptor of standard cout.
170  *
171  * Lrs writes a lot of stuff on standard cout.
172  * _oldCout_ is used to save the current cout before redirecting it
173  * to /dev/null when calling lrs.
174  * The standard cout is restored when lrs is done.
175  */
176  mutable int _oldCout_;
177 
178  /// @name lrs structs
179  /// @{
180 
181  /** @brief Structure for holding current dictionary and indices of lrs. */
182  lrs_dic* _dic_;
183 
184  /** @brief Structure for holding static problem data of lrs.*/
185  lrs_dat* _dat_;
186 
187  /** @brief One line of output of lrs : aither a ray, a vertex, a facet or
188  * a
189  * linearity. */
190  lrs_mp_vector _lrsOutput_;
191 
192  /** @brief Holds lrs input linearities if any are found. */
193  lrs_mp_matrix _Lin_;
194 
195  /// @}
196 
197  /// @name flags
198  /// @{
199 
200  bool _getVolume_;
201 
202  bool _hull_;
203 
204  bool _polytope_;
205 
206  /// @}
207 
208  /// @name cout redirection
209  /// @{
210 
211  /** @brief The function that redirects standard cout to /dev/null. */
212  void _coutOff_() const;
213 
214  /** @brief The function that restores standard cout. */
215  void _coutOn_() const;
216 
217  /// @}
218 
219  /// @name lrs datas <-> wrapper datas
220  /// @{
221 
222  /** @brief Free lrs space. */
223  void _freeLrs_();
224 
225  /** @brief Initialize lrs structs and first basis according to flags. */
226  void _initLrs_();
227 
228  /**
229  * @brief Fill lrs_dictionnary and datas from \c _input_ using integer
230  *rationals.
231  *
232  * Build polyhedron constraints and objective.
233  * Rational< GUM_SCALAR >::continuedFrac is the default algorithm used to
234  *approximate reals by integer rationals.
235  */
236  void _fill_() const;
237 
238  /**
239  * @brief Translate a single output from lrs.
240  *
241  * Only vertices are supposed to be read at this step.
242  *
243  * @param Nin Input numerators in mp format (returned by lrs).
244  * @param Din Input denominators in mp format (returned by lrs).
245  * @param Num Output integer numerators.
246  * @param Den Output integer denominators.
247  */
248  void _getLRSWrapperOutput_(lrs_mp Nin,
249  lrs_mp Din,
250  std::vector< int64_t >& Num,
251  std::vector< int64_t >& Den) const;
252 
253  /// @}
254 
255  public:
256  /// @name Constructors / Destructors
257  /// @{
258 
259  /**
260  * Default Constructor.
261  */
262  LRSWrapper();
263 
264  /**
265  * Default Destructor.
266  */
267  ~LRSWrapper();
268 
269  /// @}
270 
271  /// @name Getters and setters
272  /// @{
273 
274  /**
275  * @brief Get the intput matrix of the problem.
276  * @return A constant reference to the \c _intput_ matrix.
277  */
278  const matrix& getInput() const;
279 
280  /**
281  * @brief Get the output matrix solution of the problem.
282  * @return A constant reference to the \c _output_ matrix.
283  */
284  const matrix& getOutput() const;
285 
286  /**
287  * @brief Get the number of vertices of this polytope.
288  * @return A constant reference to the number of vertices \c _vertices_.
289  */
290  const unsigned int& getVerticesNumber() const;
291 
292  /**
293  * @brief Get the volume of the polytope that has been computed.
294  *
295  * @warning Volume can only be computed using V-representation.
296  *H-representation volume computation is not predictable.
297  *
298  * @warning Probabilistic polytopes are not full dimensional : they lie in
299  *the
300  *simplex' hyper plane,
301  * therefor a pseudo-volume will be computed by projecting the polytope.
302  *The
303  *projection used is the
304  * lexicographically smallest coordinate subspace.
305  *
306  * @return A constant reference to the polytope volume.
307  */
308  const GUM_SCALAR& getVolume() const;
309 
310  /// @}
311 
312  /// @name setUp / tearDown
313  /// @{
314 
315  /**
316  * @brief %Sets up an H-representation.
317  *
318  * Initialize input matrix \c _input_ to correct dimensions and wrapper
319  *state
320  *\c _state_ to \c _states_::Hup.
321  * @param card A constant reference to the cardinality of the variable.
322  */
323  void setUpH(const Size& card);
324 
325  /**
326  * @brief %Sets up a V-representation.
327  *
328  * Initialize input matrix \c _input_ to correct dimensions and wrapper
329  *state
330  *\c _state_ to \c _states_::Vup.
331  * @param card A constant reference to the cardinality of the variable.
332  * @param vertices A constant reference to the number of vertices of the
333  *polytope.
334  */
335  void setUpV(const Size& card, const Size& vertices);
336 
337  /**
338  * @brief Reset the wrapper as if it was built.
339  *
340  * Reset wrapper state \c _state_ to \c _states_::none and clear all
341  *member
342  *datas.
343  */
344  void tearDown();
345 
346  /**
347  * @brief Reset the wrapper for next computation for a H-representation
348  *with
349  *the same
350  * variable cardinality and number of inequalities. Usefull when creating
351  *credal networks
352  * specified as intervals over modalities.
353  *
354  * Reset wrapper state \c _state_ to it's previous state and clear output
355  *matrix \c _output_.
356  * Keeps the cardinality \c _card_ of the variable and therefor the input
357  *matrix \c _intput_ structure.
358  */
359  void nextHInput();
360 
361  /// @}
362 
363  /// @name Input filling methods
364  /// @{
365 
366  /**
367  * @brief Creates the H-representation of min <= p(X=modal | .) <= max and
368  *add
369  *it to the problem input \c _input_.
370  *
371  * @param min The lower value of p(X=modal | .).
372  * @param max The upper value of p(X=modal | .).
373  * @param modal The modality on which we put constraints.
374  */
375  void fillH(const GUM_SCALAR& min, const GUM_SCALAR& max, const Size& modal);
376 
377  /**
378  * @brief Fill the H-representation from the matrix given in argument.
379  *
380  * @param matrix The H-representation of the polytope of the form 0 <= -b
381  *+ Ax,
382  *A is the matrix, each column the coefficient of the variable in x.
383  */
384  void fillMatrix(const std::vector< std::vector< GUM_SCALAR > >& matrix);
385 
386  /**
387  * @brief Creates the V-representation of a polytope by adding a vertex to
388  *the
389  *problem input \c _input_.
390  *
391  * @param vertex The vertex we wish to add to the V-representation of the
392  *polytope.
393  */
394  void fillV(const std::vector< GUM_SCALAR >& vertex);
395 
396  /// @}
397 
398  /// @name lrs algorithms
399  /// @{
400 
401  /**
402  * @brief H-representation to V-representation.
403  *
404  * Computes the V-representation of a polytope, i.e. it's vertices, from
405  *it's
406  *H-representation, i.e. the hyper-plan inequalities.
407  */
408  void H2V();
409 
410  /**
411  * @brief V-representation to H-representation.
412  *
413  * @warning Not complete yet.
414  *
415  * Computes the H-representation of a polytope from it's V-representation.
416  */
417  void V2H();
418 
419  /**
420  * @brief Computes a polytope ( pseudo ) volume from it's
421  *V-representation.
422  *
423  * @warning Volume can only be computed using V-representation.
424  *H-representation volume computation is not predictable.
425  *
426  * @warning Probabilistic polytopes are not full dimensional : they lie in
427  *the
428  *simplex' hyper plane,
429  * therefor a pseudo-volume will be computed by projecting the polytope.
430  *The
431  *projection used is the
432  * lexicographically smallest coordinate subspace.
433  */
434  void computeVolume();
435 
436  /**
437  * @brief V-Redundancy elimination.
438  *
439  * Eliminates redundant vertices from a polytope V-representation input \c
440  * _input_.
441  */
442  void elimRedundVrep();
443 
444  /**
445  * H-redundancy elimination.
446  */
447 
448  /// @}
449  };
450 
451  } // namespace credal
452 } // namespace gum
453 
454 #include <agrum/CN/polytope/LrsWrapper_tpl.h>
455 
456 #endif
#define enumStringify(name)
Definition: LrsWrapper.h:90