/* Test Polyhedra_Powerset<PH>::BGP99_extrapolation_assign()
   on a chain that shows it is not a widening.
   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 "ppl_test.hh"
#include <vector>

using namespace std;
using namespace Parma_Polyhedra_Library;

#ifndef NOISY
#define NOISY 0
#endif

namespace {

Variable x(0);
Variable y(1);

typedef Polyhedra_PowerSet<C_Polyhedron> PSet;

const C_Polyhedron&
P(unsigned n) {
  static std::vector<C_Polyhedron> p;
  if (p.size() < 5) {
    p.resize(5, C_Polyhedron(2));
    p[2].add_constraint(0 <= x);
    p[2].add_constraint(x <= 4);
    p[2].add_constraint(0 <= y);
    p[2].add_constraint(y <= 4);
    p[1] = p[2];
    p[1].add_constraint(x-y <= 3);
    p[0] = p[1];
    p[0].add_constraint(x+y >= 1);

    p[3].add_constraint(0 <= x);
    p[3].add_constraint(x <= 8);
    p[3].add_constraint(0 <= y);
    p[3].add_constraint(y <= 8);
    p[3].add_constraint(x+y <= 14);
    p[3].add_constraint(x-y >= -6);
    p[4] = p[3];
    p[3].add_constraint(5*x-y >= -2);
    p[3].add_constraint(x+3*y >= 3);
    p[4].add_constraint(4*x-y >= -3);
    p[4].add_constraint(x+2*y >= 2);
  }

  if (n >= p.size()) {
    unsigned new_size = p.size();
    while (n >= new_size)
      new_size *= 2;
    p.resize(p.size()*2);
  }

  if (p[n].is_universe()) {
    p[n] = P(n-4);
    p[n].affine_image(x, 2*x);
    p[n].affine_image(y, 8 - 2*y);
  }

  return p[n];
}

PSet
S(unsigned n) {
  PSet s(2, Polyhedron::EMPTY);
  if (n == 0) {
#if NOISY
    cout << "S0 = { P0 }" << endl;
#endif
    s.add_disjunct(P(0));
    return s;
  }

  const int p_base = (n-1)/3*4;

  switch (n % 3) {
  case 1:
#if NOISY
    cout << "S" << n << " = { "
	 << "P" << p_base + 1 << ", "
	 << "P" << p_base + 3 << " }" << endl;
#endif
    s.add_disjunct(P(p_base + 1));
    s.add_disjunct(P(p_base + 3));
    break;
  case 2:
#if NOISY
    cout << "S" << n << " = { "
	 << "P" << p_base + 2 << ", "
	 << "P" << p_base + 3 << " }" << endl;
#endif
    s.add_disjunct(P(p_base + 2));
    s.add_disjunct(P(p_base + 3));
    break;
  case 0:
#if NOISY
    cout << "S" << n << " = { "
	 << "P" << p_base + 2 << ", "
	 << "P" << p_base + 4 << " }" << endl;
#endif
    s.add_disjunct(P(p_base + 2));
    s.add_disjunct(P(p_base + 4));
    break;
  }    
  return s;
}

void
my_output_function(ostream& s, const Variable& v) {
  s << char('x' + v.id());
}

} // namespace

int
main() TRY {
  set_handlers();

  // Install the alternate output function.
  Variable::set_output_function(my_output_function);

  PSet T = S(0);
#if NOISY
  using namespace Parma_Polyhedra_Library::IO_Operators;

  cout << "T0 = " << T << endl;
#endif
  bool converged = false;
  for (unsigned n = 1; !converged && n <= 20; ++n) {
    PSet Sn = S(n);
#if NOISY
    cout << "S" << n << " = " << Sn << endl;
#endif
    Sn.BGP99_extrapolation_assign
      (T, widen_fun(&Polyhedron::H79_widening_assign), 2);
#if NOISY
    cout << "T" << n << " = " << Sn << endl;
#endif
    if (Sn.definitely_entails(T))
      converged = true;
    else
      std::swap(Sn, T);
  }

  return !converged ? 0 : 1;
}
CATCH


syntax highlighted by Code2HTML, v. 0.9.1