00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include <ppl-config.h>
00025
00026 #include "Congruence.defs.hh"
00027
00028 #include "Variable.defs.hh"
00029 #include "assert.hh"
00030 #include <iostream>
00031 #include <sstream>
00032 #include <stdexcept>
00033 #include <string>
00034
00035 namespace PPL = Parma_Polyhedra_Library;
00036
00037 PPL::Congruence::Congruence(const Constraint& c)
00038 : Row(c.is_equality()
00039 ? c
00040 : (throw_invalid_argument("Congruence(c)",
00041 "constraint c must be an equality."),
00042 c),
00043 c.space_dimension() + 2,
00044 compute_capacity(c.space_dimension() + 2, Row::max_size())) {
00045 (*this)[size()-1] = 0;
00046 }
00047
00048 PPL::Congruence::Congruence(const Constraint& c,
00049 dimension_type sz, dimension_type capacity)
00050 : Row(c.is_equality()
00051 ? c
00052 : (throw_invalid_argument("Congruence(c)",
00053 "constraint c must be an equality."),
00054 c),
00055 sz,
00056 capacity) {
00057 PPL_ASSERT(sz > 1);
00058 (*this)[sz-1] = 0;
00059 }
00060
00061 void
00062 PPL::Congruence::sign_normalize() {
00063 Row& x = *this;
00064 const dimension_type sz = x.size() - 1;
00065
00066
00067
00068 dimension_type first_non_zero;
00069 for (first_non_zero = 1; first_non_zero < sz; ++first_non_zero)
00070 if (x[first_non_zero] != 0)
00071 break;
00072 if (first_non_zero < sz)
00073
00074
00075 if (x[first_non_zero] < 0) {
00076 for (dimension_type j = first_non_zero; j < sz; ++j)
00077 neg_assign(x[j]);
00078
00079 neg_assign(x[0]);
00080 }
00081 }
00082
00083 void
00084 PPL::Congruence::normalize() {
00085 sign_normalize();
00086
00087 dimension_type sz = size();
00088 if (sz == 0)
00089 return;
00090
00091 const Coefficient& mod = modulus();
00092 if (mod == 0)
00093 return;
00094
00095 Coefficient& row_0 = (*this)[0];
00096
00097 row_0 %= mod;
00098 if (row_0 < 0)
00099
00100 row_0 += mod;
00101 return;
00102 }
00103
00104 void
00105 PPL::Congruence::strong_normalize() {
00106 normalize();
00107 Row::normalize();
00108 }
00109
00110 PPL::Congruence
00111 PPL::Congruence::create(const Linear_Expression& e1,
00112 const Linear_Expression& e2) {
00113
00114 dimension_type dim, e1_dim, e2_dim;
00115 e1_dim = e1.space_dimension();
00116 e2_dim = e2.space_dimension();
00117 if (e1_dim > e2_dim)
00118 dim = e1_dim;
00119 else
00120 dim = e2_dim;
00121 Linear_Expression diff(e1_dim > e2_dim ? e1 : e2,
00122 dim + 2);
00123 diff -= (e1_dim > e2_dim ? e2 : e1);
00124 Congruence cg(diff, 1);
00125 return cg;
00126 }
00127
00128 void
00129 PPL::Congruence::throw_invalid_argument(const char* method,
00130 const char* message) const {
00131 std::ostringstream s;
00132 s << "PPL::Congruence::" << method << ":" << std::endl
00133 << message;
00134 throw std::invalid_argument(s.str());
00135 }
00136
00137 void
00138 PPL::Congruence::throw_dimension_incompatible(const char* method,
00139 const char* v_name,
00140 const Variable v) const {
00141 std::ostringstream s;
00142 s << "this->space_dimension() == " << space_dimension() << ", "
00143 << v_name << ".space_dimension() == " << v.space_dimension() << ".";
00144 std::string str = s.str();
00145 throw_invalid_argument(method, str.c_str());
00146 }
00147
00149 std::ostream&
00150 PPL::IO_Operators::operator<<(std::ostream& s, const Congruence& c) {
00151 const dimension_type num_variables = c.space_dimension();
00152 PPL_DIRTY_TEMP_COEFFICIENT(cv);
00153 bool first = true;
00154 for (dimension_type v = 0; v < num_variables; ++v) {
00155 cv = c.coefficient(Variable(v));
00156 if (cv != 0) {
00157 if (!first) {
00158 if (cv > 0)
00159 s << " + ";
00160 else {
00161 s << " - ";
00162 neg_assign(cv);
00163 }
00164 }
00165 else
00166 first = false;
00167 if (cv == -1)
00168 s << "-";
00169 else if (cv != 1)
00170 s << cv << "*";
00171 s << PPL::Variable(v);
00172 }
00173 }
00174 if (first)
00175 s << Coefficient_zero();
00176 s << " = " << -c.inhomogeneous_term();
00177 if (c.is_proper_congruence())
00178 s << " (mod " << c.modulus() << ")";
00179 return s;
00180 }
00181
00182 bool
00183 PPL::Congruence::is_tautological() const {
00184 if ((is_equality() && inhomogeneous_term() == 0)
00185 || (is_proper_congruence()
00186 && (inhomogeneous_term() % modulus() == 0))) {
00187 for (unsigned i = space_dimension(); i > 0; --i)
00188 if (operator[](i) != 0)
00189 return false;
00190 return true;
00191 }
00192 return false;
00193 }
00194
00195 bool
00196 PPL::Congruence::is_inconsistent() const {
00197 if (inhomogeneous_term() == 0
00198 || (is_proper_congruence()
00199 && ((inhomogeneous_term() % modulus()) == 0)))
00200 return false;
00201 for (unsigned i = space_dimension(); i > 0; --i)
00202 if (operator[](i) != 0)
00203 return false;
00204 return true;
00205 }
00206
00207 void
00208 PPL::Congruence::ascii_dump(std::ostream& s) const {
00209 const Row& x = *this;
00210 const dimension_type x_size = x.size();
00211 s << "size " << x_size << " ";
00212 if (x_size > 0) {
00213 for (dimension_type i = 0; i < x_size - 1; ++i)
00214 s << x[i] << ' ';
00215 s << "m " << x[x_size - 1];
00216 }
00217 s << std::endl;
00218 }
00219
00220 PPL_OUTPUT_DEFINITIONS(Congruence)
00221
00222 bool
00223 PPL::Congruence::ascii_load(std::istream& s) {
00224 std::string str;
00225 if (!(s >> str) || str != "size")
00226 return false;
00227 dimension_type new_size;
00228 if (!(s >> new_size))
00229 return false;
00230
00231 Row& x = *this;
00232 const dimension_type old_size = x.size();
00233 if (new_size < old_size)
00234 x.shrink(new_size);
00235 else if (new_size > old_size) {
00236 Row y(new_size, Row::Flags());
00237 x.swap(y);
00238 }
00239
00240 if (new_size > 0) {
00241 for (dimension_type col = 0; col < new_size - 1; ++col)
00242 if (!(s >> x[col]))
00243 return false;
00244 if (!(s >> str) || str != "m")
00245 return false;
00246 if (!(s >> x[new_size-1]))
00247 return false;
00248 }
00249 return true;
00250 }
00251
00252 bool
00253 PPL::Congruence::OK() const {
00254
00255 if (!Row::OK())
00256 return false;
00257
00258
00259 if (modulus() < 0) {
00260 #ifndef NDEBUG
00261 std::cerr << "Congruence has a negative modulus " << modulus() << "."
00262 << std::endl;
00263 #endif
00264 return false;
00265 }
00266
00267
00268 return true;
00269 }
00270
00271 const PPL::Congruence* PPL::Congruence::zero_dim_false_p = 0;
00272 const PPL::Congruence* PPL::Congruence::zero_dim_integrality_p = 0;
00273
00274 void
00275 PPL::Congruence::initialize() {
00276 PPL_ASSERT(zero_dim_false_p == 0);
00277 zero_dim_false_p
00278 = new Congruence((Linear_Expression::zero() %= Coefficient(-1)) / 0);
00279
00280 PPL_ASSERT(zero_dim_integrality_p == 0);
00281 zero_dim_integrality_p
00282 = new Congruence(Linear_Expression::zero() %= Coefficient(-1));
00283 }
00284
00285 void
00286 PPL::Congruence::finalize() {
00287 PPL_ASSERT(zero_dim_false_p != 0);
00288 delete zero_dim_false_p;
00289 zero_dim_false_p = 0;
00290
00291 PPL_ASSERT(zero_dim_integrality_p != 0);
00292 delete zero_dim_integrality_p;
00293 zero_dim_integrality_p = 0;
00294 }