1 /* Grid_Generator_System class implementation (non-inline functions).
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 #include "ppl-config.h"
25 #include "Grid_Generator_System_defs.hh"
26 #include "Grid_Generator_System_inlines.hh"
27 #include "Scalar_Products_defs.hh"
28 #include "Scalar_Products_inlines.hh"
29 #include "Variables_Set_defs.hh"
30 #include "assertions.hh"
31 #include <iostream>
32 
33 namespace PPL = Parma_Polyhedra_Library;
34 
35 void
insert(Grid_Generator_System & gs,Recycle_Input)36 PPL::Grid_Generator_System::insert(Grid_Generator_System& gs, Recycle_Input) {
37   const dimension_type gs_num_rows = gs.num_rows();
38 
39   if (space_dimension() < gs.space_dimension()) {
40     set_space_dimension(gs.space_dimension());
41   }
42   else {
43     gs.set_space_dimension(space_dimension());
44   }
45 
46   for (dimension_type i = 0; i < gs_num_rows; ++i) {
47     sys.insert(gs.sys.rows[i], Recycle_Input());
48   }
49 
50   gs.clear();
51 
52   unset_pending_rows();
53 }
54 
55 void
insert(const Grid_Generator & g)56 PPL::Grid_Generator_System::insert(const Grid_Generator& g) {
57   Grid_Generator tmp(g, representation());
58   insert(tmp, Recycle_Input());
59 }
60 
61 void
insert(Grid_Generator & g,Recycle_Input)62 PPL::Grid_Generator_System::insert(Grid_Generator& g, Recycle_Input) {
63   if (g.is_parameter() && g.all_homogeneous_terms_are_zero()) {
64     // There is no need to add the origin as a parameter,
65     // as it will be immediately flagged as redundant.
66     // However, we still have to adjust space dimension.
67     if (space_dimension() < g.space_dimension()) {
68       set_space_dimension(g.space_dimension());
69     }
70     return;
71   }
72 
73   sys.insert(g, Recycle_Input());
74 
75   PPL_ASSERT(OK());
76 }
77 
78 void
79 PPL::Grid_Generator_System
affine_image(Variable v,const Linear_Expression & expr,Coefficient_traits::const_reference denominator)80 ::affine_image(Variable v,
81                const Linear_Expression& expr,
82                Coefficient_traits::const_reference denominator) {
83   // This is mostly a copy of Generator_System::affine_image.
84 
85   Grid_Generator_System& x = *this;
86   PPL_ASSERT(v.space_dimension() <= x.sys.space_dimension());
87   PPL_ASSERT(expr.space_dimension() <= x.sys.space_dimension());
88   PPL_ASSERT(denominator > 0);
89 
90   const dimension_type num_rows = x.num_rows();
91 
92   // Compute the numerator of the affine transformation and assign it
93   // to the column of `*this' indexed by `v'.
94   PPL_DIRTY_TEMP_COEFFICIENT(numerator);
95 
96   for (dimension_type i = num_rows; i-- > 0; ) {
97     Grid_Generator& row = sys.rows[i];
98     Scalar_Products::assign(numerator, expr, row.expr);
99     if (denominator != 1) {
100       // Since we want integer elements in the matrix,
101       // we multiply by `denominator' all the columns of `*this'
102       // having an index different from `v'.
103       // Note that this operation also modifies the coefficient of v, but
104       // it will be overwritten by the set_coefficient() below.
105       row.expr *= denominator;
106     }
107     row.expr.set_coefficient(v, numerator);
108     // Check that the row is stll OK after fiddling with its internal data.
109     PPL_ASSERT(row.OK());
110   }
111 
112   PPL_ASSERT(sys.OK());
113 
114   // If the mapping is not invertible we may have transformed valid
115   // lines and rays into the origin of the space.
116   const bool not_invertible = (v.space_dimension() >= expr.space_dimension()
117                                || expr.coefficient(v) == 0);
118   if (not_invertible) {
119     x.remove_invalid_lines_and_parameters();
120   }
121 }
122 
PPL_OUTPUT_DEFINITIONS(Grid_Generator_System)123 PPL_OUTPUT_DEFINITIONS(Grid_Generator_System)
124 
125 void
126 PPL::Grid_Generator_System::ascii_dump(std::ostream& s) const {
127   sys.ascii_dump(s);
128 }
129 
130 bool
ascii_load(std::istream & s)131 PPL::Grid_Generator_System::ascii_load(std::istream& s) {
132   if (!sys.ascii_load(s)) {
133     return false;
134   }
135 
136   PPL_ASSERT(OK());
137   return true;
138 }
139 
140 const PPL::Grid_Generator_System*
141 PPL::Grid_Generator_System::zero_dim_univ_p = 0;
142 
143 void
initialize()144 PPL::Grid_Generator_System::initialize() {
145   PPL_ASSERT(zero_dim_univ_p == 0);
146   zero_dim_univ_p
147     = new Grid_Generator_System(Grid_Generator::zero_dim_point());
148 }
149 
150 void
finalize()151 PPL::Grid_Generator_System::finalize() {
152   PPL_ASSERT(zero_dim_univ_p != 0);
153   delete zero_dim_univ_p;
154   zero_dim_univ_p = 0;
155 }
156 
157 bool
OK() const158 PPL::Grid_Generator_System::OK() const {
159   if (sys.topology() == NOT_NECESSARILY_CLOSED) {
160 #ifndef NDEBUG
161     std::cerr << "Grid_Generator_System is NOT_NECESSARILY_CLOSED"
162               << std::endl;
163 #endif
164     return false;
165   }
166 
167   if (sys.is_sorted()) {
168 #ifndef NDEBUG
169     std::cerr << "Grid_Generator_System is marked as sorted."
170               << std::endl;
171 #endif
172     return false;
173   }
174 
175   return sys.OK();
176 }
177 
178 /*! \relates Parma_Polyhedra_Library::Grid_Generator_System */
179 std::ostream&
operator <<(std::ostream & s,const Grid_Generator_System & gs)180 PPL::IO_Operators::operator<<(std::ostream& s,
181                               const Grid_Generator_System& gs) {
182   Grid_Generator_System::const_iterator i = gs.begin();
183   const Grid_Generator_System::const_iterator gs_end = gs.end();
184   if (i == gs_end) {
185     return s << "false";
186   }
187   while (true) {
188     s << *i;
189     ++i;
190     if (i == gs_end) {
191       return s;
192     }
193     s << ", ";
194   }
195 }
196 
197 void
198 PPL::Grid_Generator_System
add_universe_rows_and_columns(dimension_type dims)199 ::add_universe_rows_and_columns(dimension_type dims) {
200   dimension_type col = sys.space_dimension();
201 
202   set_space_dimension(space_dimension() + dims);
203 
204   // Add the new rows and set their diagonal element.
205   for (dimension_type i = 0; i < dims; ++i) {
206     Grid_Generator tmp(space_dimension(), Grid_Generator::LINE_OR_EQUALITY,
207                        NECESSARILY_CLOSED, representation());
208     tmp.expr += Variable(col);
209     PPL_ASSERT(tmp.OK());
210     ++col;
211     sys.insert(tmp, Recycle_Input());
212   }
213 }
214 
215 void
216 PPL::Grid_Generator_System
remove_space_dimensions(const Variables_Set & vars)217 ::remove_space_dimensions(const Variables_Set& vars) {
218   sys.remove_space_dimensions(vars);
219 }
220 
221 void
222 PPL::Grid_Generator_System
shift_space_dimensions(Variable v,dimension_type n)223 ::shift_space_dimensions(Variable v, dimension_type n) {
224   sys.shift_space_dimensions(v, n);
225 }
226 
227 void
228 PPL::Grid_Generator_System
set_space_dimension(const dimension_type new_dimension)229 ::set_space_dimension(const dimension_type new_dimension) {
230   sys.set_space_dimension(new_dimension);
231   PPL_ASSERT(OK());
232 }
233 
234 void
remove_invalid_lines_and_parameters()235 PPL::Grid_Generator_System::remove_invalid_lines_and_parameters() {
236   // The origin of the vector space cannot be a valid line/parameter.
237   // NOTE: the following swaps will mix grid generators without even trying
238   // to preserve sortedness: as a matter of fact, it will almost always
239   // be the case that the input generator system is NOT sorted.
240 
241   // Note that the num_rows() value is *not* constant because remove_row()
242   // decreases it.
243   for (dimension_type i = 0; i < num_rows(); ) {
244     const Grid_Generator& g = (*this)[i];
245     if (g.is_line_or_parameter() && g.all_homogeneous_terms_are_zero()) {
246       sys.remove_row(i, false);
247     }
248     else {
249       ++i;
250     }
251   }
252 }
253 
254 bool
has_points() const255 PPL::Grid_Generator_System::has_points() const {
256   const Grid_Generator_System& ggs = *this;
257   for (dimension_type i = num_rows(); i-- > 0; ) {
258     if (!ggs[i].is_line_or_parameter()) {
259       return true;
260     }
261   }
262   return false;
263 }
264 
265 PPL::dimension_type
num_lines() const266 PPL::Grid_Generator_System::num_lines() const {
267   // We are sure that this method is applied only to a matrix
268   // that does not contain pending rows.
269   PPL_ASSERT(sys.num_pending_rows() == 0);
270   const Grid_Generator_System& ggs = *this;
271   dimension_type n = 0;
272   // If the Linear_System happens to be sorted, take advantage of the fact
273   // that lines are at the top of the system.
274   if (sys.is_sorted()) {
275     const dimension_type nrows = num_rows();
276     for (dimension_type i = 0; i < nrows && ggs[i].is_line(); ++i) {
277       ++n;
278     }
279   }
280   else {
281     for (dimension_type i = num_rows(); i-- > 0 ; ) {
282       if (ggs[i].is_line()) {
283         ++n;
284       }
285     }
286   }
287   return n;
288 }
289 
290 PPL::dimension_type
num_parameters() const291 PPL::Grid_Generator_System::num_parameters() const {
292   // We are sure that this method is applied only to a matrix
293   // that does not contain pending rows.
294   PPL_ASSERT(sys.num_pending_rows() == 0);
295   const Grid_Generator_System& ggs = *this;
296   dimension_type n = 0;
297   // If the Linear_System happens to be sorted, take advantage of the fact
298   // that rays and points are at the bottom of the system and
299   // rays have the inhomogeneous term equal to zero.
300   if (sys.is_sorted()) {
301     for (dimension_type i = num_rows();
302          i != 0 && ggs[--i].is_parameter_or_point(); ) {
303       if (ggs[i].is_line_or_parameter()) {
304         ++n;
305       }
306     }
307   }
308   else {
309     for (dimension_type i = num_rows(); i-- > 0 ; ) {
310       if (ggs[i].is_parameter()) {
311         ++n;
312       }
313     }
314   }
315   return n;
316 }
317