/* PowerSet class implementation: inline functions. Copyright (C) 2001-2004 Roberto Bagnara 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/ . */ #ifndef PPL_PowerSet_inlines_hh #define PPL_PowerSet_inlines_hh 1 #include #include #include namespace Parma_Polyhedra_Library { template typename PowerSet::iterator PowerSet::begin() { return sequence.begin(); } template typename PowerSet::const_iterator PowerSet::begin() const { return sequence.begin(); } template typename PowerSet::iterator PowerSet::end() { return sequence.end(); } template typename PowerSet::const_iterator PowerSet::end() const { return sequence.end(); } template typename PowerSet::reverse_iterator PowerSet::rbegin() { return sequence.rbegin(); } template typename PowerSet::const_reverse_iterator PowerSet::rbegin() const { return sequence.rbegin(); } template typename PowerSet::reverse_iterator PowerSet::rend() { return sequence.rend(); } template typename PowerSet::const_reverse_iterator PowerSet::rend() const { return sequence.rend(); } template typename PowerSet::size_type PowerSet::size() const { return sequence.size(); } template bool PowerSet::empty() const { return sequence.empty(); } template void PowerSet::push_back(const CS& y) { sequence.push_back(y); } template void PowerSet::pop_back() { sequence.pop_back(); } template typename PowerSet::iterator PowerSet::erase(iterator first, iterator last) { return sequence.erase(first, last); } template typename PowerSet::iterator PowerSet::erase(iterator position) { return sequence.erase(position); } template PowerSet::PowerSet(const PowerSet& y) : sequence(y.sequence), reduced(y.reduced) { } template PowerSet& PowerSet::operator=(const PowerSet& y) { sequence = y.sequence; reduced = y.reduced; return *this; } template inline void PowerSet::swap(PowerSet& y) { std::swap(sequence, y.sequence); std::swap(reduced, y.reduced); } template PowerSet::PowerSet() : sequence(), reduced(true) { } template void PowerSet::collapse(const iterator sink) { assert(sink != end()); // Collapse onto the disjunct pointed to by `sink' all the disjuncts // that follow. CS& d = *sink; iterator j = sink; iterator send = end(); for (++j; j != send; ++j) d.upper_bound_assign(*j); // Erase the surplus disjuncts. j = sink; erase(++j, send); // Ensure omega-reduction. for (iterator k = begin(), kn = k; k != sink; k = kn) { ++kn; if (k->definitely_entails(d)) erase(k); } assert(OK()); } template void PowerSet::omega_reduce() const { if (reduced) return; PowerSet& ps = const_cast(*this); // First remove all bottom elements. for (iterator xi = ps.begin(), xin = xi; xi != ps.end(); xi = xin) { ++xin; if (xi->is_bottom()) ps.erase(xi); } // Then remove non-maximal elements. for (iterator xi = ps.begin(), xin = xi; xi != ps.end(); xi = xin) { ++xin; const CS& xv = *xi; for (iterator yi = ps.begin(), yin = yi; yi != ps.end(); yi = yin) { ++yin; if (xi == yi) continue; const CS& yv = *yi; if (yv.definitely_entails(xv)) { if (yi == xin) ++xin; ps.erase(yi); } else if (xv.definitely_entails(yv)) { ps.erase(xi); break; } } if (abandon_expensive_computations && xin != ps.end()) { // Hurry up! ps.collapse(xin); break; } } reduced = true; assert(OK()); } template void PowerSet::collapse(const unsigned max_disjuncts) { assert(max_disjuncts > 0); // Omega-reduce before counting the number of disjuncts. omega_reduce(); size_type n = size(); if (n > max_disjuncts) { iterator i = begin(); // Move `i' to the last disjunct that will survive. for (unsigned m = max_disjuncts-1; m-- > 0; ) ++i; // This disjunct will be assigned an upper-bound of itself and of // all the disjuncts that follow. collapse(i); } assert(OK()); assert(is_omega_reduced()); } template bool PowerSet::check_omega_reduced() const { for (const_iterator sbegin = begin(), send = end(), xi = sbegin; xi != send; ++xi) { const CS& xv = *xi; if (xv.is_bottom()) return false; for (const_iterator yi = sbegin; yi != send; ++yi) { if (xi == yi) continue; const CS& yv = *yi; if (xv.definitely_entails(yv) || yv.definitely_entails(xv)) return false; } } return true; } template bool PowerSet::is_omega_reduced() const { if (!reduced && check_omega_reduced()) reduced = true; return reduced; } template void PowerSet::add_non_bottom_disjunct(Sequence& s, const CS& d, iterator& first, iterator last) { for (iterator xi = first, xin = xi; xi != last; xi = xin) { ++xin; const CS& xv = *xi; if (d.definitely_entails(xv)) return; else if (xv.definitely_entails(d)) { if (xi == first) first = xin; s.erase(xi); } } s.push_back(d); } template void PowerSet::add_non_bottom_disjunct(Sequence& s, const CS& d) { assert(!d.is_bottom()); iterator s_begin = s.begin(); iterator s_end = s.end(); add_non_bottom_disjunct(s, d, s_begin, s_end); } template void PowerSet::add_disjunct(const CS& d) { if (!d.is_bottom()) add_non_bottom_disjunct(sequence, d); } template bool PowerSet::definitely_entails(const PowerSet& y) const { const PowerSet& x = *this; bool found = true; for (const_iterator xi = x.begin(), x_end = x.end(); found && xi != x_end; ++xi) { found = false; for (const_iterator yi = y.begin(), y_end = y.end(); !found && yi != y_end; ++yi) found = (*xi).definitely_entails(*yi); } return found; } /*! \relates PowerSet */ template inline bool operator==(const PowerSet& x, const PowerSet& y) { return (x.size() == y.size() && equal(x.begin(), x.end(), y.begin())); } /*! \relates PowerSet */ template inline bool operator!=(const PowerSet& x, const PowerSet& y) { return !(x == y); } template inline bool PowerSet::is_top() const { // Must perform omega-reduction for correctness. omega_reduce(); const_iterator i = begin(); const_iterator send = end(); return i != send && i->is_top() && ++i == send; } template inline bool PowerSet::is_bottom() const { // Must perform omega-reduction for correctness. omega_reduce(); return sequence.empty(); } template inline void PowerSet::collapse() { if (!empty()) collapse(begin()); } template void PowerSet::meet_assign(const PowerSet& y) { const PowerSet& x = *this; Sequence new_sequence; for (const_iterator xi = x.begin(), x_end = x.end(); xi != x_end; ++xi) for (const_iterator yi = y.begin(), y_end = y.end(); yi != y_end; ++yi) { CS zi = *xi; zi.meet_assign(*yi); if (!zi.is_bottom()) new_sequence.push_back(zi); } std::swap(sequence, new_sequence); omega_reduce(); } template void PowerSet::upper_bound_assign(const PowerSet& y) { // Ensure omega-reduction here, since what follows has quadratic complexity. omega_reduce(); y.omega_reduce(); iterator sbegin = begin(); iterator send = end(); for (const_iterator i = y.begin(), y_end = y.end(); i != y_end; ++i) add_non_bottom_disjunct(sequence, *i, sbegin, send); } namespace IO_Operators { /*! \relates Parma_Polyhedra_Library::PowerSet */ template std::ostream& operator<<(std::ostream& s, const PowerSet& x) { if (x.is_bottom()) s << "false"; else if (x.is_top()) s << "true"; else { s << "{ "; typename PowerSet::const_iterator i = x.begin(); typename PowerSet::const_iterator x_end = x.end(); while (i != x_end) { s << *i++; if (i != x_end) s << ", "; } s << " }"; } return s; } } // namespace IO_Operators template bool PowerSet::OK(const bool disallow_bottom) const { for (const_iterator i = begin(), send = end(); i != send; ++i) { if (!i->OK()) return false; if (disallow_bottom && i->is_bottom()) { #ifndef NDEBUG std::cerr << "Bottom element in powerset!" << std::endl; #endif return false; } } if (reduced && !check_omega_reduced()) { #ifndef NDEBUG std::cerr << "Powerset claims to be reduced, but it is not!" << std::endl; #endif return false; } return true; } } // namespace Parma_Polyhedra_Library namespace std { /*! \relates Parma_Polyhedra_Library::PowerSet */ template inline void swap(Parma_Polyhedra_Library::PowerSet& x, Parma_Polyhedra_Library::PowerSet& y) { x.swap(y); } } // namespace std #endif // !defined(PPL_PowerSet_inlines_hh)