PPL  1.2
Polyhedron_conversion_templates.hh
Go to the documentation of this file.
1 /* Polyhedron class implementation: conversion().
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 #ifndef PPL_Polyhedron_conversion_templates_hh
25 #define PPL_Polyhedron_conversion_templates_hh 1
26 
27 #include "Bit_Row_defs.hh"
28 #include "Bit_Matrix_defs.hh"
29 #include "Polyhedron_defs.hh"
30 #include "Scalar_Products_defs.hh"
32 #include "Temp_defs.hh"
33 #include "math_utilities_defs.hh"
34 
35 #include <cstddef>
36 #include <climits>
37 
38 // This flag turns on the quick non-adjacency test;
39 // the performance impact of this test was evaluated by H. Le Verge (1994);
40 // see also Corollary 4.2 in B. Genov's PhD thesis (2014).
41 #ifndef PPL_QUICK_NON_ADJ_TEST
42 #define PPL_QUICK_NON_ADJ_TEST 1
43 #endif
44 
45 // This flag turns on the quick adjacency test;
46 // for a justification, see Corollary 4.3 in B. Genov's PhD thesis (2014),
47 // where it is also said that the test was implemented in cddlib.
48 #ifndef PPL_QUICK_ADJ_TEST
49 #define PPL_QUICK_ADJ_TEST 1
50 #endif
51 
52 namespace Parma_Polyhedra_Library {
53 
367 template <typename Source_Linear_System, typename Dest_Linear_System>
369 Polyhedron::conversion(Source_Linear_System& source,
370  const dimension_type start,
371  Dest_Linear_System& dest,
372  Bit_Matrix& sat,
373  dimension_type num_lines_or_equalities) {
374  typedef typename Dest_Linear_System::row_type dest_row_type;
375  typedef typename Source_Linear_System::row_type source_row_type;
376 
377  // Constraints and generators must have the same dimension,
378  // otherwise the scalar products below will bomb.
379  PPL_ASSERT(source.space_dimension() == dest.space_dimension());
380  const dimension_type source_space_dim = source.space_dimension();
381  const dimension_type source_num_rows = source.num_rows();
382  const dimension_type source_num_columns = source_space_dim
383  + (source.is_necessarily_closed() ? 1U : 2U);
384 
385 
386  dimension_type dest_num_rows = dest.num_rows();
387  // The rows removed from `dest' will be placed in this vector, so they
388  // can be recycled if needed.
389  std::vector<dest_row_type> recyclable_dest_rows;
390 
391  using std::swap;
392 
393  // By construction, the number of columns of `sat' is the same as
394  // the number of rows of `source'; also, the number of rows of `sat'
395  // is the same as the number of rows of `dest'.
396  PPL_ASSERT(source_num_rows == sat.num_columns());
397  PPL_ASSERT(dest_num_rows == sat.num_rows());
398 
399  // If `start > 0', then we are converting the pending constraints.
400  PPL_ASSERT(start == 0 || start == source.first_pending_row());
401 
402  PPL_DIRTY_TEMP_COEFFICIENT(normalized_sp_i);
403  PPL_DIRTY_TEMP_COEFFICIENT(normalized_sp_o);
404 
405  bool dest_sorted = dest.is_sorted();
406  const dimension_type dest_first_pending_row = dest.first_pending_row();
407 
408  // This will contain the row indexes of the redundant rows of `source'.
409  std::vector<dimension_type> redundant_source_rows;
410 
411 #if PPL_QUICK_ADJ_TEST
412  // This will contain the number of ones in each row of `sat'.
413  PPL_DIRTY_TEMP(std::vector<dimension_type>, sat_num_ones);
414  sat_num_ones.resize(dest_num_rows, 0);
415  for (dimension_type i = dest_num_rows; i-- > 0; ) {
416  sat_num_ones[i] = sat[i].count_ones();
417  }
418 #endif // PPL_QUICK_ADJ_TEST
419 
420  // Converting the sub-system of `source' having rows with indexes
421  // from `start' to the last one (i.e., `source_num_rows' - 1).
422  for (dimension_type k = start; k < source_num_rows; ++k) {
423  const source_row_type& source_k = source[k];
424 
425 #ifndef NDEBUG
426 #if PPL_QUICK_ADJ_TEST
427  for (dimension_type i = dest_num_rows; i-- > 0; ) {
428  PPL_ASSERT(sat_num_ones[i] == sat[i].count_ones());
429  }
430 #endif // PPL_QUICK_ADJ_TEST
431 #endif // NDEBUG
432 
433  // `scalar_prod[i]' will contain the scalar product of the
434  // constraint `source_k' and the generator `dest_rows[i]'. This
435  // product is 0 if and only if the generator saturates the
436  // constraint.
437  PPL_DIRTY_TEMP(std::vector<Coefficient>, scalar_prod);
438  if (dest_num_rows > scalar_prod.size()) {
439  scalar_prod.insert(scalar_prod.end(),
440  dest_num_rows - scalar_prod.size(),
441  Coefficient_zero());
442  }
443  // `index_non_zero' will indicate the first generator in `dest_rows'
444  // that does not saturate the constraint `source_k'.
445  dimension_type index_non_zero = 0;
446  for ( ; index_non_zero < dest_num_rows; ++index_non_zero) {
447  WEIGHT_BEGIN();
448  Scalar_Products::assign(scalar_prod[index_non_zero],
449  source_k,
450  dest.sys.rows[index_non_zero]);
451  WEIGHT_ADD_MUL(17, source_space_dim);
452  if (scalar_prod[index_non_zero] != 0) {
453  // The generator does not saturate the constraint.
454  break;
455  }
456  // Check if the client has requested abandoning all expensive
457  // computations. If so, the exception specified by the client
458  // is thrown now.
459  maybe_abandon();
460  }
461  for (dimension_type i = index_non_zero + 1; i < dest_num_rows; ++i) {
462  WEIGHT_BEGIN();
463  Scalar_Products::assign(scalar_prod[i], source_k, dest.sys.rows[i]);
464  WEIGHT_ADD_MUL(25, source_space_dim);
465  // Check if the client has requested abandoning all expensive
466  // computations. If so, the exception specified by the client
467  // is thrown now.
468  maybe_abandon();
469  }
470 
471  // We first treat the case when `index_non_zero' is less than
472  // `num_lines_or_equalities', i.e., when the generator that
473  // does not saturate the constraint `source_k' is a line.
474  // The other case (described later) is when all the lines
475  // in `dest_rows' (i.e., all the rows having indexes less than
476  // `num_lines_or_equalities') do saturate the constraint.
477 
478  if (index_non_zero < num_lines_or_equalities) {
479  // Since the generator `dest_rows[index_non_zero]' does not saturate
480  // the constraint `source_k', it can no longer be a line
481  // (see saturation rule in Section \ref prelims).
482  // Therefore, we first transform it to a ray.
483  dest.sys.rows[index_non_zero].set_is_ray_or_point_or_inequality();
484  // Of the two possible choices, we select the ray satisfying
485  // the constraint (namely, the ray whose scalar product
486  // with the constraint gives a positive result).
487  if (scalar_prod[index_non_zero] < 0) {
488  // The ray `dest_rows[index_non_zero]' lies on the wrong half-space:
489  // we change it to have the opposite direction.
490  neg_assign(scalar_prod[index_non_zero]);
491  neg_assign(dest.sys.rows[index_non_zero].expr);
492  // The modified row may still not be OK(), so don't assert OK here.
493  // They are all checked at the end of this function.
494  }
495  // Having changed a line to a ray, we set `dest_rows' to be a
496  // non-sorted system, we decrement the number of lines of `dest_rows'
497  // and, if necessary, we move the new ray below all the remaining lines.
498  dest_sorted = false;
499  --num_lines_or_equalities;
500  if (index_non_zero != num_lines_or_equalities) {
501  swap(dest.sys.rows[index_non_zero],
502  dest.sys.rows[num_lines_or_equalities]);
503  swap(scalar_prod[index_non_zero],
504  scalar_prod[num_lines_or_equalities]);
505  }
506  const dest_row_type& dest_nle = dest.sys.rows[num_lines_or_equalities];
507 
508  // Computing the new lineality space.
509  // Since each line must lie on the hyper-plane corresponding to
510  // the constraint `source_k', the scalar product between
511  // the line and the constraint must be 0.
512  // This property already holds for the lines having indexes
513  // between 0 and `index_non_zero' - 1.
514  // We have to consider the remaining lines, having indexes
515  // between `index_non_zero' and `num_lines_or_equalities' - 1.
516  // Each line that does not saturate the constraint has to be
517  // linearly combined with generator `dest_nle' so that the
518  // resulting new line saturates the constraint.
519  // Note that, by Observation 1 above, the resulting new line
520  // will still saturate all the constraints that were saturated by
521  // the old line.
522 
523  Coefficient& scalar_prod_nle = scalar_prod[num_lines_or_equalities];
524  PPL_ASSERT(scalar_prod_nle != 0);
525  for (dimension_type
526  i = index_non_zero; i < num_lines_or_equalities; ++i) {
527  if (scalar_prod[i] != 0) {
528  // The following fragment optimizes the computation of
529  //
530  // <CODE>
531  // Coefficient scale = scalar_prod[i];
532  // scale.gcd_assign(scalar_prod_nle);
533  // Coefficient normalized_sp_i = scalar_prod[i] / scale;
534  // Coefficient normalized_sp_n = scalar_prod_nle / scale;
535  // for (dimension_type c = dest_num_columns; c-- > 0; ) {
536  // dest[i][c] *= normalized_sp_n;
537  // dest[i][c] -= normalized_sp_i * dest_nle[c];
538  // }
539  // </CODE>
540  normalize2(scalar_prod[i],
541  scalar_prod_nle,
542  normalized_sp_i,
543  normalized_sp_o);
544  dest_row_type& dest_i = dest.sys.rows[i];
545  neg_assign(normalized_sp_i);
546  dest_i.expr.linear_combine(dest_nle.expr,
547  normalized_sp_o, normalized_sp_i);
548  dest_i.strong_normalize();
549  // The modified row may still not be OK(), so don't assert OK here.
550  // They are all checked at the end of this function.
551  scalar_prod[i] = 0;
552  // dest_sorted has already been set to false.
553  }
554  }
555 
556  // Computing the new pointed cone.
557  // Similarly to what we have done during the computation of
558  // the lineality space, we consider all the remaining rays
559  // (having indexes strictly greater than `num_lines_or_equalities')
560  // that do not saturate the constraint `source_k'. These rays
561  // are positively combined with the ray `dest_nle' so that the
562  // resulting new rays saturate the constraint.
563  for (dimension_type
564  i = num_lines_or_equalities + 1; i < dest_num_rows; ++i) {
565  if (scalar_prod[i] != 0) {
566  // The following fragment optimizes the computation of
567  //
568  // <CODE>
569  // Coefficient scale = scalar_prod[i];
570  // scale.gcd_assign(scalar_prod_nle);
571  // Coefficient normalized_sp_i = scalar_prod[i] / scale;
572  // Coefficient normalized_sp_n = scalar_prod_nle / scale;
573  // for (dimension_type c = dest_num_columns; c-- > 0; ) {
574  // dest[i][c] *= normalized_sp_n;
575  // dest[i][c] -= normalized_sp_i * dest_nle[c];
576  // }
577  // </CODE>
578  normalize2(scalar_prod[i],
579  scalar_prod_nle,
580  normalized_sp_i,
581  normalized_sp_o);
582  dest_row_type& dest_i = dest.sys.rows[i];
583  WEIGHT_BEGIN();
584  neg_assign(normalized_sp_i);
585  dest_i.expr.linear_combine(dest_nle.expr,
586  normalized_sp_o, normalized_sp_i);
587  dest_i.strong_normalize();
588  // The modified row may still not be OK(), so don't assert OK here.
589  // They are all checked at the end of this function.
590  scalar_prod[i] = 0;
591  // `dest_sorted' has already been set to false.
592  WEIGHT_ADD_MUL(41, source_space_dim);
593  }
594  // Check if the client has requested abandoning all expensive
595  // computations. If so, the exception specified by the client
596  // is thrown now.
597  maybe_abandon();
598  }
599  // Since the `scalar_prod_nle' is positive (by construction), it
600  // does not saturate the constraint `source_k'. Therefore, if
601  // the constraint is an inequality, we set to 1 the
602  // corresponding element of `sat' ...
603  Bit_Row& sat_nle = sat[num_lines_or_equalities];
604  if (source_k.is_ray_or_point_or_inequality()) {
605  sat_nle.set(k - redundant_source_rows.size());
606 #if PPL_QUICK_ADJ_TEST
607  ++sat_num_ones[num_lines_or_equalities];
608 #endif // PPL_QUICK_ADJ_TEST
609  }
610  else {
611  // ... otherwise, the constraint is an equality which is
612  // violated by the generator `dest_nle': the generator has to be
613  // removed from `dest_rows'.
614  --dest_num_rows;
615  swap(dest.sys.rows[num_lines_or_equalities],
616  dest.sys.rows[dest_num_rows]);
617  recyclable_dest_rows.resize(recyclable_dest_rows.size() + 1);
618  swap(dest.sys.rows.back(), recyclable_dest_rows.back());
619  dest.sys.rows.pop_back();
620  PPL_ASSERT(dest_num_rows == dest.sys.rows.size());
621 
622  swap(scalar_prod_nle, scalar_prod[dest_num_rows]);
623  swap(sat_nle, sat[dest_num_rows]);
624 #if PPL_QUICK_ADJ_TEST
625  swap(sat_num_ones[num_lines_or_equalities],
626  sat_num_ones[dest_num_rows]);
627 #endif // PPL_QUICK_ADJ_TEST
628  // dest_sorted has already been set to false.
629  }
630  // Finished handling the line or equality case:
631  // continue with next `k'.
632  continue;
633  }
634 
635  // Here all the lines in `dest_rows' saturate the constraint `source_k'.
636  PPL_ASSERT(index_non_zero >= num_lines_or_equalities);
637  // First, we reorder the generators in `dest_rows' as follows:
638  // -# all the lines should have indexes between 0 and
639  // `num_lines_or_equalities' - 1 (this already holds);
640  // -# all the rays that saturate the constraint should have
641  // indexes between `num_lines_or_equalities' and
642  // `lines_or_equal_bound' - 1; these rays form the set Q=.
643  // -# all the rays that have a positive scalar product with the
644  // constraint should have indexes between `lines_or_equal_bound'
645  // and `sup_bound' - 1; these rays form the set Q+.
646  // -# all the rays that have a negative scalar product with the
647  // constraint should have indexes between `sup_bound' and
648  // `dest_num_rows' - 1; these rays form the set Q-.
649  dimension_type lines_or_equal_bound = num_lines_or_equalities;
650  dimension_type inf_bound = dest_num_rows;
651  // While we find saturating generators, we simply increment
652  // `lines_or_equal_bound'.
653  while (inf_bound > lines_or_equal_bound
654  && scalar_prod[lines_or_equal_bound] == 0) {
655  ++lines_or_equal_bound;
656  }
657  dimension_type sup_bound = lines_or_equal_bound;
658  while (inf_bound > sup_bound) {
659  const int sp_sign = sgn(scalar_prod[sup_bound]);
660  if (sp_sign == 0) {
661  // This generator has to be moved in Q=.
662  swap(dest.sys.rows[sup_bound], dest.sys.rows[lines_or_equal_bound]);
663  swap(scalar_prod[sup_bound], scalar_prod[lines_or_equal_bound]);
664  swap(sat[sup_bound], sat[lines_or_equal_bound]);
665 #if PPL_QUICK_ADJ_TEST
666  swap(sat_num_ones[sup_bound], sat_num_ones[lines_or_equal_bound]);
667 #endif // PPL_QUICK_ADJ_TEST
668  ++lines_or_equal_bound;
669  ++sup_bound;
670  dest_sorted = false;
671  }
672  else if (sp_sign < 0) {
673  // This generator has to be moved in Q-.
674  --inf_bound;
675  swap(dest.sys.rows[sup_bound], dest.sys.rows[inf_bound]);
676  swap(sat[sup_bound], sat[inf_bound]);
677  swap(scalar_prod[sup_bound], scalar_prod[inf_bound]);
678 #if PPL_QUICK_ADJ_TEST
679  swap(sat_num_ones[sup_bound], sat_num_ones[inf_bound]);
680 #endif // PPL_QUICK_ADJ_TEST
681  dest_sorted = false;
682  }
683  else {
684  // sp_sign > 0: this generator has to be moved in Q+.
685  ++sup_bound;
686  }
687  }
688 
689  if (sup_bound == dest_num_rows) {
690  // Here the set Q- is empty.
691  // If the constraint is an inequality, then all the generators
692  // in Q= and Q+ satisfy the constraint. The constraint is redundant
693  // and it can be safely removed from the constraint system.
694  // This is why the `source' parameter is not declared `const'.
695  if (source_k.is_ray_or_point_or_inequality()) {
696  redundant_source_rows.push_back(k);
697  }
698  else {
699  // The constraint is an equality, so that all the generators
700  // in Q+ violate it. Since the set Q- is empty, we can simply
701  // remove from `dest_rows' all the generators of Q+.
702  PPL_ASSERT(dest_num_rows >= lines_or_equal_bound);
703  while (dest_num_rows != lines_or_equal_bound) {
704  recyclable_dest_rows.resize(recyclable_dest_rows.size() + 1);
705  swap(dest.sys.rows.back(), recyclable_dest_rows.back());
706  dest.sys.rows.pop_back();
707  --dest_num_rows;
708  }
709  PPL_ASSERT(dest_num_rows == dest.sys.rows.size());
710  }
711  // Finished handling the case when Q- is empty:
712  // continue with next `k'.
713  continue;
714  }
715 
716  // The set Q- is not empty, i.e., at least one generator
717  // violates the constraint `source_k'.
718  if (sup_bound == num_lines_or_equalities) {
719  // The set Q+ is empty, so that all generators that satisfy
720  // the constraint also saturate it.
721  // We can simply remove from `dest_rows' all the generators in Q-.
722  PPL_ASSERT(dest_num_rows >= sup_bound);
723  while (dest_num_rows != sup_bound) {
724  recyclable_dest_rows.resize(recyclable_dest_rows.size() + 1);
725  swap(dest.sys.rows.back(), recyclable_dest_rows.back());
726  dest.sys.rows.pop_back();
727  --dest_num_rows;
728  }
729  PPL_ASSERT(dest_num_rows == dest.sys.rows.size());
730  // Finished handling the case when Q+ is empty:
731  // continue with next `k'.
732  continue;
733  }
734 
735  // The sets Q+ and Q- are both non-empty.
736  // The generators of the new pointed cone are all those satisfying
737  // the constraint `source_k' plus a set of new rays enjoying
738  // the following properties:
739  // -# they lie on the hyper-plane represented by the constraint
740  // -# they are obtained as a positive combination of two
741  // adjacent rays, the first taken from Q+ and the second
742  // taken from Q-.
743 
744  const dimension_type bound = dest_num_rows;
745 
746 #if PPL_QUICK_NON_ADJ_TEST
747  // For the quick non-adjacency test, we refer to the definition
748  // of a minimal proper face (see comments in Polyhedron_defs.hh):
749  // an extremal ray saturates at least `n' - `t' - 1 constraints,
750  // where `n' is the dimension of the space and `t' is the dimension
751  // of the lineality space. Since `n == source_num_columns - 1' and
752  // `t == num_lines_or_equalities', we obtain that an extremal ray
753  // saturates at least `source_num_columns - num_lines_or_equalities - 2'
754  // constraints.
755  const dimension_type min_saturators
756  = source_num_columns - num_lines_or_equalities - 2;
757  // NOTE: we are treating the `k'-th constraint.
758  const dimension_type max_saturators = k - redundant_source_rows.size();
759 #endif // PPL_QUICK_NON_ADJ_TEST
760 
761  // In the following loop,
762  // `i' runs through the generators in the set Q+ and
763  // `j' runs through the generators in the set Q-.
764  for (dimension_type i = lines_or_equal_bound; i < sup_bound; ++i) {
765  for (dimension_type j = sup_bound; j < bound; ++j) {
766  // Checking if generators `dest_rows[i]' and `dest_rows[j]' are
767  // adjacent.
768  // If there exist another generator that saturates
769  // all the constraints saturated by both `dest_rows[i]' and
770  // `dest_rows[j]', then they are NOT adjacent.
771  PPL_ASSERT(sat[i].last() == C_Integer<unsigned long>::max
772  || sat[i].last() < k);
773  PPL_ASSERT(sat[j].last() == C_Integer<unsigned long>::max
774  || sat[j].last() < k);
775 
776  // Being the union of `sat[i]' and `sat[j]',
777  // `new_satrow' corresponds to a ray that saturates all the
778  // constraints saturated by both `dest_rows[i]' and
779  // `dest_rows[j]'.
780  Bit_Row new_satrow(sat[i], sat[j]);
781 
782  // Even before actually creating the new ray as a
783  // positive combination of `dest_rows[i]' and `dest_rows[j]',
784  // we exploit saturation information to perform:
785  // - a quick non-adjacency test;
786  // - a quick adjacency test.
787 
788 #if (PPL_QUICK_NON_ADJ_TEST || PPL_QUICK_ADJ_TEST)
789  // Compute the number of common saturators.
790  dimension_type new_satrow_ones = new_satrow.count_ones();
791 #endif // (PPL_QUICK_NON_ADJ_TEST || PPL_QUICK_ADJ_TEST)
792 
793 #if PPL_QUICK_NON_ADJ_TEST
794  const dimension_type num_common_satur
795  = max_saturators - new_satrow_ones;
796  if (num_common_satur < min_saturators) {
797  // Quick non-adjacency test succeded: consider next `j'.
798  continue;
799  }
800 #endif // PPL_QUICK_NON_ADJ_TEST
801 
802 #if PPL_QUICK_ADJ_TEST
803  // If either `sat[i]' or `sat[j]' has exactly one more zeroes
804  // than `new_satrow', then `dest_rows[i]' and `dest_rows[j]'
805  // are adjacent. Equivalently, adjacency holds if `new_satrow_ones'
806  // is equal to 1 plus the maximum of `sat_num_ones[i]' and
807  // `sat_num_ones[j]'.
808  const dimension_type max_ones_i_j
809  = std::max(sat_num_ones[i], sat_num_ones[j]);
810  if (max_ones_i_j + 1 == new_satrow_ones) {
811  // Quick adjacency test succeded: skip the full test.
812  goto are_adjacent;
813  }
814 #endif // PPL_QUICK_ADJ_TEST
815 
816  // Perform the full (combinatorial) adjacency test.
817  {
818  bool redundant = false;
819  WEIGHT_BEGIN();
820  for (dimension_type l = num_lines_or_equalities; l < bound; ++l) {
821  if (l != i && l != j
822  && subset_or_equal(sat[l], new_satrow)) {
823  // Found another generator saturating all the constraints
824  // saturated by both `dest_rows[i]' and `dest_rows[j]'.
825  redundant = true;
826  break;
827  }
828  }
829  PPL_ASSERT(bound >= num_lines_or_equalities);
830  WEIGHT_ADD_MUL(15, bound - num_lines_or_equalities);
831  if (redundant) {
832  // Full non-adjacency test succeded: consider next `j'.
833  continue;
834  }
835  }
836 
837 #if PPL_QUICK_ADJ_TEST
838  are_adjacent:
839 #endif // PPL_QUICK_ADJ_TEST
840  // Adding the new ray to `dest_rows' and the corresponding
841  // saturation row to `sat'.
842  dest_row_type new_row;
843  if (recyclable_dest_rows.empty()) {
844  sat.add_recycled_row(new_satrow);
845 #if PPL_QUICK_ADJ_TEST
846  sat_num_ones.push_back(new_satrow_ones);
847 #endif // PPL_QUICK_ADJ_TEST
848  }
849  else {
850  swap(new_row, recyclable_dest_rows.back());
851  recyclable_dest_rows.pop_back();
852  new_row.set_space_dimension_no_ok(source_space_dim);
853  swap(sat[dest_num_rows], new_satrow);
854 #if PPL_QUICK_ADJ_TEST
855  swap(sat_num_ones[dest_num_rows], new_satrow_ones);
856 #endif // PPL_QUICK_ADJ_TEST
857  }
858 
859  // The following fragment optimizes the computation of
860  //
861  // <CODE>
862  // Coefficient scale = scalar_prod[i];
863  // scale.gcd_assign(scalar_prod[j]);
864  // Coefficient normalized_sp_i = scalar_prod[i] / scale;
865  // Coefficient normalized_sp_j = scalar_prod[j] / scale;
866  // for (dimension_type c = dest_num_columns; c-- > 0; ) {
867  // new_row[c] = normalized_sp_i * dest[j][c];
868  // new_row[c] -= normalized_sp_j * dest[i][c];
869  // }
870  // </CODE>
871  normalize2(scalar_prod[i],
872  scalar_prod[j],
873  normalized_sp_i,
874  normalized_sp_o);
875  WEIGHT_BEGIN();
876 
877  neg_assign(normalized_sp_o);
878  new_row = dest.sys.rows[j];
879  // TODO: Check if the following assertions hold.
880  PPL_ASSERT(normalized_sp_i != 0);
881  PPL_ASSERT(normalized_sp_o != 0);
882  new_row.expr.linear_combine(dest.sys.rows[i].expr,
883  normalized_sp_i, normalized_sp_o);
884 
885  WEIGHT_ADD_MUL(86, source_space_dim);
886  new_row.strong_normalize();
887  // Don't assert new_row.OK() here, because it may fail if
888  // the parameter `dest' contained a row that wasn't ok.
889  // Since we added a new generator to `dest_rows',
890  // we also add a new element to `scalar_prod';
891  // by construction, the new ray lies on the hyper-plane
892  // represented by the constraint `source_k'.
893  // Thus, the added scalar product is 0.
894  PPL_ASSERT(scalar_prod.size() >= dest_num_rows);
895  if (scalar_prod.size() <= dest_num_rows) {
896  scalar_prod.push_back(Coefficient_zero());
897  }
898  else {
899  scalar_prod[dest_num_rows] = Coefficient_zero();
900  }
901  dest.sys.rows.resize(dest.sys.rows.size() + 1);
902  swap(dest.sys.rows.back(), new_row);
903  // Increment the number of generators.
904  ++dest_num_rows;
905  } // End of loop on `j'.
906  // Check if the client has requested abandoning all expensive
907  // computations. If so, the exception specified by the client
908  // is thrown now.
909  maybe_abandon();
910  } // End of loop on `i'.
911  // Now we substitute the rays in Q- (i.e., the rays violating
912  // the constraint) with the newly added rays.
913  dimension_type j;
914  if (source_k.is_ray_or_point_or_inequality()) {
915  // The constraint is an inequality:
916  // the violating generators are those in Q-.
917  j = sup_bound;
918  // For all the generators in Q+, set to 1 the corresponding
919  // entry for the constraint `source_k' in the saturation matrix.
920 
921  // After the removal of redundant rows in `source', the k-th
922  // row will have index `new_k'.
923  const dimension_type new_k = k - redundant_source_rows.size();
924  for (dimension_type l = lines_or_equal_bound;
925  l < sup_bound; ++l) {
926  sat[l].set(new_k);
927 #if PPL_QUICK_ADJ_TEST
928  ++sat_num_ones[l];
929 #endif // PPL_PPL_QUICK_ADJ_TEST
930  }
931  }
932  else {
933  // The constraint is an equality:
934  // the violating generators are those in the union of Q+ and Q-.
935  j = lines_or_equal_bound;
936  }
937  // Swapping the newly added rays
938  // (index `i' running through `dest_num_rows - 1' down-to `bound')
939  // with the generators violating the constraint
940  // (index `j' running through `j' up-to `bound - 1').
941  dimension_type i = dest_num_rows;
942  while (j < bound && i > bound) {
943  --i;
944  swap(dest.sys.rows[i], dest.sys.rows[j]);
945  swap(scalar_prod[i], scalar_prod[j]);
946  swap(sat[i], sat[j]);
947 #if PPL_QUICK_ADJ_TEST
948  swap(sat_num_ones[i], sat_num_ones[j]);
949 #endif // PPL_QUICK_ADJ_TEST
950  ++j;
951  dest_sorted = false;
952  }
953  // Setting the number of generators in `dest':
954  // - if the number of generators violating the constraint
955  // is less than or equal to the number of the newly added
956  // generators, we assign `i' to `dest_num_rows' because
957  // all generators above this index are significant;
958  // - otherwise, we assign `j' to `dest_num_rows' because
959  // all generators below index `j-1' violates the constraint.
960  const dimension_type new_num_rows = (j == bound) ? i : j;
961  PPL_ASSERT(dest_num_rows >= new_num_rows);
962  while (dest_num_rows != new_num_rows) {
963  recyclable_dest_rows.resize(recyclable_dest_rows.size() + 1);
964  swap(dest.sys.rows.back(), recyclable_dest_rows.back());
965  dest.sys.rows.pop_back();
966  --dest_num_rows;
967  }
968  PPL_ASSERT(dest_num_rows == dest.sys.rows.size());
969  } // End of loop on `k'.
970 
971  // We may have identified some redundant constraints in `source',
972  // which have been swapped at the end of the system.
973  if (redundant_source_rows.size() > 0) {
974  source.remove_rows(redundant_source_rows);
975  sat.remove_trailing_columns(redundant_source_rows.size());
976  }
977 
978  // If `start == 0', then `source' was sorted and remained so.
979  // If otherwise `start > 0', then the two sub-system made by the
980  // non-pending rows and the pending rows, respectively, were both sorted.
981  // Thus, the overall system is sorted if and only if either
982  // `start == source_num_rows' (i.e., the second sub-system is empty)
983  // or the row ordering holds for the two rows at the boundary between
984  // the two sub-systems.
985  if (start > 0 && start < source.num_rows()) {
986  source.set_sorted(compare(source[start - 1], source[start]) <= 0);
987  }
988  // There are no longer pending constraints in `source'.
989  source.unset_pending_rows();
990 
991  // We may have identified some redundant rays in `dest_rows',
992  // which have been swapped into recyclable_dest_rows.
993  if (!recyclable_dest_rows.empty()) {
994  const dimension_type num_removed_rows = recyclable_dest_rows.size();
995  sat.remove_trailing_rows(num_removed_rows);
996  }
997  if (dest_sorted) {
998  // If the non-pending generators in `dest' are still declared to be
999  // sorted, then we have to also check for the sortedness of the
1000  // pending generators.
1001  for (dimension_type i = dest_first_pending_row;
1002  i < dest_num_rows; ++i) {
1003  if (compare(dest.sys.rows[i - 1], dest.sys.rows[i]) > 0) {
1004  dest_sorted = false;
1005  break;
1006  }
1007  }
1008  }
1009 #ifndef NDEBUG
1010  // The previous code can modify the rows' fields, exploiting the friendness.
1011  // Check that all rows are OK now.
1012  for (dimension_type i = dest.num_rows(); i-- > 0; ) {
1013  PPL_ASSERT(dest.sys.rows[i].OK());
1014  }
1015 #endif
1016 
1017  dest.sys.index_first_pending = dest.num_rows();
1018  dest.set_sorted(dest_sorted);
1019  PPL_ASSERT(dest.sys.OK());
1020 
1021  return num_lines_or_equalities;
1022 }
1023 
1024 } // namespace Parma_Polyhedra_Library
1025 
1026 #endif // !defined(PPL_Polyhedron_conversion_templates_hh)
void swap(CO_Tree &x, CO_Tree &y)
size_t dimension_type
An unsigned integral type for representing space dimensions.
dimension_type num_rows() const
Returns the number of rows of *this.
#define PPL_DIRTY_TEMP_COEFFICIENT(id)
Declare a local variable named id, of type Coefficient, and containing an unknown initial value...
void set(unsigned long k)
Sets the bit in position k.
void add_recycled_row(Bit_Row &row)
Adds row to *this.
Definition: Bit_Matrix.cc:74
unsigned long count_ones() const
Returns the number of set bits in the row.
void swap(Polyhedron &x, Polyhedron &y)
Swaps x with y.
A row in a matrix of bits.
static dimension_type conversion(Source_Linear_System &source, dimension_type start, Dest_Linear_System &dest, Bit_Matrix &sat, dimension_type num_lines_or_equalities)
Performs the conversion from constraints to generators and vice versa.
void remove_trailing_columns(dimension_type n)
Removes the last n columns.
#define WEIGHT_ADD_MUL(delta, factor)
Definition: globals_defs.hh:90
PPL_COEFFICIENT_TYPE Coefficient
An alias for easily naming the type of PPL coefficients.
#define WEIGHT_BEGIN()
Definition: globals_defs.hh:81
int compare(const Linear_Expression &x, const Linear_Expression &y)
void remove_trailing_rows(dimension_type n)
Removes the last n rows.
#define PPL_DIRTY_TEMP(T, id)
dimension_type num_columns() const
Returns the number of columns of *this.
void neg_assign(GMP_Integer &x)
Coefficient_traits::const_reference Coefficient_zero()
Returns a const reference to a Coefficient with value 0.
The entire library is confined to this namespace.
Definition: version.hh:61
int sgn(Boundary_Type type, const T &x, const Info &info)
void normalize2(Coefficient_traits::const_reference x, Coefficient_traits::const_reference y, Coefficient &n_x, Coefficient &n_y)
If is the GCD of x and y, the values of x and y divided by are assigned to n_x and n_y...
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.