/* Row class implementation (non-inline functions).
Copyright (C) 2001-2004 Roberto Bagnara <bagnara@cs.unipr.it>
This file is part of the Parma Polyhedra Library (PPL).
The PPL is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
The PPL is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
USA.
For the most up-to-date information see the Parma Polyhedra Library
site: http://www.cs.unipr.it/ppl/ . */
#include <config.h>
#include "Integer.defs.hh"
#include "Row.defs.hh"
#include "globals.hh"
#include <algorithm>
#include <iostream>
namespace PPL = Parma_Polyhedra_Library;
void
PPL::Row::Impl::grow_no_copy(const dimension_type new_sz) {
assert(new_sz >= size());
#if !CXX_SUPPORTS_FLEXIBLE_ARRAYS
// vec[0] is already constructed.
if (size() == 0 && new_sz > 0)
bump_size();
#endif
for (dimension_type i = size(); i < new_sz; ++i) {
new (&vec_[i]) Integer();
bump_size();
}
}
void
PPL::Row::Impl::shrink(const dimension_type new_sz) {
#if !CXX_SUPPORTS_FLEXIBLE_ARRAYS
assert(new_sz > 0);
#endif
assert(new_sz <= size());
// We assume construction was done "forward".
// We thus perform destruction "backward".
for (dimension_type i = size(); i-- > new_sz; )
// ~Integer() does not throw exceptions. So we do.
vec_[i].~Integer();
set_size(new_sz);
}
void
PPL::Row::Impl::copy_construct(const Impl& y) {
const dimension_type y_size = y.size();
#if CXX_SUPPORTS_FLEXIBLE_ARRAYS
for (dimension_type i = 0; i < y_size; ++i) {
new (&vec_[i]) Integer(y.vec_[i]);
bump_size();
}
#else
assert(y_size > 0);
if (y_size > 0) {
vec_[0] = y.vec_[0];
bump_size();
for (dimension_type i = 1; i < y_size; ++i) {
new (&vec_[i]) Integer(y.vec_[i]);
bump_size();
}
}
#endif
}
void
PPL::Row::normalize() {
Row& x = *this;
// Compute the GCD of all the coefficients into tmp_Integer[1].
tmp_Integer[1] = 0;
const dimension_type sz = size();
for (dimension_type i = sz; i-- > 0; ) {
const Integer& x_i = x[i];
if (x_i != 0)
gcd_assign(tmp_Integer[1], x_i);
}
if (tmp_Integer[1] > 1)
// Divide the coefficients by the GCD.
for (dimension_type i = sz; i-- > 0; )
exact_div_assign(x[i], tmp_Integer[1]);
}
void
PPL::Row::sign_normalize() {
if (is_line_or_equality()) {
Row& x = *this;
const dimension_type sz = x.size();
// `first_non_zero' indicates the index of the first
// coefficient of the row different from zero, disregarding
// the very first coefficient (inhomogeneous term / divisor).
dimension_type first_non_zero;
for (first_non_zero = 1; first_non_zero < sz; ++first_non_zero)
if (x[first_non_zero] != 0)
break;
if (first_non_zero < sz)
// If the first non-zero coefficient of the row is negative,
// we negate the entire row.
if (x[first_non_zero] < 0) {
for (dimension_type j = first_non_zero; j < sz; ++j)
negate(x[j]);
// Also negate the first coefficient.
negate(x[0]);
}
}
}
bool
PPL::Row::check_strong_normalized() const {
Row tmp = *this;
tmp.strong_normalize();
return compare(*this, tmp) == 0;
}
/*! \relates Parma_Polyhedra_Library::Row */
int
PPL::compare(const Row& x, const Row& y) {
const bool x_is_line_or_equality = x.is_line_or_equality();
const bool y_is_line_or_equality = y.is_line_or_equality();
if (x_is_line_or_equality != y_is_line_or_equality)
// Equalities (lines) precede inequalities (ray/point).
return y_is_line_or_equality ? 2 : -2;
// Compare all the coefficients of the row starting from position 1.
const dimension_type xsz = x.size();
const dimension_type ysz = y.size();
const dimension_type min_sz = std::min(xsz, ysz);
dimension_type i;
for (i = 1; i < min_sz; ++i)
if (const int comp = cmp(x[i], y[i]))
// There is at least a different coefficient.
return (comp > 0) ? 2 : -2;
// Handle the case where `x' and `y' are of different size.
if (xsz != ysz) {
for( ; i < xsz; ++i)
if (const int sign = sgn(x[i]))
return (sign > 0) ? 2 : -2;
for( ; i < ysz; ++i)
if (const int sign = sgn(y[i]))
return (sign < 0) ? 2 : -2;
}
// If all the coefficients in `x' equal all the coefficients in `y'
// (starting from position 1) we compare coefficients in position 0,
// i.e., inhomogeneous terms.
if (const int comp = cmp(x[0], y[0]))
return (comp > 0) ? 1 : -1;
// `x' and `y' are equal.
return 0;
}
/*! \relates Parma_Polyhedra_Library::Row */
const PPL::Integer&
PPL::operator*(const Row& x, const Row& y) {
// Scalar product is only defined if `x' and `y' are
// dimension-compatible.
assert(x.size() <= y.size());
tmp_Integer[0] = 0;
for (dimension_type i = x.size(); i-- > 0; ) {
// The following two lines optimize the computation
// of tmp_Integer[0] += x[i] * y[i].
tmp_Integer[1] = x[i] * y[i];
tmp_Integer[0] += tmp_Integer[1];
}
return tmp_Integer[0];
}
/*! \relates Parma_Polyhedra_Library::Row */
const PPL::Integer&
PPL::reduced_scalar_product(const Row& x, const Row& y) {
// The reduced scalar product is only defined
// if the topology of `x' is NNC and `y' has enough coefficients.
assert(!x.is_necessarily_closed());
assert(x.size() - 1 <= y.size());
tmp_Integer[0] = 0;
for (dimension_type i = x.size() - 1; i-- > 0; ) {
// The following two lines optimize the computation
// of tmp_Integer[0] += x[i] * y[i].
tmp_Integer[1] = x[i] * y[i];
tmp_Integer[0] += tmp_Integer[1];
}
return tmp_Integer[0];
}
void
PPL::Row::linear_combine(const Row& y, const dimension_type k) {
Row& x = *this;
// We can combine only vector of the same dimension.
assert(x.size() == y.size());
assert(y[k] != 0 && x[k] != 0);
// Let g be the GCD between `x[k]' and `y[k]'.
// For each i the following computes
// x[i] = x[i]*y[k]/g - y[i]*x[k]/g.
gcd_assign(tmp_Integer[1], x[k], y[k]);
exact_div_assign(tmp_Integer[2], x[k], tmp_Integer[1]);
exact_div_assign(tmp_Integer[3], y[k], tmp_Integer[1]);
for (dimension_type i = size(); i-- > 0; )
if (i != k) {
tmp_Integer[4] = x[i] * tmp_Integer[3];
tmp_Integer[5] = y[i] * tmp_Integer[2];
x[i] = tmp_Integer[4] - tmp_Integer[5];
}
x[k] = 0;
x.strong_normalize();
}
bool
PPL::Row::all_homogeneous_terms_are_zero() const {
const Row& x = *this;
for (dimension_type i = x.size(); --i > 0; )
if (x[i] != 0)
return false;
return true;
}
bool
PPL::Row::OK(const dimension_type row_size,
const dimension_type
#if EXTRA_ROW_DEBUG
row_capacity
#endif
) const {
#ifndef NDEBUG
using std::endl;
using std::cerr;
#endif
bool is_broken = false;
#if EXTRA_ROW_DEBUG
# if !CXX_SUPPORTS_FLEXIBLE_ARRAYS
if (capacity_ == 0) {
cerr << "Illegal row capacity: is 0, should be at least 1"
<< endl;
is_broken = true;
}
else if (capacity_ == 1 && row_capacity == 0)
// This is fine.
;
else
# endif
if (capacity_ != row_capacity) {
cerr << "Row capacity mismatch: is " << capacity_
<< ", should be " << row_capacity << "."
<< endl;
is_broken = true;
}
#endif
if (size() != row_size) {
#ifndef NDEBUG
cerr << "Row size mismatch: is " << size()
<< ", should be " << row_size << "."
<< endl;
#endif
is_broken = true;
}
#if EXTRA_ROW_DEBUG
if (capacity_ < size()) {
#ifndef NDEBUG
cerr << "Row is completely broken: capacity is " << capacity_
<< ", size is " << size() << "."
<< endl;
#endif
is_broken = true;
}
#endif
// Topology consistency check.
const dimension_type min_cols = is_necessarily_closed() ? 1 : 2;
if (size() < min_cols) {
#ifndef NDEBUG
cerr << "Row has fewer coefficeints than the minumum "
<< "allowed by its topology:"
<< endl
<< "size is " << size()
<< ", minimum is " << min_cols << "."
<< endl;
#endif
is_broken = true;
}
return !is_broken;
}
syntax highlighted by Code2HTML, v. 0.9.1