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