PPL  1.2
Polyhedron_nonpublic.cc
Go to the documentation of this file.
1 /* Polyhedron class implementation
2  (non-inline private or protected 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 #include "ppl-config.h"
26 #include "Polyhedron_defs.hh"
27 #include "Scalar_Products_defs.hh"
29 #include "Linear_Form_defs.hh"
30 #include "C_Integer.hh"
31 #include "assertions.hh"
32 #include <string>
33 #include <iostream>
34 #include <sstream>
35 #include <stdexcept>
36 
37 #ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
38 
47 #endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
48 #define BE_LAZY 1
49 
50 namespace PPL = Parma_Polyhedra_Library;
51 
53  const dimension_type num_dimensions,
54  const Degenerate_Element kind)
55  : con_sys(topol, default_con_sys_repr),
56  gen_sys(topol, default_gen_sys_repr),
57  sat_c(),
58  sat_g() {
59  // Protecting against space dimension overflow is up to the caller.
60  PPL_ASSERT(num_dimensions <= max_space_dimension());
61 
62  if (kind == EMPTY) {
63  status.set_empty();
64  }
65  else if (num_dimensions > 0) {
67  con_sys.adjust_topology_and_space_dimension(topol, num_dimensions);
69  }
70  space_dim = num_dimensions;
71  PPL_ASSERT_HEAVY(OK());
72 }
73 
75  : con_sys(y.topology(), default_con_sys_repr),
76  gen_sys(y.topology(), default_gen_sys_repr),
77  status(y.status),
78  space_dim(y.space_dim) {
79  // Being a protected method, we simply assert that topologies do match.
80  PPL_ASSERT(topology() == y.topology());
83  }
84  if (y.generators_are_up_to_date()) {
86  }
87  if (y.sat_c_is_up_to_date()) {
88  sat_c = y.sat_c;
89  }
90  if (y.sat_g_is_up_to_date()) {
91  sat_g = y.sat_g;
92  }
93 }
94 
96  : con_sys(topol, default_con_sys_repr),
97  gen_sys(topol, default_gen_sys_repr),
98  sat_c(),
99  sat_g() {
100  // Protecting against space dimension overflow is up to the caller.
101  PPL_ASSERT(cs.space_dimension() <= max_space_dimension());
102 
103  // TODO: this implementation is just an executable specification.
104  Constraint_System cs_copy = cs;
105 
106  // Try to adapt `cs_copy' to the required topology.
107  const dimension_type cs_copy_space_dim = cs_copy.space_dimension();
108  if (!cs_copy.adjust_topology_and_space_dimension(topol, cs_copy_space_dim)) {
110  ? "C_Polyhedron(cs)"
111  : "NNC_Polyhedron(cs)", "cs", cs_copy);
112  }
113  // Set the space dimension.
114  space_dim = cs_copy_space_dim;
115 
116  if (space_dim > 0) {
117  // Stealing the rows from `cs_copy'.
118  using std::swap;
119  swap(con_sys, cs_copy);
120  if (con_sys.num_pending_rows() > 0) {
121  // Even though `cs_copy' has pending constraints, since the
122  // generators of the polyhedron are not up-to-date, the
123  // polyhedron cannot have pending constraints. By integrating
124  // the pending part of `con_sys' we may loose sortedness.
125  con_sys.set_sorted(false);
127  }
130  }
131  else {
132  // Here `space_dim == 0'.
133  // See if an inconsistent constraint has been passed.
134  for (dimension_type i = cs_copy.num_rows(); i-- > 0; ) {
135  if (cs_copy[i].is_inconsistent()) {
136  // Inconsistent constraint found: the polyhedron is empty.
137  set_empty();
138  break;
139  }
140  }
141  }
142  PPL_ASSERT_HEAVY(OK());
143 }
144 
146  Constraint_System& cs,
148  : con_sys(topol, default_con_sys_repr),
149  gen_sys(topol, default_gen_sys_repr),
150  sat_c(),
151  sat_g() {
152  // Protecting against space dimension overflow is up to the caller.
153  PPL_ASSERT(cs.space_dimension() <= max_space_dimension());
154 
155  // Try to adapt `cs' to the required topology.
156  const dimension_type cs_space_dim = cs.space_dimension();
157  if (!cs.adjust_topology_and_space_dimension(topol, cs_space_dim)) {
159  ? "C_Polyhedron(cs, recycle)"
160  : "NNC_Polyhedron(cs, recycle)", "cs", cs);
161  }
162 
163  // Set the space dimension.
164  space_dim = cs_space_dim;
165 
166  if (space_dim > 0) {
167  // Stealing the rows from `cs'.
168  swap(con_sys, cs);
169  if (con_sys.num_pending_rows() > 0) {
170  // Even though `cs' has pending constraints, since the generators
171  // of the polyhedron are not up-to-date, the polyhedron cannot
172  // have pending constraints. By integrating the pending part
173  // of `con_sys' we may loose sortedness.
175  con_sys.set_sorted(false);
176  }
179  }
180  else {
181  // Here `space_dim == 0'.
182 
183  // See if an inconsistent constraint has been passed.
184  for (dimension_type i = cs.num_rows(); i-- > 0; ) {
185  if (cs[i].is_inconsistent()) {
186  // Inconsistent constraint found: the polyhedron is empty.
187  set_empty();
188  break;
189  }
190  }
191  }
192  PPL_ASSERT_HEAVY(OK());
193 }
194 
196  : con_sys(topol, default_con_sys_repr),
197  gen_sys(topol, default_gen_sys_repr),
198  sat_c(),
199  sat_g() {
200  // Protecting against space dimension overflow is up to the caller.
201  PPL_ASSERT(gs.space_dimension() <= max_space_dimension());
202 
203  // An empty set of generators defines the empty polyhedron.
204  if (gs.has_no_rows()) {
205  space_dim = gs.space_dimension();
206  status.set_empty();
207  PPL_ASSERT_HEAVY(OK());
208  return;
209  }
210 
211  // Non-empty valid generator systems have a supporting point, at least.
212  if (!gs.has_points()) {
214  ? "C_Polyhedron(gs)"
215  : "NNC_Polyhedron(gs)", "gs");
216  }
217  // TODO: this implementation is just an executable specification.
218  Generator_System gs_copy = gs;
219 
220  const dimension_type gs_copy_space_dim = gs_copy.space_dimension();
221  // Try to adapt `gs_copy' to the required topology.
222  if (!gs_copy.adjust_topology_and_space_dimension(topol, gs_copy_space_dim)) {
224  ? "C_Polyhedron(gs)"
225  : "NNC_Polyhedron(gs)", "gs", gs_copy);
226  }
227 
228  if (gs_copy_space_dim > 0) {
229  // Stealing the rows from `gs_copy'.
230  using std::swap;
231  swap(gen_sys, gs_copy);
232  // In a generator system describing a NNC polyhedron,
233  // for each point we must also have the corresponding closure point.
234  if (topol == NOT_NECESSARILY_CLOSED) {
236  }
237  if (gen_sys.num_pending_rows() > 0) {
238  // Even though `gs_copy' has pending generators, since the
239  // constraints of the polyhedron are not up-to-date, the
240  // polyhedron cannot have pending generators. By integrating the
241  // pending part of `gen_sys' we may lose sortedness.
242  gen_sys.set_sorted(false);
244  }
245  // Generators are now up-to-date.
247 
248  // Set the space dimension.
249  space_dim = gs_copy_space_dim;
250  PPL_ASSERT_HEAVY(OK());
251  return;
252  }
253 
254  // Here `gs_copy.num_rows > 0' and `gs_copy_space_dim == 0':
255  // we already checked for both the topology-compatibility
256  // and the supporting point.
257  space_dim = 0;
258  PPL_ASSERT_HEAVY(OK());
259 }
260 
262  Generator_System& gs,
264  : con_sys(topol, default_con_sys_repr),
265  gen_sys(topol, default_gen_sys_repr),
266  sat_c(),
267  sat_g() {
268  // Protecting against space dimension overflow is up to the caller.
269  PPL_ASSERT(gs.space_dimension() <= max_space_dimension());
270 
271  // An empty set of generators defines the empty polyhedron.
272  if (gs.has_no_rows()) {
273  space_dim = gs.space_dimension();
274  status.set_empty();
275  PPL_ASSERT_HEAVY(OK());
276  return;
277  }
278 
279  // Non-empty valid generator systems have a supporting point, at least.
280  if (!gs.has_points()) {
282  ? "C_Polyhedron(gs, recycle)"
283  : "NNC_Polyhedron(gs, recycle)", "gs");
284  }
285 
286  const dimension_type gs_space_dim = gs.space_dimension();
287  // Try to adapt `gs' to the required topology.
288  if (!gs.adjust_topology_and_space_dimension(topol, gs_space_dim)) {
290  ? "C_Polyhedron(gs, recycle)"
291  : "NNC_Polyhedron(gs, recycle)", "gs", gs);
292  }
293 
294  if (gs_space_dim > 0) {
295  // Stealing the rows from `gs'.
296  swap(gen_sys, gs);
297  // In a generator system describing a NNC polyhedron,
298  // for each point we must also have the corresponding closure point.
299  if (topol == NOT_NECESSARILY_CLOSED) {
301  }
302  if (gen_sys.num_pending_rows() > 0) {
303  // Even though `gs' has pending generators, since the constraints
304  // of the polyhedron are not up-to-date, the polyhedron cannot
305  // have pending generators. By integrating the pending part
306  // of `gen_sys' we may loose sortedness.
307  gen_sys.set_sorted(false);
309  }
310  // Generators are now up-to-date.
312 
313  // Set the space dimension.
314  space_dim = gs_space_dim;
315  PPL_ASSERT_HEAVY(OK());
316  return;
317  }
318 
319  // Here `gs.num_rows > 0' and `gs_space_dim == 0':
320  // we already checked for both the topology-compatibility
321  // and the supporting point.
322  space_dim = 0;
323  PPL_ASSERT_HEAVY(OK());
324 }
325 
328  // Being a protected method, we simply assert that topologies do match.
329  PPL_ASSERT(topology() == y.topology());
330  space_dim = y.space_dim;
331  if (y.marked_empty()) {
332  set_empty();
333  }
334  else if (space_dim == 0) {
335  set_zero_dim_univ();
336  }
337  else {
338  status = y.status;
339  if (y.constraints_are_up_to_date()) {
340  con_sys.assign_with_pending(y.con_sys);
341  }
342  if (y.generators_are_up_to_date()) {
343  gen_sys.assign_with_pending(y.gen_sys);
344  }
345  if (y.sat_c_is_up_to_date()) {
346  sat_c = y.sat_c;
347  }
348  if (y.sat_g_is_up_to_date()) {
349  sat_g = y.sat_g;
350  }
351  }
352  return *this;
353 }
354 
357  // Private method: the caller must ensure the following.
358  PPL_ASSERT(topology() == y.topology());
359  PPL_ASSERT(space_dim == y.space_dim);
360  PPL_ASSERT(!marked_empty() && !y.marked_empty() && space_dim > 0);
361 
362  const Polyhedron& x = *this;
363 
364  if (x.is_necessarily_closed()) {
365  if (!x.has_something_pending() && !y.has_something_pending()) {
366  bool css_normalized = false;
367  if (x.constraints_are_minimized() && y.constraints_are_minimized()) {
368  // Equivalent minimized constraint systems have:
369  // - the same number of constraints; ...
370  if (x.con_sys.num_rows() != y.con_sys.num_rows()) {
371  return Polyhedron::TVB_FALSE;
372  }
373  // - the same number of equalities; ...
374  const dimension_type x_num_equalities = x.con_sys.num_equalities();
375  if (x_num_equalities != y.con_sys.num_equalities()) {
376  return Polyhedron::TVB_FALSE;
377  }
378  // - if there are no equalities, they have the same constraints.
379  // Delay this test: try cheaper tests on generators first.
380  css_normalized = (x_num_equalities == 0);
381  }
382 
383  if (x.generators_are_minimized() && y.generators_are_minimized()) {
384  // Equivalent minimized generator systems have:
385  // - the same number of generators; ...
386  if (x.gen_sys.num_rows() != y.gen_sys.num_rows()) {
387  return Polyhedron::TVB_FALSE;
388  }
389  // - the same number of lines; ...
390  const dimension_type x_num_lines = x.gen_sys.num_lines();
391  if (x_num_lines != y.gen_sys.num_lines()) {
392  return Polyhedron::TVB_FALSE;
393  }
394  // - if there are no lines, they have the same generators.
395  if (x_num_lines == 0) {
396  // Sort the two systems and check for syntactic identity.
397  x.obtain_sorted_generators();
399  if (x.gen_sys == y.gen_sys) {
400  return Polyhedron::TVB_TRUE;
401  }
402  else {
403  return Polyhedron::TVB_FALSE;
404  }
405  }
406  }
407 
408  if (css_normalized) {
409  // Sort the two systems and check for identity.
410  x.obtain_sorted_constraints();
412  if (x.con_sys == y.con_sys) {
413  return Polyhedron::TVB_TRUE;
414  }
415  else {
416  return Polyhedron::TVB_FALSE;
417  }
418  }
419  }
420  }
422 }
423 
424 bool
426  // Private method: the caller must ensure the following.
427  PPL_ASSERT(topology() == y.topology());
428  PPL_ASSERT(space_dim == y.space_dim);
429  PPL_ASSERT(!marked_empty() && !y.marked_empty() && space_dim > 0);
430 
431  const Polyhedron& x = *this;
432 
433  // `x' cannot have pending constraints, because we need its generators.
434  if (x.has_pending_constraints() && !x.process_pending_constraints()) {
435  return true;
436  }
437  // `y' cannot have pending generators, because we need its constraints.
438  if (y.has_pending_generators()) {
440  }
441 
442 #if BE_LAZY
443  if (!x.generators_are_up_to_date() && !x.update_generators()) {
444  return true;
445  }
446  if (!y.constraints_are_up_to_date()) {
447  y.update_constraints();
448  }
449 #else
450  if (!x.generators_are_minimized()) {
451  x.minimize();
452  }
453  if (!y.constraints_are_minimized()) {
454  y.minimize();
455  }
456 #endif
457 
458  PPL_ASSERT_HEAVY(x.OK());
459  PPL_ASSERT_HEAVY(y.OK());
460 
461  const Generator_System& gs = x.gen_sys;
462  const Constraint_System& cs = y.con_sys;
463 
464  if (x.is_necessarily_closed()) {
465  // When working with necessarily closed polyhedra,
466  // `x' is contained in `y' if and only if all the generators of `x'
467  // satisfy all the inequalities and saturate all the equalities of `y'.
468  // This comes from the definition of a polyhedron as the set of
469  // vectors satisfying a constraint system and the fact that all
470  // vectors in `x' can be obtained by suitably combining its generators.
471  for (dimension_type i = cs.num_rows(); i-- > 0; ) {
472  const Constraint& c = cs[i];
473  if (c.is_inequality()) {
474  for (dimension_type j = gs.num_rows(); j-- > 0; ) {
475  const Generator& g = gs[j];
476  const int sp_sign = Scalar_Products::sign(c, g);
477  if (g.is_line()) {
478  if (sp_sign != 0) {
479  return false;
480  }
481  }
482  else {
483  // `g' is a ray or a point.
484  if (sp_sign < 0) {
485  return false;
486  }
487  }
488  }
489  }
490  else {
491  // `c' is an equality.
492  for (dimension_type j = gs.num_rows(); j-- > 0; ) {
493  if (Scalar_Products::sign(c, gs[j]) != 0) {
494  return false;
495  }
496  }
497  }
498  }
499  }
500  else {
501  // Here we have an NNC polyhedron: using the reduced scalar product,
502  // which ignores the epsilon coefficient.
503  for (dimension_type i = cs.num_rows(); i-- > 0; ) {
504  const Constraint& c = cs[i];
505  switch (c.type()) {
507  for (dimension_type j = gs.num_rows(); j-- > 0; ) {
508  const Generator& g = gs[j];
509  const int sp_sign = Scalar_Products::reduced_sign(c, g);
510  if (g.is_line()) {
511  if (sp_sign != 0) {
512  return false;
513  }
514  }
515  else {
516  // `g' is a ray or a point or a closure point.
517  if (sp_sign < 0) {
518  return false;
519  }
520  }
521  }
522  break;
524  for (dimension_type j = gs.num_rows(); j-- > 0; ) {
525  if (Scalar_Products::reduced_sign(c, gs[j]) != 0) {
526  return false;
527  }
528  }
529  break;
531  for (dimension_type j = gs.num_rows(); j-- > 0; ) {
532  const Generator& g = gs[j];
533  const int sp_sign = Scalar_Products::reduced_sign(c, g);
534  switch (g.type()) {
535  case Generator::POINT:
536  // If a point violates or saturates a strict inequality
537  // (when ignoring the epsilon coefficients) then it is
538  // not included in the polyhedron.
539  if (sp_sign <= 0) {
540  return false;
541  }
542  break;
543  case Generator::LINE:
544  // Lines have to saturate all constraints.
545  if (sp_sign != 0) {
546  return false;
547  }
548  break;
549  case Generator::RAY:
550  // Intentionally fall through.
552  // The generator is a ray or closure point: usual test.
553  if (sp_sign < 0) {
554  return false;
555  }
556  break;
557  }
558  }
559  break;
560  }
561  }
562  }
563 
564  // Inclusion holds.
565  return true;
566 }
567 
568 bool
570  const bool from_above) const {
571  // The dimension of `expr' should not be greater than the dimension
572  // of `*this'.
573  const dimension_type expr_space_dim = expr.space_dimension();
574  if (space_dim < expr_space_dim) {
575  throw_dimension_incompatible((from_above
576  ? "bounds_from_above(e)"
577  : "bounds_from_below(e)"), "e", expr);
578  }
579 
580  // A zero-dimensional or empty polyhedron bounds everything.
581  if (space_dim == 0
582  || marked_empty()
583  || (has_pending_constraints() && !process_pending_constraints())
584  || (!generators_are_up_to_date() && !update_generators())) {
585  return true;
586  }
587  // The polyhedron has updated, possibly pending generators.
588  for (dimension_type i = gen_sys.num_rows(); i-- > 0; ) {
589  const Generator& g = gen_sys[i];
590  // Only lines and rays in `*this' can cause `expr' to be unbounded.
591  if (g.is_line_or_ray()) {
592  const int sp_sign = Scalar_Products::homogeneous_sign(expr, g);
593  if (sp_sign != 0
594  && (g.is_line()
595  || (from_above && sp_sign > 0)
596  || (!from_above && sp_sign < 0))) {
597  // `*this' does not bound `expr'.
598  return false;
599  }
600  }
601  }
602  // No sources of unboundedness have been found for `expr'
603  // in the given direction.
604  return true;
605 }
606 
607 bool
609  const bool maximize,
610  Coefficient& ext_n, Coefficient& ext_d,
611  bool& included,
612  Generator& g) const {
613  // The dimension of `expr' should not be greater than the dimension
614  // of `*this'.
615  const dimension_type expr_space_dim = expr.space_dimension();
616  if (space_dim < expr_space_dim) {
617  throw_dimension_incompatible((maximize
618  ? "maximize(e, ...)"
619  : "minimize(e, ...)"), "e", expr);
620  }
621 
622  // Deal with zero-dim polyhedra first.
623  if (space_dim == 0) {
624  if (marked_empty()) {
625  return false;
626  }
627  else {
628  ext_n = expr.inhomogeneous_term();
629  ext_d = 1;
630  included = true;
631  g = point();
632  return true;
633  }
634  }
635 
636  // For an empty polyhedron we simply return false.
637  if (marked_empty()
638  || (has_pending_constraints() && !process_pending_constraints())
639  || (!generators_are_up_to_date() && !update_generators())) {
640  return false;
641  }
642 
643  // The polyhedron has updated, possibly pending generators.
644  // The following loop will iterate through the generator
645  // to find the extremum.
646  PPL_DIRTY_TEMP(mpq_class, extremum);
647 
648  // True if we have no other candidate extremum to compare with.
649  bool first_candidate = true;
650 
651  // To store the position of the current candidate extremum.
652  PPL_UNINITIALIZED(dimension_type, ext_position);
653 
654  // Whether the current candidate extremum is included or not.
655  PPL_UNINITIALIZED(bool, ext_included);
656 
658  for (dimension_type i = gen_sys.num_rows(); i-- > 0; ) {
659  const Generator& gen_sys_i = gen_sys[i];
660  Scalar_Products::homogeneous_assign(sp, expr, gen_sys_i);
661  // Lines and rays in `*this' can cause `expr' to be unbounded.
662  if (gen_sys_i.is_line_or_ray()) {
663  const int sp_sign = sgn(sp);
664  if (sp_sign != 0
665  && (gen_sys_i.is_line()
666  || (maximize && sp_sign > 0)
667  || (!maximize && sp_sign < 0))) {
668  // `expr' is unbounded in `*this'.
669  return false;
670  }
671  }
672  else {
673  // We have a point or a closure point.
674  PPL_ASSERT(gen_sys_i.is_point() || gen_sys_i.is_closure_point());
675  // Notice that we are ignoring the constant term in `expr' here.
676  // We will add it to the extremum as soon as we find it.
677  PPL_DIRTY_TEMP(mpq_class, candidate);
678  assign_r(candidate.get_num(), sp, ROUND_NOT_NEEDED);
679  assign_r(candidate.get_den(), gen_sys_i.expr.inhomogeneous_term(), ROUND_NOT_NEEDED);
680  candidate.canonicalize();
681  const bool g_is_point = gen_sys_i.is_point();
682  if (first_candidate
683  || (maximize
684  && (candidate > extremum
685  || (g_is_point
686  && !ext_included
687  && candidate == extremum)))
688  || (!maximize
689  && (candidate < extremum
690  || (g_is_point
691  && !ext_included
692  && candidate == extremum)))) {
693  // We have a (new) candidate extremum.
694  first_candidate = false;
695  extremum = candidate;
696  ext_position = i;
697  ext_included = g_is_point;
698  }
699  }
700  }
701 
702  // Add in the constant term in `expr'.
703  PPL_DIRTY_TEMP(mpz_class, n);
705  extremum += n;
706 
707  // The polyhedron is bounded in the right direction and we have
708  // computed the extremum: write the result into the caller's structures.
709  PPL_ASSERT(!first_candidate);
710  ext_n = extremum.get_num();
711  ext_d = extremum.get_den();
712  included = ext_included;
713  g = gen_sys[ext_position];
714 
715  return true;
716 }
717 
718 void
720  status.set_zero_dim_univ();
721  space_dim = 0;
722  con_sys.clear();
723  gen_sys.clear();
724 }
725 
726 void
728  status.set_empty();
729  // The polyhedron is empty: we can thus throw away everything.
730  con_sys.clear();
731  gen_sys.clear();
732  sat_c.clear();
733  sat_g.clear();
734 }
735 
736 bool
738  PPL_ASSERT(space_dim > 0 && !marked_empty());
739  PPL_ASSERT(has_pending_constraints() && !has_pending_generators());
740 
741  Polyhedron& x = const_cast<Polyhedron&>(*this);
742 
743  // Integrate the pending part of the system of constraints and minimize.
744  // We need `sat_c' up-to-date and `con_sys' sorted (together with `sat_c').
745  if (!x.sat_c_is_up_to_date()) {
747  }
748  if (!x.con_sys.is_sorted()) {
750  }
751  // We sort in place the pending constraints, erasing those constraints
752  // that also occur in the non-pending part of `con_sys'.
754  if (x.con_sys.num_pending_rows() == 0) {
755  // All pending constraints were duplicates.
757  PPL_ASSERT_HEAVY(OK(true));
758  return true;
759  }
760 
761  const bool empty = add_and_minimize(true, x.con_sys, x.gen_sys, x.sat_c);
762  PPL_ASSERT(x.con_sys.num_pending_rows() == 0);
763 
764  if (empty) {
765  x.set_empty();
766  }
767  else {
771  }
772  PPL_ASSERT_HEAVY(OK(!empty));
773  return !empty;
774 }
775 
776 void
778  PPL_ASSERT(space_dim > 0 && !marked_empty());
779  PPL_ASSERT(has_pending_generators() && !has_pending_constraints());
780 
781  Polyhedron& x = const_cast<Polyhedron&>(*this);
782 
783  // Integrate the pending part of the system of generators and minimize.
784  // We need `sat_g' up-to-date and `gen_sys' sorted (together with `sat_g').
785  if (!x.sat_g_is_up_to_date()) {
787  }
788  if (!x.gen_sys.is_sorted()) {
790  }
791  // We sort in place the pending generators, erasing those generators
792  // that also occur in the non-pending part of `gen_sys'.
794  if (x.gen_sys.num_pending_rows() == 0) {
795  // All pending generators were duplicates.
797  PPL_ASSERT_HEAVY(OK(true));
798  return;
799  }
800 
801  add_and_minimize(false, x.gen_sys, x.con_sys, x.sat_g);
802  PPL_ASSERT(x.gen_sys.num_pending_rows() == 0);
803 
807 }
808 
809 void
811  PPL_ASSERT(has_something_pending());
812 
813  Polyhedron& x = const_cast<Polyhedron&>(*this);
814 
815  // If the polyhedron has pending constraints, simply unset them.
816  if (x.has_pending_constraints()) {
817  // Integrate the pending constraints, which are possibly not sorted.
818  x.con_sys.set_sorted(false);
823  }
824  else {
825  PPL_ASSERT(x.has_pending_generators());
826  // We must process the pending generators and obtain the
827  // corresponding system of constraints.
829  }
830  PPL_ASSERT_HEAVY(OK(true));
831 }
832 
833 bool
835  PPL_ASSERT(has_something_pending());
836 
837  Polyhedron& x = const_cast<Polyhedron&>(*this);
838 
839  // If the polyhedron has pending generators, simply unset them.
840  if (x.has_pending_generators()) {
841  // Integrate the pending generators, which are possibly not sorted.
842  x.gen_sys.set_sorted(false);
847  PPL_ASSERT_HEAVY(OK(true));
848  return true;
849  }
850  else {
851  PPL_ASSERT(x.has_pending_constraints());
852  // We must integrate the pending constraints and obtain the
853  // corresponding system of generators.
854  return x.process_pending_constraints();
855  }
856 }
857 
858 void
860  PPL_ASSERT(space_dim > 0);
861  PPL_ASSERT(!marked_empty());
862  PPL_ASSERT(generators_are_up_to_date());
863  // We assume the polyhedron has no pending constraints or generators.
864  PPL_ASSERT(!has_something_pending());
865 
866  Polyhedron& x = const_cast<Polyhedron&>(*this);
867  minimize(false, x.gen_sys, x.con_sys, x.sat_c);
868  // `sat_c' is the only saturation matrix up-to-date.
871  // The system of constraints and the system of generators
872  // are minimized.
875 }
876 
877 bool
879  PPL_ASSERT(space_dim > 0);
880  PPL_ASSERT(!marked_empty());
881  PPL_ASSERT(constraints_are_up_to_date());
882  // We assume the polyhedron has no pending constraints or generators.
883  PPL_ASSERT(!has_something_pending());
884 
885  Polyhedron& x = const_cast<Polyhedron&>(*this);
886  // If the system of constraints is not consistent the
887  // polyhedron is empty.
888  const bool empty = minimize(true, x.con_sys, x.gen_sys, x.sat_g);
889  if (empty) {
890  x.set_empty();
891  }
892  else {
893  // `sat_g' is the only saturation matrix up-to-date.
896  // The system of constraints and the system of generators
897  // are minimized.
900  }
901  return !empty;
902 }
903 
904 void
906  PPL_ASSERT(constraints_are_minimized());
907  PPL_ASSERT(generators_are_minimized());
908  PPL_ASSERT(!sat_c_is_up_to_date());
909 
910  // We only consider non-pending rows.
911  const dimension_type csr = con_sys.first_pending_row();
912  const dimension_type gsr = gen_sys.first_pending_row();
913  Polyhedron& x = const_cast<Polyhedron&>(*this);
914 
915  // The columns of `sat_c' represent the constraints and
916  // its rows represent the generators: resize accordingly.
917  x.sat_c.resize(gsr, csr);
918  for (dimension_type i = gsr; i-- > 0; ) {
919  for (dimension_type j = csr; j-- > 0; ) {
920  const int sp_sign = Scalar_Products::sign(con_sys[j], gen_sys[i]);
921  // The negativity of this scalar product would mean
922  // that the generator `gen_sys[i]' violates the constraint
923  // `con_sys[j]' and it is not possible because both generators
924  // and constraints are up-to-date.
925  PPL_ASSERT(sp_sign >= 0);
926  if (sp_sign > 0) {
927  // `gen_sys[i]' satisfies (without saturate) `con_sys[j]'.
928  x.sat_c[i].set(j);
929  }
930  else {
931  // `gen_sys[i]' saturates `con_sys[j]'.
932  x.sat_c[i].clear(j);
933  }
934  }
935  }
937 }
938 
939 void
941  PPL_ASSERT(constraints_are_minimized());
942  PPL_ASSERT(generators_are_minimized());
943  PPL_ASSERT(!sat_g_is_up_to_date());
944 
945  // We only consider non-pending rows.
946  const dimension_type csr = con_sys.first_pending_row();
947  const dimension_type gsr = gen_sys.first_pending_row();
948  Polyhedron& x = const_cast<Polyhedron&>(*this);
949 
950  // The columns of `sat_g' represent generators and its
951  // rows represent the constraints: resize accordingly.
952  x.sat_g.resize(csr, gsr);
953  for (dimension_type i = csr; i-- > 0; ) {
954  for (dimension_type j = gsr; j-- > 0; ) {
955  const int sp_sign = Scalar_Products::sign(con_sys[i], gen_sys[j]);
956  // The negativity of this scalar product would mean
957  // that the generator `gen_sys[j]' violates the constraint
958  // `con_sys[i]' and it is not possible because both generators
959  // and constraints are up-to-date.
960  PPL_ASSERT(sp_sign >= 0);
961  if (sp_sign > 0) {
962  // `gen_sys[j]' satisfies (without saturate) `con_sys[i]'.
963  x.sat_g[i].set(j);
964  }
965  else {
966  // `gen_sys[j]' saturates `con_sys[i]'.
967  x.sat_g[i].clear(j);
968  }
969  }
970  }
972 }
973 
974 void
976  PPL_ASSERT(constraints_are_up_to_date());
977  // `con_sys' will be sorted up to `index_first_pending'.
978  Polyhedron& x = const_cast<Polyhedron&>(*this);
979  if (!x.con_sys.is_sorted()) {
980  if (x.sat_g_is_up_to_date()) {
981  // Sorting constraints keeping `sat_g' consistent.
983  // `sat_c' is not up-to-date anymore.
985  }
986  else if (x.sat_c_is_up_to_date()) {
987  // Using `sat_c' to obtain `sat_g', then it is like previous case.
992  }
993  else {
994  // If neither `sat_g' nor `sat_c' are up-to-date,
995  // we just sort the constraints.
996  x.con_sys.sort_rows();
997  }
998  }
999 
1000  PPL_ASSERT(con_sys.check_sorted());
1001 }
1002 
1003 void
1005  PPL_ASSERT(generators_are_up_to_date());
1006  // `gen_sys' will be sorted up to `index_first_pending'.
1007  Polyhedron& x = const_cast<Polyhedron&>(*this);
1008  if (!x.gen_sys.is_sorted()) {
1009  if (x.sat_c_is_up_to_date()) {
1010  // Sorting generators keeping 'sat_c' consistent.
1012  // `sat_g' is not up-to-date anymore.
1014  }
1015  else if (x.sat_g_is_up_to_date()) {
1016  // Obtaining `sat_c' from `sat_g' and proceeding like previous case.
1021  }
1022  else {
1023  // If neither `sat_g' nor `sat_c' are up-to-date, we just sort
1024  // the generators.
1025  x.gen_sys.sort_rows();
1026  }
1027  }
1028 
1029  PPL_ASSERT(gen_sys.check_sorted());
1030 }
1031 
1032 void
1034  PPL_ASSERT(constraints_are_up_to_date());
1035  PPL_ASSERT(constraints_are_minimized());
1036  // `con_sys' will be sorted up to `index_first_pending'.
1037  Polyhedron& x = const_cast<Polyhedron&>(*this);
1038  // At least one of the saturation matrices must be up-to-date.
1039  if (!x.sat_c_is_up_to_date() && !x.sat_g_is_up_to_date()) {
1040  x.update_sat_c();
1041  }
1042  if (x.con_sys.is_sorted()) {
1043  if (x.sat_c_is_up_to_date()) {
1044  // If constraints are already sorted and sat_c is up to
1045  // date there is nothing to do.
1046  return;
1047  }
1048  }
1049  else {
1050  if (!x.sat_g_is_up_to_date()) {
1051  // If constraints are not sorted and sat_g is not up-to-date
1052  // we obtain sat_g from sat_c (that has to be up-to-date)...
1055  }
1056  // ... and sort it together with constraints.
1058  }
1059  // Obtaining sat_c from sat_g.
1062  // Constraints are sorted now.
1063  x.con_sys.set_sorted(true);
1064 
1065  PPL_ASSERT(con_sys.check_sorted());
1066 }
1067 
1068 void
1070  PPL_ASSERT(generators_are_up_to_date());
1071  // `gen_sys' will be sorted up to `index_first_pending'.
1072  Polyhedron& x = const_cast<Polyhedron&>(*this);
1073  // At least one of the saturation matrices must be up-to-date.
1074  if (!x.sat_c_is_up_to_date() && !x.sat_g_is_up_to_date()) {
1075  x.update_sat_g();
1076  }
1077 
1078  if (x.gen_sys.is_sorted()) {
1079  if (x.sat_g_is_up_to_date()) {
1080  // If generators are already sorted and sat_g is up to
1081  // date there is nothing to do.
1082  return;
1083  }
1084  }
1085  else {
1086  if (!x.sat_c_is_up_to_date()) {
1087  // If generators are not sorted and sat_c is not up-to-date
1088  // we obtain sat_c from sat_g (that has to be up-to-date)...
1091  }
1092  // ... and sort it together with generators.
1094  }
1095  // Obtaining sat_g from sat_c.
1096  x.sat_g.transpose_assign(sat_c);
1098  // Generators are sorted now.
1099  x.gen_sys.set_sorted(true);
1100 
1101  PPL_ASSERT(gen_sys.check_sorted());
1102 }
1103 
1104 bool
1106  // 0-dim space or empty polyhedra are already minimized.
1107  if (marked_empty()) {
1108  return false;
1109  }
1110  if (space_dim == 0) {
1111  return true;
1112  }
1113 
1114  // If the polyhedron has something pending, process it.
1115  if (has_something_pending()) {
1116  const bool not_empty = process_pending();
1117  PPL_ASSERT_HEAVY(OK());
1118  return not_empty;
1119  }
1120 
1121  // Here there are no pending constraints or generators.
1122  // Is the polyhedron already minimized?
1123  if (constraints_are_minimized() && generators_are_minimized()) {
1124  return true;
1125  }
1126 
1127  // If constraints or generators are up-to-date, invoking
1128  // update_generators() or update_constraints(), respectively,
1129  // minimizes both constraints and generators.
1130  // If both are up-to-date it does not matter whether we use
1131  // update_generators() or update_constraints():
1132  // both minimize constraints and generators.
1133  if (constraints_are_up_to_date()) {
1134  // We may discover here that `*this' is empty.
1135  const bool ret = update_generators();
1136  PPL_ASSERT_HEAVY(OK());
1137  return ret;
1138  }
1139  else {
1140  PPL_ASSERT(generators_are_up_to_date());
1141  update_constraints();
1142  PPL_ASSERT_HEAVY(OK());
1143  return true;
1144  }
1145 }
1146 
1147 bool
1149  PPL_ASSERT(!is_necessarily_closed());
1150 
1151  // From the user perspective, the polyhedron will not change.
1152  Polyhedron& x = const_cast<Polyhedron&>(*this);
1153 
1154  // We need `con_sys' (weakly) minimized and `gen_sys' up-to-date.
1155  // `minimize()' will process any pending constraints or generators.
1156  if (!minimize()) {
1157  return false;
1158  }
1159  // If the polyhedron `*this' is zero-dimensional
1160  // at this point it must be a universe polyhedron.
1161  if (x.space_dim == 0) {
1162  return true;
1163  }
1164  // We also need `sat_g' up-to-date.
1165  if (!sat_g_is_up_to_date()) {
1166  PPL_ASSERT(sat_c_is_up_to_date());
1167  x.sat_g.transpose_assign(sat_c);
1168  }
1169 
1170  // These Bit_Row's will be later used as masks in order to
1171  // check saturation conditions restricted to particular subsets of
1172  // the generator system.
1173  Bit_Row sat_all_but_rays;
1174  Bit_Row sat_all_but_points;
1175  Bit_Row sat_all_but_closure_points;
1176 
1177  const dimension_type gs_rows = gen_sys.num_rows();
1178  const dimension_type n_lines = gen_sys.num_lines();
1179  for (dimension_type i = gs_rows; i-- > n_lines; ) {
1180  switch (gen_sys[i].type()) {
1181  case Generator::RAY:
1182  sat_all_but_rays.set(i);
1183  break;
1184  case Generator::POINT:
1185  sat_all_but_points.set(i);
1186  break;
1188  sat_all_but_closure_points.set(i);
1189  break;
1190  case Generator::LINE:
1191  // Found a line with index i >= n_lines !
1192  PPL_UNREACHABLE;
1193  break;
1194  }
1195  }
1196  const Bit_Row
1197  sat_lines_and_rays(sat_all_but_points, sat_all_but_closure_points);
1198  const Bit_Row
1199  sat_lines_and_closure_points(sat_all_but_rays, sat_all_but_points);
1200  const Bit_Row
1201  sat_lines(sat_lines_and_rays, sat_lines_and_closure_points);
1202 
1203  // These flags are maintained to later decide if we have to add the
1204  // eps_leq_one constraint and whether or not the constraint system
1205  // was changed.
1206  bool changed = false;
1207  bool found_eps_leq_one = false;
1208 
1209  // For all the strict inequalities in `con_sys', check for
1210  // eps-redundancy and eventually move them to the bottom part of the
1211  // system.
1212  Constraint_System& cs = x.con_sys;
1213  Bit_Matrix& sat = x.sat_g;
1214  const Variable eps_var(cs.space_dimension());
1215  // Note that cs.num_rows() is *not* constant because the calls to
1216  // cs.remove_row() decrease it.
1217  for (dimension_type i = 0; i < cs.num_rows(); ) {
1218  if (cs[i].is_strict_inequality()) {
1219  // First, check if it is saturated by no closure points
1220  Bit_Row sat_ci;
1221  sat_ci.union_assign(sat[i], sat_lines_and_closure_points);
1222  if (sat_ci == sat_lines) {
1223  // It is saturated by no closure points.
1224  if (!found_eps_leq_one) {
1225  // Check if it is the eps_leq_one constraint.
1226  const Constraint& c = cs[i];
1228  && (c.expression().inhomogeneous_term() + c.epsilon_coefficient() == 0)) {
1229  // We found the eps_leq_one constraint.
1230  found_eps_leq_one = true;
1231  // Consider next constraint.
1232  ++i;
1233  continue;
1234  }
1235  }
1236  // Here `cs[i]' is not the eps_leq_one constraint,
1237  // so it is eps-redundant.
1238  // Remove it, while keeping `sat_g' consistent.
1239  cs.remove_row(i, false);
1240  swap(sat[i], sat[cs.num_rows()]);
1241  // The constraint system is changed.
1242  changed = true;
1243  // Continue by considering next constraint,
1244  // which is already in place due to the swap.
1245  continue;
1246  }
1247  // Now we check if there exists another strict inequality
1248  // constraint having a superset of its saturators,
1249  // when disregarding points.
1250  sat_ci.union_assign(sat[i], sat_all_but_points);
1251  bool eps_redundant = false;
1252  for (dimension_type j = 0; j < cs.num_rows(); ++j) {
1253  if (i != j && cs[j].is_strict_inequality()
1254  && subset_or_equal(sat[j], sat_ci)) {
1255  // Constraint `cs[i]' is eps-redundant:
1256  // remove it, while keeping `sat_g' consistent.
1257  cs.remove_row(i, false);
1258  swap(sat[i], sat[cs.num_rows()]);
1259  eps_redundant = true;
1260  // The constraint system is changed.
1261  changed = true;
1262  break;
1263  }
1264  }
1265  // Continue with next constraint, which is already in place
1266  // due to the swap if we have found an eps-redundant constraint.
1267  if (!eps_redundant) {
1268  ++i;
1269  }
1270  }
1271  else {
1272  // `cs[i]' is not a strict inequality: consider next constraint.
1273  ++i;
1274  }
1275  }
1276 
1277  PPL_ASSERT(cs.num_pending_rows() == 0);
1278 
1279  if (changed) {
1280  // If the constraint system has been changed, we have erased
1281  // the epsilon-redundant constraints.
1282 
1283  // The generator system is no longer up-to-date.
1285 
1286  // If we haven't found an upper bound for the epsilon dimension,
1287  // then we have to check whether such an upper bound is implied
1288  // by the remaining constraints (exploiting the simplex algorithm).
1289  if (!found_eps_leq_one) {
1290  MIP_Problem lp;
1291  // KLUDGE: temporarily mark the constraint system as if it was
1292  // necessarily closed, so that we can interpret the epsilon
1293  // dimension as a standard dimension. Be careful to reset the
1294  // topology of `cs' even on exceptional execution path.
1296  try {
1298  lp.add_constraints(cs);
1300  }
1301  catch (...) {
1303  throw;
1304  }
1305  // The objective function is `epsilon'.
1308  const MIP_Problem_Status status = lp.solve();
1309  PPL_ASSERT(status != UNFEASIBLE_MIP_PROBLEM);
1310  // If the epsilon dimension is actually unbounded,
1311  // then add the eps_leq_one constraint.
1312  if (status == UNBOUNDED_MIP_PROBLEM) {
1314  }
1315  }
1316  }
1317 
1318  PPL_ASSERT_HEAVY(OK());
1319  return true;
1320 }
1321 
1322 bool
1324  PPL_ASSERT(!is_necessarily_closed());
1325 
1326  // From the user perspective, the polyhedron will not change.
1327  Polyhedron& x = const_cast<Polyhedron&>(*this);
1328 
1329  // We need `gen_sys' (weakly) minimized and `con_sys' up-to-date.
1330  // `minimize()' will process any pending constraints or generators.
1331  if (!minimize()) {
1332  return false;
1333  }
1334  // If the polyhedron `*this' is zero-dimensional
1335  // at this point it must be a universe polyhedron.
1336  if (x.space_dim == 0) {
1337  return true;
1338  }
1339 
1340  // We also need `sat_c' up-to-date.
1341  if (!sat_c_is_up_to_date()) {
1342  PPL_ASSERT(sat_g_is_up_to_date());
1343  x.sat_c.transpose_assign(sat_g);
1344  }
1345 
1346  // This Bit_Row will have all and only the indexes
1347  // of strict inequalities set to 1.
1348  Bit_Row sat_all_but_strict_ineq;
1349  const dimension_type cs_rows = con_sys.num_rows();
1350  const dimension_type n_equals = con_sys.num_equalities();
1351  for (dimension_type i = cs_rows; i-- > n_equals; ) {
1352  if (con_sys[i].is_strict_inequality()) {
1353  sat_all_but_strict_ineq.set(i);
1354  }
1355  }
1356 
1357  // Will record whether or not we changed the generator system.
1358  bool changed = false;
1359 
1360  // For all points in the generator system, check for eps-redundancy
1361  // and eventually move them to the bottom part of the system.
1362  Generator_System& gs = const_cast<Generator_System&>(gen_sys);
1363  Bit_Matrix& sat = const_cast<Bit_Matrix&>(sat_c);
1364  const dimension_type old_gs_rows = gs.num_rows();
1365  dimension_type gs_rows = old_gs_rows;
1366  const dimension_type n_lines = gs.num_lines();
1367  bool gs_sorted = gs.is_sorted();
1368 
1369  for (dimension_type i = n_lines; i < gs_rows; ) {
1370  Generator& g = gs.sys.rows[i];
1371  if (g.is_point()) {
1372  // Compute the Bit_Row corresponding to the candidate point
1373  // when strict inequality constraints are ignored.
1374  const Bit_Row sat_gs_i(sat[i], sat_all_but_strict_ineq);
1375  // Check if the candidate point is actually eps-redundant:
1376  // namely, if there exists another point that saturates
1377  // all the non-strict inequalities saturated by the candidate.
1378  bool eps_redundant = false;
1379  for (dimension_type j = n_lines; j < gs_rows; ++j) {
1380  const Generator& g2 = gs.sys.rows[j];
1381  if (i != j && g2.is_point() && subset_or_equal(sat[j], sat_gs_i)) {
1382  // Point `g' is eps-redundant:
1383  // move it to the bottom of the generator system,
1384  // while keeping `sat_c' consistent.
1385  --gs_rows;
1386  swap(g, gs.sys.rows[gs_rows]);
1387  swap(sat[i], sat[gs_rows]);
1388  eps_redundant = true;
1389  changed = true;
1390  break;
1391  }
1392  }
1393  if (!eps_redundant) {
1394  // Let all point encodings have epsilon coordinate 1.
1395  if (g.epsilon_coefficient() != g.expr.inhomogeneous_term()) {
1397  // Enforce normalization.
1398  g.expr.normalize();
1399  PPL_ASSERT(g.OK());
1400  changed = true;
1401  }
1402  // Consider next generator.
1403  ++i;
1404  }
1405  }
1406  else {
1407  // Consider next generator.
1408  ++i;
1409  }
1410  }
1411 
1412  // If needed, erase the eps-redundant generators.
1413  if (gs_rows < old_gs_rows) {
1414  gs.sys.rows.resize(gs_rows);
1415  }
1416 
1417  if (changed) {
1418  // The generator system is no longer sorted.
1419  gs_sorted = false;
1420  // The constraint system is no longer up-to-date.
1422  }
1423 
1424  gs.sys.index_first_pending = gs.num_rows();
1425  gs.set_sorted(gs_sorted);
1426 
1427  PPL_ASSERT(gs.sys.OK());
1428 
1429  PPL_ASSERT_HEAVY(OK());
1430  return true;
1431 }
1432 
1433 void
1435  PPL_ASSERT(!marked_empty());
1436  PPL_ASSERT(space_dim >= c.space_dimension());
1437 
1438  // Dealing with a zero-dimensional space polyhedron first.
1439  if (space_dim == 0) {
1440  if (c.is_inconsistent()) {
1441  set_empty();
1442  }
1443  return;
1444  }
1445 
1446  // The constraints (possibly with pending rows) are required.
1447  if (has_pending_generators()) {
1448  process_pending_generators();
1449  }
1450  else if (!constraints_are_up_to_date()) {
1451  update_constraints();
1452  }
1453 
1454  const bool adding_pending = can_have_something_pending();
1455 
1456  if (c.is_necessarily_closed() || !is_necessarily_closed()) {
1457  // Since `con_sys' is not empty, the topology and space dimension
1458  // of the inserted constraint are automatically adjusted.
1459  if (adding_pending) {
1460  con_sys.insert_pending(c);
1461  }
1462  else {
1463  con_sys.insert(c);
1464  }
1465  }
1466  else {
1467  // Here we know that the system of constraints has at least a row.
1468  // However, by barely invoking `con_sys.insert(c)' we would
1469  // cause a change in the topology of `con_sys', which is wrong.
1470  // Thus, we insert a "topology corrected" copy of `c'.
1471  const Linear_Expression nc_expr(c.expression());
1472  if (c.is_equality()) {
1473  if (adding_pending) {
1474  con_sys.insert_pending(nc_expr == 0);
1475  }
1476  else {
1477  con_sys.insert(nc_expr == 0);
1478  }
1479  }
1480  else {
1481  if (adding_pending) {
1482  con_sys.insert_pending(nc_expr >= 0);
1483  }
1484  else {
1485  con_sys.insert(nc_expr >= 0);
1486  }
1487  }
1488  }
1489 
1490  if (adding_pending) {
1491  set_constraints_pending();
1492  }
1493  else {
1494  // Constraints are not minimized and generators are not up-to-date.
1495  clear_constraints_minimized();
1496  clear_generators_up_to_date();
1497  }
1498 
1499  // Note: the constraint system may have become unsatisfiable, thus
1500  // we do not check for satisfiability.
1501  PPL_ASSERT_HEAVY(OK());
1502 }
1503 
1504 bool
1506  Polyhedron& x = *this;
1507 
1508  // Private method: the caller must ensure the following.
1509  PPL_ASSERT(x.topology() == y.topology());
1510  PPL_ASSERT(x.space_dim == y.space_dim);
1511 
1512  // The zero-dim case is trivial.
1513  if (x.space_dim == 0) {
1514  x.upper_bound_assign(y);
1515  return true;
1516  }
1517 
1518  // If `x' or `y' are (known to be) empty, the upper bound is exact.
1519  if (x.marked_empty()) {
1520  x = y;
1521  return true;
1522  }
1523  else if (y.is_empty()) {
1524  return true;
1525  }
1526  else if (x.is_empty()) {
1527  x = y;
1528  return true;
1529  }
1530 
1531  if (x.is_necessarily_closed()) {
1533  }
1534  else {
1536  }
1537 }
1538 
1539 bool
1541  Polyhedron& x = *this;
1542  // Private method: the caller must ensure the following.
1543  PPL_ASSERT(x.is_necessarily_closed() && y.is_necessarily_closed());
1544  PPL_ASSERT(x.space_dim > 0 && x.space_dim == y.space_dim);
1545  PPL_ASSERT(!x.is_empty() && !y.is_empty());
1546 
1547  // Minimization is not really required, but it is probably the best
1548  // way of getting constraints, generators and saturation matrices
1549  // up-to-date. Minimization it also removes redundant
1550  // constraints/generators.
1551  (void) x.minimize();
1552  (void) y.minimize();
1553 
1554  // Handle a special case: for topologically closed polyhedra P and Q,
1555  // if the affine dimension of P is greater than that of Q, then
1556  // their upper bound is exact if and only if P includes Q.
1557  const dimension_type x_affine_dim = x.affine_dimension();
1558  const dimension_type y_affine_dim = y.affine_dimension();
1559  if (x_affine_dim > y_affine_dim) {
1560  return y.is_included_in(x);
1561  }
1562  else if (x_affine_dim < y_affine_dim) {
1563  if (x.is_included_in(y)) {
1564  x = y;
1565  return true;
1566  }
1567  else {
1568  return false;
1569  }
1570  }
1571 
1572  const Constraint_System& x_cs = x.con_sys;
1573  const Generator_System& x_gs = x.gen_sys;
1574  const Generator_System& y_gs = y.gen_sys;
1575  const dimension_type x_gs_num_rows = x_gs.num_rows();
1576  const dimension_type y_gs_num_rows = y_gs.num_rows();
1577 
1578  // Step 1: generators of `x' that are redundant in `y', and vice versa.
1579  Bit_Row x_gs_red_in_y;
1580  dimension_type num_x_gs_red_in_y = 0;
1581  for (dimension_type i = x_gs_num_rows; i-- > 0; ) {
1583  x_gs_red_in_y.set(i);
1584  ++num_x_gs_red_in_y;
1585  }
1586  }
1587 
1588  Bit_Row y_gs_red_in_x;
1589  dimension_type num_y_gs_red_in_x = 0;
1590  for (dimension_type i = y_gs_num_rows; i-- > 0; ) {
1592  y_gs_red_in_x.set(i);
1593  ++num_y_gs_red_in_x;
1594  }
1595  }
1596  // Step 2: filter away special cases.
1597 
1598  // Step 2.1: inclusion tests.
1599  if (num_y_gs_red_in_x == y_gs_num_rows) {
1600  // `y' is included into `x': upper bound `x' is exact.
1601  return true;
1602  }
1603  if (num_x_gs_red_in_y == x_gs_num_rows) {
1604  // `x' is included into `y': upper bound `y' is exact.
1605  x = y;
1606  return true;
1607  }
1608 
1609  // Step 2.2: if no generator of `x' is redundant for `y', then
1610  // (as by 2.1 there exists a constraint of `x' non-redundant for `y')
1611  // the upper bound is not exact; the same if exchanging `x' and `y'.
1612  if (num_x_gs_red_in_y == 0 || num_y_gs_red_in_x == 0) {
1613  return false;
1614  }
1615 
1616  // Step 3: see if `x' has a non-redundant constraint `c_x' that is not
1617  // satisfied by `y' and a non-redundant generator in `y' (see Step 1)
1618  // saturating `c_x'. If so, the upper bound is not exact.
1619 
1620  // Make sure the saturation matrix for `x' is up to date.
1621  // Any sat matrix would do: we choose `sat_g' because it matches
1622  // the two nested loops (constraints on rows and generators on columns).
1623  if (!x.sat_g_is_up_to_date()) {
1624  x.update_sat_g();
1625  }
1626  const Bit_Matrix& x_sat = x.sat_g;
1627 
1628  Bit_Row all_ones;
1629  all_ones.set_until(x_gs_num_rows);
1630  Bit_Row row_union;
1631  for (dimension_type i = x_cs.num_rows(); i-- > 0; ) {
1632  const bool included
1634  if (!included) {
1635  row_union.union_assign(x_gs_red_in_y, x_sat[i]);
1636  if (row_union != all_ones) {
1637  return false;
1638  }
1639  }
1640  }
1641 
1642  // Here we know that the upper bound is exact: compute it.
1643  for (dimension_type j = y_gs_num_rows; j-- > 0; ) {
1644  if (!y_gs_red_in_x[j]) {
1645  add_generator(y_gs[j]);
1646  }
1647  }
1648 
1649  PPL_ASSERT_HEAVY(OK());
1650  return true;
1651 }
1652 
1653 bool
1655  const Polyhedron& x = *this;
1656  // Private method: the caller must ensure the following.
1657  PPL_ASSERT(!x.is_necessarily_closed() && !y.is_necessarily_closed());
1658  PPL_ASSERT(x.space_dim > 0 && x.space_dim == y.space_dim);
1659  PPL_ASSERT(!x.is_empty() && !y.is_empty());
1660 
1661  // Minimization is not really required, but it is probably the best
1662  // way of getting constraints, generators and saturation matrices
1663  // up-to-date. Minimization also removes redundant
1664  // constraints/generators.
1665  (void) x.minimize();
1666  (void) y.minimize();
1667 
1668  const Generator_System& x_gs = x.gen_sys;
1669  const Generator_System& y_gs = y.gen_sys;
1670  const dimension_type x_gs_num_rows = x_gs.num_rows();
1671  const dimension_type y_gs_num_rows = y_gs.num_rows();
1672 
1673  // Compute generators of `x' that are non-redundant in `y' ...
1674  Bit_Row x_gs_non_redundant_in_y;
1675  Bit_Row x_points_non_redundant_in_y;
1676  Bit_Row x_closure_points;
1677  dimension_type num_x_gs_non_redundant_in_y = 0;
1678  for (dimension_type i = x_gs_num_rows; i-- > 0; ) {
1679  const Generator& x_gs_i = x_gs[i];
1680  if (x_gs_i.is_closure_point()) {
1681  x_closure_points.set(i);
1682  }
1684  continue;
1685  }
1686  x_gs_non_redundant_in_y.set(i);
1687  ++num_x_gs_non_redundant_in_y;
1688  if (x_gs_i.is_point()) {
1689  x_points_non_redundant_in_y.set(i);
1690  }
1691  }
1692 
1693  // If `x' is included into `y', the upper bound `y' is exact.
1694  if (num_x_gs_non_redundant_in_y == 0) {
1695  *this = y;
1696  return true;
1697  }
1698 
1699  // ... and vice versa, generators of `y' that are non-redundant in `x'.
1700  Bit_Row y_gs_non_redundant_in_x;
1701  Bit_Row y_points_non_redundant_in_x;
1702  Bit_Row y_closure_points;
1703  dimension_type num_y_gs_non_redundant_in_x = 0;
1704  for (dimension_type i = y_gs_num_rows; i-- > 0; ) {
1705  const Generator& y_gs_i = y_gs[i];
1706  if (y_gs_i.is_closure_point()) {
1707  y_closure_points.set(i);
1708  }
1710  continue;
1711  }
1712  y_gs_non_redundant_in_x.set(i);
1713  ++num_y_gs_non_redundant_in_x;
1714  if (y_gs_i.is_point()) {
1715  y_points_non_redundant_in_x.set(i);
1716  }
1717  }
1718 
1719  // If `y' is included into `x', the upper bound `x' is exact.
1720  if (num_y_gs_non_redundant_in_x == 0) {
1721  return true;
1722  }
1723 
1724  Bit_Row x_non_points_non_redundant_in_y;
1725  x_non_points_non_redundant_in_y
1726  .difference_assign(x_gs_non_redundant_in_y,
1727  x_points_non_redundant_in_y);
1728 
1729  const Constraint_System& x_cs = x.con_sys;
1730  const Constraint_System& y_cs = y.con_sys;
1731  const dimension_type x_cs_num_rows = x_cs.num_rows();
1732  const dimension_type y_cs_num_rows = y_cs.num_rows();
1733 
1734  // Filter away the points of `x_gs' that would be redundant
1735  // in the topological closure of `y'.
1736  Bit_Row x_points_non_redundant_in_y_closure;
1737  for (dimension_type i = x_points_non_redundant_in_y.first();
1739  i = x_points_non_redundant_in_y.next(i)) {
1740  const Generator& x_p = x_gs[i];
1741  PPL_ASSERT(x_p.is_point());
1742  // NOTE: we cannot use Constraint_System::relation_with()
1743  // as we need to treat strict inequalities as if they were nonstrict.
1744  for (dimension_type j = y_cs_num_rows; j-- > 0; ) {
1745  const Constraint& y_c = y_cs[j];
1746  const int sp_sign = Scalar_Products::reduced_sign(y_c, x_p);
1747  if (sp_sign < 0 || (y_c.is_equality() && sp_sign > 0)) {
1748  x_points_non_redundant_in_y_closure.set(i);
1749  break;
1750  }
1751  }
1752  }
1753 
1754  // Make sure the saturation matrix for `x' is up to date.
1755  // Any sat matrix would do: we choose `sat_g' because it matches
1756  // the two nested loops (constraints on rows and generators on columns).
1757  if (!x.sat_g_is_up_to_date()) {
1758  x.update_sat_g();
1759  }
1760  const Bit_Matrix& x_sat = x.sat_g;
1761 
1762  Bit_Row x_cs_condition_3;
1763  Bit_Row x_gs_condition_3;
1764  Bit_Row all_ones;
1765  all_ones.set_until(x_gs_num_rows);
1766  Bit_Row saturators;
1767  Bit_Row tmp_set;
1768  for (dimension_type i = x_cs_num_rows; i-- > 0; ) {
1769  const Constraint& x_c = x_cs[i];
1770  // Skip constraint if it is not violated by `y'.
1772  continue;
1773  }
1774  saturators.difference_assign(all_ones, x_sat[i]);
1775  // Check condition 1.
1776  tmp_set.intersection_assign(x_non_points_non_redundant_in_y, saturators);
1777  if (!tmp_set.empty()) {
1778  return false;
1779  }
1780  if (x_c.is_strict_inequality()) {
1781  // Postpone check for condition 3.
1782  x_cs_condition_3.set(i);
1783  tmp_set.intersection_assign(x_closure_points, saturators);
1784  x_gs_condition_3.union_assign(x_gs_condition_3, tmp_set);
1785  }
1786  else {
1787  // Check condition 2.
1788  tmp_set.intersection_assign(x_points_non_redundant_in_y_closure,
1789  saturators);
1790  if (!tmp_set.empty()) {
1791  return false;
1792  }
1793  }
1794  }
1795 
1796  // Now exchange the roles of `x' and `y'
1797  // (the statement of the NNC theorem in BHZ09 is symmetric).
1798 
1799  Bit_Row y_non_points_non_redundant_in_x;
1800  y_non_points_non_redundant_in_x
1801  .difference_assign(y_gs_non_redundant_in_x,
1802  y_points_non_redundant_in_x);
1803 
1804  // Filter away the points of `y_gs' that would be redundant
1805  // in the topological closure of `x'.
1806  Bit_Row y_points_non_redundant_in_x_closure;
1807  for (dimension_type i = y_points_non_redundant_in_x.first();
1809  i = y_points_non_redundant_in_x.next(i)) {
1810  const Generator& y_p = y_gs[i];
1811  PPL_ASSERT(y_p.is_point());
1812  // NOTE: we cannot use Constraint_System::relation_with()
1813  // as we need to treat strict inequalities as if they were nonstrict.
1814  for (dimension_type j = x_cs_num_rows; j-- > 0; ) {
1815  const Constraint& x_c = x_cs[j];
1816  const int sp_sign = Scalar_Products::reduced_sign(x_c, y_p);
1817  if (sp_sign < 0 || (x_c.is_equality() && sp_sign > 0)) {
1818  y_points_non_redundant_in_x_closure.set(i);
1819  break;
1820  }
1821  }
1822  }
1823 
1824  // Make sure the saturation matrix `sat_g' for `y' is up to date.
1825  if (!y.sat_g_is_up_to_date()) {
1826  y.update_sat_g();
1827  }
1828  const Bit_Matrix& y_sat = y.sat_g;
1829 
1830  Bit_Row y_cs_condition_3;
1831  Bit_Row y_gs_condition_3;
1832  all_ones.clear();
1833  all_ones.set_until(y_gs_num_rows);
1834  for (dimension_type i = y_cs_num_rows; i-- > 0; ) {
1835  const Constraint& y_c = y_cs[i];
1836  // Skip constraint if it is not violated by `x'.
1838  continue;
1839  }
1840  saturators.difference_assign(all_ones, y_sat[i]);
1841  // Check condition 1.
1842  tmp_set.intersection_assign(y_non_points_non_redundant_in_x, saturators);
1843  if (!tmp_set.empty()) {
1844  return false;
1845  }
1846  if (y_c.is_strict_inequality()) {
1847  // Postpone check for condition 3.
1848  y_cs_condition_3.set(i);
1849  tmp_set.intersection_assign(y_closure_points, saturators);
1850  y_gs_condition_3.union_assign(y_gs_condition_3, tmp_set);
1851  }
1852  else {
1853  // Check condition 2.
1854  tmp_set.intersection_assign(y_points_non_redundant_in_x_closure,
1855  saturators);
1856  if (!tmp_set.empty()) {
1857  return false;
1858  }
1859  }
1860  }
1861 
1862  // Now considering condition 3.
1863 
1864  if (x_cs_condition_3.empty() && y_cs_condition_3.empty()) {
1865  // No test for condition 3 is needed.
1866  // The hull is exact: compute it.
1867  for (dimension_type j = y_gs_num_rows; j-- > 0; ) {
1868  if (y_gs_non_redundant_in_x[j]) {
1869  add_generator(y_gs[j]);
1870  }
1871  }
1872  return true;
1873  }
1874 
1875  // We have anyway to compute the upper bound and its constraints too.
1876  Polyhedron ub(x);
1877  for (dimension_type j = y_gs_num_rows; j-- > 0; ) {
1878  if (y_gs_non_redundant_in_x[j]) {
1879  ub.add_generator(y_gs[j]);
1880  }
1881  }
1882  (void) ub.minimize();
1883  PPL_ASSERT(!ub.is_empty());
1884 
1885  // NOTE: the following computation of x_gs_condition_3_not_in_y
1886  // (resp., y_gs_condition_3_not_in_x) is not required for correctness.
1887  // It is done so as to later apply a speculative test
1888  // (i.e., a non-conclusive but computationally lighter test).
1889 
1890  // Filter away from `x_gs_condition_3' those closure points
1891  // that, when considered as points, would belong to `y',
1892  // i.e., those that violate no strict constraint in `y_cs'.
1893  Bit_Row x_gs_condition_3_not_in_y;
1894  for (dimension_type i = y_cs_num_rows; i-- > 0; ) {
1895  const Constraint& y_c = y_cs[i];
1896  if (y_c.is_strict_inequality()) {
1897  for (dimension_type j = x_gs_condition_3.first();
1898  j != C_Integer<unsigned long>::max; j = x_gs_condition_3.next(j)) {
1899  const Generator& x_cp = x_gs[j];
1900  PPL_ASSERT(x_cp.is_closure_point());
1901  const int sp_sign = Scalar_Products::reduced_sign(y_c, x_cp);
1902  PPL_ASSERT(sp_sign >= 0);
1903  if (sp_sign == 0) {
1904  x_gs_condition_3.clear(j);
1905  x_gs_condition_3_not_in_y.set(j);
1906  }
1907  }
1908  if (x_gs_condition_3.empty()) {
1909  break;
1910  }
1911  }
1912  }
1913  // Symmetrically, filter away from `y_gs_condition_3' those
1914  // closure points that, when considered as points, would belong to `x',
1915  // i.e., those that violate no strict constraint in `x_cs'.
1916  Bit_Row y_gs_condition_3_not_in_x;
1917  for (dimension_type i = x_cs_num_rows; i-- > 0; ) {
1918  if (x_cs[i].is_strict_inequality()) {
1919  const Constraint& x_c = x_cs[i];
1920  for (dimension_type j = y_gs_condition_3.first();
1921  j != C_Integer<unsigned long>::max; j = y_gs_condition_3.next(j)) {
1922  const Generator& y_cp = y_gs[j];
1923  PPL_ASSERT(y_cp.is_closure_point());
1924  const int sp_sign = Scalar_Products::reduced_sign(x_c, y_cp);
1925  PPL_ASSERT(sp_sign >= 0);
1926  if (sp_sign == 0) {
1927  y_gs_condition_3.clear(j);
1928  y_gs_condition_3_not_in_x.set(j);
1929  }
1930  }
1931  if (y_gs_condition_3.empty()) {
1932  break;
1933  }
1934  }
1935  }
1936 
1937  // NOTE: here we apply the speculative test.
1938  // Check if there exists a closure point in `x_gs_condition_3_not_in_y'
1939  // or `y_gs_condition_3_not_in_x' that belongs (as point) to the hull.
1940  // If so, the hull is not exact.
1941  const Constraint_System& ub_cs = ub.constraints();
1942  for (dimension_type i = ub_cs.num_rows(); i-- > 0; ) {
1943  if (ub_cs[i].is_strict_inequality()) {
1944  const Constraint& ub_c = ub_cs[i];
1945  for (dimension_type j = x_gs_condition_3_not_in_y.first();
1947  j = x_gs_condition_3_not_in_y.next(j)) {
1948  const Generator& x_cp = x_gs[j];
1949  PPL_ASSERT(x_cp.is_closure_point());
1950  const int sp_sign = Scalar_Products::reduced_sign(ub_c, x_cp);
1951  PPL_ASSERT(sp_sign >= 0);
1952  if (sp_sign == 0) {
1953  x_gs_condition_3_not_in_y.clear(j);
1954  }
1955  }
1956  for (dimension_type j = y_gs_condition_3_not_in_x.first();
1958  j = y_gs_condition_3_not_in_x.next(j)) {
1959  const Generator& y_cp = y_gs[j];
1960  PPL_ASSERT(y_cp.is_closure_point());
1961  const int sp_sign = Scalar_Products::reduced_sign(ub_c, y_cp);
1962  PPL_ASSERT(sp_sign >= 0);
1963  if (sp_sign == 0) {
1964  y_gs_condition_3_not_in_x.clear(j);
1965  }
1966  }
1967  }
1968  }
1969 
1970  if (!(x_gs_condition_3_not_in_y.empty()
1971  && y_gs_condition_3_not_in_x.empty())) {
1972  // There exist a closure point satisfying condition 3,
1973  // hence the hull is not exact.
1974  return false;
1975  }
1976  // The speculative test was not successful:
1977  // apply the expensive (but conclusive) test for condition 3.
1978 
1979  // Consider strict inequalities in `x' violated by `y'.
1980  for (dimension_type i = x_cs_condition_3.first();
1981  i != C_Integer<unsigned long>::max; i = x_cs_condition_3.next(i)) {
1982  const Constraint& x_cs_i = x_cs[i];
1983  PPL_ASSERT(x_cs_i.is_strict_inequality());
1984  // Build the equality constraint induced by x_cs_i.
1985  const Linear_Expression expr(x_cs_i.expression());
1986  const Constraint eq_i(expr == 0);
1987  PPL_ASSERT(!(ub.relation_with(eq_i)
1989  Polyhedron ub_inters_hyperplane(ub);
1990  ub_inters_hyperplane.add_constraint(eq_i);
1991  Polyhedron y_inters_hyperplane(y);
1992  y_inters_hyperplane.add_constraint(eq_i);
1993  if (!y_inters_hyperplane.contains(ub_inters_hyperplane)) {
1994  // The hull is not exact.
1995  return false;
1996  }
1997  }
1998 
1999  // Consider strict inequalities in `y' violated by `x'.
2000  for (dimension_type i = y_cs_condition_3.first();
2001  i != C_Integer<unsigned long>::max; i = y_cs_condition_3.next(i)) {
2002  const Constraint& y_cs_i = y_cs[i];
2003  PPL_ASSERT(y_cs_i.is_strict_inequality());
2004  // Build the equality constraint induced by y_cs_i.
2005  const Constraint eq_i(Linear_Expression(y_cs_i.expression()) == 0);
2006  PPL_ASSERT(!(ub.relation_with(eq_i)
2008  Polyhedron ub_inters_hyperplane(ub);
2009  ub_inters_hyperplane.add_constraint(eq_i);
2010  Polyhedron x_inters_hyperplane(x);
2011  x_inters_hyperplane.add_constraint(eq_i);
2012  if (!x_inters_hyperplane.contains(ub_inters_hyperplane)) {
2013  // The hull is not exact.
2014  return false;
2015  }
2016  }
2017 
2018  // The hull is exact.
2019  m_swap(ub);
2020  return true;
2021 }
2022 
2023 bool
2025  // Declare a const reference to *this (to avoid accidental modifications).
2026  const Polyhedron& x = *this;
2027  // Private method: the caller must ensure the following.
2028  PPL_ASSERT(x.is_necessarily_closed());
2029  PPL_ASSERT(x.topology() == y.topology());
2030  PPL_ASSERT(x.space_dim == y.space_dim);
2031 
2032  // The zero-dim case is trivial.
2033  if (x.space_dim == 0) {
2034  upper_bound_assign(y);
2035  return true;
2036  }
2037  // If `x' or `y' is (known to be) empty, the convex union is exact.
2038  if (x.marked_empty()) {
2039  *this = y;
2040  return true;
2041  }
2042  else if (y.is_empty()) {
2043  return true;
2044  }
2045  else if (x.is_empty()) {
2046  *this = y;
2047  return true;
2048  }
2049 
2050  // Here both `x' and `y' are known to be non-empty.
2051 
2052  // Implementation based on Algorithm 8.1 (page 15) in [BemporadFT00TR],
2053  // generalized so as to also allow for unbounded polyhedra.
2054  // The extension to unbounded polyhedra is obtained by mimicking
2055  // what done in Algorithm 8.2 (page 19) with respect to
2056  // Algorithm 6.2 (page 13).
2057  // We also apply a couple of improvements (see steps 2.1, 3.1, 6.1, 7.1)
2058  // so as to quickly handle special cases and avoid the splitting
2059  // of equalities/lines into pairs of inequalities/rays.
2060 
2061  (void) x.minimize();
2062  (void) y.minimize();
2063  const Constraint_System& x_cs = x.con_sys;
2064  const Constraint_System& y_cs = y.con_sys;
2065  const Generator_System& x_gs = x.gen_sys;
2066  const Generator_System& y_gs = y.gen_sys;
2067  const dimension_type x_gs_num_rows = x_gs.num_rows();
2068  const dimension_type y_gs_num_rows = y_gs.num_rows();
2069 
2070  // Step 1: generators of `x' that are redundant in `y', and vice versa.
2071  std::vector<bool> x_gs_red_in_y(x_gs_num_rows, false);
2072  dimension_type num_x_gs_red_in_y = 0;
2073  for (dimension_type i = x_gs_num_rows; i-- > 0; ) {
2075  x_gs_red_in_y[i] = true;
2076  ++num_x_gs_red_in_y;
2077  }
2078  }
2079  std::vector<bool> y_gs_red_in_x(y_gs_num_rows, false);
2080  dimension_type num_y_gs_red_in_x = 0;
2081  for (dimension_type i = y_gs_num_rows; i-- > 0; ) {
2083  y_gs_red_in_x[i] = true;
2084  ++num_y_gs_red_in_x;
2085  }
2086  }
2087 
2088  // Step 2: if no redundant generator has been identified,
2089  // then the union is not convex. CHECKME: why?
2090  if (num_x_gs_red_in_y == 0 && num_y_gs_red_in_x == 0) {
2091  return false;
2092  }
2093 
2094  // Step 2.1: while at it, also perform quick inclusion tests.
2095  if (num_y_gs_red_in_x == y_gs_num_rows) {
2096  // `y' is included into `x': union is convex.
2097  return true;
2098  }
2099  if (num_x_gs_red_in_y == x_gs_num_rows) {
2100  // `x' is included into `y': union is convex.
2101  *this = y;
2102  return true;
2103  }
2104 
2105  // Here we know that `x' is not included in `y', and vice versa.
2106 
2107  // Step 3: constraints of `x' that are satisfied by `y', and vice versa.
2108  const dimension_type x_cs_num_rows = x_cs.num_rows();
2109  std::vector<bool> x_cs_red_in_y(x_cs_num_rows, false);
2110  for (dimension_type i = x_cs_num_rows; i-- > 0; ) {
2111  const Constraint& x_cs_i = x_cs[i];
2113  x_cs_red_in_y[i] = true;
2114  }
2115  else if (x_cs_i.is_equality()) {
2116  // Step 3.1: `x' has an equality not satisfied by `y':
2117  // union is not convex (recall that `y' does not contain `x').
2118  // NOTE: this would be false for NNC polyhedra.
2119  // Example: x = { A == 0 }, y = { 0 < A <= 1 }.
2120  return false;
2121  }
2122  }
2123  const dimension_type y_cs_num_rows = y_cs.num_rows();
2124  std::vector<bool> y_cs_red_in_x(y_cs_num_rows, false);
2125  for (dimension_type i = y_cs_num_rows; i-- > 0; ) {
2126  const Constraint& y_cs_i = y_cs[i];
2128  y_cs_red_in_x[i] = true;
2129  }
2130  else if (y_cs_i.is_equality()) {
2131  // Step 3.1: `y' has an equality not satisfied by `x':
2132  // union is not convex (see explanation above).
2133  return false;
2134  }
2135  }
2136 
2137  // Loop in steps 5-9: for each pair of non-redundant generators,
2138  // compute their "mid-point" and check if it is both in `x' and `y'.
2139 
2140  // Note: reasoning at the polyhedral cone level.
2141  Generator mid_g;
2142 
2143  for (dimension_type i = x_gs_num_rows; i-- > 0; ) {
2144  if (x_gs_red_in_y[i]) {
2145  continue;
2146  }
2147  const Generator& x_g = x_gs[i];
2148  const bool x_g_is_line = x_g.is_line_or_equality();
2149  for (dimension_type j = y_gs_num_rows; j-- > 0; ) {
2150  if (y_gs_red_in_x[j]) {
2151  continue;
2152  }
2153  const Generator& y_g = y_gs[j];
2154  const bool y_g_is_line = y_g.is_line_or_equality();
2155 
2156  // Step 6: compute mid_g = x_g + y_g.
2157  // NOTE: no need to actually compute the "mid-point",
2158  // since any strictly positive combination would do.
2159  mid_g = x_g;
2160  mid_g.expr += y_g.expr;
2161  // A zero ray is not a well formed generator.
2162  const bool illegal_ray
2163  = (mid_g.expr.inhomogeneous_term() == 0 && mid_g.expr.all_homogeneous_terms_are_zero());
2164  // A zero ray cannot be generated from a line: this holds
2165  // because x_row (resp., y_row) is not subsumed by y (resp., x).
2166  PPL_ASSERT(!(illegal_ray && (x_g_is_line || y_g_is_line)));
2167  if (illegal_ray) {
2168  continue;
2169  }
2170  mid_g.expr.normalize();
2171  if (x_g_is_line) {
2172  if (y_g_is_line) {
2173  // mid_row is a line too: sign normalization is needed.
2174  mid_g.sign_normalize();
2175  }
2176  else {
2177  // mid_row is a ray/point.
2179  }
2180  }
2181  PPL_ASSERT(mid_g.OK());
2182 
2183  // Step 7: check if mid_g is in the union of x and y.
2184  if (x.relation_with(mid_g) == Poly_Gen_Relation::nothing()
2185  && y.relation_with(mid_g) == Poly_Gen_Relation::nothing()) {
2186  return false;
2187  }
2188  // If either x_g or y_g is a line, we should use its
2189  // negation to produce another generator to be tested too.
2190  // NOTE: exclusive-or is meant.
2191  if (!x_g_is_line && y_g_is_line) {
2192  // Step 6.1: (re-)compute mid_row = x_g - y_g.
2193  mid_g = x_g;
2194  mid_g.expr -= y_g.expr;
2195  mid_g.expr.normalize();
2196  PPL_ASSERT(mid_g.OK());
2197  // Step 7.1: check if mid_g is in the union of x and y.
2198  if (x.relation_with(mid_g) == Poly_Gen_Relation::nothing()
2199  && y.relation_with(mid_g) == Poly_Gen_Relation::nothing()) {
2200  return false;
2201  }
2202  }
2203  else if (x_g_is_line && !y_g_is_line) {
2204  // Step 6.1: (re-)compute mid_row = - x_row + y_row.
2205  mid_g = y_g;
2206  mid_g.expr -= x_g.expr;
2207  mid_g.expr.normalize();
2208  PPL_ASSERT(mid_g.OK());
2209  // Step 7.1: check if mid_g is in the union of x and y.
2210  if (x.relation_with(mid_g) == Poly_Gen_Relation::nothing()
2211  && y.relation_with(mid_g) == Poly_Gen_Relation::nothing()) {
2212  return false;
2213  }
2214  }
2215  }
2216  }
2217 
2218  // Here we know that the union of x and y is convex.
2219  // TODO: exploit knowledge on the cardinality of non-redundant
2220  // constraints/generators to improve the convex-hull computation.
2221  // Using generators allows for exploiting incrementality.
2222  for (dimension_type j = 0; j < y_gs_num_rows; ++j) {
2223  if (!y_gs_red_in_x[j]) {
2224  add_generator(y_gs[j]);
2225  }
2226  }
2227  PPL_ASSERT_HEAVY(OK());
2228  return true;
2229 }
2230 
2231 void
2233  Complexity_Class complexity) {
2234  // There is nothing to do for an empty set of variables.
2235  if (vars_p != 0 && vars_p->empty()) {
2236  return;
2237  }
2238 
2239  // Any empty polyhedron does not contain integer points.
2240  if (marked_empty()) {
2241  return;
2242  }
2243 
2244  // A zero-dimensional, universe polyhedron has, by convention, an
2245  // integer point.
2246  if (space_dim == 0) {
2247  set_empty();
2248  return;
2249  }
2250 
2251  // The constraints (possibly with pending rows) are required.
2252  if (has_pending_generators()) {
2253  // Processing of pending generators is exponential in the worst case.
2254  if (complexity != ANY_COMPLEXITY) {
2255  return;
2256  }
2257  else {
2258  process_pending_generators();
2259  }
2260  }
2261  if (!constraints_are_up_to_date()) {
2262  // Constraints update is exponential in the worst case.
2263  if (complexity != ANY_COMPLEXITY) {
2264  return;
2265  }
2266  else {
2267  update_constraints();
2268  }
2269  }
2270  // For NNC polyhedra we need to process any pending constraints.
2271  if (!is_necessarily_closed() && has_pending_constraints()) {
2272  if (complexity != ANY_COMPLEXITY) {
2273  return;
2274  }
2275  else if (!process_pending_constraints()) {
2276  // We just discovered the polyhedron is empty.
2277  return;
2278  }
2279  }
2280 
2281  PPL_ASSERT(!has_pending_generators() && constraints_are_up_to_date());
2282  PPL_ASSERT(is_necessarily_closed() || !has_pending_constraints());
2283 
2284  bool changed = false;
2286 
2287  const bool con_sys_was_sorted = con_sys.is_sorted();
2288 
2289  Variables_Set other_vars;
2290  if (vars_p != 0) {
2291  // Compute the complement of `*vars_p'.
2292  for (dimension_type i = 0; i < space_dim; ++i) {
2293  if (vars_p->find(i) == vars_p->end()) {
2294  other_vars.insert(Variable(i));
2295  }
2296  }
2297  }
2298 
2299  for (dimension_type j = con_sys.sys.rows.size(); j-- > 0; ) {
2300  Constraint& c = con_sys.sys.rows[j];
2301  if (c.is_tautological()) {
2302  continue;
2303  }
2304  if (!other_vars.empty()) {
2305  // Skip constraints having a nonzero coefficient for a variable
2306  // that does not occurr in the input set.
2307  if (!c.expression().all_zeroes(other_vars)) {
2308  continue;
2309  }
2310  }
2311 
2312  if (!is_necessarily_closed()) {
2313  // Transform all strict inequalities into non-strict ones,
2314  // with the inhomogeneous term incremented by 1.
2315  if (c.epsilon_coefficient() < 0) {
2317  Linear_Expression& e = c.expr;
2319  // Enforce normalization.
2320  // FIXME: is this really necessary?
2321  e.normalize();
2322  PPL_ASSERT(c.OK());
2323  changed = true;
2324  }
2325  }
2326 
2327  // Compute the GCD of all the homogeneous terms.
2328  gcd = c.expression().gcd(1, space_dim + 1);
2329 
2330  if (gcd != 0 && gcd != 1) {
2331  PPL_ASSERT(c.expr.inhomogeneous_term() % gcd != 0);
2332 
2333  // If we have an equality, the polyhedron becomes empty.
2334  if (c.is_equality()) {
2335  set_empty();
2336  return;
2337  }
2338 
2339  // Divide the inhomogeneous coefficients by the GCD.
2340  c.expr.exact_div_assign(gcd, 1, space_dim + 1);
2341 
2343  c_0 = c.expr.inhomogeneous_term();
2344  const int c_0_sign = sgn(c_0);
2345  c_0 /= gcd;
2346  if (c_0_sign < 0) {
2347  --c_0;
2348  }
2350  PPL_ASSERT(c.OK());
2351  changed = true;
2352  }
2353  }
2354 
2355  con_sys.set_sorted(!changed && con_sys_was_sorted);
2356  PPL_ASSERT(con_sys.sys.OK());
2357 
2358  if (changed) {
2359  if (is_necessarily_closed()) {
2360  con_sys.insert(Constraint::zero_dim_positivity());
2361  }
2362  else {
2363  con_sys.insert(Constraint::epsilon_leq_one());
2364  }
2365  // After changing the system of constraints, the generators
2366  // are no longer up-to-date and the constraints are no longer
2367  // minimized.
2368  clear_generators_up_to_date();
2369  clear_constraints_minimized();
2370  }
2371  PPL_ASSERT_HEAVY(OK());
2372 }
2373 
2374 void
2376  // Private method: the caller must ensure the following.
2377  PPL_ASSERT(!is_necessarily_closed());
2378 
2379  Polyhedron& x = *this;
2380  // Dimension-compatibility checks.
2381  if (x.space_dim != y.space_dim) {
2382  throw_dimension_incompatible("positive_time_elapse_assign(y)", "y", y);
2383  }
2384 
2385  // Dealing with the zero-dimensional case.
2386  if (x.space_dim == 0) {
2387  if (y.marked_empty()) {
2388  x.set_empty();
2389  }
2390  return;
2391  }
2392 
2393  // If either one of `x' or `y' is empty, the result is empty too.
2394  if (x.marked_empty() || y.marked_empty()
2398  || (!y.generators_are_up_to_date() && !y.update_generators())) {
2399  x.set_empty();
2400  return;
2401  }
2402 
2403  // At this point both generator systems are up-to-date,
2404  // possibly containing pending generators.
2405 
2406  // The new system of generators that will replace the one of x.
2407  Generator_System new_gs(x.gen_sys);
2408  dimension_type num_rows = new_gs.num_rows();
2409 
2410  // We are going to do all sorts of funny things with new_gs, so we better
2411  // mark it unsorted.
2412  // Note: `sorted' is an attribute of Linear_System, encapsulated by
2413  // Generator_System; hence, the following is equivalent to
2414  // new_gs.set_sorted(false).
2415  new_gs.sys.set_sorted(false);
2416 
2417  // Remove all points from new_gs and put them in 'x_points_gs' for later use.
2418  // Notice that we do not remove the corresponding closure points.
2419  Generator_System x_points_gs;
2420  for (dimension_type i = num_rows; i-- > 0;) {
2421  Generator &g = new_gs.sys.rows[i];
2422  if (g.is_point()) {
2423  x_points_gs.insert(g);
2424  --num_rows;
2425  swap(g, new_gs.sys.rows[num_rows]);
2426  }
2427  }
2428  new_gs.sys.rows.resize(num_rows);
2429 
2430  // When there are no pending rows, the pending row index points at
2431  // the smallest non-valid row, i.e., it is equal to the number of rows.
2432  // Hence, each time the system is manually resized, the pending row index
2433  // must be updated.
2434  new_gs.unset_pending_rows();
2435  PPL_ASSERT(new_gs.sys.OK());
2436 
2437  // We use a pointer in order to avoid copying the generator
2438  // system when it is not necessary, i.e., when y is an NNC.
2439  const Generator_System *gs = &y.gen_sys;
2440  Generator_System y_gs;
2441 
2442  // If y is closed, promote its generator system to not necessarily closed.
2443  if (y.is_necessarily_closed()) {
2444  y_gs = y.gen_sys;
2447  gs = &y_gs;
2448  }
2449 
2450  PPL_ASSERT(gs->OK());
2451 
2452  const dimension_type gs_num_rows = gs->num_rows();
2453 
2454  // For each generator g of y...
2455  for (dimension_type i = gs_num_rows; i-- > 0; ) {
2456  const Generator &g = gs->sys.rows[i];
2457 
2458  switch (g.type()) {
2459  case Generator::POINT:
2460  // In principle, points should be added to new_gs as rays.
2461  // However, for each point there is a corresponding closure point in "gs".
2462  // Hence, we leave this operation to closure points.
2463 
2464  // Insert into new_gs the sum of g and each point of x.
2465  // For each original point gx of x...
2466  for (dimension_type j = x_points_gs.sys.num_rows(); j-- > 0; ) {
2467  const Generator &gx = x_points_gs.sys.rows[j];
2468  PPL_ASSERT(gx.is_point());
2469  // ...insert the point obtained as the sum of g and gx.
2470  Generator new_g = g; // make a copy
2471  Coefficient new_divisor = g.expr.inhomogeneous_term() * gx.expr.inhomogeneous_term();
2472 
2473  new_g.expr.linear_combine(gx.expr, gx.expr.inhomogeneous_term(), g.expr.inhomogeneous_term());
2474  new_g.expr.set_inhomogeneous_term(new_divisor);
2475  if (new_g.is_not_necessarily_closed()) {
2476  new_g.set_epsilon_coefficient(g.epsilon_coefficient());
2477  }
2478  new_g.expr.normalize();
2479  PPL_ASSERT(new_g.OK());
2480  new_gs.insert(new_g);
2481  }
2482  break;
2484  // If g is not the origin, insert g into new_gs, as a ray.
2486  // Turn a copy of g into a ray.
2487  Generator g_as_a_ray = g;
2488  g_as_a_ray.expr.set_inhomogeneous_term(0);
2489  g_as_a_ray.expr.normalize();
2490  PPL_ASSERT(g_as_a_ray.OK());
2491  // Insert the ray.
2492  new_gs.insert(g_as_a_ray);
2493  }
2494  break;
2495  case Generator::RAY:
2496  case Generator::LINE:
2497  // Insert g into new_gs.
2498  new_gs.insert(g);
2499  break;
2500  }
2501  }
2503  // Notice: add_corresponding_closure_points adds them as pending.
2504  new_gs.unset_pending_rows();
2505 
2506  //Polyhedron new_x(...,new_gs);
2507  //swap(x,new_x);
2508 
2509  PPL_ASSERT(new_gs.sys.OK());
2510 
2511  // Stealing the rows from `new_gs'.
2512  using std::swap;
2513  swap(gen_sys, new_gs);
2514 
2515  gen_sys.set_sorted(false);
2516  clear_generators_minimized();
2517  // Generators are now up-to-date.
2518  set_generators_up_to_date();
2519  // Constraints are not up-to-date.
2520  clear_constraints_up_to_date();
2521 
2522  PPL_ASSERT_HEAVY(x.OK(true) && y.OK(true));
2523 }
2524 
2525 void
2527  const char* reason) const {
2528  std::ostringstream s;
2529  s << "PPL::";
2530  if (is_necessarily_closed()) {
2531  s << "C_";
2532  }
2533  else {
2534  s << "NNC_";
2535  }
2536  s << "Polyhedron::" << method << ":" << std::endl
2537  << reason << ".";
2538  throw std::invalid_argument(s.str());
2539 }
2540 
2541 void
2543  const char* ph_name,
2544  const Polyhedron& ph) const {
2545  std::ostringstream s;
2546  s << "PPL::";
2547  if (is_necessarily_closed()) {
2548  s << "C_";
2549  }
2550  else {
2551  s << "NNC_";
2552  }
2553  s << "Polyhedron::" << method << ":" << std::endl
2554  << ph_name << " is a ";
2555  if (ph.is_necessarily_closed()) {
2556  s << "C_";
2557  }
2558  else {
2559  s << "NNC_";
2560  }
2561  s << "Polyhedron." << std::endl;
2562  throw std::invalid_argument(s.str());
2563 }
2564 
2565 void
2567  const char* c_name,
2568  const Constraint&) const {
2569  PPL_ASSERT(is_necessarily_closed());
2570  std::ostringstream s;
2571  s << "PPL::C_Polyhedron::" << method << ":" << std::endl
2572  << c_name << " is a strict inequality.";
2573  throw std::invalid_argument(s.str());
2574 }
2575 
2576 void
2578  const char* g_name,
2579  const Generator&) const {
2580  PPL_ASSERT(is_necessarily_closed());
2581  std::ostringstream s;
2582  s << "PPL::C_Polyhedron::" << method << ":" << std::endl
2583  << g_name << " is a closure point.";
2584  throw std::invalid_argument(s.str());
2585 }
2586 
2587 void
2589  const char* cs_name,
2590  const Constraint_System&) const {
2591  PPL_ASSERT(is_necessarily_closed());
2592  std::ostringstream s;
2593  s << "PPL::C_Polyhedron::" << method << ":" << std::endl
2594  << cs_name << " contains strict inequalities.";
2595  throw std::invalid_argument(s.str());
2596 }
2597 
2598 void
2600  const char* gs_name,
2601  const Generator_System&) const {
2602  std::ostringstream s;
2603  s << "PPL::C_Polyhedron::" << method << ":" << std::endl
2604  << gs_name << " contains closure points.";
2605  throw std::invalid_argument(s.str());
2606 }
2607 
2608 void
2610  const char* other_name,
2611  dimension_type other_dim) const {
2612  std::ostringstream s;
2613  s << "PPL::"
2614  << (is_necessarily_closed() ? "C_" : "NNC_")
2615  << "Polyhedron::" << method << ":\n"
2616  << "this->space_dimension() == " << space_dimension() << ", "
2617  << other_name << ".space_dimension() == " << other_dim << ".";
2618  throw std::invalid_argument(s.str());
2619 }
2620 
2621 void
2623  const char* ph_name,
2624  const Polyhedron& ph) const {
2625  throw_dimension_incompatible(method, ph_name, ph.space_dimension());
2626 }
2627 
2628 void
2631  const char* le_name,
2632  const Linear_Expression& le) const {
2633  throw_dimension_incompatible(method, le_name, le.space_dimension());
2634 }
2635 
2636 void
2638  const char* c_name,
2639  const Constraint& c) const {
2640  throw_dimension_incompatible(method, c_name, c.space_dimension());
2641 }
2642 
2643 void
2645  const char* g_name,
2646  const Generator& g) const {
2647  throw_dimension_incompatible(method, g_name, g.space_dimension());
2648 }
2649 
2650 void
2652  const char* cg_name,
2653  const Congruence& cg) const {
2654  throw_dimension_incompatible(method, cg_name, cg.space_dimension());
2655 }
2656 
2657 void
2659  const char* cs_name,
2660  const Constraint_System& cs) const {
2661  throw_dimension_incompatible(method, cs_name, cs.space_dimension());
2662 }
2663 
2664 void
2667  const char* gs_name,
2668  const Generator_System& gs) const {
2669  throw_dimension_incompatible(method, gs_name, gs.space_dimension());
2670 }
2671 
2672 void
2675  const char* cgs_name,
2676  const Congruence_System& cgs) const {
2677  throw_dimension_incompatible(method, cgs_name, cgs.space_dimension());
2678 }
2679 
2680 void
2682  const char* var_name,
2683  const Variable var) const {
2684  std::ostringstream s;
2685  s << "PPL::";
2686  if (is_necessarily_closed()) {
2687  s << "C_";
2688  }
2689  else {
2690  s << "NNC_";
2691  }
2692  s << "Polyhedron::" << method << ":" << std::endl
2693  << "this->space_dimension() == " << space_dimension() << ", "
2694  << var_name << ".space_dimension() == " << var.space_dimension() << ".";
2695  throw std::invalid_argument(s.str());
2696 }
2697 
2698 void
2700 throw_dimension_incompatible(const char* method,
2701  dimension_type required_space_dim) const {
2702  std::ostringstream s;
2703  s << "PPL::";
2704  if (is_necessarily_closed()) {
2705  s << "C_";
2706  }
2707  else {
2708  s << "NNC_";
2709  }
2710  s << "Polyhedron::" << method << ":" << std::endl
2711  << "this->space_dimension() == " << space_dimension()
2712  << ", required space dimension == " << required_space_dim << ".";
2713  throw std::invalid_argument(s.str());
2714 }
2715 
2718  const dimension_type max,
2719  const Topology topol,
2720  const char* method,
2721  const char* reason) {
2722  const char* const domain = (topol == NECESSARILY_CLOSED)
2723  ? "PPL::C_Polyhedron::" : "PPL::NNC_Polyhedron::";
2724  return PPL::check_space_dimension_overflow(dim, max, domain, method, reason);
2725 }
2726 
2729  const Topology topol,
2730  const char* method,
2731  const char* reason) {
2733  topol, method, reason);
2734 }
2735 
2736 void
2738  const char* g_name) const {
2739  std::ostringstream s;
2740  s << "PPL::";
2741  if (is_necessarily_closed()) {
2742  s << "C_";
2743  }
2744  else {
2745  s << "NNC_";
2746  }
2747  s << "Polyhedron::" << method << ":" << std::endl
2748  << "*this is an empty polyhedron and "
2749  << g_name << " is not a point.";
2750  throw std::invalid_argument(s.str());
2751 }
2752 
2753 void
2755  const char* gs_name) const {
2756  std::ostringstream s;
2757  s << "PPL::";
2758  if (is_necessarily_closed()) {
2759  s << "C_";
2760  }
2761  else {
2762  s << "NNC_";
2763  }
2764  s << "Polyhedron::" << method << ":" << std::endl
2765  << "*this is an empty polyhedron and" << std::endl
2766  << "the non-empty generator system " << gs_name << " contains no points.";
2767  throw std::invalid_argument(s.str());
2768 }
bool has_pending_constraints() const
Returns true if there are pending constraints.
bool constraints_are_minimized() const
Returns true if the system of constraints is minimized.
static int homogeneous_sign(const Linear_Expression &x, const Linear_Expression &y)
Returns the sign of the homogeneous scalar product of x and y, where the inhomogeneous terms are igno...
Enable_If< Is_Native_Or_Checked< To >::value &&Is_Special< From >::value, Result >::type assign_r(To &to, const From &, Rounding_Dir dir)
bool is_tautological() const
Returns true if and only if *this is a tautology (i.e., an always true constraint).
Definition: Constraint.cc:105
void drop_some_non_integer_points(Complexity_Class complexity=ANY_COMPLEXITY)
Possibly tightens *this by dropping some points with non-integer coordinates.
void set_until(unsigned long k)
Sets bits up to position k (excluded).
Definition: Bit_Row.cc:166
bool marked_empty() const
Returns true if the polyhedron is known to be empty.
The empty element, i.e., the empty set.
static Poly_Con_Relation is_disjoint()
The polyhedron and the set of points satisfying the constraint are disjoint.
static Poly_Gen_Relation subsumes()
Adding the generator would not change the polyhedron.
void sort_and_remove_with_sat(Bit_Matrix &sat)
Sorts the system, removing duplicates, keeping the saturation matrix consistent.
void set_optimization_mode(Optimization_Mode mode)
Sets the optimization mode to mode.
void set_sat_g_up_to_date()
Sets status to express that sat_g is up-to-date.
A linear equality or inequality.
bool is_equality() const
Returns true if and only if *this is an equality constraint.
void swap(CO_Tree &x, CO_Tree &y)
bool minimize() const
Applies (weak) minimization to both the constraints and generators.
void clear_constraints_up_to_date()
Sets status to express that constraints are no longer up-to-date.
bool strongly_minimize_constraints() const
Applies strong minimization to the constraints of an NNC polyhedron.
bool adjust_topology_and_space_dimension(Topology new_topology, dimension_type new_space_dim)
Adjusts *this so that it matches the new_topology and new_space_dim (adding or removing columns if ne...
bool remove_pending_to_obtain_generators() const
Lazily integrates the pending descriptions of the polyhedron to obtain a generator system without pen...
static bool implies(flags_t x, flags_t y)
True if and only if the conjunction x implies the conjunction y.
size_t dimension_type
An unsigned integral type for representing space dimensions.
void update_constraints() const
Updates constraints starting from generators and minimizes them.
Type type() const
Returns the constraint type of *this.
void intersection_assign(const Bit_Row &x, const Bit_Row &y)
Assigns to *this the set-theoretic intersection of x and y.
bool is_necessarily_closed() const
Returns true if and only if the topology of *this row is necessarily closed.
bool max_min(const Linear_Expression &expr, bool maximize, Coefficient &ext_n, Coefficient &ext_d, bool &included, Generator &g) const
Maximizes or minimizes expr subject to *this.
An std::set of variables' indexes.
void resize(dimension_type new_n_rows, dimension_type new_n_columns)
Resizes the matrix copying the old contents.
Definition: Bit_Matrix.cc:132
Generator_System gen_sys
The system of generators.
A line, ray, point or closure point.
Linear_Expression expr
The linear expression encoding *this.
void add_constraints(const Constraint_System &cs)
Adds a copy of the constraints in cs to the MIP problem.
Definition: MIP_Problem.cc:184
bool generators_are_minimized() const
Returns true if the system of generators is minimized.
bool is_empty() const
Returns true if and only if *this is an empty polyhedron.
void union_assign(const Bit_Row &x, const Bit_Row &y)
Assigns to *this the set-theoretic union of x and y.
bool is_line_or_ray() const
Returns true if and only if *this is a line or a ray.
Coefficient_traits::const_reference inhomogeneous_term() const
Returns the inhomogeneous term of *this.
void set_generators_up_to_date()
Sets status to express that generators are up-to-date.
void clear_pending_generators()
Sets status to express that there are no longer pending generators.
#define PPL_DIRTY_TEMP_COEFFICIENT(id)
Declare a local variable named id, of type Coefficient, and containing an unknown initial value...
void assign_with_pending(const Constraint_System &y)
Full assignment operator: pending rows are copied as pending.
void add_constraint(const Constraint &c)
Adds a copy of constraint c to the system of constraints of *this (without minimizing the result)...
bool strongly_minimize_generators() const
Applies strong minimization to the generators of an NNC polyhedron.
void insert(const Constraint &c)
Inserts in *this a copy of the constraint c, increasing the number of space dimensions if needed...
dimension_type space_dimension() const
Returns the dimension of the vector space enclosing *this.
static Poly_Con_Relation is_included()
The polyhedron is included in the set of points satisfying the constraint.
bool sat_c_is_up_to_date() const
Returns true if the saturation matrix sat_c is up-to-date.
dimension_type num_pending_rows() const
Returns the number of rows that are in the pending part of the system.
void set(unsigned long k)
Sets the bit in position k.
bool update_generators() const
Updates generators starting from constraints and minimizes them.
void set_constraints_up_to_date()
Sets status to express that constraints are up-to-date.
void difference_assign(const Bit_Row &x, const Bit_Row &y)
Assigns to *this the set-theoretic difference of x and y.
void swap(Polyhedron &x, Polyhedron &y)
Swaps x with y.
bool is_sorted() const
Returns the value of the sortedness flag.
bool sat_g_is_up_to_date() const
Returns true if the saturation matrix sat_g is up-to-date.
void throw_dimension_incompatible(const char *method, const char *other_name, dimension_type other_dim) const
bool has_points() const
Returns true if and only if *this contains one or more points.
dimension_type space_dimension() const
Returns the dimension of the vector space enclosing *this.
const Constraint_System & constraints() const
Returns the system of constraints.
void clear(unsigned long k)
Clears the bit in position k.
void assign_with_pending(const Generator_System &y)
Full assignment operator: pending rows are copied as pending.
void set_inhomogeneous_term(Coefficient_traits::const_reference n)
Sets the inhomogeneous term of *this to n.
A row in a matrix of bits.
Polyhedron & operator=(const Polyhedron &y)
The assignment operator. (*this and y can be dimension-incompatible.)
void obtain_sorted_constraints() const
Sorts the matrix of constraints keeping status consistency.
Coefficient gcd(dimension_type start, dimension_type end) const
Returns the gcd of the nonzero coefficients in [start,end). Returns zero if all the coefficients in t...
Polyhedron(Topology topol, dimension_type num_dimensions, Degenerate_Element kind)
Builds a polyhedron having the specified properties.
bool BFT00_poly_hull_assign_if_exact(const Polyhedron &y)
If the poly-hull of *this and y is exact it is assigned to *this and true is returned, otherwise false is returned.
void mark_as_not_necessarily_closed()
Marks the last dimension as the epsilon dimension.
bool is_sorted() const
Returns the value of the sortedness flag.
A dimension of the vector space.
bool is_strict_inequality() const
Returns true if and only if *this is a strict inequality constraint.
void sort_pending_and_remove_duplicates()
Sorts the pending rows and eliminates those that also occur in the non-pending part of the system...
Complexity_Class
Complexity pseudo-classes.
The base class for convex polyhedra.
void remove_row(dimension_type i, bool keep_sorted=false)
Makes the system shrink by removing its i-th row.
dimension_type space_dimension() const
Returns the dimension of the vector space enclosing *this.
void set_sat_c_up_to_date()
Sets status to express that sat_c is up-to-date.
bool BHZ09_C_poly_hull_assign_if_exact(const Polyhedron &y)
void update_sat_g() const
Updates sat_g using the updated constraints and generators.
bool is_inequality() const
Returns true if and only if *this is an inequality constraint (either strict or non-strict).
void throw_invalid_generators(const char *method, const char *gs_name) const
Topology topology() const
Returns the topological kind of the polyhedron.
bool generators_are_up_to_date() const
Returns true if the system of generators is up-to-date.
void throw_invalid_argument(const char *method, const char *reason) const
Constraint_System con_sys
The system of constraints.
dimension_type space_dimension() const
Returns the dimension of the vector space enclosing *this.
static int reduced_sign(const Linear_Expression &x, const Linear_Expression &y)
Returns the sign of the reduced scalar product of x and y, where the coefficient of x is ignored...
void clear_pending_constraints()
Sets status to express that there are no longer pending constraints.
dimension_type num_equalities() const
Returns the number of equality constraints.
static dimension_type check_space_dimension_overflow(dimension_type dim, dimension_type max, const Topology topol, const char *method, const char *reason)
dimension_type space_dimension() const
Returns the dimension of the vector space enclosing *this.
Degenerate_Element
Kinds of degenerate abstract elements.
Type type() const
Returns the generator type of *this.
bool constraints_are_up_to_date() const
Returns true if the system of constraints is up-to-date.
void clear()
Clears the matrix deallocating all its rows.
bool OK() const
Checks if all the invariants are satisfied.
Definition: Generator.cc:432
void refine_no_check(const Constraint &c)
Uses a copy of constraint c to refine the system of constraints of *this.
void throw_topology_incompatible(const char *method, const char *ph_name, const Polyhedron &ph) const
bool BHZ09_NNC_poly_hull_assign_if_exact(const Polyhedron &y)
void obtain_sorted_generators_with_sat_g() const
Sorts the matrix of generators and updates sat_g.
dimension_type space_dimension() const
Returns the dimension of the vector space enclosing *this.
void obtain_sorted_constraints_with_sat_c() const
Sorts the matrix of constraints and updates sat_c.
dimension_type check_space_dimension_overflow(const dimension_type dim, const dimension_type max, const char *domain, const char *method, const char *reason)
Definition: globals.cc:48
Bit_Matrix sat_g
The saturation matrix having generators on its columns.
void set_generators_minimized()
Sets status to express that generators are minimized.
static dimension_type max_space_dimension()
Returns the maximum space dimension all kinds of Polyhedron can handle.
A Mixed Integer (linear) Programming problem.
void sort_and_remove_with_sat(Bit_Matrix &sat)
Sorts the system, removing duplicates, keeping the saturation matrix consistent.
bool is_inconsistent() const
Returns true if and only if *this is inconsistent (i.e., an always false constraint).
Definition: Constraint.cc:148
void sign_normalize()
Normalizes the sign of the coefficients so that the first non-zero (homogeneous) coefficient of a lin...
Definition: Generator.cc:264
bool empty() const
Returns true if no bit is set in the row.
unsigned long first() const
Returns the index of the first set bit or ULONG_MAX if no bit is set.
Definition: Bit_Row.cc:32
PPL_COEFFICIENT_TYPE Coefficient
An alias for easily naming the type of PPL coefficients.
bool all_homogeneous_terms_are_zero() const
Returns true if and only if all the homogeneous terms of *this are .
bool is_point() const
Returns true if and only if *this is a point.
void process_pending_generators() const
Processes the pending generators and obtains a minimized polyhedron.
bool all_homogeneous_terms_are_zero() const
Returns true if and only if all the homogeneous terms of *this are zero.
dimension_type space_dimension() const
Returns the dimension of the vector space enclosing *this.
void add_generator(const Generator &g)
Adds a copy of generator g to the system of generators of *this (without minimizing the result)...
void sort_rows()
Sorts the non-pending rows (in growing order) and eliminates duplicated ones.
Status status
The status flags to keep track of the polyhedron's internal state.
bool is_included_in(const Polyhedron &y) const
Returns true if and only if *this is included in y.
void set_epsilon_coefficient(Coefficient_traits::const_reference n)
Sets the epsilon coefficient to n. The constraint must be NNC.
#define PPL_DIRTY_TEMP(T, id)
void sort_rows()
Sorts the non-pending rows (in growing order) and eliminates duplicated ones.
void positive_time_elapse_assign_impl(const Polyhedron &y)
Assuming *this is NNC, assigns to *this the result of the "positive time-elapse" between *this and y...
void remove_pending_to_obtain_constraints() const
Lazily integrates the pending descriptions of the polyhedron to obtain a constraint system without pe...
void add_corresponding_closure_points()
For each unmatched point in *this, adds the corresponding closure point.
bool minimize(const Linear_Expression &expr, Coefficient &inf_n, Coefficient &inf_d, bool &minimum) const
Returns true if and only if *this is not empty and expr is bounded from below in *this, in which case the infimum value is computed.
void set_empty()
Sets status to express that the polyhedron is empty, clearing all corresponding matrices.
void set_is_ray_or_point_or_inequality()
Sets to RAY_OR_POINT_OR_INEQUALITY the kind of *this row.
The entire library is confined to this namespace.
Definition: version.hh:61
dimension_type space_dim
The number of dimensions of the enclosing vector space.
void insert(Variable v)
Inserts the index of variable v into the set.
bool bounds(const Linear_Expression &expr, bool from_above) const
Checks if and how expr is bounded in *this.
void set_sorted(bool b)
Sets the sortedness flag of the system to b.
void set_epsilon_coefficient(Coefficient_traits::const_reference n)
Sets the epsilon coefficient to n. The generator must be NNC.
Maximization is requested.
void upper_bound_assign(const Polyhedron &y)
Same as poly_hull_assign(y).
bool contains(const Polyhedron &y) const
Returns true if and only if *this contains y.
dimension_type space_dimension() const
Returns the dimension of the vector space enclosing *this.
static const Constraint & epsilon_leq_one()
The zero-dimension space constraint (used to implement NNC polyhedra).
bool is_necessarily_closed() const
Returns true if and only if the polyhedron is necessarily closed.
Coefficient_traits::const_reference epsilon_coefficient() const
Returns the epsilon coefficient. The constraint must be NNC.
Coefficient_traits::const_reference epsilon_coefficient() const
Returns the epsilon coefficient. The generator must be NNC.
static const Constraint & zero_dim_positivity()
The true (zero-dimension space) constraint , also known as positivity constraint. ...
void clear_sat_g_up_to_date()
Sets status to express that sat_g is no longer up-to-date.
void unset_pending_rows()
Sets the index to indicate that the system has no pending rows.
dimension_type num_lines() const
Returns the number of lines of the system.
void set_objective_function(const Linear_Expression &obj)
Sets the objective function to obj.
Definition: MIP_Problem.cc:208
MIP_Problem_Status solve() const
Optimizes the MIP problem.
Definition: MIP_Problem.cc:293
bool OK(bool check_not_empty=false) const
Checks if all the invariants are satisfied.
bool process_pending_constraints() const
Processes the pending constraints and obtains a minimized polyhedron.
void clear_constraints_minimized()
Sets status to express that constraints are no longer minimized.
void add_low_level_constraints()
Adds low-level constraints to the constraint system.
bool OK() const
Checks if all the invariants are satisfied.
Definition: Constraint.cc:467
int sgn(Boundary_Type type, const T &x, const Info &info)
static void homogeneous_assign(Coefficient &z, const Linear_Expression &x, const Linear_Expression &y)
Computes the homogeneous scalar product of x and y, where the inhomogeneous terms are ignored...
static int sign(const Linear_Expression &x, const Linear_Expression &y)
Returns the sign of the scalar product between x and y.
void exact_div_assign(Coefficient_traits::const_reference c, dimension_type start, dimension_type end)
void update_sat_c() const
Updates sat_c using the updated constraints and generators.
Three_Valued_Boolean quick_equivalence_test(const Polyhedron &y) const
Polynomial but incomplete equivalence test between polyhedra.
void obtain_sorted_generators() const
Sorts the matrix of generators keeping status consistency.
unsigned long next(unsigned long position) const
Returns the index of the first set bit after position or ULONG_MAX if no bit after position is set...
Definition: Bit_Row.cc:47
bool BHZ09_poly_hull_assign_if_exact(const Polyhedron &y)
bool has_pending_generators() const
Returns true if there are pending generators.
dimension_type affine_dimension() const
Returns , if *this is empty; otherwise, returns the affine dimension of *this.
void set_sorted(bool b)
Sets the sortedness flag of the system to b.
void clear_sat_c_up_to_date()
Sets status to express that sat_c is no longer up-to-date.
dimension_type num_pending_rows() const
Returns the number of rows that are in the pending part of the system.
Coefficient c
Definition: PIP_Tree.cc:64
void sort_pending_and_remove_duplicates()
Sorts the pending rows and eliminates those that also occur in the non-pending part of the system...
Bit_Matrix sat_c
The saturation matrix having constraints on its columns.
void throw_invalid_generator(const char *method, const char *g_name) const
void set_constraints_minimized()
Sets status to express that constraints are minimized.
void add_space_dimensions_and_embed(dimension_type m)
Adds m new space dimensions and embeds the old MIP problem in the new vector space.
Definition: MIP_Problem.cc:374
expr_type expression() const
Partial read access to the (adapted) internal expression.
#define PPL_UNINITIALIZED(type, name)
Definition: compiler.hh:72
void upper_bound_assign(std::map< dimension_type, Linear_Form< FP_Interval_Type > > &ls1, const std::map< dimension_type, Linear_Form< FP_Interval_Type > > &ls2)
bool is_line_or_equality() const
Returns true if and only if *this row represents a line or an equality.
void insert(const Generator &g)
Inserts in *this a copy of the generator g, increasing the number of space dimensions if needed...
dimension_type space_dimension() const
Returns the dimension of the vector space enclosing *this.
bool is_line() const
Returns true if and only if *this is a line.
bool adjust_topology_and_space_dimension(Topology new_topology, dimension_type new_space_dim)
Adjusts *this so that it matches new_topology and new_space_dim (adding or removing columns if needed...
void mark_as_necessarily_closed()
Marks the epsilon dimension as a standard dimension.
static Poly_Gen_Relation nothing()
The assertion that says nothing.
bool le(Boundary_Type type1, const T1 &x1, const Info1 &info1, Boundary_Type type2, const T2 &x2, const Info2 &info2)
void clear_generators_up_to_date()
Sets status to express that generators are no longer up-to-date.
void unset_pending_rows()
Sets the index to indicate that the system has no pending rows.
bool all_zeroes(const Variables_Set &vars) const
Returns true if the coefficient of each variable in vars is zero.
void set_zero_dim_univ()
Sets status to express that the polyhedron is the universe 0-dimension vector space, clearing all corresponding matrices.
Topology
Kinds of polyhedra domains.
void transpose_assign(const Bit_Matrix &y)
Makes *this a transposed copy of y.
Definition: Bit_Matrix.cc:117
void clear_generators_minimized()
Sets status to express that generators are no longer minimized.
Poly_Con_Relation relation_with(const Constraint &c) const
Returns the relations holding between the polyhedron *this and the constraint c.
MIP_Problem_Status
Possible outcomes of the MIP_Problem solver.
Coefficient_traits::const_reference inhomogeneous_term() const
Returns the inhomogeneous term of *this.
bool has_something_pending() const
Returns true if there are either pending constraints or pending generators.
bool is_closure_point() const
Returns true if and only if *this is a closure point.