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