1 /* Generator_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_Generator_System_defs_hh 25 #define PPL_Generator_System_defs_hh 1 26 27 #include "Generator_System_types.hh" 28 29 #include "Linear_Expression_types.hh" 30 #include "Linear_System_defs.hh" 31 #include "Generator_defs.hh" 32 #include "Constraint_types.hh" 33 #include "Poly_Con_Relation_defs.hh" 34 #include "Polyhedron_types.hh" 35 #include <iosfwd> 36 #include <cstddef> 37 38 namespace Parma_Polyhedra_Library { 39 40 namespace IO_Operators { 41 42 //! Output operator. 43 /*! 44 \relates Parma_Polyhedra_Library::Generator_System 45 Writes <CODE>false</CODE> if \p gs is empty. Otherwise, writes on 46 \p s the generators of \p gs, all in one row and separated by ", ". 47 */ 48 std::ostream& operator<<(std::ostream& s, const Generator_System& gs); 49 50 } // namespace IO_Operators 51 52 // TODO: Consider removing this. 53 #ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS 54 //! Returns <CODE>true</CODE> if and only if \p x and \p y are identical. 55 /*! \relates Generator_System */ 56 #endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS) 57 bool operator==(const Generator_System& x, const Generator_System& y); 58 59 // TODO: Consider removing this. 60 #ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS 61 //! Returns <CODE>true</CODE> if and only if \p x and \p y are different. 62 /*! \relates Generator_System */ 63 #endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS) 64 bool operator!=(const Generator_System& x, const Generator_System& y); 65 66 /*! \relates Generator_System */ 67 void 68 swap(Generator_System& x, Generator_System& y); 69 70 } // namespace Parma_Polyhedra_Library 71 72 //! A system of generators. 73 /*! \ingroup PPL_CXX_interface 74 An object of the class Generator_System is a system of generators, 75 i.e., a multiset of objects of the class Generator 76 (lines, rays, points and closure points). 77 When inserting generators in a system, space dimensions are automatically 78 adjusted so that all the generators in the system are defined 79 on the same vector space. 80 A system of generators which is meant to define a non-empty 81 polyhedron must include at least one point: the reason is that 82 lines, rays and closure points need a supporting point 83 (lines and rays only specify directions while closure points only 84 specify points in the topological closure of the NNC polyhedron). 85 86 \par 87 In all the examples it is assumed that variables 88 <CODE>x</CODE> and <CODE>y</CODE> are defined as follows: 89 \code 90 Variable x(0); 91 Variable y(1); 92 \endcode 93 94 \par Example 1 95 The following code defines the line having the same direction 96 as the \f$x\f$ axis (i.e., the first Cartesian axis) 97 in \f$\Rset^2\f$: 98 \code 99 Generator_System gs; 100 gs.insert(line(x + 0*y)); 101 \endcode 102 As said above, this system of generators corresponds to 103 an empty polyhedron, because the line has no supporting point. 104 To define a system of generators that does correspond to 105 the \f$x\f$ axis, we can add the following code which 106 inserts the origin of the space as a point: 107 \code 108 gs.insert(point(0*x + 0*y)); 109 \endcode 110 Since space dimensions are automatically adjusted, the following 111 code obtains the same effect: 112 \code 113 gs.insert(point(0*x)); 114 \endcode 115 In contrast, if we had added the following code, we would have 116 defined a line parallel to the \f$x\f$ axis through 117 the point \f$(0, 1)^\transpose \in \Rset^2\f$. 118 \code 119 gs.insert(point(0*x + 1*y)); 120 \endcode 121 122 \par Example 2 123 The following code builds a ray having the same direction as 124 the positive part of the \f$x\f$ axis in \f$\Rset^2\f$: 125 \code 126 Generator_System gs; 127 gs.insert(ray(x + 0*y)); 128 \endcode 129 To define a system of generators indeed corresponding to the set 130 \f[ 131 \bigl\{\, 132 (x, 0)^\transpose \in \Rset^2 133 \bigm| 134 x \geq 0 135 \,\bigr\}, 136 \f] 137 one just has to add the origin: 138 \code 139 gs.insert(point(0*x + 0*y)); 140 \endcode 141 142 \par Example 3 143 The following code builds a system of generators having four points 144 and corresponding to a square in \f$\Rset^2\f$ 145 (the same as Example 1 for the system of constraints): 146 \code 147 Generator_System gs; 148 gs.insert(point(0*x + 0*y)); 149 gs.insert(point(0*x + 3*y)); 150 gs.insert(point(3*x + 0*y)); 151 gs.insert(point(3*x + 3*y)); 152 \endcode 153 154 \par Example 4 155 By using closure points, we can define the \e kernel 156 (i.e., the largest open set included in a given set) 157 of the square defined in the previous example. 158 Note that a supporting point is needed and, for that purpose, 159 any inner point could be considered. 160 \code 161 Generator_System gs; 162 gs.insert(point(x + y)); 163 gs.insert(closure_point(0*x + 0*y)); 164 gs.insert(closure_point(0*x + 3*y)); 165 gs.insert(closure_point(3*x + 0*y)); 166 gs.insert(closure_point(3*x + 3*y)); 167 \endcode 168 169 \par Example 5 170 The following code builds a system of generators having two points 171 and a ray, corresponding to a half-strip in \f$\Rset^2\f$ 172 (the same as Example 2 for the system of constraints): 173 \code 174 Generator_System gs; 175 gs.insert(point(0*x + 0*y)); 176 gs.insert(point(0*x + 1*y)); 177 gs.insert(ray(x - y)); 178 \endcode 179 180 \note 181 After inserting a multiset of generators in a generator system, 182 there are no guarantees that an <EM>exact</EM> copy of them 183 can be retrieved: 184 in general, only an <EM>equivalent</EM> generator system 185 will be available, where original generators may have been 186 reordered, removed (if they are duplicate or redundant), etc. 187 */ 188 class Parma_Polyhedra_Library::Generator_System { 189 public: 190 typedef Generator row_type; 191 192 static const Representation default_representation = SPARSE; 193 194 //! Default constructor: builds an empty system of generators. 195 Generator_System(Representation r = default_representation); 196 197 //! Builds the singleton system containing only generator \p g. 198 explicit Generator_System(const Generator& g, 199 Representation r = default_representation); 200 201 //! Ordinary copy constructor. 202 //! The new Generator_System will have the same representation as `gs'. 203 Generator_System(const Generator_System& gs); 204 205 //! Copy constructor with specified representation. 206 Generator_System(const Generator_System& gs, Representation r); 207 208 //! Destructor. 209 ~Generator_System(); 210 211 //! Assignment operator. 212 Generator_System& operator=(const Generator_System& y); 213 214 //! Returns the current representation of *this. 215 Representation representation() const; 216 217 //! Converts *this to the specified representation. 218 void set_representation(Representation r); 219 220 //! Returns the maximum space dimension a Generator_System can handle. 221 static dimension_type max_space_dimension(); 222 223 //! Returns the dimension of the vector space enclosing \p *this. 224 dimension_type space_dimension() const; 225 226 //! Sets the space dimension of the rows in the system to \p space_dim . 227 void set_space_dimension(dimension_type space_dim); 228 229 /*! \brief 230 Removes all the generators from the generator system 231 and sets its space dimension to 0. 232 */ 233 void clear(); 234 235 /*! \brief 236 Inserts in \p *this a copy of the generator \p g, 237 increasing the number of space dimensions if needed. 238 */ 239 void insert(const Generator& g); 240 241 /*! \brief 242 Inserts in \p *this the generator \p g, stealing its contents and 243 increasing the number of space dimensions if needed. 244 */ 245 void insert(Generator& g, Recycle_Input); 246 247 //! Initializes the class. 248 static void initialize(); 249 250 //! Finalizes the class. 251 static void finalize(); 252 253 /*! \brief 254 Returns the singleton system containing only Generator::zero_dim_point(). 255 */ 256 static const Generator_System& zero_dim_univ(); 257 258 typedef Generator_System_const_iterator const_iterator; 259 260 //! Returns <CODE>true</CODE> if and only if \p *this has no generators. 261 bool empty() const; 262 263 /*! \brief 264 Returns the const_iterator pointing to the first generator, 265 if \p *this is not empty; 266 otherwise, returns the past-the-end const_iterator. 267 */ 268 const_iterator begin() const; 269 270 //! Returns the past-the-end const_iterator. 271 const_iterator end() const; 272 273 //! Checks if all the invariants are satisfied. 274 bool OK() const; 275 276 PPL_OUTPUT_DECLARATIONS 277 278 /*! \brief 279 Loads from \p s an ASCII representation (as produced by 280 ascii_dump(std::ostream&) const) and sets \p *this accordingly. 281 Returns <CODE>true</CODE> if successful, <CODE>false</CODE> otherwise. 282 283 Resizes the matrix of generators using the numbers of rows and columns 284 read from \p s, then initializes the coordinates of each generator 285 and its type reading the contents from \p s. 286 */ 287 bool ascii_load(std::istream& s); 288 289 //! Returns the total size in bytes of the memory occupied by \p *this. 290 memory_size_type total_memory_in_bytes() const; 291 292 //! Returns the size in bytes of the memory managed by \p *this. 293 memory_size_type external_memory_in_bytes() const; 294 295 //! Swaps \p *this with \p y. 296 void m_swap(Generator_System& y); 297 298 private: 299 300 bool has_no_rows() const; 301 302 //! Removes all the specified dimensions from the generator system. 303 /*! 304 The space dimension of the variable with the highest space 305 dimension in \p vars must be at most the space dimension 306 of \p this. 307 */ 308 void remove_space_dimensions(const Variables_Set& vars); 309 310 //! Shift by \p n positions the coefficients of variables, starting from 311 //! the coefficient of \p v. This increases the space dimension by \p n. 312 void shift_space_dimensions(Variable v, dimension_type n); 313 314 //! Permutes the space dimensions of the matrix. 315 /* 316 \param cycle 317 A vector representing a cycle of the permutation according to which the 318 columns must be rearranged. 319 320 The \p cycle vector represents a cycle of a permutation of space 321 dimensions. 322 For example, the permutation 323 \f$ \{ x_1 \mapsto x_2, x_2 \mapsto x_3, x_3 \mapsto x_1 \}\f$ can be 324 represented by the vector containing \f$ x_1, x_2, x_3 \f$. 325 */ 326 void permute_space_dimensions(const std::vector<Variable>& cycle); 327 328 //! Swaps the coefficients of the variables \p v1 and \p v2 . 329 void swap_space_dimensions(Variable v1, Variable v2); 330 331 dimension_type num_rows() const; 332 333 //! Adds \p n rows and space dimensions to the system. 334 /*! 335 \param n 336 The number of rows and space dimensions to be added: must be strictly 337 positive. 338 339 Turns the system \f$M \in \Rset^r \times \Rset^c\f$ into 340 the system \f$N \in \Rset^{r+n} \times \Rset^{c+n}\f$ 341 such that 342 \f$N = \bigl(\genfrac{}{}{0pt}{}{0}{M}\genfrac{}{}{0pt}{}{J}{o}\bigr)\f$, 343 where \f$J\f$ is the specular image 344 of the \f$n \times n\f$ identity matrix. 345 */ 346 void add_universe_rows_and_space_dimensions(dimension_type n); 347 348 Topology topology() const; 349 350 //! Returns the index of the first pending row. 351 dimension_type first_pending_row() const; 352 353 //! Sets the index to indicate that the system has no pending rows. 354 void unset_pending_rows(); 355 356 //! Sets the sortedness flag of the system to \p b. 357 void set_sorted(bool b); 358 359 //! Returns the value of the sortedness flag. 360 bool is_sorted() const; 361 362 //! Sets the index of the first pending row to \p i. 363 void set_index_first_pending_row(dimension_type i); 364 365 /*! \brief 366 Returns <CODE>true</CODE> if and only if 367 the system topology is <CODE>NECESSARILY_CLOSED</CODE>. 368 */ 369 bool is_necessarily_closed() const; 370 371 //! Full assignment operator: pending rows are copied as pending. 372 void assign_with_pending(const Generator_System& y); 373 374 //! Returns the number of rows that are in the pending part of the system. 375 dimension_type num_pending_rows() const; 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 /*! \brief 393 Sorts the non-pending rows (in growing order) and eliminates 394 duplicated ones. 395 */ 396 void sort_rows(); 397 398 /*! \brief 399 Returns <CODE>true</CODE> if and only if \p *this is sorted, 400 without checking for duplicates. 401 */ 402 bool check_sorted() const; 403 404 /*! \brief 405 Returns the number of rows in the system 406 that represent either lines or equalities. 407 */ 408 dimension_type num_lines_or_equalities() const; 409 410 //! Makes the system shrink by removing its i-th row. 411 /*! 412 When \p keep_sorted is \p true and the system is sorted, sortedness will 413 be preserved, but this method costs O(n). 414 415 Otherwise, this method just swaps the i-th row with the last and then 416 removes it, so it costs O(1). 417 */ 418 void remove_row(dimension_type i, bool keep_sorted = false); 419 420 //! Makes the system shrink by removing the rows in [first,last). 421 /*! 422 When \p keep_sorted is \p true and the system is sorted, sortedness will 423 be preserved, but this method costs O(num_rows()). 424 425 Otherwise, this method just swaps the rows with the last ones and then 426 removes them, so it costs O(last - first). 427 */ 428 void remove_rows(dimension_type first, dimension_type last, 429 bool keep_sorted = false); 430 431 //! Removes the specified rows. The row ordering of remaining rows is 432 //! preserved. 433 /*! 434 \param indexes specifies a list of row indexes. 435 It must be sorted. 436 */ 437 void remove_rows(const std::vector<dimension_type>& indexes); 438 439 //! Makes the system shrink by removing its \p n trailing rows. 440 void remove_trailing_rows(dimension_type n); 441 442 //! Minimizes the subsystem of equations contained in \p *this. 443 /*! 444 This method works only on the equalities of the system: 445 the system is required to be partially sorted, so that 446 all the equalities are grouped at its top; it is assumed that 447 the number of equalities is exactly \p n_lines_or_equalities. 448 The method finds a minimal system for the equalities and 449 returns its rank, i.e., the number of linearly independent equalities. 450 The result is an upper triangular subsystem of equalities: 451 for each equality, the pivot is chosen starting from 452 the right-most columns. 453 */ 454 dimension_type gauss(dimension_type n_lines_or_equalities); 455 456 /*! \brief 457 Back-substitutes the coefficients to reduce 458 the complexity of the system. 459 460 Takes an upper triangular system having \p n_lines_or_equalities rows. 461 For each row, starting from the one having the minimum number of 462 coefficients different from zero, computes the expression of an element 463 as a function of the remaining ones and then substitutes this expression 464 in all the other rows. 465 */ 466 void back_substitute(dimension_type n_lines_or_equalities); 467 468 //! Strongly normalizes the system. 469 void strong_normalize(); 470 471 /*! \brief 472 Assigns to \p *this the result of merging its rows with 473 those of \p y, obtaining a sorted system. 474 475 Duplicated rows will occur only once in the result. 476 On entry, both systems are assumed to be sorted and have 477 no pending rows. 478 */ 479 void merge_rows_assign(const Generator_System& y); 480 481 //! Adds to \p *this a copy of the rows of \p y. 482 /*! 483 It is assumed that \p *this has no pending rows. 484 */ 485 void insert(const Generator_System& y); 486 487 //! Adds a copy of the rows of `y' to the pending part of `*this'. 488 void insert_pending(const Generator_System& r); 489 490 /*! \brief 491 Holds (between class initialization and finalization) a pointer to 492 the singleton system containing only Generator::zero_dim_point(). 493 */ 494 static const Generator_System* zero_dim_univ_p; 495 496 friend class Generator_System_const_iterator; 497 498 //! Builds an empty system of generators having the specified topology. 499 explicit Generator_System(Topology topol, 500 Representation r = default_representation); 501 502 /*! \brief 503 Builds a system of rays/points on a \p space_dim dimensional space. If 504 \p topol is <CODE>NOT_NECESSARILY_CLOSED</CODE> the \f$\epsilon\f$ 505 dimension is added. 506 */ 507 Generator_System(Topology topol, dimension_type space_dim, 508 Representation r = default_representation); 509 510 /*! \brief 511 Adjusts \p *this so that it matches the \p new_topology and 512 \p new_space_dim (adding or removing columns if needed). 513 Returns <CODE>false</CODE> if and only if \p topol is 514 equal to <CODE>NECESSARILY_CLOSED</CODE> and \p *this 515 contains closure points. 516 */ 517 bool adjust_topology_and_space_dimension(Topology new_topology, 518 dimension_type new_space_dim); 519 520 /*! \brief 521 For each unmatched closure point in \p *this, adds the 522 corresponding point. 523 524 It is assumed that the topology of \p *this 525 is <CODE>NOT_NECESSARILY_CLOSED</CODE>. 526 */ 527 void add_corresponding_points(); 528 529 /*! \brief 530 Returns <CODE>true</CODE> if and only if \p *this 531 contains one or more points. 532 */ 533 bool has_points() const; 534 535 /*! \brief 536 For each unmatched point in \p *this, adds the corresponding 537 closure point. 538 539 It is assumed that the topology of \p *this 540 is <CODE>NOT_NECESSARILY_CLOSED</CODE>. 541 */ 542 void add_corresponding_closure_points(); 543 544 /*! \brief 545 Returns <CODE>true</CODE> if and only if \p *this 546 contains one or more closure points. 547 548 Note: the check for the presence of closure points is 549 done under the point of view of the user. Namely, we scan 550 the generator system using high-level iterators, so that 551 closure points that are matching the corresponding points 552 will be disregarded. 553 */ 554 bool has_closure_points() const; 555 556 //! Converts this generator system into a non-necessarily closed generator 557 //! system. 558 void convert_into_non_necessarily_closed(); 559 560 //! Returns a constant reference to the \p k- th generator of the system. 561 const Generator& operator[](dimension_type k) const; 562 563 /*! \brief 564 Returns the relations holding between the generator system 565 and the constraint \p c. 566 */ 567 Parma_Polyhedra_Library::Poly_Con_Relation 568 relation_with(const Constraint& c) const; 569 570 //! Returns <CODE>true</CODE> if all the generators satisfy \p c. 571 bool satisfied_by_all_generators(const Constraint& c) const; 572 573 //! Returns <CODE>true</CODE> if all the generators satisfy \p c. 574 /*! 575 It is assumed that <CODE>c.is_necessarily_closed()</CODE> holds. 576 */ 577 bool satisfied_by_all_generators_C(const Constraint& c) const; 578 579 //! Returns <CODE>true</CODE> if all the generators satisfy \p c. 580 /*! 581 It is assumed that <CODE>c.is_necessarily_closed()</CODE> does not hold. 582 */ 583 bool satisfied_by_all_generators_NNC(const Constraint& c) const; 584 585 //! Assigns to a given variable an affine expression. 586 /*! 587 \param v 588 The variable to which the affine transformation is assigned; 589 590 \param expr 591 The numerator of the affine transformation: 592 \f$\sum_{i = 0}^{n - 1} a_i x_i + b\f$; 593 594 \param denominator 595 The denominator of the affine transformation. 596 597 We want to allow affine transformations (see the Introduction) having 598 any rational coefficients. Since the coefficients of the 599 constraints are integers we must also provide an integer \p denominator 600 that will be used as denominator of the affine transformation. 601 The denominator is required to be a positive integer. 602 603 The affine transformation assigns to each element of the column containing 604 the coefficients of v the follow expression: 605 \f[ 606 \frac{\sum_{i = 0}^{n - 1} a_i x_i + b} 607 {\mathrm{denominator}}. 608 \f] 609 610 \p expr is a constant parameter and unaltered by this computation. 611 */ 612 void affine_image(Variable v, 613 const Linear_Expression& expr, 614 Coefficient_traits::const_reference denominator); 615 616 //! Returns the number of lines of the system. 617 dimension_type num_lines() const; 618 619 //! Returns the number of rays of the system. 620 dimension_type num_rays() const; 621 622 //! Removes all the invalid lines and rays. 623 /*! 624 The invalid lines and rays are those with all 625 the homogeneous terms set to zero. 626 */ 627 void remove_invalid_lines_and_rays(); 628 629 /*! \brief 630 Applies Gaussian elimination and back-substitution so as 631 to provide a partial simplification of the system of generators. 632 633 It is assumed that the system has no pending generators. 634 */ 635 void simplify(); 636 637 /*! \brief 638 Inserts in \p *this a copy of the generator \p g, 639 increasing the number of space dimensions if needed. 640 It is a pending generator. 641 */ 642 void insert_pending(const Generator& g); 643 644 /*! \brief 645 Inserts in \p *this the generator \p g, stealing its contents and 646 increasing the number of space dimensions if needed. 647 It is a pending generator. 648 */ 649 void insert_pending(Generator& g, Recycle_Input); 650 651 Linear_System<Generator> sys; 652 653 friend bool 654 operator==(const Generator_System& x, const Generator_System& y); 655 656 friend class Polyhedron; 657 }; 658 659 //! An iterator over a system of generators 660 /*! \ingroup PPL_CXX_interface 661 A const_iterator is used to provide read-only access 662 to each generator contained in an object of Generator_System. 663 664 \par Example 665 The following code prints the system of generators 666 of the polyhedron <CODE>ph</CODE>: 667 \code 668 const Generator_System& gs = ph.generators(); 669 for (Generator_System::const_iterator i = gs.begin(), 670 gs_end = gs.end(); i != gs_end; ++i) 671 cout << *i << endl; 672 \endcode 673 The same effect can be obtained more concisely by using 674 more features of the STL: 675 \code 676 const Generator_System& gs = ph.generators(); 677 copy(gs.begin(), gs.end(), ostream_iterator<Generator>(cout, "\n")); 678 \endcode 679 */ 680 class Parma_Polyhedra_Library::Generator_System_const_iterator 681 : public std::iterator<std::forward_iterator_tag, 682 Generator, 683 std::ptrdiff_t, 684 const Generator*, 685 const Generator&> { 686 public: 687 //! Default constructor. 688 Generator_System_const_iterator(); 689 690 //! Ordinary copy constructor. 691 Generator_System_const_iterator(const Generator_System_const_iterator& y); 692 693 //! Destructor. 694 ~Generator_System_const_iterator(); 695 696 //! Assignment operator. 697 Generator_System_const_iterator& operator=(const Generator_System_const_iterator& y); 698 699 //! Dereference operator. 700 const Generator& operator*() const; 701 702 //! Indirect member selector. 703 const Generator* operator->() const; 704 705 //! Prefix increment operator. 706 Generator_System_const_iterator& operator++(); 707 708 //! Postfix increment operator. 709 Generator_System_const_iterator operator++(int); 710 711 /*! \brief 712 Returns <CODE>true</CODE> if and only if 713 \p *this and \p y are identical. 714 */ 715 bool operator==(const Generator_System_const_iterator& y) const; 716 717 /*! \brief 718 Returns <CODE>true</CODE> if and only if 719 \p *this and \p y are different. 720 */ 721 bool operator!=(const Generator_System_const_iterator& y) const; 722 723 private: 724 friend class Generator_System; 725 726 //! The const iterator over the Linear_System. 727 Linear_System<Generator>::const_iterator i; 728 729 //! A const pointer to the Linear_System. 730 const Linear_System<Generator>* gsp; 731 732 //! Constructor. 733 Generator_System_const_iterator(const Linear_System<Generator>::const_iterator& iter, 734 const Generator_System& gsys); 735 736 /*! \brief 737 \p *this skips to the next generator, skipping those 738 closure points that are immediately followed by a matching point. 739 */ 740 void skip_forward(); 741 }; 742 743 // Generator_System_inlines.hh is not included here on purpose. 744 745 #endif // !defined(PPL_Generator_System_defs_hh) 746