00001 /* Polyhedron class implementation: conversion(). 00002 Copyright (C) 2001-2010 Roberto Bagnara <bagnara@cs.unipr.it> 00003 Copyright (C) 2010-2011 BUGSENG srl (http://bugseng.com) 00004 00005 This file is part of the Parma Polyhedra Library (PPL). 00006 00007 The PPL is free software; you can redistribute it and/or modify it 00008 under the terms of the GNU General Public License as published by the 00009 Free Software Foundation; either version 3 of the License, or (at your 00010 option) any later version. 00011 00012 The PPL is distributed in the hope that it will be useful, but WITHOUT 00013 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 00014 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 00015 for more details. 00016 00017 You should have received a copy of the GNU General Public License 00018 along with this program; if not, write to the Free Software Foundation, 00019 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307, USA. 00020 00021 For the most up-to-date information see the Parma Polyhedra Library 00022 site: http://www.cs.unipr.it/ppl/ . */ 00023 00024 #include <ppl-config.h> 00025 00026 #include "Linear_Row.defs.hh" 00027 #include "Linear_System.defs.hh" 00028 #include "Bit_Row.defs.hh" 00029 #include "Bit_Matrix.defs.hh" 00030 #include "Polyhedron.defs.hh" 00031 #include "Scalar_Products.defs.hh" 00032 #include "Temp.defs.hh" 00033 #include <cstddef> 00034 #include <climits> 00035 00036 namespace PPL = Parma_Polyhedra_Library; 00037 00347 PPL::dimension_type 00348 PPL::Polyhedron::conversion(Linear_System& source, 00349 const dimension_type start, 00350 Linear_System& dest, 00351 Bit_Matrix& sat, 00352 dimension_type num_lines_or_equalities) { 00353 dimension_type source_num_rows = source.num_rows(); 00354 dimension_type dest_num_rows = dest.num_rows(); 00355 const dimension_type source_num_columns = source.num_columns(); 00356 const dimension_type dest_num_columns = dest.num_columns(); 00357 00358 // By construction, the number of columns of `sat' is the same as 00359 // the number of rows of `source'; also, the number of rows of `sat' 00360 // is the same as the number of rows of `dest'. 00361 PPL_ASSERT(source_num_rows == sat.num_columns()); 00362 PPL_ASSERT(dest_num_rows == sat.num_rows()); 00363 00364 // If `start > 0', then we are converting the pending constraints. 00365 PPL_ASSERT(start == 0 || start == source.first_pending_row()); 00366 00367 // During the iteration on the constraints in `source' we may identify 00368 // constraints that are redundant: these have to be removed by swapping 00369 // the rows of `source', taking care not to compromise the sortedness 00370 // of the constraints that still have to be considered. 00371 // To this end, the following counter keeps the number of redundant 00372 // constraints seen so far, to be used as a displacement when swapping rows. 00373 dimension_type source_num_redundant = 0; 00374 00375 PPL_DIRTY_TEMP_COEFFICIENT(normalized_sp_i); 00376 PPL_DIRTY_TEMP_COEFFICIENT(normalized_sp_o); 00377 00378 // Converting the sub-system of `source' having rows with indexes 00379 // from `start' to the last one (i.e., `source_num_rows' - 1). 00380 for (dimension_type k = start; k < source_num_rows; ) { 00381 00382 // All the `source_num_redundant' redundant constraints identified so far 00383 // have consecutive indices starting from `k'. 00384 if (source_num_redundant > 0) 00385 // Let the next constraint have index `k'. 00386 // There is no need to swap the columns of `sat' (all zeroes). 00387 std::swap(source[k], source[k+source_num_redundant]); 00388 00389 Linear_Row& source_k = source[k]; 00390 00391 // Constraints and generators must have the same dimension, 00392 // otherwise the scalar product below will bomb. 00393 PPL_ASSERT(source_num_columns == dest_num_columns); 00394 00395 // `scalar_prod[i]' will contain the scalar product of the 00396 // constraint `source_k' and the generator `dest[i]'. This 00397 // product is 0 if and only if the generator saturates the 00398 // constraint. 00399 PPL_DIRTY_TEMP0(std::vector<Coefficient>, scalar_prod); 00400 const int needed_space = dest_num_rows - scalar_prod.size(); 00401 if (needed_space > 0) 00402 scalar_prod.insert(scalar_prod.end(), needed_space, Coefficient_zero()); 00403 // `index_non_zero' will indicate the first generator in `dest' 00404 // that does not saturate the constraint `source_k'. 00405 dimension_type index_non_zero = 0; 00406 for ( ; index_non_zero < dest_num_rows; ++index_non_zero) { 00407 WEIGHT_BEGIN(); 00408 Scalar_Products::assign(scalar_prod[index_non_zero], 00409 source_k, 00410 dest[index_non_zero]); 00411 WEIGHT_ADD_MUL(17, source_num_columns); 00412 if (scalar_prod[index_non_zero] != 0) 00413 // The generator does not saturate the constraint. 00414 break; 00415 // Check if the client has requested abandoning all expensive 00416 // computations. If so, the exception specified by the client 00417 // is thrown now. 00418 maybe_abandon(); 00419 } 00420 for (dimension_type i = index_non_zero + 1; i < dest_num_rows; ++i) { 00421 WEIGHT_BEGIN(); 00422 Scalar_Products::assign(scalar_prod[i], source_k, dest[i]); 00423 WEIGHT_ADD_MUL(25, source_num_columns); 00424 // Check if the client has requested abandoning all expensive 00425 // computations. If so, the exception specified by the client 00426 // is thrown now. 00427 maybe_abandon(); 00428 } 00429 00430 // We first treat the case when `index_non_zero' is less than 00431 // `num_lines_or_equalities', i.e., when the generator that 00432 // does not saturate the constraint `source_k' is a line. 00433 // The other case (described later) is when all the lines 00434 // in `dest' (i.e., all the rows having indexes less than 00435 // `num_lines_or_equalities') do saturate the constraint. 00436 00437 if (index_non_zero < num_lines_or_equalities) { 00438 // Since the generator `dest[index_non_zero]' does not saturate 00439 // the constraint `source_k', it can no longer be a line 00440 // (see saturation rule in Section \ref prelims). 00441 // Therefore, we first transform it to a ray. 00442 dest[index_non_zero].set_is_ray_or_point_or_inequality(); 00443 // Of the two possible choices, we select the ray satisfying 00444 // the constraint (namely, the ray whose scalar product 00445 // with the constraint gives a positive result). 00446 if (scalar_prod[index_non_zero] < 0) { 00447 // The ray `dest[index_non_zero]' lies on the wrong half-space: 00448 // we change it to have the opposite direction. 00449 neg_assign(scalar_prod[index_non_zero]); 00450 for (dimension_type j = dest_num_columns; j-- > 0; ) 00451 neg_assign(dest[index_non_zero][j]); 00452 } 00453 // Having changed a line to a ray, we set `dest' to be a 00454 // non-sorted system, we decrement the number of lines of `dest' and, 00455 // if necessary, we move the new ray below all the remaining lines. 00456 dest.set_sorted(false); 00457 --num_lines_or_equalities; 00458 if (index_non_zero != num_lines_or_equalities) { 00459 std::swap(dest[index_non_zero], 00460 dest[num_lines_or_equalities]); 00461 std::swap(scalar_prod[index_non_zero], 00462 scalar_prod[num_lines_or_equalities]); 00463 } 00464 Linear_Row& dest_nle = dest[num_lines_or_equalities]; 00465 00466 // Computing the new lineality space. 00467 // Since each line must lie on the hyper-plane corresponding to 00468 // the constraint `source_k', the scalar product between 00469 // the line and the constraint must be 0. 00470 // This property already holds for the lines having indexes 00471 // between 0 and `index_non_zero' - 1. 00472 // We have to consider the remaining lines, having indexes 00473 // between `index_non_zero' and `num_lines_or_equalities' - 1. 00474 // Each line that does not saturate the constraint has to be 00475 // linearly combined with generator `dest_nle' so that the 00476 // resulting new line saturates the constraint. 00477 // Note that, by Observation 1 above, the resulting new line 00478 // will still saturate all the constraints that were saturated by 00479 // the old line. 00480 00481 Coefficient& scalar_prod_nle = scalar_prod[num_lines_or_equalities]; 00482 for (dimension_type 00483 i = index_non_zero; i < num_lines_or_equalities; ++i) { 00484 if (scalar_prod[i] != 0) { 00485 // The following fragment optimizes the computation of 00486 // 00487 // Coefficient scale = scalar_prod[i]; 00488 // scale.gcd_assign(scalar_prod_nle); 00489 // Coefficient normalized_sp_i = scalar_prod[i] / scale; 00490 // Coefficient normalized_sp_n = scalar_prod_nle / scale; 00491 // for (dimension_type c = dest_num_columns; c-- > 0; ) { 00492 // dest[i][c] *= normalized_sp_n; 00493 // dest[i][c] -= normalized_sp_i * dest_nle[c]; 00494 // } 00495 normalize2(scalar_prod[i], 00496 scalar_prod_nle, 00497 normalized_sp_i, 00498 normalized_sp_o); 00499 Linear_Row& dest_i = dest[i]; 00500 for (dimension_type c = dest_num_columns; c-- > 0; ) { 00501 Coefficient& dest_i_c = dest_i[c]; 00502 dest_i_c *= normalized_sp_o; 00503 sub_mul_assign(dest_i_c, normalized_sp_i, dest_nle[c]); 00504 } 00505 dest_i.strong_normalize(); 00506 scalar_prod[i] = 0; 00507 // `dest' has already been set as non-sorted. 00508 } 00509 } 00510 00511 // Computing the new pointed cone. 00512 // Similarly to what we have done during the computation of 00513 // the lineality space, we consider all the remaining rays 00514 // (having indexes strictly greater than `num_lines_or_equalities') 00515 // that do not saturate the constraint `source_k'. These rays 00516 // are positively combined with the ray `dest_nle' so that the 00517 // resulting new rays saturate the constraint. 00518 for (dimension_type 00519 i = num_lines_or_equalities + 1; i < dest_num_rows; ++i) { 00520 if (scalar_prod[i] != 0) { 00521 // The following fragment optimizes the computation of 00522 // 00523 // Coefficient scale = scalar_prod[i]; 00524 // scale.gcd_assign(scalar_prod_nle); 00525 // Coefficient normalized_sp_i = scalar_prod[i] / scale; 00526 // Coefficient normalized_sp_n = scalar_prod_nle / scale; 00527 // for (dimension_type c = dest_num_columns; c-- > 0; ) { 00528 // dest[i][c] *= normalized_sp_n; 00529 // dest[i][c] -= normalized_sp_i * dest_nle[c]; 00530 // } 00531 normalize2(scalar_prod[i], 00532 scalar_prod_nle, 00533 normalized_sp_i, 00534 normalized_sp_o); 00535 Linear_Row& dest_i = dest[i]; 00536 WEIGHT_BEGIN(); 00537 for (dimension_type c = dest_num_columns; c-- > 0; ) { 00538 Coefficient& dest_i_c = dest_i[c]; 00539 dest_i_c *= normalized_sp_o; 00540 sub_mul_assign(dest_i_c, normalized_sp_i, dest_nle[c]); 00541 } 00542 dest_i.strong_normalize(); 00543 scalar_prod[i] = 0; 00544 // `dest' has already been set as non-sorted. 00545 WEIGHT_ADD_MUL(41, dest_num_columns); 00546 } 00547 // Check if the client has requested abandoning all expensive 00548 // computations. If so, the exception specified by the client 00549 // is thrown now. 00550 maybe_abandon(); 00551 } 00552 // Since the `scalar_prod_nle' is positive (by construction), it 00553 // does not saturate the constraint `source_k'. Therefore, if 00554 // the constraint is an inequality, we set to 1 the 00555 // corresponding element of `sat' ... 00556 Bit_Row& sat_nle = sat[num_lines_or_equalities]; 00557 if (source_k.is_ray_or_point_or_inequality()) 00558 sat_nle.set(k); 00559 // ... otherwise, the constraint is an equality which is 00560 // violated by the generator `dest_nle': the generator has to be 00561 // removed from `dest'. 00562 else { 00563 --dest_num_rows; 00564 std::swap(dest_nle, dest[dest_num_rows]); 00565 std::swap(scalar_prod_nle, scalar_prod[dest_num_rows]); 00566 std::swap(sat_nle, sat[dest_num_rows]); 00567 // `dest' has already been set as non-sorted. 00568 } 00569 // We continue with the next constraint. 00570 ++k; 00571 } 00572 // Here we have `index_non_zero' >= `num_lines_or_equalities', 00573 // so that all the lines in `dest' saturate the constraint `source_k'. 00574 else { 00575 // First, we reorder the generators in `dest' as follows: 00576 // -# all the lines should have indexes between 0 and 00577 // `num_lines_or_equalities' - 1 (this already holds); 00578 // -# all the rays that saturate the constraint should have 00579 // indexes between `num_lines_or_equalities' and 00580 // `lines_or_equal_bound' - 1; these rays form the set Q=. 00581 // -# all the rays that have a positive scalar product with the 00582 // constraint should have indexes between `lines_or_equal_bound' 00583 // and `sup_bound' - 1; these rays form the set Q+. 00584 // -# all the rays that have a negative scalar product with the 00585 // constraint should have indexes between `sup_bound' and 00586 // `dest_num_rows' - 1; these rays form the set Q-. 00587 dimension_type lines_or_equal_bound = num_lines_or_equalities; 00588 dimension_type inf_bound = dest_num_rows; 00589 // While we find saturating generators, we simply increment 00590 // `lines_or_equal_bound'. 00591 while (inf_bound > lines_or_equal_bound 00592 && scalar_prod[lines_or_equal_bound] == 0) 00593 ++lines_or_equal_bound; 00594 dimension_type sup_bound = lines_or_equal_bound; 00595 while (inf_bound > sup_bound) { 00596 const int sp_sign = sgn(scalar_prod[sup_bound]); 00597 if (sp_sign == 0) { 00598 // This generator has to be moved in Q=. 00599 std::swap(dest[sup_bound], dest[lines_or_equal_bound]); 00600 std::swap(scalar_prod[sup_bound], scalar_prod[lines_or_equal_bound]); 00601 std::swap(sat[sup_bound], sat[lines_or_equal_bound]); 00602 ++lines_or_equal_bound; 00603 ++sup_bound; 00604 dest.set_sorted(false); 00605 } 00606 else if (sp_sign < 0) { 00607 // This generator has to be moved in Q-. 00608 --inf_bound; 00609 std::swap(dest[sup_bound], dest[inf_bound]); 00610 std::swap(scalar_prod[sup_bound], scalar_prod[inf_bound]); 00611 std::swap(sat[sup_bound], sat[inf_bound]); 00612 dest.set_sorted(false); 00613 } 00614 else 00615 // sp_sign > 0: this generator has to be moved in Q+. 00616 ++sup_bound; 00617 } 00618 00619 if (sup_bound == dest_num_rows) { 00620 // Here the set Q- is empty. 00621 // If the constraint is an inequality, then all the generators 00622 // in Q= and Q+ satisfy the constraint. The constraint is redundant 00623 // and it can be safely removed from the constraint system. 00624 // This is why the `source' parameter is not declared `const'. 00625 if (source_k.is_ray_or_point_or_inequality()) { 00626 ++source_num_redundant; 00627 --source_num_rows; 00628 // NOTE: we continue with the next cycle of the loop 00629 // without incrementing the index `k', because: 00630 // -# either `k == source_num_rows', and we will exit the loop; 00631 // -# or, having increased `source_num_redundant', we will swap 00632 // in position `k' a constraint that still has to be examined. 00633 } 00634 else { 00635 // The constraint is an equality, so that all the generators 00636 // in Q+ violate it. Since the set Q- is empty, we can simply 00637 // remove from `dest' all the generators of Q+. 00638 dest_num_rows = lines_or_equal_bound; 00639 // We continue with the next constraint. 00640 ++k; 00641 } 00642 } 00643 else { 00644 // The set Q- is not empty, i.e., at least one generator 00645 // violates the constraint `source_k'. 00646 // We have to further distinguish two cases: 00647 if (sup_bound == num_lines_or_equalities) 00648 // The set Q+ is empty, so that all generators that satisfy 00649 // the constraint also saturate it. 00650 // We can simply remove from `dest' all the generators in Q-. 00651 dest_num_rows = sup_bound; 00652 else { 00653 // The sets Q+ and Q- are both non-empty. 00654 // The generators of the new pointed cone are all those satisfying 00655 // the constraint `source_k' plus a set of new rays enjoying 00656 // the following properties: 00657 // -# they lie on the hyper-plane represented by the constraint 00658 // -# they are obtained as a positive combination of two 00659 // adjacent rays, the first taken from Q+ and the second 00660 // taken from Q-. 00661 00662 // The adjacency property is necessary to have an irredundant 00663 // set of new rays (see proposition 2). 00664 const dimension_type bound = dest_num_rows; 00665 00666 // In the following loop, 00667 // `i' runs through the generators in the set Q+ and 00668 // `j' runs through the generators in the set Q-. 00669 for (dimension_type i = lines_or_equal_bound; i < sup_bound; ++i) { 00670 for(dimension_type j = sup_bound; j < bound; ++j) { 00671 // Checking if generators `dest[i]' and `dest[j]' are adjacent. 00672 // If there exist another generator that saturates 00673 // all the constraints saturated by both `dest[i]' and 00674 // `dest[j]', then they are NOT adjacent. 00675 PPL_ASSERT(sat[i].last() == ULONG_MAX || sat[i].last() < k); 00676 PPL_ASSERT(sat[j].last() == ULONG_MAX || sat[j].last() < k); 00677 00678 // Being the union of `sat[i]' and `sat[j]', 00679 // `new_satrow' corresponds to a ray that saturates all the 00680 // constraints saturated by both `dest[i]' and `dest[j]'. 00681 Bit_Row new_satrow(sat[i], sat[j]); 00682 00683 // Compute the number of common saturators. 00684 // NOTE: this number has to be less than `k' because 00685 // we are treating the `k'-th constraint. 00686 const dimension_type 00687 num_common_satur = k - new_satrow.count_ones(); 00688 00689 // Even before actually creating the new ray as a 00690 // positive combination of `dest[i]' and `dest[j]', 00691 // we exploit saturation information to check if 00692 // it can be an extremal ray. To this end, we refer 00693 // to the definition of a minimal proper face 00694 // (see comments in Polyhedron.defs.hh): 00695 // an extremal ray saturates at least `n' - `t' - 1 00696 // constraints, where `n' is the dimension of the space 00697 // and `t' is the dimension of the lineality space. 00698 // Since `n == source_num_columns - 1' and 00699 // `t == num_lines_or_equalities', we obtain that 00700 // an extremal ray saturates at least 00701 // `source_num_columns - num_lines_or_equalities - 2' 00702 // constraints. 00703 if (num_common_satur 00704 >= source_num_columns - num_lines_or_equalities - 2) { 00705 // The minimal proper face rule is satisfied. 00706 // Now we actually check for redundancy by computing 00707 // adjacency information. 00708 bool redundant = false; 00709 WEIGHT_BEGIN(); 00710 for (dimension_type 00711 l = num_lines_or_equalities; l < bound; ++l) 00712 if (l != i && l != j 00713 && subset_or_equal(sat[l], new_satrow)) { 00714 // Found another generator saturating all the 00715 // constraints saturated by both `dest[i]' and `dest[j]'. 00716 redundant = true; 00717 break; 00718 } 00719 PPL_ASSERT(bound >= num_lines_or_equalities); 00720 WEIGHT_ADD_MUL(15, bound - num_lines_or_equalities); 00721 if (!redundant) { 00722 // Adding the new ray to `dest' and the corresponding 00723 // saturation row to `sat'. 00724 if (dest_num_rows == dest.num_rows()) { 00725 // Make room for one more row. 00726 dest.add_pending_row(Linear_Row::Flags(dest.topology(), 00727 Linear_Row::RAY_OR_POINT_OR_INEQUALITY)); 00728 sat.add_recycled_row(new_satrow); 00729 } 00730 else 00731 sat[dest_num_rows].swap(new_satrow); 00732 00733 Linear_Row& new_row = dest[dest_num_rows]; 00734 // The following fragment optimizes the computation of 00735 // 00736 // Coefficient scale = scalar_prod[i]; 00737 // scale.gcd_assign(scalar_prod[j]); 00738 // Coefficient normalized_sp_i = scalar_prod[i] / scale; 00739 // Coefficient normalized_sp_j = scalar_prod[j] / scale; 00740 // for (dimension_type c = dest_num_columns; c-- > 0; ) { 00741 // new_row[c] = normalized_sp_i * dest[j][c]; 00742 // new_row[c] -= normalized_sp_j * dest[i][c]; 00743 // } 00744 normalize2(scalar_prod[i], 00745 scalar_prod[j], 00746 normalized_sp_i, 00747 normalized_sp_o); 00748 WEIGHT_BEGIN(); 00749 for (dimension_type c = dest_num_columns; c-- > 0; ) { 00750 Coefficient& new_row_c = new_row[c]; 00751 new_row_c = normalized_sp_i * dest[j][c]; 00752 sub_mul_assign(new_row_c, normalized_sp_o, dest[i][c]); 00753 } 00754 WEIGHT_ADD_MUL(86, dest_num_columns); 00755 new_row.strong_normalize(); 00756 // Since we added a new generator to `dest', 00757 // we also add a new element to `scalar_prod'; 00758 // by construction, the new ray lies on the hyper-plane 00759 // represented by the constraint `source_k'. 00760 // Thus, the added scalar product is 0. 00761 PPL_ASSERT(scalar_prod.size() >= dest_num_rows); 00762 if (scalar_prod.size() <= dest_num_rows) 00763 scalar_prod.push_back(Coefficient_zero()); 00764 else 00765 scalar_prod[dest_num_rows] = Coefficient_zero(); 00766 // Increment the number of generators. 00767 ++dest_num_rows; 00768 } // if (!redundant) 00769 } 00770 } 00771 // Check if the client has requested abandoning all expensive 00772 // computations. If so, the exception specified by the client 00773 // is thrown now. 00774 maybe_abandon(); 00775 } 00776 // Now we substitute the rays in Q- (i.e., the rays violating 00777 // the constraint) with the newly added rays. 00778 dimension_type j; 00779 if (source_k.is_ray_or_point_or_inequality()) { 00780 // The constraint is an inequality: 00781 // the violating generators are those in Q-. 00782 j = sup_bound; 00783 // For all the generators in Q+, set to 1 the corresponding 00784 // entry for the constraint `source_k' in the saturation matrix. 00785 for (dimension_type l = lines_or_equal_bound; l < sup_bound; ++l) 00786 sat[l].set(k); 00787 } 00788 else 00789 // The constraint is an equality: 00790 // the violating generators are those in the union of Q+ and Q-. 00791 j = lines_or_equal_bound; 00792 00793 // Swapping the newly added rays 00794 // (index `i' running through `dest_num_rows - 1' down-to `bound') 00795 // with the generators violating the constraint 00796 // (index `j' running through `j' up-to `bound - 1'). 00797 dimension_type i = dest_num_rows; 00798 while (j < bound && i > bound) { 00799 --i; 00800 std::swap(dest[i], dest[j]); 00801 std::swap(scalar_prod[i], scalar_prod[j]); 00802 std::swap(sat[i], sat[j]); 00803 ++j; 00804 dest.set_sorted(false); 00805 } 00806 // Setting the number of generators in `dest': 00807 // - if the number of generators violating the constraint 00808 // is less than or equal to the number of the newly added 00809 // generators, we assign `i' to `dest_num_rows' because 00810 // all generators above this index are significant; 00811 // - otherwise, we assign `j' to `dest_num_rows' because 00812 // all generators below index `j-1' violates the constraint. 00813 dest_num_rows = (j == bound) ? i : j; 00814 } 00815 // We continue with the next constraint. 00816 ++k; 00817 } 00818 } 00819 } 00820 00821 // We may have identified some redundant constraints in `source', 00822 // which have been swapped at the end of the system. 00823 if (source_num_redundant > 0) { 00824 PPL_ASSERT(source_num_redundant == source.num_rows() - source_num_rows); 00825 source.erase_to_end(source_num_rows); 00826 sat.columns_erase_to_end(source_num_rows); 00827 } 00828 // If `start == 0', then `source' was sorted and remained so. 00829 // If otherwise `start > 0', then the two sub-system made by the 00830 // non-pending rows and the pending rows, respectively, were both sorted. 00831 // Thus, the overall system is sorted if and only if either 00832 // `start == source_num_rows' (i.e., the second sub-system is empty) 00833 // or the row ordering holds for the two rows at the boundary between 00834 // the two sub-systems. 00835 if (start > 0 && start < source_num_rows) 00836 source.set_sorted(compare(source[start - 1], source[start]) <= 0); 00837 // There are no longer pending constraints in `source'. 00838 source.unset_pending_rows(); 00839 00840 // We may have identified some redundant rays in `dest', 00841 // which have been swapped at the end of the system. 00842 if (dest_num_rows < dest.num_rows()) { 00843 dest.erase_to_end(dest_num_rows); 00844 // Be careful: we might have erased some of the non-pending rows. 00845 if (dest.first_pending_row() > dest_num_rows) 00846 dest.unset_pending_rows(); 00847 sat.rows_erase_to_end(dest_num_rows); 00848 } 00849 if (dest.is_sorted()) 00850 // If the non-pending generators in `dest' are still declared to be 00851 // sorted, then we have to also check for the sortedness of the 00852 // pending generators. 00853 for (dimension_type i = dest.first_pending_row(); i < dest_num_rows; ++i) 00854 if (compare(dest[i - 1], dest[i]) > 0) { 00855 dest.set_sorted(false); 00856 break; 00857 } 00858 // There are no pending generators in `dest'. 00859 dest.unset_pending_rows(); 00860 00861 return num_lines_or_equalities; 00862 }
1.6.3