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