PPL  1.2
Grid_public.cc
Go to the documentation of this file.
1 /* Grid class implementation (non-inline public functions).
2  Copyright (C) 2001-2010 Roberto Bagnara <bagnara@cs.unipr.it>
3  Copyright (C) 2010-2016 BUGSENG srl (http://bugseng.com)
4 
5 This file is part of the Parma Polyhedra Library (PPL).
6 
7 The PPL is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11 
12 The PPL is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software Foundation,
19 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307, USA.
20 
21 For the most up-to-date information see the Parma Polyhedra Library
22 site: http://bugseng.com/products/ppl/ . */
23 
24 #include "ppl-config.h"
25 #include "Grid_defs.hh"
26 #include "Topology_types.hh"
27 #include "Scalar_Products_defs.hh"
29 #include "Polyhedron_defs.hh"
30 #include "assertions.hh"
31 #include <iostream>
32 
33 namespace PPL = Parma_Polyhedra_Library;
34 
35 // TODO: In the Grid constructors adapt and use the given system if it
36 // is modifiable, instead of using a copy.
37 
39  : con_sys(),
40  gen_sys(),
41  status(y.status),
42  space_dim(y.space_dim),
43  dim_kinds(y.dim_kinds) {
44  if (space_dim == 0) {
45  con_sys = y.con_sys;
46  gen_sys = y.gen_sys;
47  }
48  else {
50  con_sys = y.con_sys;
51  }
52  else {
54  }
55  if (y.generators_are_up_to_date()) {
56  gen_sys = y.gen_sys;
57  }
58  else {
60  }
61  }
62 }
63 
65  : con_sys(check_space_dimension_overflow(cs.space_dimension(),
67  "PPL::Grid::",
68  "Grid(cs)",
69  "the space dimension of cs "
70  "exceeds the maximum allowed "
71  "space dimension")),
72  gen_sys(cs.space_dimension()) {
74 
75  if (space_dim == 0) {
76  // See if an inconsistent constraint has been passed.
78  cs_end = cs.end(); i != cs_end; ++i) {
79  if (i->is_inconsistent()) {
80  // Inconsistent constraint found: the grid is empty.
81  status.set_empty();
82  // Insert the zero dim false congruence system into `con_sys'.
83  // `gen_sys' is already in empty form.
85  PPL_ASSERT(OK());
86  return;
87  }
88  }
90  PPL_ASSERT(OK());
91  return;
92  }
93 
96  cs_end = cs.end(); i != cs_end; ++i) {
97  if (i->is_equality()) {
98  cgs.insert(*i);
99  }
100  else {
101  throw_invalid_constraints("Grid(cs)", "cs");
102  }
103  }
104  construct(cgs);
105 }
106 
108  : con_sys(check_space_dimension_overflow(cs.space_dimension(),
110  "PPL::Grid::",
111  "Grid(cs, recycle)",
112  "the space dimension of cs "
113  "exceeds the maximum allowed "
114  "space dimension")),
115  gen_sys(cs.space_dimension()) {
116  space_dim = cs.space_dimension();
117 
118  if (space_dim == 0) {
119  // See if an inconsistent constraint has been passed.
121  cs_end = cs.end(); i != cs_end; ++i) {
122  if (i->is_inconsistent()) {
123  // Inconsistent constraint found: the grid is empty.
124  status.set_empty();
125  // Insert the zero dim false congruence system into `con_sys'.
126  // `gen_sys' is already in empty form.
128  PPL_ASSERT(OK());
129  return;
130  }
131  }
133  PPL_ASSERT(OK());
134  return;
135  }
136 
139  cs_end = cs.end(); i != cs_end; ++i) {
140  if (i->is_equality()) {
141  cgs.insert(*i);
142  }
143  else {
144  throw_invalid_constraint("Grid(cs)", "cs");
145  }
146  }
147  construct(cgs);
148 }
149 
151  Complexity_Class complexity)
152  : con_sys(check_space_dimension_overflow(ph.space_dimension(),
154  "PPL::Grid::",
155  "Grid(ph)",
156  "the space dimension of ph "
157  "exceeds the maximum allowed "
158  "space dimension")),
159  gen_sys(ph.space_dimension()) {
160  space_dim = ph.space_dimension();
161 
162  // A zero-dim polyhedron causes no complexity problems.
163  if (space_dim == 0) {
164  if (ph.is_empty()) {
165  set_empty();
166  }
167  else {
169  }
170  return;
171  }
172 
173  // A polyhedron known to be empty causes no complexity problems.
174  if (ph.marked_empty()) {
175  set_empty();
176  return;
177  }
178 
179  const bool use_constraints = ph.constraints_are_minimized()
180  || !ph.generators_are_up_to_date();
181 
182  // Minimize the constraint description if it is needed and
183  // the complexity allows it.
184  if (use_constraints && complexity == ANY_COMPLEXITY) {
185  if (!ph.minimize()) {
186  set_empty();
187  return;
188  }
189  }
190  if (use_constraints) {
191  // Only the equality constraints need be used.
192  PPL_ASSERT(ph.constraints_are_up_to_date());
193  const Constraint_System& cs = ph.constraints();
195  for (Constraint_System::const_iterator i = cs.begin(),
196  cs_end = cs.end(); i != cs_end; ++i) {
197  if (i->is_equality()) {
198  cgs.insert(*i);
199  }
200  }
201  construct(cgs);
202  }
203  else {
204  // First find a point or closure point and convert it to a
205  // grid point and add to the (initially empty) set of grid generators.
206  PPL_ASSERT(ph.generators_are_up_to_date());
207  const Generator_System& gs = ph.generators();
209  Linear_Expression point_expr;
210  point_expr.set_space_dimension(space_dim);
211  PPL_DIRTY_TEMP_COEFFICIENT(point_divisor);
212  for (Generator_System::const_iterator g = gs.begin(),
213  gs_end = gs.end(); g != gs_end; ++g) {
214  if (g->is_point() || g->is_closure_point()) {
215  point_expr.linear_combine(g->expr, Coefficient_one(), Coefficient_one(),
216  1, space_dim + 1);
217  point_divisor = g->divisor();
218  ggs.insert(grid_point(point_expr, point_divisor));
219  break;
220  }
221  }
222  // Add grid lines for all the other generators.
223  // If the polyhedron's generator is a (closure) point, the grid line must
224  // have the direction given by a line that joins the grid point already
225  // inserted and the new point.
226  for (Generator_System::const_iterator g = gs.begin(),
227  gs_end = gs.end(); g != gs_end; ++g) {
230  if (g->is_point() || g->is_closure_point()) {
231  e.linear_combine(point_expr, Coefficient_one(), g->divisor(),
232  1, space_dim + 1);
233  e.linear_combine(g->expr, Coefficient_one(), -point_divisor,
234  1, space_dim + 1);
236  continue;
237  }
238  }
239  else {
241  1, space_dim + 1);
242  }
243  ggs.insert(grid_line(e));
244  }
245  construct(ggs);
246  }
247  PPL_ASSERT(OK());
248 }
249 
250 PPL::Grid&
252  space_dim = y.space_dim;
253  dim_kinds = y.dim_kinds;
254  if (y.marked_empty()) {
255  set_empty();
256  }
257  else if (space_dim == 0) {
258  set_zero_dim_univ();
259  }
260  else {
261  status = y.status;
262  if (y.congruences_are_up_to_date()) {
263  con_sys = y.con_sys;
264  }
265  if (y.generators_are_up_to_date()) {
266  gen_sys = y.gen_sys;
267  }
268  }
269  return *this;
270 }
271 
274  if (space_dim == 0 || is_empty()) {
275  return 0;
276  }
277 
278  if (generators_are_up_to_date()) {
279  if (generators_are_minimized()) {
280  return gen_sys.num_rows() - 1;
281  }
282  if (!(congruences_are_up_to_date() && congruences_are_minimized())) {
283  return minimized_grid_generators().num_rows() - 1;
284  }
285  }
286  else {
287  minimized_congruences();
288  }
289  PPL_ASSERT(congruences_are_minimized());
290  dimension_type d = space_dim;
291  for (dimension_type i = con_sys.num_rows(); i-- > 0; ) {
292  if (con_sys[i].is_equality()) {
293  --d;
294  }
295  }
296  return d;
297 }
298 
301  if (marked_empty()) {
302  return con_sys;
303  }
304 
305  if (space_dim == 0) {
306  // Zero-dimensional universe.
307  PPL_ASSERT(con_sys.num_rows() == 0 && con_sys.space_dimension() == 0);
308  return con_sys;
309  }
310 
311  if (!congruences_are_up_to_date()) {
312  update_congruences();
313  }
314 
315  return con_sys;
316 }
317 
320  if (congruences_are_up_to_date() && !congruences_are_minimized()) {
321  // Minimize the congruences.
322  Grid& gr = const_cast<Grid&>(*this);
323  if (gr.simplify(gr.con_sys, gr.dim_kinds)) {
324  gr.set_empty();
325  }
326  else {
328  }
329  }
330  return congruences();
331 }
332 
335  if (space_dim == 0) {
336  PPL_ASSERT(gen_sys.space_dimension() == 0
337  && gen_sys.num_rows() == (marked_empty() ? 0U : 1U));
338  return gen_sys;
339  }
340 
341  if (marked_empty()) {
342  PPL_ASSERT(gen_sys.has_no_rows());
343  return gen_sys;
344  }
345 
346  if (!generators_are_up_to_date() && !update_generators()) {
347  // Updating found the grid empty.
348  const_cast<Grid&>(*this).set_empty();
349  return gen_sys;
350  }
351 
352  return gen_sys;
353 }
354 
357  if (space_dim == 0) {
358  PPL_ASSERT(gen_sys.space_dimension() == 0
359  && gen_sys.num_rows() == (marked_empty() ? 0U : 1U));
360  return gen_sys;
361  }
362 
363  if (marked_empty()) {
364  PPL_ASSERT(gen_sys.has_no_rows());
365  return gen_sys;
366  }
367 
368  if (generators_are_up_to_date()) {
369  if (!generators_are_minimized()) {
370  // Minimize the generators.
371  Grid& gr = const_cast<Grid&>(*this);
372  gr.simplify(gr.gen_sys, gr.dim_kinds);
374  }
375  }
376  else if (!update_generators()) {
377  // Updating found the grid empty.
378  const_cast<Grid&>(*this).set_empty();
379  return gen_sys;
380  }
381 
382  return gen_sys;
383 }
384 
387  // Dimension-compatibility check.
388  if (space_dim < cg.space_dimension()) {
389  throw_dimension_incompatible("relation_with(cg)", "cg", cg);
390  }
391 
392  if (marked_empty()) {
396  }
397 
398  if (space_dim == 0) {
399  if (cg.is_inconsistent()) {
401  }
402  else if (cg.is_equality()) {
405  }
406  else if (cg.inhomogeneous_term() % cg.modulus() == 0) {
409  }
410  }
411 
412  if (!generators_are_up_to_date() && !update_generators()) {
413  // Updating found the grid empty.
417  }
418 
419  // Return one of the relations
420  // 'strictly_intersects' a strict subset of the grid points satisfy cg
421  // 'is_included' every grid point satisfies cg
422  // 'is_disjoint' cg and the grid occupy separate spaces.
423  // There is always a point.
424  // Scalar product of the congruence and the first point that
425  // satisfies the congruence.
426  PPL_DIRTY_TEMP_COEFFICIENT(point_sp);
427  point_sp = 0;
428 
430  div = cg.modulus();
431 
433 
434  bool known_to_intersect = false;
435 
436  for (Grid_Generator_System::const_iterator i = gen_sys.begin(),
437  i_end = gen_sys.end(); i != i_end; ++i) {
438  const Grid_Generator& g = *i;
439  Scalar_Products::assign(sp, cg, g);
440 
441  switch (g.type()) {
442 
444  if (cg.is_proper_congruence()) {
445  sp %= div;
446  }
447  if (sp == 0) {
448  // The point satisfies the congruence.
449  if (point_sp == 0) {
450  // Any previous points satisfied the congruence.
451  known_to_intersect = true;
452  }
453  else {
455  }
456  }
457  else {
458  if (point_sp == 0) {
459  if (known_to_intersect) {
461  }
462  // Assign `sp' to `point_sp' as `sp' is the scalar product
463  // of cg and a point g and is non-zero.
464  point_sp = sp;
465  }
466  else {
467  // A previously considered point p failed to satisfy cg such that
468  // `point_sp' = `scalar_prod(p, cg)'
469  // so, if we consider the parameter g-p instead of g, we have
470  // scalar_prod(g-p, cg) = scalar_prod(g, cg) - scalar_prod(p, cg)
471  // = sp - point_sp
472  sp -= point_sp;
473 
474  if (sp != 0) {
475  // Find the GCD between sp and the previous GCD.
476  gcd_assign(div, div, sp);
477  if (point_sp % div == 0) {
478  // There is a point in the grid satisfying cg.
480  }
481  }
482  }
483  }
484  break;
485 
487  if (cg.is_proper_congruence()) {
488  sp %= (div * g.divisor());
489  }
490  if (sp == 0) {
491  // Parameter g satisfies the cg so the relation depends
492  // entirely on the other generators.
493  break;
494  }
495  if (known_to_intersect) {
496  // At least one point satisfies cg. However, the sum of such
497  // a point and the parameter g fails to satisfy cg (due to g).
499  }
500  // Find the GCD between sp and the previous GCD.
501  gcd_assign(div, div, sp);
502  if (point_sp != 0) {
503  // At least one of any previously encountered points fails to
504  // satisfy cg.
505  if (point_sp % div == 0) {
506  // There is also a grid point that satisfies cg.
508  }
509  }
510  break;
511 
513  if (sp == 0) {
514  // Line g satisfies the cg so the relation depends entirely on
515  // the other generators.
516  break;
517  }
518 
519  // Line g intersects the congruence.
520  //
521  // There is a point p in the grid. Suppose <p*cg> = p_sp. Then
522  // (-p_sp/sp)*g + p is a point that satisfies cg: <((-p_sp/sp)*g
523  // + p).cg> = -(p_sp/sp)*sp + p_sp) = 0. If p does not satisfy
524  // `cg' and hence is not in the grid defined by `cg', the grid
525  // `*this' strictly intersects the `cg' grid. On the other
526  // hand, if `p' is in the grid defined by `cg' so that p_sp = 0,
527  // then <p+g.cg> = p_sp + sp != 0; thus `p+g' is a point in
528  // *this that does not satisfy `cg' and hence `p+g' is a point
529  // in *this not in the grid defined by `cg'; therefore `*this'
530  // strictly intersects the `cg' grid.
532  }
533  }
534 
535  if (point_sp == 0) {
536  if (cg.is_equality()) {
537  // Every generator satisfied the cg.
540  }
541  else {
542  // Every generator satisfied the cg.
544  }
545  }
546 
547  PPL_ASSERT(!known_to_intersect);
549 }
550 
553  // Dimension-compatibility check.
554  if (space_dim < g.space_dimension()) {
555  throw_dimension_incompatible("relation_with(g)", "g", g);
556  }
557 
558  // The empty grid cannot subsume a generator.
559  if (marked_empty()) {
561  }
562 
563  // A universe grid in a zero-dimensional space subsumes all the
564  // generators of a zero-dimensional space.
565  if (space_dim == 0) {
567  }
568 
569  if (!congruences_are_up_to_date()) {
570  update_congruences();
571  }
572 
573  return
574  con_sys.satisfies_all_congruences(g)
577 }
578 
581  const dimension_type g_space_dim = g.space_dimension();
582 
583  // Dimension-compatibility check.
584  if (space_dim < g_space_dim) {
585  throw_dimension_incompatible("relation_with(g)", "g", g);
586  }
587 
588  // The empty grid cannot subsume a generator.
589  if (marked_empty()) {
591  }
592 
593  // A universe grid in a zero-dimensional space subsumes all the
594  // generators of a zero-dimensional space.
595  if (space_dim == 0) {
597  }
598 
599  if (!congruences_are_up_to_date()) {
600  update_congruences();
601  }
602 
603  const Linear_Expression expr(g.expression());
604  Grid_Generator gg(grid_point());
605  if (g.is_point() || g.is_closure_point()) {
606  // Points and closure points are converted to grid points.
607  gg = grid_point(expr, g.divisor());
608  }
609  else {
610  // The generator is a ray or line.
611  // In both cases, we convert it to a grid line
612  gg = grid_line(expr);
613  }
614 
615  return
616  con_sys.satisfies_all_congruences(gg)
619 }
620 
623  // Dimension-compatibility check.
624  if (space_dim < c.space_dimension()) {
625  throw_dimension_incompatible("relation_with(c)", "c", c);
626  }
627 
628  if (c.is_equality()) {
629  const Congruence cg(c);
630  return relation_with(cg);
631  }
632 
633  if (marked_empty()) {
637  }
638 
639  if (space_dim == 0) {
640  if (c.is_inconsistent()) {
641  if (c.is_strict_inequality() && c.inhomogeneous_term() == 0) {
642  // The constraint 0 > 0 implicitly defines the hyperplane 0 = 0;
643  // thus, the zero-dimensional point also saturates it.
646  }
647  else {
649  }
650  }
651  else if (c.inhomogeneous_term() == 0) {
654  }
655  else {
656  // The zero-dimensional point saturates
657  // neither the positivity constraint 1 >= 0,
658  // nor the strict positivity constraint 1 > 0.
660  }
661  }
662 
663  if (!generators_are_up_to_date() && !update_generators()) {
664  // Updating found the grid empty.
668  }
669 
670  // Return one of the relations
671  // 'strictly_intersects' a strict subset of the grid points satisfy c
672  // 'is_included' every grid point satisfies c
673  // 'is_disjoint' c and the grid occupy separate spaces.
674  // There is always a point.
675 
676  bool point_is_included = false;
677  bool point_saturates = false;
678  const Grid_Generator* first_point = 0;
679 
680  for (Grid_Generator_System::const_iterator i = gen_sys.begin(),
681  i_end = gen_sys.end(); i != i_end; ++i) {
682  const Grid_Generator& g = *i;
683  switch (g.type()) {
685  {
686  if (first_point == 0) {
687  first_point = &g;
688  const int sign = Scalar_Products::sign(c, g);
689  if (sign == 0) {
690  point_saturates = !c.is_strict_inequality();
691  }
692  else if (sign > 0) {
693  point_is_included = !c.is_equality();
694  }
695  break;
696  }
697  // Not the first point: convert `g' to be a parameter
698  // and fall through into the parameter case.
699  Grid_Generator& gen = const_cast<Grid_Generator&>(g);
700  const Grid_Generator& point = *first_point;
701  const Coefficient& p_div = point.divisor();
702  const Coefficient& g_div = gen.divisor();
703  gen.expr.linear_combine(point.expr, p_div, -g_div,
704  1, gen.expr.space_dimension());
705  gen.expr.set_inhomogeneous_term(g_div * p_div);
706  gen.strong_normalize();
707  gen.set_is_parameter();
708  PPL_ASSERT(gen.OK());
709  }
710  // Intentionally fall through.
711 
714  {
715  const int sign = c.is_strict_inequality()
718  if (sign != 0) {
720  }
721  }
722  break;
723  } // switch
724  }
725 
726  // If this program point is reached, then all lines and parameters
727  // saturate the constraint. Hence, the result is determined by
728  // the previosly computed relation with the point.
729  if (point_saturates) {
732  }
733 
734  if (point_is_included) {
736  }
737 
739 }
740 
741 bool
743  if (marked_empty()) {
744  return true;
745  }
746  // Try a fast-fail test: if generators are up-to-date then the
747  // generator system (since it is well formed) contains a point.
748  if (generators_are_up_to_date()) {
749  return false;
750  }
751  if (space_dim == 0) {
752  return false;
753  }
754  if (congruences_are_minimized()) {
755  // If the grid was empty it would be marked empty.
756  return false;
757  }
758  // Minimize the congruences to check if the grid is empty.
759  Grid& gr = const_cast<Grid&>(*this);
760  if (gr.simplify(gr.con_sys, gr.dim_kinds)) {
761  gr.set_empty();
762  return true;
763  }
765  return false;
766 }
767 
768 bool
770  if (marked_empty()) {
771  return false;
772  }
773 
774  if (space_dim == 0) {
775  return true;
776  }
777 
778  if (congruences_are_up_to_date()) {
779  if (congruences_are_minimized()) {
780  // The minimized universe congruence system has only one row,
781  // the integrality congruence.
782  return con_sys.num_rows() == 1 && con_sys[0].is_tautological();
783  }
784  }
785  else {
786  update_congruences();
787  return con_sys.num_rows() == 1 && con_sys[0].is_tautological();
788  }
789 
790  // Test con_sys's inclusion in a universe generator system.
791 
792  // The zero dimension cases are handled above.
793  for (dimension_type i = space_dim; i-- > 0; ) {
794  Linear_Expression expr;
795  expr.set_space_dimension(space_dim);
796  expr += Variable(i);
797  if (!con_sys.satisfies_all_congruences(grid_line(expr))) {
798  return false;
799  }
800  }
801 #ifndef NDEBUG
802  Linear_Expression expr;
803  expr.set_space_dimension(space_dim);
804  PPL_ASSERT(con_sys.satisfies_all_congruences(grid_point(expr)));
805 #endif
806  return true;
807 }
808 
809 bool
811  // A zero-dimensional or empty grid is bounded.
812  if (space_dim == 0
813  || marked_empty()
814  || (!generators_are_up_to_date() && !update_generators())) {
815  return true;
816  }
817  // TODO: Consider using con_sys when gen_sys is out of date.
818 
819  if (gen_sys.num_rows() > 1) {
820  // Check if all generators are the same point.
821  const Grid_Generator& first_point = gen_sys[0];
822  if (first_point.is_line_or_parameter()) {
823  return false;
824  }
825  for (dimension_type row = gen_sys.num_rows(); row-- > 0; ) {
826  const Grid_Generator& gen = gen_sys[row];
827  if (gen.is_line_or_parameter() || gen != first_point) {
828  return false;
829  }
830  }
831  }
832  return true;
833 }
834 
835 bool
837  // A zero-dimensional or empty grid is discrete.
838  if (space_dim == 0
839  || marked_empty()
840  || (!generators_are_up_to_date() && !update_generators())) {
841  return true;
842  }
843  // Search for lines in the generator system.
844  for (dimension_type row = gen_sys.num_rows(); row-- > 1; ) {
845  if (gen_sys[row].is_line()) {
846  return false;
847  }
848  }
849 
850  // The system of generators is composed only by
851  // points and parameters: the grid is discrete.
852  return true;
853 }
854 
855 bool
857  return true;
858 }
859 
860 bool
862  // Empty grids have no points.
863  if (marked_empty()) {
864  return false;
865  }
866 
867  // A zero-dimensional, universe grid has, by convention, an
868  // integer point.
869  if (space_dim == 0) {
870  return true;
871  }
872 
873  // A grid has an integer point if its intersection with the integer
874  // grid is non-empty.
875  Congruence_System cgs;
876  for (dimension_type var_index = space_dim; var_index-- > 0; ) {
877  cgs.insert(Variable(var_index) %= 0);
878  }
879 
880  Grid gr = *this;
881  gr.add_recycled_congruences(cgs);
882  return !gr.is_empty();
883 }
884 
885 bool
886 PPL::Grid::constrains(const Variable var) const {
887  // `var' should be one of the dimensions of the grid.
888  const dimension_type var_space_dim = var.space_dimension();
889  if (space_dim < var_space_dim) {
890  throw_dimension_incompatible("constrains(v)", "v", var);
891  }
892 
893  // An empty grid constrains all variables.
894  if (marked_empty()) {
895  return true;
896  }
897 
898  if (generators_are_up_to_date()) {
899  // Since generators are up-to-date, the generator system (since it is
900  // well formed) contains a point. Hence the grid is not empty.
901  if (congruences_are_up_to_date()) {
902  // Here a variable is constrained if and only if it is
903  // syntactically constrained.
904  goto syntactic_check;
905  }
906 
907  if (generators_are_minimized()) {
908  // Try a quick, incomplete check for the universe grid:
909  // a universe grid constrains no variable.
910  // Count the number of lines (they are linearly independent).
911  dimension_type num_lines = 0;
912  for (dimension_type i = gen_sys.num_rows(); i-- > 0; ) {
913  if (gen_sys[i].is_line()) {
914  ++num_lines;
915  }
916  }
917 
918  if (num_lines == space_dim) {
919  return false;
920  }
921  }
922 
923  // Scan generators: perhaps we will find line(var).
924  for (dimension_type i = gen_sys.num_rows(); i-- > 0; ) {
925  const Grid_Generator& g_i = gen_sys[i];
926  if (!g_i.is_line()) {
927  continue;
928  }
929  if (sgn(g_i.coefficient(var)) != 0) {
930  if (g_i.expression().all_zeroes(1, var.space_dimension())
931  && g_i.expression().all_zeroes(var.space_dimension() + 1, space_dim + 1)) {
932  // The only nonzero coefficient in g_i is the one of var.
933  return true;
934  }
935  }
936  }
937 
938  // We are still here: at least we know that the grid is not empty.
939  update_congruences();
940  goto syntactic_check;
941  }
942 
943  // We must minimize to detect emptiness and obtain constraints.
944  if (!minimize()) {
945  return true;
946  }
947 
948  syntactic_check:
949  for (dimension_type i = con_sys.num_rows(); i-- > 0; ) {
950  if (con_sys[i].coefficient(var) != 0) {
951  return true;
952  }
953  }
954  return false;
955 }
956 
957 bool
958 PPL::Grid::OK(bool check_not_empty) const {
959 #ifndef NDEBUG
960  using std::endl;
961  using std::cerr;
962 #endif
963 
964  // Check whether the status information is legal.
965  if (!status.OK()) {
966  goto fail;
967  }
968 
969  if (marked_empty()) {
970  if (check_not_empty) {
971  // The caller does not want the grid to be empty.
972 #ifndef NDEBUG
973  cerr << "Empty grid!" << endl;
974 #endif
975  goto fail;
976  }
977 
978  if (con_sys.space_dimension() != space_dim) {
979 #ifndef NDEBUG
980  cerr << "The grid is in a space of dimension " << space_dim
981  << " while the system of congruences is in a space of dimension "
982  << con_sys.space_dimension()
983  << endl;
984 #endif
985  goto fail;
986  }
987  return true;
988  }
989 
990  // A zero-dimensional universe grid is legal only if the system of
991  // congruences `con_sys' is empty, and the generator system contains
992  // one point.
993  if (space_dim == 0) {
994  if (con_sys.has_no_rows()) {
995  if (gen_sys.num_rows() == 1 && gen_sys[0].is_point()) {
996  return true;
997  }
998  }
999 #ifndef NDEBUG
1000  cerr << "Zero-dimensional grid should have an empty congruence" << endl
1001  << "system and a generator system of a single point." << endl;
1002 #endif
1003  goto fail;
1004  }
1005 
1006  // A grid is defined by a system of congruences or a system of
1007  // generators. At least one of them must be up to date.
1008  if (!congruences_are_up_to_date() && !generators_are_up_to_date()) {
1009 #ifndef NDEBUG
1010  cerr << "Grid not empty, not zero-dimensional" << endl
1011  << "and with neither congruences nor generators up-to-date!"
1012  << endl;
1013 #endif
1014  goto fail;
1015  }
1016 
1017  {
1018  // The expected number of columns in the congruence and generator
1019  // systems, if they are not empty.
1020  const dimension_type num_columns = space_dim + 1;
1021 
1022  // Here we check if the size of the matrices is consistent.
1023  // Let us suppose that all the matrices are up-to-date; this means:
1024  // `con_sys' : number of congruences x poly_num_columns
1025  // `gen_sys' : number of generators x poly_num_columns
1026  if (congruences_are_up_to_date()) {
1027  if (con_sys.space_dimension() != space_dim) {
1028 #ifndef NDEBUG
1029  cerr << "Incompatible size! (con_sys and space_dim)"
1030  << endl;
1031 #endif
1032  goto fail;
1033  }
1034  }
1035  if (generators_are_up_to_date()) {
1036  if (gen_sys.space_dimension() != space_dim) {
1037 #ifndef NDEBUG
1038  cerr << "Incompatible size! (gen_sys and space_dim)"
1039  << endl;
1040 #endif
1041  goto fail;
1042  }
1043 
1044  // A non-empty system of generators describing a grid is valid
1045  // if and only if it contains a point.
1046  if (!gen_sys.has_no_rows() && !gen_sys.has_points()) {
1047 #ifndef NDEBUG
1048  cerr << "Non-empty generator system declared up-to-date "
1049  << "has no points!"
1050  << endl;
1051 #endif
1052  goto fail;
1053  }
1054 
1055  if (generators_are_minimized()) {
1056  Grid_Generator_System gs = gen_sys;
1057 
1058  if (dim_kinds.size() != num_columns) {
1059 #ifndef NDEBUG
1060  cerr << "Size of dim_kinds should equal the number of columns."
1061  << endl;
1062 #endif
1063  goto fail;
1064  }
1065 
1066  if (!upper_triangular(gs, dim_kinds)) {
1067 #ifndef NDEBUG
1068  cerr << "Reduced generators should be upper triangular."
1069  << endl;
1070 #endif
1071  goto fail;
1072  }
1073 
1074  // Check that dim_kinds corresponds to the row kinds in gen_sys.
1075  for (dimension_type dim = space_dim,
1076  row = gen_sys.num_rows(); dim > 0; --dim) {
1077  if (dim_kinds[dim] == GEN_VIRTUAL) {
1078  goto ok;
1079  }
1080  if (gen_sys[--row].is_parameter_or_point()
1081  && dim_kinds[dim] == PARAMETER) {
1082  goto ok;
1083  }
1084  PPL_ASSERT(gen_sys[row].is_line());
1085  if (dim_kinds[dim] == LINE) {
1086  goto ok;
1087  }
1088 #ifndef NDEBUG
1089  cerr << "Kinds in dim_kinds should match those in gen_sys."
1090  << endl;
1091 #endif
1092  goto fail;
1093  ok:
1094  PPL_ASSERT(row <= dim);
1095  }
1096 
1097  // A reduced generator system must be the same as a temporary
1098  // reduced copy.
1099  Dimension_Kinds dim_kinds_copy = dim_kinds;
1100  // `gs' is minimized and marked_empty returned false, so `gs'
1101  // should contain rows.
1102  PPL_ASSERT(!gs.has_no_rows());
1103  simplify(gs, dim_kinds_copy);
1104  // gs contained rows before being reduced, so it should
1105  // contain at least a single point afterward.
1106  PPL_ASSERT(!gs.has_no_rows());
1107  for (dimension_type row = gen_sys.num_rows(); row-- > 0; ) {
1108  const Grid_Generator& g = gs[row];
1109  const Grid_Generator& g_copy = gen_sys[row];
1110  if (g.is_equal_to(g_copy)) {
1111  continue;
1112  }
1113 #ifndef NDEBUG
1114  cerr << "Generators are declared minimized,"
1115  " but they change under reduction.\n"
1116  << "Here is the generator system:\n";
1117  gen_sys.ascii_dump(cerr);
1118  cerr << "and here is the minimized form of the temporary copy:\n";
1119  gs.ascii_dump(cerr);
1120 #endif
1121  goto fail;
1122  }
1123  }
1124 
1125  } // if (congruences_are_up_to_date())
1126  }
1127 
1128  if (congruences_are_up_to_date()) {
1129  // Check if the system of congruences is well-formed.
1130  if (!con_sys.OK()) {
1131  goto fail;
1132  }
1133 
1134  Grid tmp_gr = *this;
1135  // Make a copy here, before changing tmp_gr, to check later.
1136  const Congruence_System cs_copy = tmp_gr.con_sys;
1137 
1138  // Clear the generators in tmp_gr.
1139  Grid_Generator_System gs(space_dim);
1140  tmp_gr.gen_sys.m_swap(gs);
1141  tmp_gr.clear_generators_up_to_date();
1142 
1143  if (!tmp_gr.update_generators()) {
1144  if (check_not_empty) {
1145  // Want to know the satisfiability of the congruences.
1146 #ifndef NDEBUG
1147  cerr << "Unsatisfiable system of congruences!"
1148  << endl;
1149 #endif
1150  goto fail;
1151  }
1152  // The grid is empty, all checks are done.
1153  return true;
1154  }
1155 
1156  if (congruences_are_minimized()) {
1157  // A reduced congruence system must be lower triangular.
1158  if (!lower_triangular(con_sys, dim_kinds)) {
1159 #ifndef NDEBUG
1160  cerr << "Reduced congruences should be lower triangular." << endl;
1161 #endif
1162  goto fail;
1163  }
1164 
1165  // If the congruences are minimized, all the elements in the
1166  // congruence system must be the same as those in the temporary,
1167  // minimized system `cs_copy'.
1168  if (!con_sys.is_equal_to(cs_copy)) {
1169 #ifndef NDEBUG
1170  cerr << "Congruences are declared minimized, but they change under reduction!"
1171  << endl
1172  << "Here is the minimized form of the congruence system:"
1173  << endl;
1174  cs_copy.ascii_dump(cerr);
1175  cerr << endl;
1176 #endif
1177  goto fail;
1178  }
1179 
1180  if (dim_kinds.size() != con_sys.space_dimension() + 1 /* inhomogeneous term */) {
1181 #ifndef NDEBUG
1182  cerr << "Size of dim_kinds should equal the number of columns."
1183  << endl;
1184 #endif
1185  goto fail;
1186  }
1187 
1188  // Check that dim_kinds corresponds to the row kinds in con_sys.
1189  for (dimension_type dim = space_dim, row = 0; dim > 0; --dim) {
1190  if (dim_kinds[dim] == CON_VIRTUAL) {
1191  continue;
1192  }
1193  if (con_sys[row++].is_proper_congruence()
1194  && dim_kinds[dim] == PROPER_CONGRUENCE) {
1195  continue;
1196  }
1197  PPL_ASSERT(con_sys[row-1].is_equality());
1198  if (dim_kinds[dim] == EQUALITY) {
1199  continue;
1200  }
1201 #ifndef NDEBUG
1202  cerr << "Kinds in dim_kinds should match those in con_sys." << endl;
1203 #endif
1204  goto fail;
1205  }
1206  }
1207  }
1208 
1209  return true;
1210 
1211  fail:
1212 #ifndef NDEBUG
1213  cerr << "Here is the grid under check:" << endl;
1214  ascii_dump(cerr);
1215 #endif
1216  return false;
1217 }
1218 
1219 void
1221  // The dimension of `cs' must be at most `space_dim'.
1222  if (space_dim < cs.space_dimension()) {
1223  throw_dimension_incompatible("add_constraints(cs)", "cs", cs);
1224  }
1225  if (marked_empty()) {
1226  return;
1227  }
1228 
1230  cs_end = cs.end(); i != cs_end; ++i) {
1231  add_constraint_no_check(*i);
1232  if (marked_empty()) {
1233  return;
1234  }
1235  }
1236 }
1237 
1238 void
1240  // The dimension of `g' must be at most space_dim.
1241  const dimension_type g_space_dim = g.space_dimension();
1242  if (space_dim < g_space_dim) {
1243  throw_dimension_incompatible("add_grid_generator(g)", "g", g);
1244  }
1245 
1246  // Deal with zero-dimension case first.
1247  if (space_dim == 0) {
1248  // Points and parameters are the only zero-dimension generators
1249  // that can be created.
1250  if (marked_empty()) {
1251  if (g.is_parameter()) {
1252  throw_invalid_generator("add_grid_generator(g)", "g");
1253  }
1254  set_zero_dim_univ();
1255  }
1256  PPL_ASSERT(OK());
1257  return;
1258  }
1259 
1260  if (marked_empty()
1261  || (!generators_are_up_to_date() && !update_generators())) {
1262  // Here the grid is empty: the specification says we can only
1263  // insert a point.
1264  if (g.is_line_or_parameter()) {
1265  throw_invalid_generator("add_grid_generator(g)", "g");
1266  }
1267  gen_sys.insert(g);
1268  clear_empty();
1269  }
1270  else {
1271  PPL_ASSERT(generators_are_up_to_date());
1272  gen_sys.insert(g);
1273  if (g.is_parameter_or_point()) {
1274  normalize_divisors(gen_sys);
1275  }
1276  }
1277 
1278  // With the added generator, congruences are out of date.
1279  clear_congruences_up_to_date();
1280 
1281  clear_generators_minimized();
1282  set_generators_up_to_date();
1283  PPL_ASSERT(OK());
1284 }
1285 
1286 void
1288  // Dimension-compatibility check.
1289  const dimension_type cgs_space_dim = cgs.space_dimension();
1290  if (space_dim < cgs_space_dim) {
1291  throw_dimension_incompatible("add_recycled_congruences(cgs)", "cgs", cgs);
1292  }
1293 
1294  if (cgs.has_no_rows()) {
1295  return;
1296  }
1297 
1298  if (marked_empty()) {
1299  return;
1300  }
1301 
1302  if (space_dim == 0) {
1303  // In a 0-dimensional space the congruences are trivial (e.g., 0
1304  // == 0 or 1 %= 0) or false (e.g., 1 == 0). In a system of
1305  // congruences `begin()' and `end()' are equal if and only if the
1306  // system contains only trivial congruences.
1307  if (cgs.begin() != cgs.end()) {
1308  // There is a congruence, it must be false, the grid becomes empty.
1309  set_empty();
1310  }
1311  return;
1312  }
1313 
1314  // The congruences are required.
1315  if (!congruences_are_up_to_date()) {
1316  update_congruences();
1317  }
1318 
1319  // Swap (instead of copying) the coefficients of `cgs' (which is
1320  // writable).
1321  con_sys.insert(cgs, Recycle_Input());
1322 
1323  // Congruences may not be minimized and generators are out of date.
1324  clear_congruences_minimized();
1325  clear_generators_up_to_date();
1326  // Note: the congruence system may have become unsatisfiable, thus
1327  // we do not check for satisfiability.
1328  PPL_ASSERT(OK());
1329 }
1330 
1331 void
1333  // Dimension-compatibility check.
1334  const dimension_type gs_space_dim = gs.space_dimension();
1335  if (space_dim < gs_space_dim) {
1336  throw_dimension_incompatible("add_recycled_grid_generators(gs)", "gs", gs);
1337  }
1338 
1339  // Adding no generators leaves the grid the same.
1340  if (gs.has_no_rows()) {
1341  return;
1342  }
1343 
1344  // Adding valid generators to a zero-dimensional grid transforms it
1345  // to the zero-dimensional universe grid.
1346  if (space_dim == 0) {
1347  if (marked_empty()) {
1348  set_zero_dim_univ();
1349  }
1350  else {
1351  PPL_ASSERT(gs.has_points());
1352  }
1353  PPL_ASSERT(OK(true));
1354  return;
1355  }
1356 
1357  if (!marked_empty()) {
1358  // The grid contains at least one point.
1359 
1360  if (!generators_are_up_to_date()) {
1361  update_generators();
1362  }
1363  normalize_divisors(gs, gen_sys);
1364 
1365  gen_sys.insert(gs, Recycle_Input());
1366 
1367  // Congruences are out of date and generators are not minimized.
1368  clear_congruences_up_to_date();
1369  clear_generators_minimized();
1370 
1371  PPL_ASSERT(OK(true));
1372  return;
1373  }
1374 
1375  // The grid is empty.
1376 
1377  // `gs' must contain at least one point.
1378  if (!gs.has_points()) {
1379  throw_invalid_generators("add_recycled_grid_generators(gs)", "gs");
1380  }
1381  // Adjust `gs' to the right dimension.
1382  gs.set_space_dimension(space_dim);
1383 
1384  gen_sys.m_swap(gs);
1385 
1386  normalize_divisors(gen_sys);
1387 
1388  // The grid is no longer empty and generators are up-to-date.
1389  set_generators_up_to_date();
1390  clear_empty();
1391 
1392  PPL_ASSERT(OK());
1393 }
1394 
1395 void
1397  // TODO: this is just an executable specification.
1398  Grid_Generator_System gs_copy = gs;
1399  add_recycled_grid_generators(gs_copy);
1400 }
1401 
1402 void
1404  // The dimension of `c' must be at most `space_dim'.
1405  if (space_dim < c.space_dimension()) {
1406  throw_dimension_incompatible("refine_with_constraint(c)", "c", c);
1407  }
1408  if (marked_empty()) {
1409  return;
1410  }
1411  refine_no_check(c);
1412 }
1413 
1414 void
1416  // The dimension of `cs' must be at most `space_dim'.
1417  if (space_dim < cs.space_dimension()) {
1418  throw_dimension_incompatible("refine_with_constraints(cs)", "cs", cs);
1419  }
1420 
1422  cs_end = cs.end(); !marked_empty() && i != cs_end; ++i) {
1423  refine_no_check(*i);
1424  }
1425 }
1426 
1427 void
1429  // Dimension-compatibility check.
1430  if (space_dim < var.space_dimension()) {
1431  throw_dimension_incompatible("unconstrain(var)", var.space_dimension());
1432  }
1433 
1434  // Do something only if the grid is non-empty.
1435  if (marked_empty()
1436  || (!generators_are_up_to_date() && !update_generators())) {
1437  // Empty: do nothing.
1438  return;
1439  }
1440  PPL_ASSERT(generators_are_up_to_date());
1441  Grid_Generator l = grid_line(var);
1442  gen_sys.insert(l, Recycle_Input());
1443  // With the added generator, congruences are out of date.
1444  clear_congruences_up_to_date();
1445  clear_generators_minimized();
1446  PPL_ASSERT(OK());
1447 }
1448 
1449 void
1451  // The cylindrification with respect to no dimensions is a no-op.
1452  // This case also captures the only legal cylindrification
1453  // of a grid in a 0-dim space.
1454  if (vars.empty()) {
1455  return;
1456  }
1457  // Dimension-compatibility check.
1458  const dimension_type min_space_dim = vars.space_dimension();
1459  if (space_dim < min_space_dim) {
1460  throw_dimension_incompatible("unconstrain(vs)", min_space_dim);
1461  }
1462 
1463  // Do something only if the grid is non-empty.
1464  if (marked_empty()
1465  || (!generators_are_up_to_date() && !update_generators())) {
1466  // Empty: do nothing.
1467  return;
1468  }
1469 
1470  PPL_ASSERT(generators_are_up_to_date());
1471  // Since `gen_sys' is not empty, the space dimension of the inserted
1472  // generators are automatically adjusted.
1473  for (Variables_Set::const_iterator vsi = vars.begin(),
1474  vsi_end = vars.end(); vsi != vsi_end; ++vsi) {
1475  Grid_Generator l = grid_line(Variable(*vsi));
1476  gen_sys.insert(l, Recycle_Input());
1477  }
1478  // Constraints are no longer up-to-date.
1479  clear_generators_minimized();
1480  clear_congruences_up_to_date();
1481  PPL_ASSERT(OK());
1482 }
1483 
1484 void
1486  Grid& x = *this;
1487  // Dimension-compatibility check.
1488  if (x.space_dim != y.space_dim) {
1489  throw_dimension_incompatible("intersection_assign(y)", "y", y);
1490  }
1491  // If one of the two grids is empty, the intersection is empty.
1492  if (x.marked_empty()) {
1493  return;
1494  }
1495  if (y.marked_empty()) {
1496  x.set_empty();
1497  return;
1498  }
1499 
1500  // If both grids are zero-dimensional, then at this point they are
1501  // necessarily universe, so the intersection is also universe.
1502  if (x.space_dim == 0) {
1503  return;
1504  }
1505 
1506  // The congruences must be up-to-date.
1507  if (!x.congruences_are_up_to_date()) {
1508  x.update_congruences();
1509  }
1510  if (!y.congruences_are_up_to_date()) {
1511  y.update_congruences();
1512  }
1513 
1514  if (!y.con_sys.has_no_rows()) {
1515  x.con_sys.insert(y.con_sys);
1516  // Grid_Generators may be out of date and congruences may have changed
1517  // from minimal form.
1520  }
1521 
1522  PPL_ASSERT(x.OK() && y.OK());
1523 }
1524 
1525 void
1527  Grid& x = *this;
1528  // Dimension-compatibility check.
1529  if (x.space_dim != y.space_dim) {
1530  throw_dimension_incompatible("upper_bound_assign(y)", "y", y);
1531  }
1532  // The join of a grid `gr' with an empty grid is `gr'.
1533  if (y.marked_empty()) {
1534  return;
1535  }
1536  if (x.marked_empty()) {
1537  x = y;
1538  return;
1539  }
1540 
1541  // If both grids are zero-dimensional, then they are necessarily
1542  // universe grids, and so is their join.
1543  if (x.space_dim == 0) {
1544  return;
1545  }
1546 
1547  // The generators must be up-to-date.
1548  if (!x.generators_are_up_to_date() && !x.update_generators()) {
1549  // Discovered `x' empty when updating generators.
1550  x = y;
1551  return;
1552  }
1553  if (!y.generators_are_up_to_date() && !y.update_generators()) {
1554  // Discovered `y' empty when updating generators.
1555  return;
1556  }
1557  // Match the divisors of the x and y generator systems.
1559  normalize_divisors(x.gen_sys, gs);
1560  x.gen_sys.insert(gs, Recycle_Input());
1561  // Congruences may be out of date and generators may have lost
1562  // minimal form.
1565 
1566  // At this point both `x' and `y' are not empty.
1567  PPL_ASSERT(x.OK(true) && y.OK(true));
1568 }
1569 
1570 bool
1572  const Grid& x = *this;
1573 
1574  // Dimension-compatibility check.
1575  if (x.space_dim != y.space_dim) {
1576  throw_dimension_incompatible("upper_bound_assign_if_exact(y)", "y", y);
1577  }
1578 
1579  if (x.marked_empty()
1580  || y.marked_empty()
1581  || x.space_dim == 0
1582  || x.is_included_in(y)
1583  || y.is_included_in(x)) {
1584  upper_bound_assign(y);
1585  return true;
1586  }
1587 
1588  // The above test 'x.is_included_in(y)' will ensure the generators of x
1589  // are up to date.
1590  PPL_ASSERT(generators_are_up_to_date());
1591 
1592  Grid x_copy = x;
1593  x_copy.upper_bound_assign(y);
1594  x_copy.difference_assign(y);
1595  if (x_copy.is_included_in(x)) {
1596  upper_bound_assign(y);
1597  return true;
1598  }
1599 
1600  return false;
1601 }
1602 
1603 void
1605  Grid& x = *this;
1606  // Dimension-compatibility check.
1607  if (x.space_dim != y.space_dim) {
1608  throw_dimension_incompatible("difference_assign(y)", "y", y);
1609  }
1610 
1611  if (y.marked_empty() || x.marked_empty()) {
1612  return;
1613  }
1614 
1615  // If both grids are zero-dimensional, then they are necessarily
1616  // universe grids, so the result is empty.
1617  if (x.space_dim == 0) {
1618  x.set_empty();
1619  return;
1620  }
1621 
1622  if (y.contains(x)) {
1623  x.set_empty();
1624  return;
1625  }
1626 
1627  Grid new_grid(x.space_dim, EMPTY);
1628 
1629  const Congruence_System& y_cgs = y.congruences();
1630  for (Congruence_System::const_iterator i = y_cgs.begin(),
1631  y_cgs_end = y_cgs.end(); i != y_cgs_end; ++i) {
1632  const Congruence& cg = *i;
1633 
1634  // The 2-complement cg2 of cg = ((e %= 0) / m) is the congruence
1635  // defining the sets of points exactly half-way between successive
1636  // hyperplanes e = km and e = (k+1)m, for any integer k; that is,
1637  // the hyperplanes defined by 2e = (2k + 1)m, for any integer k.
1638  // Thus `cg2' is the congruence ((2e %= m) / 2m).
1639 
1640  // As the grid difference must be a grid, only add the
1641  // 2-complement congruence to x if the resulting grid includes all
1642  // the points in x that did not satisfy `cg'.
1643 
1644  // The 2-complement of cg can be included in the result only if x
1645  // holds points other than those in cg.
1647  continue;
1648  }
1649 
1650  if (cg.is_proper_congruence()) {
1651  const Linear_Expression e(cg.expression());
1652  // Congruence cg is ((e %= 0) / m).
1653  const Coefficient& m = cg.modulus();
1654  // If x is included in the grid defined by the congruences cg
1655  // and its 2-complement (i.e. the grid defined by the congruence
1656  // (2e %= 0) / m) then add the 2-complement to the potential
1657  // result.
1658  if (x.relation_with((2*e %= 0) / m)
1660  Grid z = x;
1661  z.add_congruence_no_check((2*e %= m) / (2*m));
1662  new_grid.upper_bound_assign(z);
1663  continue;
1664  }
1665  }
1666  return;
1667  }
1668 
1669  *this = new_grid;
1670 
1671  PPL_ASSERT(OK());
1672 }
1673 
1674 namespace {
1675 
1676 struct Ruled_Out_Pair {
1677  PPL::dimension_type congruence_index;
1678  PPL::dimension_type num_ruled_out;
1679 };
1680 
1681 struct Ruled_Out_Less_Than {
1682  bool operator()(const Ruled_Out_Pair& x,
1683  const Ruled_Out_Pair& y) const {
1684  return x.num_ruled_out > y.num_ruled_out;
1685  }
1686 };
1687 
1688 } // namespace
1689 
1690 bool
1692  Grid& x = *this;
1693  // Dimension-compatibility check.
1694  if (x.space_dim != y.space_dim) {
1695  throw_dimension_incompatible("simplify_using_context_assign(y)", "y", y);
1696  }
1697 
1698  // Filter away the zero-dimensional case.
1699  if (x.space_dim == 0) {
1700  if (y.is_empty()) {
1701  set_zero_dim_univ();
1702  PPL_ASSERT(OK());
1703  return false;
1704  }
1705  else {
1706  return !x.is_empty();
1707  }
1708  }
1709 
1710  // If `y' is empty, the biggest enlargement for `x' is the universe.
1711  if (!y.minimize()) {
1712  Grid gr(x.space_dim, UNIVERSE);
1713  m_swap(gr);
1714  return false;
1715  }
1716 
1717  // If `x' is empty, the intersection is empty.
1718  if (!x.minimize()) {
1719  // Search for a congruence of `y' that is not a tautology.
1720  PPL_ASSERT(y.congruences_are_up_to_date());
1721  Grid gr(x.space_dim, UNIVERSE);
1722  for (dimension_type i = y.con_sys.num_rows(); i-- > 0; ) {
1723  const Congruence& y_con_sys_i = y.con_sys[i];
1724  if (!y_con_sys_i.is_tautological()) {
1725  // Found: we obtain a congruence `c' contradicting the one we
1726  // found, and assign to `x' the grid `gr' with `c' as
1727  // the only congruence.
1728  const Linear_Expression le(y_con_sys_i.expression());
1729  if (y_con_sys_i.is_equality()) {
1730  gr.refine_no_check(le == 1);
1731  break;
1732  }
1733  else {
1734  const Coefficient& y_modulus_i = y_con_sys_i.modulus();
1735  if (y_modulus_i > 1) {
1736  gr.refine_no_check(le == 1);
1737  }
1738  else {
1739  Linear_Expression le2 = le;
1740  le2 *= 2;
1741  gr.refine_no_check(le2 == y_modulus_i);
1742  }
1743  break;
1744  }
1745  }
1746  }
1747  m_swap(gr);
1748  PPL_ASSERT(OK());
1749  return false;
1750  }
1751 
1752  PPL_ASSERT(x.congruences_are_minimized()
1753  && y.generators_are_minimized());
1754 
1755  const Congruence_System& x_cs = x.con_sys;
1756  const dimension_type x_cs_num_rows = x_cs.num_rows();
1757 
1758  // Record into `redundant_by_y' the info about which congruences of
1759  // `x' are redundant in the context `y'. Count the number of
1760  // redundancies found.
1761  std::vector<bool> redundant_by_y(x_cs_num_rows, false);
1762  dimension_type num_redundant_by_y = 0;
1763  for (dimension_type i = 0; i < x_cs_num_rows; ++i) {
1765  redundant_by_y[i] = true;
1766  ++num_redundant_by_y;
1767  }
1768  }
1769 
1770  if (num_redundant_by_y < x_cs_num_rows) {
1771 
1772  // Some congruences were not identified as redundant.
1773 
1774  Congruence_System result_cs;
1775  const Congruence_System& y_cs = y.con_sys;
1776  const dimension_type y_cs_num_rows = y_cs.num_rows();
1777  // Compute into `z' the intersection of `x' and `y'.
1778  const bool x_first = (x_cs_num_rows > y_cs_num_rows);
1779  Grid z(x_first ? x : y);
1780  if (x_first) {
1781  z.add_congruences(y_cs);
1782  }
1783  else {
1784  // Only copy (and then recycle) the non-redundant congruences.
1785  Congruence_System tmp_cs;
1786  for (dimension_type i = 0; i < x_cs_num_rows; ++i) {
1787  if (!redundant_by_y[i]) {
1788  tmp_cs.insert(x_cs[i]);
1789  }
1790  }
1791  z.add_recycled_congruences(tmp_cs);
1792  }
1793 
1794  // Congruences are added to `w' until it equals `z'.
1795  // We do not care about minimization or maximization, since
1796  // we are only interested in satisfiability.
1797  Grid w;
1799  // First add the congruences for `y'.
1800  w.add_congruences(y_cs);
1801 
1802  // We apply the following heuristics here: congruences of `x' that
1803  // are not made redundant by `y' are added to `w' depending on
1804  // the number of generators of `y' they rule out (the more generators)
1805  // (they rule out, the sooner they are added). Of course, as soon
1806  // as `w' becomes empty, we stop adding.
1807  std::vector<Ruled_Out_Pair>
1808  ruled_out_vec(x_cs_num_rows - num_redundant_by_y);
1809 
1812 
1813  for (dimension_type i = 0, j = 0; i < x_cs_num_rows; ++i) {
1814  if (!redundant_by_y[i]) {
1815  const Congruence& c = x_cs[i];
1816  const Coefficient& modulus = c.modulus();
1817  div = modulus;
1818 
1819  const Grid_Generator_System& y_gs = y.gen_sys;
1820  dimension_type num_ruled_out_generators = 0;
1822  y_gs_end = y_gs.end(); k != y_gs_end; ++k) {
1823  const Grid_Generator& g = *k;
1824  // If the generator is not to be ruled out,
1825  // it must saturate the congruence.
1826  Scalar_Products::assign(sp, c, g);
1827  // If `c' is a proper congruence the scalar product must be
1828  // reduced modulo a (possibly scaled) modulus.
1829  if (c.is_proper_congruence()) {
1830  // If `g' is a parameter the congruence modulus must be scaled
1831  // up by the divisor of the generator.
1832  if (g.is_parameter()) {
1833  sp %= (div * g.divisor());
1834  }
1835  else {
1836  if (g.is_point()) {
1837  sp %= div;
1838  }
1839  }
1840  }
1841  if (sp == 0) {
1842  continue;
1843  }
1844  ++num_ruled_out_generators;
1845  }
1846  ruled_out_vec[j].congruence_index = i;
1847  ruled_out_vec[j].num_ruled_out = num_ruled_out_generators;
1848  ++j;
1849  }
1850  }
1851  std::sort(ruled_out_vec.begin(), ruled_out_vec.end(),
1852  Ruled_Out_Less_Than());
1853 
1854  const bool empty_intersection = (!z.minimize());
1855 
1856  // Add the congruences in the "ruled out" order to `w'
1857  // until the result is the intersection.
1858  for (std::vector<Ruled_Out_Pair>::const_iterator
1859  j = ruled_out_vec.begin(), ruled_out_vec_end = ruled_out_vec.end();
1860  j != ruled_out_vec_end;
1861  ++j) {
1862  const Congruence& c = x_cs[j->congruence_index];
1863  result_cs.insert(c);
1864  w.add_congruence(c);
1865  if ((empty_intersection && w.is_empty())
1866  || (!empty_intersection && w.is_included_in(z))) {
1867  Grid result_gr(x.space_dim, UNIVERSE);
1868  result_gr.add_congruences(result_cs);
1869  x.m_swap(result_gr);
1870  PPL_ASSERT(x.OK());
1871  return !empty_intersection;
1872  }
1873  }
1874  // Cannot exit from here.
1875  PPL_UNREACHABLE;
1876  }
1877 
1878  // All the congruences are redundant so that the simplified grid
1879  // is the universe.
1880  Grid result_gr(x.space_dim, UNIVERSE);
1881  x.m_swap(result_gr);
1882  PPL_ASSERT(x.OK());
1883  return true;
1884 }
1885 
1886 void
1888  const Linear_Expression& expr,
1889  Coefficient_traits::const_reference denominator) {
1890  // The denominator cannot be zero.
1891  if (denominator == 0) {
1892  throw_invalid_argument("affine_image(v, e, d)", "d == 0");
1893  }
1894 
1895  // Dimension-compatibility checks.
1896  // The dimension of `expr' must be at most the dimension of `*this'.
1897  const dimension_type expr_space_dim = expr.space_dimension();
1898  if (space_dim < expr_space_dim) {
1899  throw_dimension_incompatible("affine_image(v, e, d)", "e", expr);
1900  }
1901  // `var' must be one of the dimensions of the grid.
1902  const dimension_type var_space_dim = var.space_dimension();
1903  if (space_dim < var_space_dim) {
1904  throw_dimension_incompatible("affine_image(v, e, d)", "v", var);
1905  }
1906 
1907  if (marked_empty()) {
1908  return;
1909  }
1910 
1911  Coefficient_traits::const_reference expr_var = expr.coefficient(var);
1912 
1913  if (var_space_dim <= expr_space_dim
1914  && expr_var != 0) {
1915  // The transformation is invertible.
1916  if (generators_are_up_to_date()) {
1917  // Grid_Generator_System::affine_image() requires the third argument
1918  // to be a positive Coefficient.
1919  if (denominator > 0) {
1920  gen_sys.affine_image(var, expr, denominator);
1921  }
1922  else {
1923  gen_sys.affine_image(var, -expr, -denominator);
1924  }
1925  clear_generators_minimized();
1926  // Strong normalization in gs::affine_image may have modified
1927  // divisors.
1928  normalize_divisors(gen_sys);
1929  }
1930  if (congruences_are_up_to_date()) {
1931  // To build the inverse transformation,
1932  // after copying and negating `expr',
1933  // we exchange the roles of `expr[var_space_dim]' and `denominator'.
1935  if (expr_var > 0) {
1936  inverse = -expr;
1937  inverse.set_coefficient(var, denominator);
1938  con_sys.affine_preimage(var, inverse, expr_var);
1939  }
1940  else {
1941  // The new denominator is negative: we negate everything once
1942  // more, as Congruence_System::affine_preimage() requires the
1943  // third argument to be positive.
1944  inverse = expr;
1945  inverse.set_coefficient(var, -denominator);
1946  con_sys.affine_preimage(var, inverse, -expr_var);
1947  }
1948  clear_congruences_minimized();
1949  }
1950  }
1951  else {
1952  // The transformation is not invertible.
1953  // We need an up-to-date system of generators.
1954  if (!generators_are_up_to_date()) {
1955  minimize();
1956  }
1957  if (!marked_empty()) {
1958  // Grid_Generator_System::affine_image() requires the third argument
1959  // to be a positive Coefficient.
1960  if (denominator > 0) {
1961  gen_sys.affine_image(var, expr, denominator);
1962  }
1963  else {
1964  gen_sys.affine_image(var, -expr, -denominator);
1965  }
1966 
1967  clear_congruences_up_to_date();
1968  clear_generators_minimized();
1969  // Strong normalization in gs::affine_image may have modified
1970  // divisors.
1971  normalize_divisors(gen_sys);
1972  }
1973  }
1974  PPL_ASSERT(OK());
1975 }
1976 
1977 void
1980  const Linear_Expression& expr,
1981  Coefficient_traits::const_reference denominator) {
1982  // The denominator cannot be zero.
1983  if (denominator == 0) {
1984  throw_invalid_argument("affine_preimage(v, e, d)", "d == 0");
1985  }
1986 
1987  // Dimension-compatibility checks.
1988  // The dimension of `expr' should not be greater than the dimension
1989  // of `*this'.
1990  const dimension_type expr_space_dim = expr.space_dimension();
1991  if (space_dim < expr_space_dim) {
1992  throw_dimension_incompatible("affine_preimage(v, e, d)", "e", expr);
1993  }
1994  // `var' should be one of the dimensions of the grid.
1995  const dimension_type var_space_dim = var.space_dimension();
1996  if (space_dim < var_space_dim) {
1997  throw_dimension_incompatible("affine_preimage(v, e, d)", "v", var);
1998  }
1999 
2000  if (marked_empty()) {
2001  return;
2002  }
2003 
2004  Coefficient_traits::const_reference expr_var = expr.coefficient(var);
2005 
2006  if (var_space_dim <= expr_space_dim && expr_var != 0) {
2007  // The transformation is invertible.
2008  if (congruences_are_up_to_date()) {
2009  // Congruence_System::affine_preimage() requires the third argument
2010  // to be a positive Coefficient.
2011  if (denominator > 0) {
2012  con_sys.affine_preimage(var, expr, denominator);
2013  }
2014  else {
2015  con_sys.affine_preimage(var, -expr, -denominator);
2016  }
2017  clear_congruences_minimized();
2018  }
2019  if (generators_are_up_to_date()) {
2020  // To build the inverse transformation,
2021  // after copying and negating `expr',
2022  // we exchange the roles of `expr[var_space_dim]' and `denominator'.
2024  if (expr_var > 0) {
2025  inverse = -expr;
2026  inverse.set_coefficient(var, denominator);
2027  gen_sys.affine_image(var, inverse, expr_var);
2028  }
2029  else {
2030  // The new denominator is negative: we negate everything once
2031  // more, as Grid_Generator_System::affine_image() requires the
2032  // third argument to be positive.
2033  inverse = expr;
2034  inverse.set_coefficient(var, -denominator);
2035  gen_sys.affine_image(var, inverse, -expr_var);
2036  }
2037  clear_generators_minimized();
2038  }
2039  }
2040  else {
2041  // The transformation is not invertible.
2042  // We need an up-to-date system of congruences.
2043  if (!congruences_are_up_to_date()) {
2044  minimize();
2045  }
2046  // Congruence_System::affine_preimage() requires the third argument
2047  // to be a positive Coefficient.
2048  if (denominator > 0) {
2049  con_sys.affine_preimage(var, expr, denominator);
2050  }
2051  else {
2052  con_sys.affine_preimage(var, -expr, -denominator);
2053  }
2054 
2055  clear_generators_up_to_date();
2056  clear_congruences_minimized();
2057  }
2058  PPL_ASSERT(OK());
2059 }
2060 
2061 void
2064  const Relation_Symbol relsym,
2065  const Linear_Expression& expr,
2066  Coefficient_traits::const_reference denominator,
2067  Coefficient_traits::const_reference modulus) {
2068  // The denominator cannot be zero.
2069  if (denominator == 0) {
2070  throw_invalid_argument("generalized_affine_image(v, r, e, d, m)",
2071  "d == 0");
2072  }
2073 
2074  // Dimension-compatibility checks.
2075  // The dimension of `expr' should not be greater than the dimension
2076  // of `*this'.
2077  const dimension_type expr_space_dim = expr.space_dimension();
2078  if (space_dim < expr_space_dim) {
2079  throw_dimension_incompatible("generalized_affine_image(v, r, e, d, m)",
2080  "e", expr);
2081  }
2082  // `var' should be one of the dimensions of the grid.
2083  const dimension_type var_space_dim = var.space_dimension();
2084  if (space_dim < var_space_dim) {
2085  throw_dimension_incompatible("generalized_affine_image(v, r, e, d, m)",
2086  "v", var);
2087  }
2088  // The relation symbol cannot be a disequality.
2089  if (relsym == NOT_EQUAL) {
2090  throw_invalid_argument("generalized_affine_image(v, r, e, d, m)",
2091  "r is the disequality relation symbol");
2092  }
2093 
2094  // Any image of an empty grid is empty.
2095  if (marked_empty()) {
2096  return;
2097  }
2098 
2099  // If relsym is not EQUAL, then we return a safe approximation
2100  // by adding a line in the direction of var.
2101  if (relsym != EQUAL) {
2102 
2103  if (modulus != 0) {
2104  throw_invalid_argument("generalized_affine_image(v, r, e, d, m)",
2105  "r != EQUAL && m != 0");
2106  }
2107 
2108  if (!generators_are_up_to_date()) {
2109  minimize();
2110  }
2111 
2112  // Any image of an empty grid is empty.
2113  if (marked_empty()) {
2114  return;
2115  }
2116 
2117  add_grid_generator(grid_line(var));
2118 
2119  PPL_ASSERT(OK());
2120  return;
2121  }
2122 
2123  PPL_ASSERT(relsym == EQUAL);
2124 
2125  affine_image(var, expr, denominator);
2126 
2127  if (modulus == 0) {
2128  return;
2129  }
2130 
2131  // Modulate dimension `var' according to `modulus'.
2132 
2133  if (!generators_are_up_to_date()) {
2134  minimize();
2135  }
2136 
2137  // Test if minimization, possibly in affine_image, found an empty
2138  // grid.
2139  if (marked_empty()) {
2140  return;
2141  }
2142 
2143  if (modulus < 0) {
2144  gen_sys.insert(parameter(-modulus * var));
2145  }
2146  else {
2147  gen_sys.insert(parameter(modulus * var));
2148  }
2149 
2150  normalize_divisors(gen_sys);
2151 
2152  clear_generators_minimized();
2153  clear_congruences_up_to_date();
2154 
2155  PPL_ASSERT(OK());
2156 }
2157 
2158 void
2161  const Relation_Symbol relsym,
2162  const Linear_Expression& expr,
2163  Coefficient_traits::const_reference denominator,
2164  Coefficient_traits::const_reference modulus) {
2165  // The denominator cannot be zero.
2166  if (denominator == 0) {
2167  throw_invalid_argument("generalized_affine_preimage(v, r, e, d, m)",
2168  "d == 0");
2169  }
2170 
2171  // The dimension of `expr' should be at most the dimension of
2172  // `*this'.
2173  const dimension_type expr_space_dim = expr.space_dimension();
2174  if (space_dim < expr_space_dim) {
2175  throw_dimension_incompatible("generalized_affine_preimage(v, r, e, d, m)",
2176  "e", expr);
2177  }
2178  // `var' should be one of the dimensions of the grid.
2179  const dimension_type var_space_dim = var.space_dimension();
2180  if (space_dim < var_space_dim) {
2181  throw_dimension_incompatible("generalized_affine_preimage(v, r, e, d, m)",
2182  "v", var);
2183  }
2184  // The relation symbol cannot be a disequality.
2185  if (relsym == NOT_EQUAL) {
2186  throw_invalid_argument("generalized_affine_preimage(v, r, e, d, m)",
2187  "r is the disequality relation symbol");
2188  }
2189 
2190  // If relsym is not EQUAL, then we return a safe approximation
2191  // by adding a line in the direction of var.
2192  if (relsym != EQUAL) {
2193 
2194  if (modulus != 0) {
2195  throw_invalid_argument("generalized_affine_preimage(v, r, e, d, m)",
2196  "r != EQUAL && m != 0");
2197  }
2198 
2199  if (!generators_are_up_to_date()) {
2200  minimize();
2201  }
2202 
2203  // Any image of an empty grid is empty.
2204  if (marked_empty()) {
2205  return;
2206  }
2207 
2208  add_grid_generator(grid_line(var));
2209 
2210  PPL_ASSERT(OK());
2211  return;
2212  }
2213 
2214  PPL_ASSERT(relsym == EQUAL);
2215  // Any image of an empty grid is empty.
2216  if (marked_empty()) {
2217  return;
2218  }
2219  // Check whether the affine relation is an affine function.
2220  if (modulus == 0) {
2221  affine_preimage(var, expr, denominator);
2222  return;
2223  }
2224 
2225  // Check whether the preimage of this affine relation can be easily
2226  // computed as the image of its inverse relation.
2227  const Coefficient& var_coefficient = expr.coefficient(var);
2228  if (var_space_dim <= expr_space_dim && var_coefficient != 0) {
2229  const Linear_Expression inverse_expr
2230  = expr - (denominator + var_coefficient) * var;
2231  PPL_DIRTY_TEMP_COEFFICIENT(inverse_denominator);
2232  neg_assign(inverse_denominator, var_coefficient);
2233  if (modulus < 0) {
2234  generalized_affine_image(var, EQUAL, inverse_expr, inverse_denominator,
2235  - modulus);
2236  }
2237  else {
2238  generalized_affine_image(var, EQUAL, inverse_expr, inverse_denominator,
2239  modulus);
2240  }
2241  return;
2242  }
2243 
2244  // Here `var_coefficient == 0', so that the preimage cannot be
2245  // easily computed by inverting the affine relation. Add the
2246  // congruence induced by the affine relation.
2247  {
2248  Congruence cg((denominator*var %= expr) / denominator);
2249  if (modulus < 0) {
2250  cg /= -modulus;
2251  }
2252  else {
2253  cg /= modulus;
2254  }
2255  add_congruence_no_check(cg);
2256  }
2257 
2258  // If the resulting grid is empty, its preimage is empty too.
2259  // Note: DO check for emptiness here, as we will later add a line.
2260  if (is_empty()) {
2261  return;
2262  }
2263  add_grid_generator(grid_line(var));
2264  PPL_ASSERT(OK());
2265 }
2266 
2267 void
2270  const Relation_Symbol relsym,
2271  const Linear_Expression& rhs,
2272  Coefficient_traits::const_reference modulus) {
2273  // Dimension-compatibility checks.
2274  // The dimension of `lhs' should be at most the dimension of
2275  // `*this'.
2276  dimension_type lhs_space_dim = lhs.space_dimension();
2277  if (space_dim < lhs_space_dim) {
2278  throw_dimension_incompatible("generalized_affine_image(e1, r, e2, m)",
2279  "e1", lhs);
2280  }
2281  // The dimension of `rhs' should be at most the dimension of
2282  // `*this'.
2283  const dimension_type rhs_space_dim = rhs.space_dimension();
2284  if (space_dim < rhs_space_dim) {
2285  throw_dimension_incompatible("generalized_affine_image(e1, r, e2, m)",
2286  "e2", rhs);
2287  }
2288  // The relation symbol cannot be a disequality.
2289  if (relsym == NOT_EQUAL) {
2290  throw_invalid_argument("generalized_affine_image(e1, r, e2, m)",
2291  "r is the disequality relation symbol");
2292  }
2293 
2294  // Any image of an empty grid is empty.
2295  if (marked_empty()) {
2296  return;
2297  }
2298 
2299  // If relsym is not EQUAL, then we return a safe approximation
2300  // by adding a line in the direction of var.
2301  if (relsym != EQUAL) {
2302 
2303  if (modulus != 0) {
2304  throw_invalid_argument("generalized_affine_image(e1, r, e2, m)",
2305  "r != EQUAL && m != 0");
2306  }
2307 
2308  if (!generators_are_up_to_date()) {
2309  minimize();
2310  }
2311 
2312  // Any image of an empty grid is empty.
2313  if (marked_empty()) {
2314  return;
2315  }
2316 
2317  for (Linear_Expression::const_iterator i = lhs.begin(), i_end = lhs.end();
2318  i != i_end; ++i) {
2319  add_grid_generator(grid_line(i.variable()));
2320  }
2321 
2322  PPL_ASSERT(OK());
2323  return;
2324  }
2325 
2326  PPL_ASSERT(relsym == EQUAL);
2327 
2328  PPL_DIRTY_TEMP_COEFFICIENT(tmp_modulus);
2329  tmp_modulus = modulus;
2330  if (tmp_modulus < 0) {
2331  neg_assign(tmp_modulus);
2332  }
2333 
2334  // Compute the actual space dimension of `lhs',
2335  // i.e., the highest dimension having a non-zero coefficient in `lhs'.
2336 
2337  lhs_space_dim = lhs.last_nonzero();
2338  if (lhs_space_dim == 0) {
2339  // All variables have zero coefficients, so `lhs' is a constant.
2340  add_congruence_no_check((lhs %= rhs) / tmp_modulus);
2341  return;
2342  }
2343 
2344  // Gather in `new_lines' the collections of all the lines having the
2345  // direction of variables occurring in `lhs'.
2346  Grid_Generator_System new_lines;
2348  i_end = lhs.lower_bound(Variable(lhs_space_dim)); i != i_end; ++i) {
2349  new_lines.insert(grid_line(i.variable()));
2350  }
2351 
2352  const dimension_type num_common_dims = std::min(lhs_space_dim, rhs_space_dim);
2353  if (lhs.have_a_common_variable(rhs, Variable(0), Variable(num_common_dims))) {
2354  // Some variables in `lhs' also occur in `rhs'.
2355  // To ease the computation, add an additional dimension.
2356  const Variable new_var(space_dim);
2357  add_space_dimensions_and_embed(1);
2358 
2359  // Constrain the new dimension to be equal to the right hand side.
2360  // TODO: Use add_congruence() when it has been updated.
2361  Congruence_System new_cgs1(new_var == rhs);
2362  add_recycled_congruences(new_cgs1);
2363  if (!is_empty()) {
2364  // The grid still contains points.
2365 
2366  // Existentially quantify all the variables occurring in the left
2367  // hand side expression.
2368 
2369  // Adjust `new_lines' to the right dimension.
2370  new_lines.set_space_dimension(space_dim);
2371  // Add the lines to `gen_sys' (first make sure they are up-to-date).
2372  update_generators();
2373  gen_sys.insert(new_lines, Recycle_Input());
2374  normalize_divisors(gen_sys);
2375  // Update the flags.
2376  clear_congruences_up_to_date();
2377  clear_generators_minimized();
2378 
2379  // Constrain the new dimension so that it is congruent to the left
2380  // hand side expression modulo `modulus'.
2381  // TODO: Use add_congruence() when it has been updated.
2382  Congruence_System new_cgs2((lhs %= new_var) / tmp_modulus);
2383  add_recycled_congruences(new_cgs2);
2384  }
2385 
2386  // Remove the temporarily added dimension.
2387  remove_higher_space_dimensions(space_dim-1);
2388  }
2389  else {
2390  // `lhs' and `rhs' variables are disjoint:
2391  // there is no need to add a further dimension.
2392 
2393  // Only add the lines and congruence if there are points.
2394  if (is_empty()) {
2395  return;
2396  }
2397 
2398  // Existentially quantify all the variables occurring in the left hand
2399  // side expression.
2400  add_recycled_grid_generators(new_lines);
2401 
2402  // Constrain the left hand side expression so that it is congruent to
2403  // the right hand side expression modulo `modulus'.
2404  add_congruence_no_check((lhs %= rhs) / tmp_modulus);
2405  }
2406 
2407  PPL_ASSERT(OK());
2408 }
2409 
2410 void
2413  const Relation_Symbol relsym,
2414  const Linear_Expression& rhs,
2415  Coefficient_traits::const_reference modulus) {
2416  // The dimension of `lhs' must be at most the dimension of `*this'.
2417  dimension_type lhs_space_dim = lhs.space_dimension();
2418  if (space_dim < lhs_space_dim) {
2419  throw_dimension_incompatible("generalized_affine_preimage(e1, r, e2, m)",
2420  "lhs", lhs);
2421  }
2422  // The dimension of `rhs' must be at most the dimension of `*this'.
2423  const dimension_type rhs_space_dim = rhs.space_dimension();
2424  if (space_dim < rhs_space_dim) {
2425  throw_dimension_incompatible("generalized_affine_preimage(e1, r, e2, m)",
2426  "e2", rhs);
2427  }
2428  // The relation symbol cannot be a disequality.
2429  if (relsym == NOT_EQUAL) {
2430  throw_invalid_argument("generalized_affine_preimage(e1, r, e2, m)",
2431  "r is the disequality relation symbol");
2432  }
2433 
2434  // Any preimage of an empty grid is empty.
2435  if (marked_empty()) {
2436  return;
2437  }
2438 
2439  // If relsym is not EQUAL, then we return a safe approximation
2440  // by adding a line in the direction of var.
2441  if (relsym != EQUAL) {
2442 
2443  if (modulus != 0) {
2444  throw_invalid_argument("generalized_affine_preimage(e1, r, e2, m)",
2445  "r != EQUAL && m != 0");
2446  }
2447 
2448  if (!generators_are_up_to_date()) {
2449  minimize();
2450  }
2451  // Any image of an empty grid is empty.
2452  if (marked_empty()) {
2453  return;
2454  }
2455 
2456  for (Linear_Expression::const_iterator i = lhs.begin(), i_end = lhs.end();
2457  i != i_end; ++i) {
2458  add_grid_generator(grid_line(i.variable()));
2459  }
2460 
2461  PPL_ASSERT(OK());
2462  return;
2463  }
2464 
2465  PPL_ASSERT(relsym == EQUAL);
2466 
2467  PPL_DIRTY_TEMP_COEFFICIENT(tmp_modulus);
2468  tmp_modulus = modulus;
2469  if (tmp_modulus < 0) {
2470  neg_assign(tmp_modulus);
2471  }
2472 
2473  // Compute the actual space dimension of `lhs',
2474  // i.e., the highest dimension having a non-zero coefficient in `lhs'.
2475  lhs_space_dim = lhs.last_nonzero();
2476  if (lhs_space_dim == 0) {
2477  // All variables have zero coefficients, so `lhs' is a constant.
2478  // In this case, preimage and image happen to be the same.
2479  add_congruence_no_check((lhs %= rhs) / tmp_modulus);
2480  return;
2481  }
2482 
2483  // Gather in `new_lines' the collections of all the lines having
2484  // the direction of variables occurring in `lhs'.
2485  Grid_Generator_System new_lines;
2487  i_end = lhs.lower_bound(Variable(lhs_space_dim)); i != i_end; ++i) {
2488  new_lines.insert(grid_line(i.variable()));
2489  }
2490 
2491  const dimension_type num_common_dims
2492  = std::min(lhs_space_dim, rhs_space_dim);
2493  if (lhs.have_a_common_variable(rhs, Variable(0), Variable(num_common_dims))) {
2494  // Some variables in `lhs' also occur in `rhs'.
2495  // To ease the computation, add an additional dimension.
2496  const Variable new_var(space_dim);
2497  add_space_dimensions_and_embed(1);
2498 
2499  // Constrain the new dimension to be equal to `lhs'
2500  // TODO: Use add_congruence() when it has been updated.
2501  Congruence_System new_cgs1(new_var == lhs);
2502  add_recycled_congruences(new_cgs1);
2503  if (!is_empty()) {
2504  // The grid still contains points.
2505 
2506  // Existentially quantify all the variables occurring in the left
2507  // hand side
2508 
2509  // Adjust `new_lines' to the right dimension.
2510  new_lines.set_space_dimension(space_dim);
2511  // Add the lines to `gen_sys' (first make sure they are up-to-date).
2512  update_generators();
2513  gen_sys.insert(new_lines, Recycle_Input());
2514  normalize_divisors(gen_sys);
2515  // Update the flags.
2516  clear_congruences_up_to_date();
2517  clear_generators_minimized();
2518 
2519  // Constrain the new dimension so that it is related to
2520  // the right hand side modulo `modulus'.
2521  // TODO: Use add_congruence() when it has been updated.
2522  Congruence_System new_cgs2((rhs %= new_var) / tmp_modulus);
2523  add_recycled_congruences(new_cgs2);
2524  }
2525 
2526  // Remove the temporarily added dimension.
2527  remove_higher_space_dimensions(space_dim-1);
2528  }
2529  else {
2530  // `lhs' and `rhs' variables are disjoint:
2531  // there is no need to add a further dimension.
2532 
2533  // Constrain the left hand side expression so that it is congruent to
2534  // the right hand side expression modulo `mod'.
2535  add_congruence_no_check((lhs %= rhs) / tmp_modulus);
2536 
2537  // Any image of an empty grid is empty.
2538  if (is_empty()) {
2539  return;
2540  }
2541 
2542  // Existentially quantify all the variables occurring in `lhs'.
2543  add_recycled_grid_generators(new_lines);
2544  }
2545  PPL_ASSERT(OK());
2546 }
2547 
2548 void
2551  const Linear_Expression& lb_expr,
2552  const Linear_Expression& ub_expr,
2553  Coefficient_traits::const_reference denominator) {
2554 
2555  // The denominator cannot be zero.
2556  if (denominator == 0) {
2557  throw_invalid_argument("bounded_affine_image(v, lb, ub, d)", "d == 0");
2558  }
2559  // Dimension-compatibility checks.
2560  // `var' should be one of the dimensions of the grid.
2561  const dimension_type var_space_dim = var.space_dimension();
2562  if (space_dim < var_space_dim) {
2563  throw_dimension_incompatible("bounded_affine_image(v, lb, ub, d)",
2564  "v", var);
2565  }
2566  // The dimension of `lb_expr' and `ub_expr' should not be
2567  // greater than the dimension of `*this'.
2568  const dimension_type lb_space_dim = lb_expr.space_dimension();
2569  if (space_dim < lb_space_dim) {
2570  throw_dimension_incompatible("bounded_affine_image(v, lb, ub, d)",
2571  "lb", lb_expr);
2572  }
2573  const dimension_type ub_space_dim = ub_expr.space_dimension();
2574  if (space_dim < ub_space_dim) {
2575  throw_dimension_incompatible("bounded_affine_image(v, lb, ub, d)",
2576  "ub", ub_expr);
2577  }
2578 
2579  // Any image of an empty grid is empty.
2580  if (marked_empty()) {
2581  return;
2582  }
2583  // In all other cases, generalized_affine_preimage() must
2584  // just add a line in the direction of var.
2585  generalized_affine_image(var,
2586  LESS_OR_EQUAL,
2587  ub_expr,
2588  denominator);
2589 
2590  PPL_ASSERT(OK());
2591 }
2592 
2593 
2594 void
2597  const Linear_Expression& lb_expr,
2598  const Linear_Expression& ub_expr,
2599  Coefficient_traits::const_reference denominator) {
2600 
2601  // The denominator cannot be zero.
2602  if (denominator == 0) {
2603  throw_invalid_argument("bounded_affine_preimage(v, lb, ub, d)", "d == 0");
2604  }
2605  // Dimension-compatibility checks.
2606  // `var' should be one of the dimensions of the grid.
2607  const dimension_type var_space_dim = var.space_dimension();
2608  if (space_dim < var_space_dim) {
2609  throw_dimension_incompatible("bounded_affine_preimage(v, lb, ub, d)",
2610  "v", var);
2611  }
2612  // The dimension of `lb_expr' and `ub_expr' should not be
2613  // greater than the dimension of `*this'.
2614  const dimension_type lb_space_dim = lb_expr.space_dimension();
2615  if (space_dim < lb_space_dim) {
2616  throw_dimension_incompatible("bounded_affine_preimage(v, lb, ub, d)",
2617  "lb", lb_expr);
2618  }
2619  const dimension_type ub_space_dim = ub_expr.space_dimension();
2620  if (space_dim < ub_space_dim) {
2621  throw_dimension_incompatible("bounded_affine_preimage(v, lb, ub, d)",
2622  "ub", ub_expr);
2623  }
2624 
2625  // Any preimage of an empty grid is empty.
2626  if (marked_empty()) {
2627  return;
2628  }
2629 
2630  // In all other cases, generalized_affine_preimage() must
2631  // just add a line in the direction of var.
2632  generalized_affine_preimage(var,
2633  LESS_OR_EQUAL,
2634  ub_expr,
2635  denominator);
2636 
2637  PPL_ASSERT(OK());
2638 }
2639 
2640 void
2642  Grid& x = *this;
2643  // Check dimension-compatibility.
2644  if (x.space_dim != y.space_dim) {
2645  throw_dimension_incompatible("time_elapse_assign(y)", "y", y);
2646  }
2647 
2648  // Deal with the zero-dimensional case.
2649  if (x.space_dim == 0) {
2650  if (y.marked_empty()) {
2651  x.set_empty();
2652  }
2653  return;
2654  }
2655 
2656  // If either one of `x' or `y' is empty, the result is empty too.
2657  if (x.marked_empty()) {
2658  return;
2659  }
2660  if (y.marked_empty()
2662  || (!y.generators_are_up_to_date() && !y.update_generators())) {
2663  x.set_empty();
2664  return;
2665  }
2666 
2667  // At this point both generator systems are up-to-date.
2669  const dimension_type gs_num_rows = gs.num_rows();
2670 
2671  normalize_divisors(gs, gen_sys);
2672 
2673  for (dimension_type i = gs_num_rows; i-- > 0; ) {
2674  Grid_Generator& g = gs.sys.rows[i];
2675  if (g.is_point()) {
2676  // Transform the point into a parameter.
2677  g.set_is_parameter();
2678  }
2679  }
2680 
2681  PPL_ASSERT(gs.sys.OK());
2682 
2683  if (gs_num_rows == 0) {
2684  // `y' was the grid containing a single point at the origin, so
2685  // the result is `x'.
2686  return;
2687  }
2688 
2689  // Append `gs' to the generators of `x'.
2690 
2691  gen_sys.insert(gs, Recycle_Input());
2692 
2695 
2696  PPL_ASSERT(x.OK(true) && y.OK(true));
2697 }
2698 
2699 bool
2701  Coefficient& freq_n, Coefficient& freq_d,
2702  Coefficient& val_n, Coefficient& val_d) const {
2703  // The dimension of `expr' must be at most the dimension of *this.
2704  if (space_dim < expr.space_dimension()) {
2705  throw_dimension_incompatible("frequency(e, ...)", "e", expr);
2706  }
2707 
2708  // Space dimension is 0: if empty, then return false;
2709  // otherwise the frequency is 1 and the value is 0.
2710  if (space_dim == 0) {
2711  if (is_empty()) {
2712  return false;
2713  }
2714  freq_n = 0;
2715  freq_d = 1;
2716  val_n = 0;
2717  val_d = 1;
2718  return true;
2719  }
2720  if (!generators_are_minimized() && !minimize()) {
2721  // Minimizing found `this' empty.
2722  return false;
2723  }
2724 
2725  return frequency_no_check(expr, freq_n, freq_d, val_n, val_d);
2726 }
2727 
2729 bool
2730 PPL::operator==(const Grid& x, const Grid& y) {
2731  if (x.space_dim != y.space_dim) {
2732  return false;
2733  }
2734  if (x.marked_empty()) {
2735  return y.is_empty();
2736  }
2737  if (y.marked_empty()) {
2738  return x.is_empty();
2739  }
2740  if (x.space_dim == 0) {
2741  return true;
2742  }
2743 
2744  switch (x.quick_equivalence_test(y)) {
2745  case Grid::TVB_TRUE:
2746  return true;
2747 
2748  case Grid::TVB_FALSE:
2749  return false;
2750 
2751  default:
2752  if (x.is_included_in(y)) {
2753  if (x.marked_empty()) {
2754  return y.is_empty();
2755  }
2756  return y.is_included_in(x);
2757  }
2758  return false;
2759  }
2760 }
2761 
2762 bool
2763 PPL::Grid::contains(const Grid& y) const {
2764  const Grid& x = *this;
2765 
2766  // Dimension-compatibility check.
2767  if (x.space_dim != y.space_dim) {
2768  throw_dimension_incompatible("contains(y)", "y", y);
2769  }
2770 
2771  if (y.marked_empty()) {
2772  return true;
2773  }
2774  if (x.marked_empty()) {
2775  return y.is_empty();
2776  }
2777  if (y.space_dim == 0) {
2778  return true;
2779  }
2780  if (x.quick_equivalence_test(y) == Grid::TVB_TRUE) {
2781  return true;
2782  }
2783  return y.is_included_in(x);
2784 }
2785 
2786 bool
2788  // Dimension-compatibility check.
2789  if (space_dim != y.space_dim) {
2790  throw_dimension_incompatible("is_disjoint_from(y)", "y", y);
2791  }
2792  Grid z = *this;
2793  z.intersection_assign(y);
2794  return z.is_empty();
2795 }
2796 
2797 void
2798 PPL::Grid::ascii_dump(std::ostream& s) const {
2799  using std::endl;
2800 
2801  s << "space_dim "
2802  << space_dim
2803  << endl;
2804  status.ascii_dump(s);
2805  s << "con_sys ("
2806  << (congruences_are_up_to_date() ? "" : "not_")
2807  << "up-to-date)"
2808  << endl;
2809  con_sys.ascii_dump(s);
2810  s << "gen_sys ("
2811  << (generators_are_up_to_date() ? "" : "not_")
2812  << "up-to-date)"
2813  << endl;
2814  gen_sys.ascii_dump(s);
2815  s << "dimension_kinds";
2816  if ((generators_are_up_to_date() && generators_are_minimized())
2817  || (congruences_are_up_to_date() && congruences_are_minimized())) {
2818  for (Dimension_Kinds::const_iterator i = dim_kinds.begin();
2819  i != dim_kinds.end();
2820  ++i) {
2821  s << " " << *i;
2822  }
2823  }
2824  s << endl;
2825 }
2826 
2828 
2829 bool
2830 PPL::Grid::ascii_load(std::istream& s) {
2831  std::string str;
2832 
2833  if (!(s >> str) || str != "space_dim") {
2834  return false;
2835  }
2836 
2837  if (!(s >> space_dim)) {
2838  return false;
2839  }
2840 
2841  if (!status.ascii_load(s)) {
2842  return false;
2843  }
2844 
2845  if (!(s >> str) || str != "con_sys") {
2846  return false;
2847  }
2848 
2849  if (!(s >> str)) {
2850  return false;
2851  }
2852  if (str == "(up-to-date)") {
2853  set_congruences_up_to_date();
2854  }
2855  else if (str != "(not_up-to-date)") {
2856  return false;
2857  }
2858 
2859  if (!con_sys.ascii_load(s)) {
2860  return false;
2861  }
2862 
2863  if (!(s >> str) || str != "gen_sys") {
2864  return false;
2865  }
2866 
2867  if (!(s >> str)) {
2868  return false;
2869  }
2870  if (str == "(up-to-date)") {
2871  set_generators_up_to_date();
2872  }
2873  else if (str != "(not_up-to-date)") {
2874  return false;
2875  }
2876 
2877  if (!gen_sys.ascii_load(s)) {
2878  return false;
2879  }
2880 
2881  if (!(s >> str) || str != "dimension_kinds") {
2882  return false;
2883  }
2884 
2885  if (!marked_empty()
2886  && ((generators_are_up_to_date() && generators_are_minimized())
2887  || (congruences_are_up_to_date() && congruences_are_minimized()))) {
2888  dim_kinds.resize(space_dim + 1);
2889  for (Dimension_Kinds::size_type dim = 0; dim <= space_dim; ++dim) {
2890  short unsigned int dim_kind;
2891  if (!(s >> dim_kind)) {
2892  return false;
2893  }
2894  switch (dim_kind) {
2895  case 0:
2896  dim_kinds[dim] = PARAMETER;
2897  break;
2898  case 1:
2899  dim_kinds[dim] = LINE;
2900  break;
2901  case 2:
2902  dim_kinds[dim] = GEN_VIRTUAL;
2903  break;
2904  default:
2905  return false;
2906  }
2907  }
2908  }
2909 
2910  // Check invariants.
2911  PPL_ASSERT(OK());
2912  return true;
2913 }
2914 
2917  return
2918  con_sys.external_memory_in_bytes()
2919  + gen_sys.external_memory_in_bytes();
2920 }
2921 
2922 void
2927  const Constraint_System* cs_p,
2928  unsigned /* complexity_threshold */,
2929  bool /* wrap_individually */) {
2930 
2931  // Dimension-compatibility check of `*cs_p', if any.
2932  if (cs_p != 0) {
2933  const dimension_type cs_p_space_dim = cs_p->space_dimension();
2934  if (cs_p->space_dimension() > space_dim) {
2935  throw_dimension_incompatible("wrap_assign(vs, ...)", cs_p_space_dim);
2936  }
2937  }
2938 
2939  // Wrapping no variable is a no-op.
2940  if (vars.empty()) {
2941  return;
2942  }
2943 
2944  // Dimension-compatibility check of `vars'.
2945  const dimension_type min_space_dim = vars.space_dimension();
2946  if (space_dim < min_space_dim) {
2947  throw_dimension_incompatible("wrap_assign(vs, ...)", min_space_dim);
2948  }
2949 
2950  // Wrapping an empty grid is a no-op.
2951  if (marked_empty()) {
2952  return;
2953  }
2954  if (!generators_are_minimized() && !minimize()) {
2955  // Minimizing found `this' empty.
2956  return;
2957  }
2958 
2959  // Set the wrap frequency for variables of width `w'.
2960  // This is independent of the signedness `s'.
2961  PPL_DIRTY_TEMP_COEFFICIENT(wrap_frequency);
2962  mul_2exp_assign(wrap_frequency, Coefficient_one(), w);
2963  // Set `min_value' and `max_value' to the minimum and maximum values
2964  // a variable of width `w' and signedness `s' can take.
2965  PPL_DIRTY_TEMP_COEFFICIENT(min_value);
2966  PPL_DIRTY_TEMP_COEFFICIENT(max_value);
2967  if (r == UNSIGNED) {
2968  min_value = 0;
2969  mul_2exp_assign(max_value, Coefficient_one(), w);
2970  --max_value;
2971  }
2972  else {
2973  PPL_ASSERT(r == SIGNED_2_COMPLEMENT);
2974  mul_2exp_assign(max_value, Coefficient_one(), w-1);
2975  neg_assign(min_value, max_value);
2976  --max_value;
2977  }
2978 
2979  // Generators are up-to-date and minimized.
2980  const Grid gr = *this;
2981 
2982  // Overflow is impossible or wraps.
2983  if (o == OVERFLOW_IMPOSSIBLE || o == OVERFLOW_WRAPS) {
2988  for (Variables_Set::const_iterator i = vars.begin(),
2989  vars_end = vars.end(); i != vars_end; ++i) {
2990  const Variable x(*i);
2991  // Find the frequency and a value for `x' in `gr'.
2992  if (!gr.frequency_no_check(x, f_n, f_d, v_n, v_d)) {
2993  continue;
2994  }
2995  if (f_n == 0) {
2996 
2997  // `x' is a constant in `gr'.
2998  if (v_d != 1) {
2999  // The value for `x' is not integral (`frequency_no_check()'
3000  // ensures that `v_n' and `v_d' have no common divisors).
3001  set_empty();
3002  return;
3003  }
3004 
3005  // `x' is a constant and has an integral value.
3006  if ((v_n > max_value) || (v_n < min_value)) {
3007  // The value is outside the range of the bounded integer type.
3008  if (o == OVERFLOW_IMPOSSIBLE) {
3009  // Then `x' has no possible value and hence set empty.
3010  set_empty();
3011  return;
3012  }
3013  PPL_ASSERT(o == OVERFLOW_WRAPS);
3014  // The value v_n for `x' is wrapped modulo the 'wrap_frequency'.
3015  v_n %= wrap_frequency;
3016  // `v_n' is the value closest to 0 and may be negative.
3017  if (r == UNSIGNED && v_n < 0) {
3018  v_n += wrap_frequency;
3019  }
3020  unconstrain(x);
3021  add_constraint(x == v_n);
3022  }
3023  continue;
3024  }
3025 
3026  // `x' is not a constant in `gr'.
3027  PPL_ASSERT(f_n != 0);
3028 
3029  if (f_d % v_d != 0) {
3030  // Then `x' has no integral value and hence `gr' is set empty.
3031  set_empty();
3032  return;
3033  }
3034  if (f_d != 1) {
3035  // `x' has non-integral values, so add the integrality
3036  // congruence for `x'.
3037  add_congruence((x %= 0) / 1);
3038  }
3039  if (o == OVERFLOW_WRAPS && f_n != wrap_frequency) {
3040  // We know that `x' is not a constant, so, if overflow wraps,
3041  // `x' may wrap to a value modulo the `wrap_frequency'.
3042  add_grid_generator(parameter(wrap_frequency * x));
3043  }
3044  else if ((o == OVERFLOW_IMPOSSIBLE && 2*f_n >= wrap_frequency)
3045  || (f_n == wrap_frequency)) {
3046  // In these cases, `x' can only take a unique (ie constant)
3047  // value.
3048  if (r == UNSIGNED && v_n < 0) {
3049  // `v_n' is the value closest to 0 and may be negative.
3050  v_n += f_n;
3051  }
3052  unconstrain(x);
3053  add_constraint(x == v_n);
3054  }
3055  else {
3056  // If overflow is impossible but the grid frequency is less than
3057  // half the wrap frequency, then there is more than one possible
3058  // value for `x' in the range of the bounded integer type,
3059  // so the grid is unchanged.
3060  PPL_ASSERT(o == OVERFLOW_IMPOSSIBLE && 2*f_n < wrap_frequency);
3061  }
3062  }
3063  return;
3064  }
3065 
3066  PPL_ASSERT(o == OVERFLOW_UNDEFINED);
3067  // If overflow is undefined, then all we know is that the variable
3068  // may take any integer within the range of the bounded integer type.
3069  const Grid_Generator& point = gr.gen_sys[0];
3070  const Coefficient& div = point.divisor();
3071  max_value *= div;
3072  min_value *= div;
3073  for (Variables_Set::const_iterator i = vars.begin(),
3074  vars_end = vars.end(); i != vars_end; ++i) {
3075  const Variable x(*i);
3076  if (!gr.bounds_no_check(x)) {
3077  // `x' is not a constant in `gr'.
3078  // We know that `x' is not a constant, so `x' may wrap to any
3079  // value `x + z' where z is an integer.
3080  if (point.coefficient(x) % div != 0) {
3081  // We know that `x' can take non-integral values, so enforce
3082  // integrality.
3083  unconstrain(x);
3084  add_congruence(x %= 0);
3085  }
3086  else {
3087  // `x' has at least one integral value.
3088  // `x' may also take other non-integral values,
3089  // but checking could be costly so we ignore this.
3090  add_grid_generator(parameter(x));
3091  }
3092  }
3093  else {
3094  // `x' is a constant `v' in `gr'.
3095  const Coefficient& coeff_x = point.coefficient(x);
3096  // `x' should be integral.
3097  if (coeff_x % div != 0) {
3098  set_empty();
3099  return;
3100  }
3101  // If the value `v' for `x' is not within the range for the
3102  // bounded integer type, then `x' may wrap to any value `v + z'
3103  // where `z' is an integer; otherwise `x' is unchanged.
3104  if (coeff_x > max_value || coeff_x < min_value) {
3105  add_grid_generator(parameter(x));
3106  }
3107  }
3108  }
3109 }
3110 
3111 void
3113  if (marked_empty() || space_dim == 0) {
3114  return;
3115  }
3116 
3117  // By adding integral congruences for each dimension to the
3118  // congruence system, defining \p *this, the grid will keep only
3119  // those points that have integral coordinates. All points in \p
3120  // *this with non-integral coordinates are removed.
3121  for (dimension_type i = space_dim; i-- > 0; ) {
3122  add_congruence(Variable(i) %= 0);
3123  }
3124 
3125  PPL_ASSERT(OK());
3126 }
3127 
3128 void
3130  Complexity_Class) {
3131  // Dimension-compatibility check.
3132  const dimension_type min_space_dim = vars.space_dimension();
3133  if (space_dimension() < min_space_dim) {
3134  throw_dimension_incompatible("drop_some_non_integer_points(vs, cmpl)",
3135  min_space_dim);
3136  }
3137 
3138  if (marked_empty() || min_space_dim == 0) {
3139  return;
3140  }
3141 
3142  // By adding the integral congruences for each dimension in vars to
3143  // the congruence system defining \p *this, the grid will keep only
3144  // those points that have integer coordinates for all the dimensions
3145  // in vars. All points in \p *this with non-integral coordinates for
3146  // the dimensions in vars are removed.
3147  for (Variables_Set::const_iterator i = vars.begin(),
3148  vars_end = vars.end(); i != vars_end; ++i) {
3149  add_congruence(Variable(*i) %= 0);
3150  }
3151 
3152  PPL_ASSERT(OK());
3153 }
3154 
3156 std::ostream&
3157 PPL::IO_Operators::operator<<(std::ostream& s, const Grid& gr) {
3158  if (gr.is_empty()) {
3159  s << "false";
3160  }
3161  else if (gr.is_universe()) {
3162  s << "true";
3163  }
3164  else {
3165  s << gr.minimized_congruences();
3166  }
3167  return s;
3168 }
bool is_parameter_or_point() const
Returns true if and only if *this row represents a parameter or a point.
Grid_Generator_System gen_sys
The system of generators.
Definition: Grid_defs.hh:1973
memory_size_type external_memory_in_bytes() const
Returns the size in bytes of the memory managed by *this.
bool constraints_are_minimized() const
Returns true if the system of constraints is minimized.
void add_space_dimensions_and_embed(dimension_type m)
Adds m new space dimensions and embeds the old grid in the new vector space.
Definition: Grid_chdims.cc:77
void drop_some_non_integer_points(Complexity_Class complexity=ANY_COMPLEXITY)
Possibly tightens *this by dropping all points with non-integer coordinates.
dimension_type space_dimension() const
Returns the dimension of the smallest vector space enclosing all the variables whose indexes are in t...
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.
dimension_type max_space_dimension()
Returns the maximum space dimension this library can handle.
bool constrains(Variable var) const
Returns true if and only if var is constrained in *this.
Definition: Grid_public.cc:886
Status status
The status flags to keep track of the grid's internal state.
Definition: Grid_defs.hh:1980
Coefficient_traits::const_reference modulus() const
Returns a const reference to the modulus of *this.
void clear_congruences_minimized()
Sets status to express that congruences are no longer minimized.
Definition: Grid_inlines.hh:87
A linear equality or inequality.
void generalized_affine_image(Variable var, Relation_Symbol relsym, const Linear_Expression &expr, Coefficient_traits::const_reference denominator=Coefficient_one(), Coefficient_traits::const_reference modulus=Coefficient_zero())
Assigns to *this the image of *this with respect to the generalized affine relation ...
bool is_equality() const
Returns true if and only if *this is an equality constraint.
bool is_universe() const
Returns true if and only if *this is a universe grid.
Definition: Grid_public.cc:769
void clear_generators_up_to_date()
Sets status to express that generators are out of date.
bool is_included_in(const Grid &y) const
Returns true if and only if *this is included in y.
void set_space_dimension(dimension_type n)
Sets the dimension of the vector space enclosing *this to n .
void difference_assign(const Grid &y)
Assigns to *this the grid-difference of *this and y.
void set_empty()
Sets status to express that the grid is empty, clearing all corresponding matrices.
Grid(dimension_type num_dimensions=0, Degenerate_Element kind=UNIVERSE)
Builds a grid having the specified properties.
static bool implies(flags_t x, flags_t y)
True if and only if the conjunction x implies the conjunction y.
bool is_equal_to(const Grid_Generator &y) const
Returns true if *this is identical to y.
void ascii_dump() const
Writes to std::cerr an ASCII representation of *this.
void add_constraints(const Constraint_System &cs)
Adds to *this congruences equivalent to the constraints in cs.
size_t dimension_type
An unsigned integral type for representing space dimensions.
void insert(const Congruence &cg)
Inserts in *this a copy of the congruence cg, increasing the number of space dimensions if needed...
An std::set of variables' indexes.
Congruence_System con_sys
The system of congruences.
Definition: Grid_defs.hh:1970
bool is_line() const
Returns true if and only if *this is a line.
const Congruence_System & congruences() const
Returns the system of congruences.
Definition: Grid_public.cc:300
A line, ray, point or closure point.
void clear_generators_minimized()
Sets status to express that generators are no longer minimized.
Definition: Grid_inlines.hh:92
bool is_empty() const
Returns true if and only if *this is an empty polyhedron.
const Grid_Generator_System & minimized_grid_generators() const
Returns the minimized system of generators.
Definition: Grid_public.cc:356
void add_congruence_no_check(const Congruence &cg)
Adds the congruence cg to *this.
const_iterator end() const
Returns the past-the-end const_iterator.
#define PPL_DIRTY_TEMP_COEFFICIENT(id)
Declare a local variable named id, of type Coefficient, and containing an unknown initial value...
bool is_inconsistent() const
Returns true if and only if *this is inconsistent (i.e., an always false congruence).
Definition: Congruence.cc:218
Enable_If< Is_Native_Or_Checked< T >::value, void >::type ascii_dump(std::ostream &s, const T &t)
bool is_disjoint_from(const Grid &y) const
Returns true if and only if *this and y are disjoint.
void bounded_affine_image(Variable var, const Linear_Expression &lb_expr, const Linear_Expression &ub_expr, Coefficient_traits::const_reference denominator=Coefficient_one())
Assigns to *this the image of *this with respect to the bounded affine relation . ...
bool set_space_dimension(dimension_type new_space_dim)
Sets the number of space dimensions to new_space_dim.
std::ostream & operator<<(std::ostream &s, const Ask_Tell< D > &x)
bool has_points() const
Returns true if and only if *this contains one or more points.
bool is_discrete() const
Returns true if and only if *this is discrete.
Definition: Grid_public.cc:836
const_iterator end() const
Returns the past-the-end const_iterator.
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.
The standard C++ namespace.
const_iterator begin() const
Returns the const_iterator pointing to the first generator, if this is not empty; otherwise...
expr_type expression() const
Partial read access to the (adapted) internal expression.
expr_type expression() const
Partial read access to the (adapted) internal expression.
void add_congruences(const Congruence_System &cgs)
Adds a copy of each congruence in cgs to *this.
dimension_type space_dimension() const
Returns the dimension of the vector space enclosing *this.
Poly_Con_Relation relation_with(const Congruence &cg) const
Returns the relations holding between *this and cg.
Definition: Grid_public.cc:386
const Constraint_System & constraints() const
Returns the system of constraints.
void set_coefficient(Variable v, Coefficient_traits::const_reference n)
Sets the coefficient of v in *this to n.
static Poly_Con_Relation saturates()
The polyhedron is included in the set of points saturating the constraint.
void set_inhomogeneous_term(Coefficient_traits::const_reference n)
Sets the inhomogeneous term of *this to n.
bool contains_integer_point() const
Returns true if and only if *this contains at least one integer point.
Definition: Grid_public.cc:861
Coefficient_traits::const_reference inhomogeneous_term() const
Returns the inhomogeneous term of *this.
const_iterator begin() const
Returns the const_iterator pointing to the first constraint, if *this is not empty; otherwise...
On overflow, wrapping takes place.
void refine_with_constraints(const Constraint_System &cs)
Uses a copy of the constraints in cs to refine *this.
static bool simplify(Congruence_System &cgs, Dimension_Kinds &dim_kinds)
Converts cgs to upper triangular (i.e. minimized) form.
void set_space_dimension(dimension_type space_dim)
Resizes the system to the specified space dimension.
bool congruences_are_up_to_date() const
Returns true if the system of congruences is up-to-date.
Definition: Grid_inlines.hh:40
expr_type expression() const
Partial read access to the (adapted) internal expression.
void clear_congruences_up_to_date()
Sets status to express that congruences are out of date.
Definition: Grid_inlines.hh:97
void m_swap(Grid_Generator_System &y)
Swaps *this with y.
Coefficient_traits::const_reference coefficient(Variable v) const
Returns the coefficient of v in *this.
void time_elapse_assign(const Grid &y)
Assigns to *this the result of computing the time-elapse between *this and y.
void ascii_dump() const
Writes to std::cerr an ASCII representation of *this.
void ascii_dump() const
Writes to std::cerr an ASCII representation of *this.
void set_generators_minimized()
Sets status to express that generators are minimized.
Definition: Grid_inlines.hh:76
bool is_proper_congruence() const
Returns true if the modulus is greater than zero.
static const Congruence & zero_dim_false()
Returns a reference to the false (zero-dimension space) congruence .
A dimension of the vector space.
void ascii_dump() const
Writes to std::cerr an ASCII representation of *this.
bool have_a_common_variable(const Linear_Expression &x, Variable first, Variable last) const
Returns true if there is a variable from index first (included) to index last (excluded) whose coeffi...
Rounding_Dir inverse(Rounding_Dir dir)
bool is_strict_inequality() const
Returns true if and only if *this is a strict inequality constraint.
bool simplify_using_context_assign(const Grid &y)
Assigns to *this a meet-preserving simplification of *this with respect to y. If false is returned...
Complexity_Class
Complexity pseudo-classes.
void add_recycled_grid_generators(Grid_Generator_System &gs)
Adds the generators in gs to the system of generators of this.
The base class for convex polyhedra.
dimension_type space_dimension() const
Returns the dimension of the vector space enclosing *this.
Three_Valued_Boolean quick_equivalence_test(const Grid &y) const
Polynomial but incomplete equivalence test between grids.
bool upper_bound_assign_if_exact(const Grid &y)
If the upper bound of *this and y is exact it is assigned to this and true is returned, otherwise false is returned.
bool generators_are_up_to_date() const
Returns true if the system of generators is up-to-date.
bool OK(bool check_not_empty=false) const
Checks if all the invariants are satisfied.
Definition: Grid_public.cc:958
void intersection_assign(const Grid &y)
Assigns to *this the intersection of *this and y.
dimension_type space_dimension() const
Returns the dimension of the vector space enclosing *this.
void affine_preimage(Variable var, const Linear_Expression &expr, Coefficient_traits::const_reference denominator=Coefficient_one())
Assigns to *this the affine preimage of *this under the function mapping variable var to the affine e...
Coefficient_traits::const_reference divisor() const
Returns the divisor of *this.
On overflow, the result is undefined.
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...
Relation_Symbol
Relation symbols.
dimension_type space_dimension() const
Returns the dimension of the vector space enclosing *this.
bool is_equality() const
Returns true if *this is an equality.
bool constraints_are_up_to_date() const
Returns true if the system of constraints is up-to-date.
std::vector< Dimension_Kind > Dimension_Kinds
Definition: Grid_defs.hh:1994
dimension_type space_dimension() const
Returns the dimension of the vector space enclosing *this.
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
const_iterator end() const
Returns the past-the-end const_iterator.
const Congruence_System & minimized_congruences() const
Returns the system of congruences in minimal form.
Definition: Grid_public.cc:319
bool is_line_or_parameter() const
Returns true if and only if *this is a line or a parameter.
const Generator_System & generators() const
Returns the system of generators.
bool is_topologically_closed() const
Returns true if and only if *this is a topologically closed subset of the vector space.
Definition: Grid_public.cc:856
bool is_inconsistent() const
Returns true if and only if *this is inconsistent (i.e., an always false constraint).
Definition: Constraint.cc:148
bool is_point() const
Returns true if and only if *this is a point.
void add_grid_generator(const Grid_Generator &g)
Adds a copy of grid generator g to the system of generators of *this.
Enable_If< Is_Native_Or_Checked< T >::value, bool >::type ascii_load(std::istream &s, T &t)
void bounded_affine_preimage(Variable var, const Linear_Expression &lb_expr, const Linear_Expression &ub_expr, Coefficient_traits::const_reference denominator=Coefficient_one())
Assigns to *this the preimage of *this with respect to the bounded affine relation ...
Type type() const
Returns the generator type of *this.
const_iterator begin() const
Returns the const_iterator pointing to the first congruence, if this is not empty; otherwise...
PPL_COEFFICIENT_TYPE Coefficient
An alias for easily naming the type of PPL coefficients.
const Grid_Generator_System & grid_generators() const
Returns the system of generators.
Definition: Grid_public.cc:334
bool contains(const Grid &y) const
Returns true if and only if *this contains y.
bool all_homogeneous_terms_are_zero() const
Returns true if and only if all the homogeneous terms of *this are .
bool frequency_no_check(const Linear_Expression &expr, Coefficient &freq_n, Coefficient &freq_d, Coefficient &val_n, Coefficient &val_d) const
Returns true if and only if *this is not empty and frequency for *this with respect to expr is define...
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.
bool is_point() const
Returns true if and only if *this is a point.
bool is_tautological() const
Returns true if and only if *this is a tautology (i.e., an always true congruence).
Definition: Congruence.cc:210
void wrap_assign(const Variables_Set &vars, Bounded_Integer_Type_Width w, Bounded_Integer_Type_Representation r, Bounded_Integer_Type_Overflow o, const Constraint_System *cs_p=0, unsigned complexity_threshold=16, bool wrap_individually=true)
Wraps the specified dimensions of the vector space.
void unconstrain(Variable var)
Computes the cylindrification of *this with respect to space dimension var, assigning the result to *...
void mul_2exp_assign(GMP_Integer &x, const GMP_Integer &y, unsigned int exp)
dimension_type space_dimension() const
Returns the dimension of the vector space enclosing *this.
bool generators_are_up_to_date() const
Returns true if the system of generators is up-to-date.
Definition: Grid_inlines.hh:45
The universe element, i.e., the whole vector space.
void set_zero_dim_univ()
Sets status to express that the grid is the universe 0-dimension vector space, clearing all correspon...
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.
dimension_type space_dim
The number of dimensions of the enclosing vector space.
Definition: Grid_defs.hh:1983
void neg_assign(GMP_Integer &x)
#define PPL_OUTPUT_DEFINITIONS(class_name)
The entire library is confined to this namespace.
Definition: version.hh:61
void refine_with_constraint(const Constraint &c)
Uses a copy of the constraint c to refine *this.
dimension_type affine_dimension() const
Returns , if *this is empty; otherwise, returns the affine dimension of *this.
Definition: Grid_public.cc:273
dimension_type num_rows() const
Returns the number of rows in the system.
dimension_type space_dimension() const
Returns the dimension of the vector space enclosing *this.
Signed binary where negative values are represented by the two's complement of the absolute value...
bool marked_empty() const
Returns true if the grid is known to be empty.
Definition: Grid_inlines.hh:35
dimension_type num_rows() const
Returns the number of rows (generators) in the system.
bool congruences_are_minimized() const
Returns true if the system of congruences is minimized.
Definition: Grid_inlines.hh:50
void add_congruence(const Congruence &cg)
Adds a copy of congruence cg to *this.
static void throw_invalid_constraints(const char *method, const char *cs_name)
bool frequency(const Linear_Expression &expr, Coefficient &freq_n, Coefficient &freq_d, Coefficient &val_n, Coefficient &val_d) const
Returns true if and only if *this is not empty and frequency for *this with respect to expr is define...
dimension_type space_dimension() const
Returns the dimension of the vector space enclosing *this.
void gcd_assign(GMP_Integer &x, const GMP_Integer &y, const GMP_Integer &z)
int sgn(Boundary_Type type, const T &x, const Info &info)
bool operator==(const Box< ITV > &x, const Box< ITV > &y)
bool is_bounded() const
Returns true if and only if *this is bounded.
Definition: Grid_public.cc:810
void update_congruences() const
Updates and minimizes the congruences from the generators.
static int sign(const Linear_Expression &x, const Linear_Expression &y)
Returns the sign of the scalar product between x and y.
void strong_normalize()
Strong normalization: ensures that different Grid_Generator objects represent different hyperplanes o...
static void assign(Coefficient &z, const Linear_Expression &x, const Linear_Expression &y)
Computes the scalar product of x and y and assigns it to z.
size_t memory_size_type
An unsigned integral type for representing memory size in bytes.
Coefficient_traits::const_reference divisor() const
If *this is either a point or a closure point, returns its divisor.
void add_grid_generators(const Grid_Generator_System &gs)
Adds a copy of the generators in gs to the system of generators of *this.
bool has_no_rows() const
Returns true if num_rows()==0.
Coefficient c
Definition: PIP_Tree.cc:64
void linear_combine(const Linear_Expression &y, Variable v)
void generalized_affine_preimage(Variable var, Relation_Symbol relsym, const Linear_Expression &expr, Coefficient_traits::const_reference denominator=Coefficient_one(), Coefficient_traits::const_reference modulus=Coefficient_zero())
Assigns to *this the preimage of *this with respect to the generalized affine relation ...
Coefficient_traits::const_reference inhomogeneous_term() const
Returns the inhomogeneous term of *this.
Coefficient_traits::const_reference coefficient(Variable v) const
Returns the coefficient of v in *this.
bool is_parameter() const
Returns true if and only if *this is a parameter.
Coefficient_traits::const_reference Coefficient_one()
Returns a const reference to a Coefficient with value 1.
void m_swap(Grid &y)
Swaps *this with grid y. (*this and y can be dimension-incompatible.)
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 generators_are_minimized() const
Returns true if the system of generators is minimized.
Definition: Grid_inlines.hh:55
Grid & operator=(const Grid &y)
The assignment operator. (*this and y can be dimension-incompatible.)
Definition: Grid_public.cc:251
dimension_type space_dimension() const
Returns the dimension of the vector space enclosing *this.
bool bounds_no_check(const Linear_Expression &expr) const
Checks if and how expr is bounded in *this.
void add_recycled_congruences(Congruence_System &cgs)
Adds the congruences in cgs to *this.
static void throw_invalid_constraint(const char *method, const char *c_name)
void construct(dimension_type num_dimensions, Degenerate_Element kind)
Builds a grid universe or empty grid.
static Poly_Con_Relation strictly_intersects()
The polyhedron intersects the set of points satisfying the constraint, but it is not included in it...
bool OK() const
Checks if all the invariants are satisfied.
static Poly_Gen_Relation nothing()
The assertion that says nothing.
void insert(const Grid_Generator &g)
Inserts into *this a copy of the generator g, increasing the number of space dimensions if needed...
void upper_bound_assign(const Grid &y)
Assigns to *this the least upper bound of *this and y.
void affine_image(Variable var, const Linear_Expression &expr, Coefficient_traits::const_reference denominator=Coefficient_one())
Assigns to *this the affine image of this under the function mapping variable var to the affine expre...
bool le(Boundary_Type type1, const T1 &x1, const Info1 &info1, Boundary_Type type2, const T2 &x2, const Info2 &info2)
The relation between a polyhedron and a generator.
bool update_generators() const
Updates and minimizes the generators from the congruences.
A grid line, parameter or grid point.
bool all_zeroes(const Variables_Set &vars) const
Returns true if the coefficient of each variable in vars is zero.
void set_congruences_minimized()
Sets status to express that congruences are minimized.
Definition: Grid_inlines.hh:70
bool is_empty() const
Returns true if and only if *this is an empty grid.
Definition: Grid_public.cc:742
The relation between a polyhedron and a constraint.
bool is_closure_point() const
Returns true if and only if *this is a closure point.
void set_is_parameter()
Converts the Grid_Generator into a parameter.