1 /* Linear_System class declaration.
2    Copyright (C) 2001-2010 Roberto Bagnara <bagnara@cs.unipr.it>
3    Copyright (C) 2010-2016 BUGSENG srl (http://bugseng.com)
4 
5 This file is part of the Parma Polyhedra Library (PPL).
6 
7 The PPL is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11 
12 The PPL is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software Foundation,
19 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307, USA.
20 
21 For the most up-to-date information see the Parma Polyhedra Library
22 site: http://bugseng.com/products/ppl/ . */
23 
24 #ifndef PPL_Linear_System_defs_hh
25 #define PPL_Linear_System_defs_hh 1
26 
27 #include "Linear_System_types.hh"
28 
29 #include "Swapping_Vector_defs.hh"
30 #include "globals_defs.hh"
31 #include "Variable_defs.hh"
32 #include "Variables_Set_defs.hh"
33 
34 #include "Polyhedron_types.hh"
35 #include "Bit_Row_types.hh"
36 #include "Bit_Matrix_types.hh"
37 #include "Generator_System_types.hh"
38 #include "Topology_types.hh"
39 
40 // TODO: Check how much of this description is still true.
41 #ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
42 //! The base class for systems of constraints and generators.
43 /*! \ingroup PPL_CXX_interface
44   An object of this class represents either a constraint system
45   or a generator system. Each Linear_System object can be viewed
46   as a finite sequence of strong-normalized Row objects,
47   where each Row implements a constraint or a generator.
48   Linear systems are characterized by the matrix of coefficients,
49   also encoding the number, size and capacity of Row objects,
50   as well as a few additional information, including:
51    - the topological kind of (all) the rows;
52    - an indication of whether or not some of the rows in the Linear_System
53      are <EM>pending</EM>, meaning that they still have to undergo
54      an (unspecified) elaboration; if there are pending rows, then these
55      form a proper suffix of the overall sequence of rows;
56    - a Boolean flag that, when <CODE>true</CODE>, ensures that the
57      non-pending prefix of the sequence of rows is sorted.
58 */
59 #endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
60 template <typename Row>
61 class Parma_Polyhedra_Library::Linear_System {
62 public:
63 
64   // NOTE: `iterator' is actually a const_iterator.
65   typedef typename Swapping_Vector<Row>::const_iterator iterator;
66   typedef typename Swapping_Vector<Row>::const_iterator const_iterator;
67 
68   //! Builds an empty linear system with specified topology.
69   /*!
70     Rows size and capacity are initialized to \f$0\f$.
71   */
72   Linear_System(Topology topol, Representation r);
73 
74   //! Builds a system with specified topology and dimensions.
75   /*!
76     \param topol
77     The topology of the system that will be created;
78 
79     \param space_dim
80     The number of space dimensions of the system that will be created.
81 
82     \param r
83     The representation for system's rows.
84 
85     Creates a \p n_rows \f$\times\f$ \p space_dim system whose
86     coefficients are all zero and with the given topology.
87   */
88   Linear_System(Topology topol, dimension_type space_dim, Representation r);
89 
90 #ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
91   //! A tag class.
92   /*! \ingroup PPL_CXX_interface
93     Tag class to differentiate the Linear_System copy constructor that
94     copies pending rows as pending from the one that transforms
95     pending rows into non-pending ones.
96   */
97 #endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
98   struct With_Pending {
99   };
100 
101   //! Copy constructor: pending rows are transformed into non-pending ones.
102   Linear_System(const Linear_System& y);
103 
104   //! Copy constructor with specified representation. Pending rows are
105   //! transformed into non-pending ones.
106   Linear_System(const Linear_System& y, Representation r);
107 
108   //! Full copy constructor: pending rows are copied as pending.
109   Linear_System(const Linear_System& y, With_Pending);
110 
111   //! Full copy constructor: pending rows are copied as pending.
112   Linear_System(const Linear_System& y, Representation r, With_Pending);
113 
114   //! Assignment operator: pending rows are transformed into non-pending ones.
115   Linear_System& operator=(const Linear_System& y);
116 
117   //! Full assignment operator: pending rows are copied as pending.
118   void assign_with_pending(const Linear_System& y);
119 
120   //! Swaps \p *this with \p y.
121   void m_swap(Linear_System& y);
122 
123   //! Returns the current representation of *this.
124   Representation representation() const;
125 
126   //! Converts *this to the specified representation.
127   void set_representation(Representation r);
128 
129   //! Returns the maximum space dimension a Linear_System can handle.
130   static dimension_type max_space_dimension();
131 
132   //! Returns the space dimension of the rows in the system.
133   /*!
134     The computation of the space dimension correctly ignores
135     the column encoding the inhomogeneous terms of constraint
136     (resp., the divisors of generators);
137     if the system topology is <CODE>NOT_NECESSARILY_CLOSED</CODE>,
138     also the column of the \f$\epsilon\f$-dimension coefficients
139     will be ignored.
140   */
141   dimension_type space_dimension() const;
142 
143   //! Sets the space dimension of the rows in the system to \p space_dim .
144   void set_space_dimension(dimension_type space_dim);
145 
146   //! Makes the system shrink by removing its \p n trailing rows.
147   void remove_trailing_rows(dimension_type n);
148 
149   //! Makes the system shrink by removing its i-th row.
150   /*!
151     When \p keep_sorted is \p true and the system is sorted, sortedness will
152     be preserved, but this method costs O(n).
153 
154     Otherwise, this method just swaps the i-th row with the last and then
155     removes it, so it costs O(1).
156   */
157   void remove_row(dimension_type i, bool keep_sorted = false);
158 
159   //! Makes the system shrink by removing the rows in [first,last).
160   /*!
161     When \p keep_sorted is \p true and the system is sorted, sortedness will
162     be preserved, but this method costs O(num_rows()).
163 
164     Otherwise, this method just swaps the rows with the last ones and then
165     removes them, so it costs O(last - first).
166   */
167   void remove_rows(dimension_type first, dimension_type last,
168                   bool keep_sorted = false);
169 
170   // TODO: Consider removing this.
171   //! Removes the specified rows. The row ordering of remaining rows is
172   //! preserved.
173   /*!
174     \param indexes specifies a list of row indexes.
175                    It must be sorted.
176   */
177   void remove_rows(const std::vector<dimension_type>& indexes);
178 
179   // TODO: Consider making this private.
180   //! Removes all the specified dimensions from the system.
181   /*!
182     The space dimension of the variable with the highest space
183     dimension in \p vars must be at most the space dimension
184     of \p this.
185   */
186   void remove_space_dimensions(const Variables_Set& vars);
187 
188   //! Shift by \p n positions the coefficients of variables, starting from
189   //! the coefficient of \p v. This increases the space dimension by \p n.
190   void shift_space_dimensions(Variable v, dimension_type n);
191 
192   // TODO: Consider making this private.
193   //! Permutes the space dimensions of the matrix.
194   /*
195     \param cycle
196     A vector representing a cycle of the permutation according to which the
197     space dimensions must be rearranged.
198 
199     The \p cycle vector represents a cycle of a permutation of space
200     dimensions.
201     For example, the permutation
202     \f$ \{ x_1 \mapsto x_2, x_2 \mapsto x_3, x_3 \mapsto x_1 \}\f$ can be
203     represented by the vector containing \f$ x_1, x_2, x_3 \f$.
204   */
205   void permute_space_dimensions(const std::vector<Variable>& cycle);
206 
207   //! Swaps the coefficients of the variables \p v1 and \p v2 .
208   void swap_space_dimensions(Variable v1, Variable v2);
209 
210   //! \name Subscript operators
211   //@{
212   //! Returns a const reference to the \p k-th row of the system.
213   const Row& operator[](dimension_type k) const;
214   //@} // Subscript operators
215 
216   iterator begin();
217   iterator end();
218   const_iterator begin() const;
219   const_iterator end() const;
220 
221   bool has_no_rows() const;
222   dimension_type num_rows() const;
223 
224   //! Strongly normalizes the system.
225   void strong_normalize();
226 
227   //! Sign-normalizes the system.
228   void sign_normalize();
229 
230   //! \name Accessors
231   //@{
232   //! Returns the system topology.
233   Topology topology() const;
234 
235   //! Returns the value of the sortedness flag.
236   bool is_sorted() const;
237 
238   /*! \brief
239     Returns <CODE>true</CODE> if and only if
240     the system topology is <CODE>NECESSARILY_CLOSED</CODE>.
241   */
242   bool is_necessarily_closed() const;
243 
244   /*! \brief
245     Returns the number of rows in the system
246     that represent either lines or equalities.
247   */
248   dimension_type num_lines_or_equalities() const;
249 
250   //! Returns the index of the first pending row.
251   dimension_type first_pending_row() const;
252 
253   //! Returns the number of rows that are in the pending part of the system.
254   dimension_type num_pending_rows() const;
255   //@} // Accessors
256 
257   /*! \brief
258     Returns <CODE>true</CODE> if and only if \p *this is sorted,
259     without checking for duplicates.
260   */
261   bool check_sorted() const;
262 
263   //! Sets the system topology to \p t .
264   void set_topology(Topology t);
265 
266   //! Sets the system topology to <CODE>NECESSARILY_CLOSED</CODE>.
267   void set_necessarily_closed();
268 
269   //! Sets the system topology to <CODE>NOT_NECESSARILY_CLOSED</CODE>.
270   void set_not_necessarily_closed();
271 
272   // TODO: Consider removing this, or making it private.
273   //! Marks the epsilon dimension as a standard dimension.
274   /*!
275     The system topology is changed to <CODE>NOT_NECESSARILY_CLOSED</CODE>, and
276     the number of space dimensions is increased by 1.
277   */
278   void mark_as_necessarily_closed();
279 
280   // TODO: Consider removing this, or making it private.
281   //! Marks the last dimension as the epsilon dimension.
282   /*!
283     The system topology is changed to <CODE>NECESSARILY_CLOSED</CODE>, and
284     the number of space dimensions is decreased by 1.
285   */
286   void mark_as_not_necessarily_closed();
287 
288   //! Sets the index to indicate that the system has no pending rows.
289   void unset_pending_rows();
290 
291   //! Sets the index of the first pending row to \p i.
292   void set_index_first_pending_row(dimension_type i);
293 
294   //! Sets the sortedness flag of the system to \p b.
295   void set_sorted(bool b);
296 
297   //! Adds \p n rows and space dimensions to the system.
298   /*!
299     \param n
300     The number of rows and space dimensions to be added: must be strictly
301     positive.
302 
303     Turns the system \f$M \in \Rset^r \times \Rset^c\f$ into
304     the system \f$N \in \Rset^{r+n} \times \Rset^{c+n}\f$
305     such that
306     \f$N = \bigl(\genfrac{}{}{0pt}{}{0}{M}\genfrac{}{}{0pt}{}{J}{o}\bigr)\f$,
307     where \f$J\f$ is the specular image
308     of the \f$n \times n\f$ identity matrix.
309   */
310   void add_universe_rows_and_space_dimensions(dimension_type n);
311 
312   /*! \brief
313     Adds a copy of \p r to the system,
314     automatically resizing the system or the row's copy, if needed.
315   */
316   void insert(const Row& r);
317 
318   /*! \brief
319     Adds a copy of the given row to the pending part of the system,
320     automatically resizing the system or the row, if needed.
321   */
322   void insert_pending(const Row& r);
323 
324   /*! \brief
325     Adds \p r to the system, stealing its contents and
326     automatically resizing the system or the row, if needed.
327   */
328   void insert(Row& r, Recycle_Input);
329 
330   /*! \brief
331     Adds the given row to the pending part of the system, stealing its
332     contents and automatically resizing the system or the row, if needed.
333   */
334   void insert_pending(Row& r, Recycle_Input);
335 
336   //! Adds to \p *this a copy of  the rows of \p y.
337   /*!
338     It is assumed that \p *this has no pending rows.
339   */
340   void insert(const Linear_System& y);
341 
342   //! Adds a copy of the rows of `y' to the pending part of `*this'.
343   void insert_pending(const Linear_System& r);
344 
345   //! Adds to \p *this a the rows of `y', stealing them from `y'.
346   /*!
347     It is assumed that \p *this has no pending rows.
348   */
349   void insert(Linear_System& r, Recycle_Input);
350 
351   //! Adds the rows of `y' to the pending part of `*this', stealing them from
352   //! `y'.
353   void insert_pending(Linear_System& r, Recycle_Input);
354 
355   /*! \brief
356     Sorts the non-pending rows (in growing order) and eliminates
357     duplicated ones.
358   */
359   void sort_rows();
360 
361   /*! \brief
362     Sorts the rows (in growing order) form \p first_row to
363     \p last_row and eliminates duplicated ones.
364   */
365   void sort_rows(dimension_type first_row, dimension_type last_row);
366 
367   /*! \brief
368     Assigns to \p *this the result of merging its rows with
369     those of \p y, obtaining a sorted system.
370 
371     Duplicated rows will occur only once in the result.
372     On entry, both systems are assumed to be sorted and have
373     no pending rows.
374   */
375   void merge_rows_assign(const Linear_System& y);
376 
377   /*! \brief
378     Sorts the pending rows and eliminates those that also occur
379     in the non-pending part of the system.
380   */
381   void sort_pending_and_remove_duplicates();
382 
383   /*! \brief
384     Sorts the system, removing duplicates, keeping the saturation
385     matrix consistent.
386 
387     \param sat
388     Bit matrix with rows corresponding to the rows of \p *this.
389   */
390   void sort_and_remove_with_sat(Bit_Matrix& sat);
391 
392   //! Minimizes the subsystem of equations contained in \p *this.
393   /*!
394     This method works only on the equalities of the system:
395     the system is required to be partially sorted, so that
396     all the equalities are grouped at its top; it is assumed that
397     the number of equalities is exactly \p n_lines_or_equalities.
398     The method finds a minimal system for the equalities and
399     returns its rank, i.e., the number of linearly independent equalities.
400     The result is an upper triangular subsystem of equalities:
401     for each equality, the pivot is chosen starting from
402     the right-most space dimensions.
403   */
404   dimension_type gauss(dimension_type n_lines_or_equalities);
405 
406   /*! \brief
407     Back-substitutes the coefficients to reduce
408     the complexity of the system.
409 
410     Takes an upper triangular system having \p n_lines_or_equalities rows.
411     For each row, starting from the one having the minimum number of
412     coefficients different from zero, computes the expression of an element
413     as a function of the remaining ones and then substitutes this expression
414     in all the other rows.
415   */
416   void back_substitute(dimension_type n_lines_or_equalities);
417 
418   /*! \brief
419     Applies Gaussian elimination and back-substitution so as to
420     simplify the linear system.
421   */
422   void simplify();
423 
424   //! Clears the system deallocating all its rows.
425   void clear();
426 
427   PPL_OUTPUT_DECLARATIONS
428 
429   /*! \brief
430     Loads from \p s an ASCII representation (as produced by
431     ascii_dump(std::ostream&) const) and sets \p *this accordingly.
432     Returns <CODE>true</CODE> if successful, <CODE>false</CODE> otherwise.
433 
434     Reads into a Linear_System object the information produced by the
435     output of ascii_dump(std::ostream&) const.  The specialized methods
436     provided by Constraint_System and Generator_System take care of
437     properly reading the contents of the system.
438   */
439   bool ascii_load(std::istream& s);
440 
441   //! Returns the total size in bytes of the memory occupied by \p *this.
442   memory_size_type total_memory_in_bytes() const;
443 
444   //! Returns the size in bytes of the memory managed by \p *this.
445   memory_size_type external_memory_in_bytes() const;
446 
447   //! The vector that contains the rows.
448   /*!
449     \note This is public for convenience. Clients that modify if must preserve
450           the class invariant.
451   */
452   Swapping_Vector<Row> rows;
453 
454   //! Checks if all the invariants are satisfied.
455   bool OK() const;
456 
457 private:
458   //! Makes the system shrink by removing its i-th row.
459   /*!
460     When \p keep_sorted is \p true and the system is sorted, sortedness will
461     be preserved, but this method costs O(n).
462 
463     Otherwise, this method just swaps the i-th row with the last and then
464     removes it, so it costs O(1).
465 
466     This method is for internal use, it does *not* assert OK() at the end,
467     so it can be used for invalid systems.
468   */
469   void remove_row_no_ok(dimension_type i, bool keep_sorted = false);
470 
471   /*! \brief
472     Adds \p r to the pending part of the system, stealing its contents and
473     automatically resizing the system or the row, if needed.
474 
475     This method is for internal use, it does *not* assert OK() at the end,
476     so it can be used for invalid systems.
477   */
478   void insert_pending_no_ok(Row& r, Recycle_Input);
479 
480   /*! \brief
481     Adds \p r to the system, stealing its contents and
482     automatically resizing the system or the row, if needed.
483 
484     This method is for internal use, it does *not* assert OK() at the end,
485     so it can be used for invalid systems.
486   */
487   void insert_no_ok(Row& r, Recycle_Input);
488 
489   //! Sets the space dimension of the rows in the system to \p space_dim .
490   /*!
491     This method is for internal use, it does *not* assert OK() at the end,
492     so it can be used for invalid systems.
493   */
494   void set_space_dimension_no_ok(dimension_type space_dim);
495 
496   //! Swaps the [first,last) row interval with the
497   //! [first + offset, last + offset) interval.
498   /*!
499     These intervals may not be disjunct.
500 
501     Sorting of these intervals is *not* preserved.
502 
503     Either both intervals contain only not-pending rows, or they both
504     contain pending rows.
505   */
506   void swap_row_intervals(dimension_type first, dimension_type last,
507                           dimension_type offset);
508 
509   //! The space dimension of each row. All rows must have this number of
510   //! space dimensions.
511   dimension_type space_dimension_;
512 
513   //! The topological kind of the rows in the system. All rows must have this
514   //! topology.
515   Topology row_topology;
516 
517   //! The index of the first pending row.
518   dimension_type index_first_pending;
519 
520   /*! \brief
521     <CODE>true</CODE> if rows are sorted in the ascending order as defined by
522     <CODE>bool compare(const Row&, const Row&)</CODE>.
523     If <CODE>false</CODE> may not be sorted.
524   */
525   bool sorted;
526 
527   Representation representation_;
528 
529   //! Ordering predicate (used when implementing the sort algorithm).
530   struct Row_Less_Than {
531     bool operator()(const Row& x, const Row& y) const;
532   };
533 
534   //! Comparison predicate (used when implementing the unique algorithm).
535   struct Unique_Compare {
536     Unique_Compare(const Swapping_Vector<Row>& cont,
537                    dimension_type base = 0);
538 
539     bool operator()(dimension_type i, dimension_type j) const;
540 
541     const Swapping_Vector<Row>& container;
542     const dimension_type base_index;
543   };
544 
545   friend class Polyhedron;
546   friend class Generator_System;
547 };
548 
549 namespace Parma_Polyhedra_Library {
550 
551 #ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
552 //! Swaps \p x with \p y.
553 /*! \relates Linear_System */
554 #endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
555 template <typename Row>
556 void swap(Parma_Polyhedra_Library::Linear_System<Row>& x,
557           Parma_Polyhedra_Library::Linear_System<Row>& y);
558 
559 } // namespace std
560 
561 namespace Parma_Polyhedra_Library {
562 
563 #ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
564 //! Returns <CODE>true</CODE> if and only if \p x and \p y are identical.
565 /*! \relates Linear_System */
566 #endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
567 template <typename Row>
568 bool operator==(const Linear_System<Row>& x, const Linear_System<Row>& y);
569 
570 #ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
571 //! Returns <CODE>true</CODE> if and only if \p x and \p y are different.
572 /*! \relates Linear_System */
573 #endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
574 template <typename Row>
575 bool operator!=(const Linear_System<Row>& x, const Linear_System<Row>& y);
576 
577 } // namespace Parma_Polyhedra_Library
578 
579 #include "Linear_System_inlines.hh"
580 #include "Linear_System_templates.hh"
581 
582 #endif // !defined(PPL_Linear_System_defs_hh)
583