1 /* Partially_Reduced_Product class implementation:
2 non-inline template functions.
3 Copyright (C) 2001-2010 Roberto Bagnara <bagnara@cs.unipr.it>
4 Copyright (C) 2010-2016 BUGSENG srl (http://bugseng.com)
5
6 This file is part of the Parma Polyhedra Library (PPL).
7
8 The PPL is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by the
10 Free Software Foundation; either version 3 of the License, or (at your
11 option) any later version.
12
13 The PPL is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software Foundation,
20 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307, USA.
21
22 For the most up-to-date information see the Parma Polyhedra Library
23 site: http://bugseng.com/products/ppl/ . */
24
25 #ifndef PPL_Partially_Reduced_Product_templates_hh
26 #define PPL_Partially_Reduced_Product_templates_hh 1
27
28 #include "Grid_Generator_defs.hh"
29 #include "Grid_Generator_System_defs.hh"
30 #include "Grid_Generator_System_inlines.hh"
31 #include <algorithm>
32 #include <deque>
33
34 namespace Parma_Polyhedra_Library {
35
36 template <typename D1, typename D2, typename R>
37 void
38 Partially_Reduced_Product<D1, D2, R>
throw_space_dimension_overflow(const char * method,const char * reason)39 ::throw_space_dimension_overflow(const char* method,
40 const char* reason) {
41 std::ostringstream s;
42 s << "PPL::Partially_Reduced_Product::" << method << ":" << std::endl
43 << reason << ".";
44 throw std::length_error(s.str());
45 }
46
47 template <typename D1, typename D2, typename R>
48 Constraint_System
constraints() const49 Partially_Reduced_Product<D1, D2, R>::constraints() const {
50 reduce();
51 Constraint_System cs = d2.constraints();
52 const Constraint_System& cs1 = d1.constraints();
53 for (Constraint_System::const_iterator i = cs1.begin(),
54 cs_end = cs1.end(); i != cs_end; ++i) {
55 cs.insert(*i);
56 }
57 return cs;
58 }
59
60 template <typename D1, typename D2, typename R>
61 Constraint_System
minimized_constraints() const62 Partially_Reduced_Product<D1, D2, R>::minimized_constraints() const {
63 reduce();
64 Constraint_System cs = d2.constraints();
65 const Constraint_System& cs1 = d1.constraints();
66 for (Constraint_System::const_iterator i = cs1.begin(),
67 cs_end = cs1.end(); i != cs_end; ++i) {
68 cs.insert(*i);
69 }
70 if (cs.has_strict_inequalities()) {
71 NNC_Polyhedron ph(cs);
72 return ph.minimized_constraints();
73 }
74 else {
75 C_Polyhedron ph(cs);
76 return ph.minimized_constraints();
77 }
78 }
79
80 template <typename D1, typename D2, typename R>
81 Congruence_System
congruences() const82 Partially_Reduced_Product<D1, D2, R>::congruences() const {
83 reduce();
84 Congruence_System cgs = d2.congruences();
85 const Congruence_System& cgs1 = d1.congruences();
86 for (Congruence_System::const_iterator i = cgs1.begin(),
87 cgs_end = cgs1.end(); i != cgs_end; ++i) {
88 cgs.insert(*i);
89 }
90 return cgs;
91 }
92
93 template <typename D1, typename D2, typename R>
94 Congruence_System
minimized_congruences() const95 Partially_Reduced_Product<D1, D2, R>::minimized_congruences() const {
96 reduce();
97 Congruence_System cgs = d2.congruences();
98 const Congruence_System& cgs1 = d1.congruences();
99 for (Congruence_System::const_iterator i = cgs1.begin(),
100 cgs_end = cgs1.end(); i != cgs_end; ++i) {
101 cgs.insert(*i);
102 }
103 Grid gr(cgs);
104 return gr.minimized_congruences();
105 }
106
107 template <typename D1, typename D2, typename R>
108 void
109 Partially_Reduced_Product<D1, D2, R>
add_recycled_constraints(Constraint_System & cs)110 ::add_recycled_constraints(Constraint_System& cs) {
111 if (d1.can_recycle_constraint_systems()) {
112 d2.refine_with_constraints(cs);
113 d1.add_recycled_constraints(cs);
114 }
115 else {
116 if (d2.can_recycle_constraint_systems()) {
117 d1.refine_with_constraints(cs);
118 d2.add_recycled_constraints(cs);
119 }
120 else {
121 d1.add_constraints(cs);
122 d2.add_constraints(cs);
123 }
124 }
125 clear_reduced_flag();
126 }
127
128 template <typename D1, typename D2, typename R>
129 void
130 Partially_Reduced_Product<D1, D2, R>
add_recycled_congruences(Congruence_System & cgs)131 ::add_recycled_congruences(Congruence_System& cgs) {
132 if (d1.can_recycle_congruence_systems()) {
133 d2.refine_with_congruences(cgs);
134 d1.add_recycled_congruences(cgs);
135 }
136 else {
137 if (d2.can_recycle_congruence_systems()) {
138 d1.refine_with_congruences(cgs);
139 d2.add_recycled_congruences(cgs);
140 }
141 else {
142 d1.add_congruences(cgs);
143 d2.add_congruences(cgs);
144 }
145 }
146 clear_reduced_flag();
147 }
148
149 template <typename D1, typename D2, typename R>
150 Poly_Gen_Relation
151 Partially_Reduced_Product<D1, D2, R>
relation_with(const Generator & g) const152 ::relation_with(const Generator& g) const {
153 reduce();
154 if (Poly_Gen_Relation::nothing() == d1.relation_with(g)
155 || Poly_Gen_Relation::nothing() == d2.relation_with(g)) {
156 return Poly_Gen_Relation::nothing();
157 }
158 else {
159 return Poly_Gen_Relation::subsumes();
160 }
161 }
162
163 template <typename D1, typename D2, typename R>
164 Poly_Con_Relation
165 Partially_Reduced_Product<D1, D2, R>
relation_with(const Constraint & c) const166 ::relation_with(const Constraint& c) const {
167 reduce();
168 Poly_Con_Relation relation1 = d1.relation_with(c);
169 Poly_Con_Relation relation2 = d2.relation_with(c);
170
171 Poly_Con_Relation result = Poly_Con_Relation::nothing();
172
173 if (relation1.implies(Poly_Con_Relation::is_included())) {
174 result = result && Poly_Con_Relation::is_included();
175 }
176 else if (relation2.implies(Poly_Con_Relation::is_included())) {
177 result = result && Poly_Con_Relation::is_included();
178 }
179 if (relation1.implies(Poly_Con_Relation::saturates())) {
180 result = result && Poly_Con_Relation::saturates();
181 }
182 else if (relation2.implies(Poly_Con_Relation::saturates())) {
183 result = result && Poly_Con_Relation::saturates();
184 }
185 if (relation1.implies(Poly_Con_Relation::is_disjoint())) {
186 result = result && Poly_Con_Relation::is_disjoint();
187 }
188 else if (relation2.implies(Poly_Con_Relation::is_disjoint())) {
189 result = result && Poly_Con_Relation::is_disjoint();
190 }
191
192 return result;
193 }
194
195 template <typename D1, typename D2, typename R>
196 Poly_Con_Relation
197 Partially_Reduced_Product<D1, D2, R>
relation_with(const Congruence & cg) const198 ::relation_with(const Congruence& cg) const {
199 reduce();
200 Poly_Con_Relation relation1 = d1.relation_with(cg);
201 Poly_Con_Relation relation2 = d2.relation_with(cg);
202
203 Poly_Con_Relation result = Poly_Con_Relation::nothing();
204
205 if (relation1.implies(Poly_Con_Relation::is_included())) {
206 result = result && Poly_Con_Relation::is_included();
207 }
208 else if (relation2.implies(Poly_Con_Relation::is_included())) {
209 result = result && Poly_Con_Relation::is_included();
210 }
211 if (relation1.implies(Poly_Con_Relation::saturates())) {
212 result = result && Poly_Con_Relation::saturates();
213 }
214 else if (relation2.implies(Poly_Con_Relation::saturates())) {
215 result = result && Poly_Con_Relation::saturates();
216 }
217 if (relation1.implies(Poly_Con_Relation::is_disjoint())) {
218 result = result && Poly_Con_Relation::is_disjoint();
219 }
220 else if (relation2.implies(Poly_Con_Relation::is_disjoint())) {
221 result = result && Poly_Con_Relation::is_disjoint();
222 }
223
224 return result;
225 }
226
227 template <typename D1, typename D2, typename R>
228 bool
229 Partially_Reduced_Product<D1, D2, R>
maximize(const Linear_Expression & expr,Coefficient & sup_n,Coefficient & sup_d,bool & maximum) const230 ::maximize(const Linear_Expression& expr,
231 Coefficient& sup_n,
232 Coefficient& sup_d,
233 bool& maximum) const {
234 reduce();
235
236 if (is_empty()) {
237 return false;
238 }
239
240 PPL_DIRTY_TEMP_COEFFICIENT(sup1_n);
241 PPL_DIRTY_TEMP_COEFFICIENT(sup1_d);
242 PPL_DIRTY_TEMP_COEFFICIENT(sup2_n);
243 PPL_DIRTY_TEMP_COEFFICIENT(sup2_d);
244 bool maximum1;
245 bool maximum2;
246 bool r1 = d1.maximize(expr, sup1_n, sup1_d, maximum1);
247 bool r2 = d2.maximize(expr, sup2_n, sup2_d, maximum2);
248 // If neither is bounded from above, return false.
249 if (!r1 && !r2) {
250 return false;
251 }
252 // If only d2 is bounded from above, then use the values for d2.
253 if (!r1) {
254 sup_n = sup2_n;
255 sup_d = sup2_d;
256 maximum = maximum2;
257 return true;
258 }
259 // If only d1 is bounded from above, then use the values for d1.
260 if (!r2) {
261 sup_n = sup1_n;
262 sup_d = sup1_d;
263 maximum = maximum1;
264 return true;
265 }
266 // If both d1 and d2 are bounded from above, then use the minimum values.
267 if (sup2_d * sup1_n >= sup1_d * sup2_n) {
268 sup_n = sup1_n;
269 sup_d = sup1_d;
270 maximum = maximum1;
271 }
272 else {
273 sup_n = sup2_n;
274 sup_d = sup2_d;
275 maximum = maximum2;
276 }
277 return true;
278 }
279
280 template <typename D1, typename D2, typename R>
281 bool
282 Partially_Reduced_Product<D1, D2, R>
minimize(const Linear_Expression & expr,Coefficient & inf_n,Coefficient & inf_d,bool & minimum) const283 ::minimize(const Linear_Expression& expr,
284 Coefficient& inf_n,
285 Coefficient& inf_d,
286 bool& minimum) const {
287 reduce();
288
289 if (is_empty()) {
290 return false;
291 }
292 PPL_ASSERT(reduced);
293
294 PPL_DIRTY_TEMP_COEFFICIENT(inf1_n);
295 PPL_DIRTY_TEMP_COEFFICIENT(inf1_d);
296 PPL_DIRTY_TEMP_COEFFICIENT(inf2_n);
297 PPL_DIRTY_TEMP_COEFFICIENT(inf2_d);
298 bool minimum1;
299 bool minimum2;
300 bool r1 = d1.minimize(expr, inf1_n, inf1_d, minimum1);
301 bool r2 = d2.minimize(expr, inf2_n, inf2_d, minimum2);
302 // If neither is bounded from below, return false.
303 if (!r1 && !r2) {
304 return false;
305 }
306 // If only d2 is bounded from below, then use the values for d2.
307 if (!r1) {
308 inf_n = inf2_n;
309 inf_d = inf2_d;
310 minimum = minimum2;
311 return true;
312 }
313 // If only d1 is bounded from below, then use the values for d1.
314 if (!r2) {
315 inf_n = inf1_n;
316 inf_d = inf1_d;
317 minimum = minimum1;
318 return true;
319 }
320 // If both d1 and d2 are bounded from below, then use the minimum values.
321 if (inf2_d * inf1_n <= inf1_d * inf2_n) {
322 inf_n = inf1_n;
323 inf_d = inf1_d;
324 minimum = minimum1;
325 }
326 else {
327 inf_n = inf2_n;
328 inf_d = inf2_d;
329 minimum = minimum2;
330 }
331 return true;
332 }
333
334 template <typename D1, typename D2, typename R>
335 bool
336 Partially_Reduced_Product<D1, D2, R>
maximize(const Linear_Expression & expr,Coefficient & sup_n,Coefficient & sup_d,bool & maximum,Generator & g) const337 ::maximize(const Linear_Expression& expr,
338 Coefficient& sup_n,
339 Coefficient& sup_d,
340 bool& maximum,
341 Generator& g) const {
342 reduce();
343
344 if (is_empty()) {
345 return false;
346 }
347 PPL_ASSERT(reduced);
348
349 PPL_DIRTY_TEMP_COEFFICIENT(sup1_n);
350 PPL_DIRTY_TEMP_COEFFICIENT(sup1_d);
351 PPL_DIRTY_TEMP_COEFFICIENT(sup2_n);
352 PPL_DIRTY_TEMP_COEFFICIENT(sup2_d);
353 bool maximum1;
354 bool maximum2;
355 Generator g1(point());
356 Generator g2(point());
357 bool r1 = d1.maximize(expr, sup1_n, sup1_d, maximum1, g1);
358 bool r2 = d2.maximize(expr, sup2_n, sup2_d, maximum2, g2);
359 // If neither is bounded from above, return false.
360 if (!r1 && !r2) {
361 return false;
362 }
363 // If only d2 is bounded from above, then use the values for d2.
364 if (!r1) {
365 sup_n = sup2_n;
366 sup_d = sup2_d;
367 maximum = maximum2;
368 g = g2;
369 return true;
370 }
371 // If only d1 is bounded from above, then use the values for d1.
372 if (!r2) {
373 sup_n = sup1_n;
374 sup_d = sup1_d;
375 maximum = maximum1;
376 g = g1;
377 return true;
378 }
379 // If both d1 and d2 are bounded from above, then use the minimum values.
380 if (sup2_d * sup1_n >= sup1_d * sup2_n) {
381 sup_n = sup1_n;
382 sup_d = sup1_d;
383 maximum = maximum1;
384 g = g1;
385 }
386 else {
387 sup_n = sup2_n;
388 sup_d = sup2_d;
389 maximum = maximum2;
390 g = g2;
391 }
392 return true;
393 }
394
395 template <typename D1, typename D2, typename R>
396 bool
397 Partially_Reduced_Product<D1, D2, R>
minimize(const Linear_Expression & expr,Coefficient & inf_n,Coefficient & inf_d,bool & minimum,Generator & g) const398 ::minimize(const Linear_Expression& expr,
399 Coefficient& inf_n,
400 Coefficient& inf_d,
401 bool& minimum,
402 Generator& g) const {
403 reduce();
404
405 if (is_empty()) {
406 return false;
407 }
408 PPL_ASSERT(reduced);
409
410 PPL_DIRTY_TEMP_COEFFICIENT(inf1_n);
411 PPL_DIRTY_TEMP_COEFFICIENT(inf1_d);
412 PPL_DIRTY_TEMP_COEFFICIENT(inf2_n);
413 PPL_DIRTY_TEMP_COEFFICIENT(inf2_d);
414 bool minimum1;
415 bool minimum2;
416 Generator g1(point());
417 Generator g2(point());
418 bool r1 = d1.minimize(expr, inf1_n, inf1_d, minimum1, g1);
419 bool r2 = d2.minimize(expr, inf2_n, inf2_d, minimum2, g2);
420 // If neither is bounded from below, return false.
421 if (!r1 && !r2) {
422 return false;
423 }
424 // If only d2 is bounded from below, then use the values for d2.
425 if (!r1) {
426 inf_n = inf2_n;
427 inf_d = inf2_d;
428 minimum = minimum2;
429 g = g2;
430 return true;
431 }
432 // If only d1 is bounded from below, then use the values for d1.
433 if (!r2) {
434 inf_n = inf1_n;
435 inf_d = inf1_d;
436 minimum = minimum1;
437 g = g1;
438 return true;
439 }
440 // If both d1 and d2 are bounded from below, then use the minimum values.
441 if (inf2_d * inf1_n <= inf1_d * inf2_n) {
442 inf_n = inf1_n;
443 inf_d = inf1_d;
444 minimum = minimum1;
445 g = g1;
446 }
447 else {
448 inf_n = inf2_n;
449 inf_d = inf2_d;
450 minimum = minimum2;
451 g = g2;
452 }
453 return true;
454 }
455
456 template <typename D1, typename D2, typename R>
457 inline bool
OK() const458 Partially_Reduced_Product<D1, D2, R>::OK() const {
459 if (reduced) {
460 Partially_Reduced_Product<D1, D2, R> dp1 = *this;
461 Partially_Reduced_Product<D1, D2, R> dp2 = *this;
462 /* Force dp1 reduction */
463 dp1.clear_reduced_flag();
464 dp1.reduce();
465 if (dp1 != dp2) {
466 return false;
467 }
468 }
469 return d1.OK() && d2.OK();
470 }
471
472 template <typename D1, typename D2, typename R>
473 bool
ascii_load(std::istream & s)474 Partially_Reduced_Product<D1, D2, R>::ascii_load(std::istream& s) {
475 const char yes = '+';
476 const char no = '-';
477 std::string str;
478 if (!(s >> str) || str != "Partially_Reduced_Product") {
479 return false;
480 }
481 if (!(s >> str)
482 || (str[0] != yes && str[0] != no)
483 || str.substr(1) != "reduced") {
484 return false;
485 }
486 reduced = (str[0] == yes);
487 if (!(s >> str) || str != "Domain") {
488 return false;
489 }
490 if (!(s >> str) || str != "1:") {
491 return false;
492 }
493 if (!d1.ascii_load(s)) {
494 return false;
495 }
496 if (!(s >> str) || str != "Domain") {
497 return false;
498 }
499 if (!(s >> str) || str != "2:") {
500 return false;
501 }
502 return d2.ascii_load(s);
503 }
504
505 template <typename D1, typename D2>
product_reduce(D1 & d1,D2 & d2)506 void Smash_Reduction<D1, D2>::product_reduce(D1& d1, D2& d2) {
507 using std::swap;
508 if (d2.is_empty()) {
509 if (!d1.is_empty()) {
510 D1 new_d1(d1.space_dimension(), EMPTY);
511 swap(d1, new_d1);
512 }
513 }
514 else if (d1.is_empty()) {
515 D2 new_d2(d2.space_dimension(), EMPTY);
516 swap(d2, new_d2);
517 }
518 }
519
520 template <typename D1, typename D2>
product_reduce(D1 & d1,D2 & d2)521 void Constraints_Reduction<D1, D2>::product_reduce(D1& d1, D2& d2) {
522 if (d1.is_empty() || d2.is_empty()) {
523 // If one of the components is empty, do the smash reduction and return.
524 Parma_Polyhedra_Library::Smash_Reduction<D1, D2> sr;
525 sr.product_reduce(d1, d2);
526 return;
527 }
528 else {
529 using std::swap;
530 dimension_type space_dim = d1.space_dimension();
531 d1.refine_with_constraints(d2.minimized_constraints());
532 if (d1.is_empty()) {
533 D2 new_d2(space_dim, EMPTY);
534 swap(d2, new_d2);
535 return;
536 }
537 d2.refine_with_constraints(d1.minimized_constraints());
538 if (d2.is_empty()) {
539 D1 new_d1(space_dim, EMPTY);
540 swap(d1, new_d1);
541 }
542 }
543 }
544
545 /* Auxiliary procedure for the Congruences_Reduction() method.
546 If more than one hyperplane defined by congruence cg intersect
547 d2, then d1 and d2 are unchanged; if exactly one intersects d2, then
548 the corresponding equality is added to d1 and d2;
549 otherwise d1 and d2 are set empty. */
550 template <typename D1, typename D2>
shrink_to_congruence_no_check(D1 & d1,D2 & d2,const Congruence & cg)551 bool shrink_to_congruence_no_check(D1& d1, D2& d2, const Congruence& cg) {
552 // It is assumed that cg is a proper congruence.
553 PPL_ASSERT(cg.modulus() != 0);
554 // It is assumed that cg is satisfied by all points in d1.
555 PPL_ASSERT(d1.relation_with(cg) == Poly_Con_Relation::is_included());
556
557 Linear_Expression e(cg.expression());
558
559 // Find the maximum and minimum bounds for the domain element d with the
560 // linear expression e.
561 PPL_DIRTY_TEMP_COEFFICIENT(max_numer);
562 PPL_DIRTY_TEMP_COEFFICIENT(max_denom);
563 bool max_included;
564 PPL_DIRTY_TEMP_COEFFICIENT(min_numer);
565 PPL_DIRTY_TEMP_COEFFICIENT(min_denom);
566 if (d2.maximize(e, max_numer, max_denom, max_included)) {
567 bool min_included;
568 if (d2.minimize(e, min_numer, min_denom, min_included)) {
569 // Adjust values to allow for the denominators max_denom and min_denom.
570 max_numer *= min_denom;
571 min_numer *= max_denom;
572 PPL_DIRTY_TEMP_COEFFICIENT(denom);
573 PPL_DIRTY_TEMP_COEFFICIENT(mod);
574 denom = max_denom * min_denom;
575 mod = cg.modulus() * denom;
576 // If the difference between the maximum and minimum bounds is more than
577 // twice the modulus, then there will be two neighboring hyperplanes
578 // defined by cg that are intersected by the domain element d;
579 // there is no possible reduction in this case.
580 PPL_DIRTY_TEMP_COEFFICIENT(mod2);
581 mod2 = 2 * mod;
582 if (max_numer - min_numer < mod2
583 || (max_numer - min_numer == mod2 && (!max_included || !min_included)))
584 {
585 PPL_DIRTY_TEMP_COEFFICIENT(shrink_amount);
586 PPL_DIRTY_TEMP_COEFFICIENT(max_decreased);
587 PPL_DIRTY_TEMP_COEFFICIENT(min_increased);
588 // Find the amount by which the maximum value may be decreased.
589 shrink_amount = max_numer % mod;
590 if (!max_included && shrink_amount == 0) {
591 shrink_amount = mod;
592 }
593 if (shrink_amount < 0) {
594 shrink_amount += mod;
595 }
596 max_decreased = max_numer - shrink_amount;
597 // Find the amount by which the minimum value may be increased.
598 shrink_amount = min_numer % mod;
599 if (!min_included && shrink_amount == 0) {
600 shrink_amount = - mod;
601 }
602 if (shrink_amount > 0) {
603 shrink_amount -= mod;
604 }
605 min_increased = min_numer - shrink_amount;
606 if (max_decreased == min_increased) {
607 // The domain element d2 intersects exactly one hyperplane
608 // defined by cg, so add the equality to d1 and d2.
609 Constraint new_c(denom * e == min_increased);
610 d1.refine_with_constraint(new_c);
611 d2.refine_with_constraint(new_c);
612 return true;
613 }
614 else {
615 if (max_decreased < min_increased) {
616 using std::swap;
617 // In this case, d intersects no hyperplanes defined by cg,
618 // so set d to empty and return false.
619 D1 new_d1(d1.space_dimension(), EMPTY);
620 swap(d1, new_d1);
621 D2 new_d2(d2.space_dimension(), EMPTY);
622 swap(d2, new_d2);
623 return false;
624 }
625 }
626 }
627 }
628 }
629 return true;
630 }
631
632 template <typename D1, typename D2>
633 void
product_reduce(D1 & d1,D2 & d2)634 Congruences_Reduction<D1, D2>::product_reduce(D1& d1, D2& d2) {
635 if (d1.is_empty() || d2.is_empty()) {
636 // If one of the components is empty, do the smash reduction and return.
637 Parma_Polyhedra_Library::Smash_Reduction<D1, D2> sr;
638 sr.product_reduce(d1, d2);
639 return;
640 }
641 // Use the congruences representing d1 to shrink both components.
642 const Congruence_System cgs1 = d1.minimized_congruences();
643 for (Congruence_System::const_iterator i = cgs1.begin(),
644 cgs_end = cgs1.end(); i != cgs_end; ++i) {
645 const Congruence& cg1 = *i;
646 if (cg1.is_equality()) {
647 d2.refine_with_congruence(cg1);
648 }
649 else {
650 if (!Parma_Polyhedra_Library::
651 shrink_to_congruence_no_check(d1, d2, cg1)) {
652 // The product is empty.
653 return;
654 }
655 }
656 }
657 // Use the congruences representing d2 to shrink both components.
658 const Congruence_System cgs2 = d2.minimized_congruences();
659 for (Congruence_System::const_iterator i = cgs2.begin(),
660 cgs_end = cgs2.end(); i != cgs_end; ++i) {
661 const Congruence& cg2 = *i;
662 if (cg2.is_equality()) {
663 d1.refine_with_congruence(cg2);
664 }
665 else {
666 if (!Parma_Polyhedra_Library::
667 shrink_to_congruence_no_check(d2, d1, cg2)) {
668 // The product is empty.
669 return;
670 }
671 }
672 }
673 }
674
675 template <typename D1, typename D2>
676 void
product_reduce(D1 & d1,D2 & d2)677 Shape_Preserving_Reduction<D1, D2>::product_reduce(D1& d1, D2& d2) {
678 // First do the congruences reduction.
679 Parma_Polyhedra_Library::Congruences_Reduction<D1, D2> cgr;
680 cgr.product_reduce(d1, d2);
681 if (d1.is_empty()) {
682 return;
683 }
684
685 PPL_DIRTY_TEMP_COEFFICIENT(freq_n);
686 PPL_DIRTY_TEMP_COEFFICIENT(freq_d);
687 PPL_DIRTY_TEMP_COEFFICIENT(val_n);
688 PPL_DIRTY_TEMP_COEFFICIENT(val_d);
689
690 // Use the constraints representing d2.
691 Constraint_System cs = d2.minimized_constraints();
692 Constraint_System refining_cs;
693 for (Constraint_System::const_iterator i = cs.begin(),
694 cs_end = cs.end(); i != cs_end; ++i) {
695 const Constraint& c = *i;
696 if (c.is_equality()) {
697 continue;
698 }
699 // Check the frequency and value of the linear expression for
700 // the constraint `c'.
701 Linear_Expression le(c.expression());
702 if (!d1.frequency(le, freq_n, freq_d, val_n, val_d)) {
703 // Nothing to do.
704 continue;
705 }
706 if (val_n == 0) {
707 // Nothing to do.
708 continue;
709 }
710 // Adjust the value of the inhomogeneous term to satisfy
711 // the implied congruence.
712 if (val_n < 0) {
713 val_n = val_n*freq_d + val_d*freq_n;
714 val_d *= freq_d;
715 }
716 le *= val_d;
717 le -= val_n;
718 refining_cs.insert(le >= 0);
719 }
720 d2.refine_with_constraints(refining_cs);
721
722 // Use the constraints representing d1.
723 cs = d1.minimized_constraints();
724 refining_cs.clear();
725 for (Constraint_System::const_iterator i = cs.begin(),
726 cs_end = cs.end(); i != cs_end; ++i) {
727 const Constraint& c = *i;
728 if (c.is_equality()) {
729 // Equalities already shared.
730 continue;
731 }
732 // Check the frequency and value of the linear expression for
733 // the constraint `c'.
734 Linear_Expression le(c.expression());
735 if (!d2.frequency(le, freq_n, freq_d, val_n, val_d)) {
736 // Nothing to do.
737 continue;
738 }
739 if (val_n == 0) {
740 // Nothing to do.
741 continue;
742 }
743 // Adjust the value of the inhomogeneous term to satisfy
744 // the implied congruence.
745 if (val_n < 0) {
746 val_n = val_n*freq_d + val_d*freq_n;
747 val_d *= freq_d;
748 }
749 le *= val_d;
750 le -= val_n;
751 refining_cs.insert(le >= 0);
752 }
753 d1.refine_with_constraints(refining_cs);
754
755 // The reduction may have introduced additional equalities
756 // so these must be shared with the other component.
757 Parma_Polyhedra_Library::Constraints_Reduction<D1, D2> cr;
758 cr.product_reduce(d1, d2);
759 }
760
761 } // namespace Parma_Polyhedra_Library
762
763 #endif // !defined(PPL_Partially_Reduced_Product_templates_hh)
764