PPL  1.2
Parma_Polyhedra_Library::PIP_Solution_Node Class Reference

A tree node representing part of the space of solutions. More...

#include <PIP_Tree_defs.hh>

Inheritance diagram for Parma_Polyhedra_Library::PIP_Solution_Node:
Collaboration diagram for Parma_Polyhedra_Library::PIP_Solution_Node:

Classes

struct  No_Constraints
 A tag type to select the alternative copy constructor. More...
 
struct  Tableau
 The type for parametric simplex tableau. More...
 

Public Member Functions

 PIP_Solution_Node (const PIP_Problem *owner)
 Constructor: builds a solution node owned by *owner. More...
 
virtual PIP_Tree_Nodeclone () const
 Returns a pointer to a dynamically-allocated copy of *this. More...
 
virtual ~PIP_Solution_Node ()
 Destructor. More...
 
virtual bool OK () const
 Returns true if and only if *this is well formed. More...
 
virtual const PIP_Solution_Nodeas_solution () const
 Returns this. More...
 
virtual const PIP_Decision_Nodeas_decision () const
 Returns 0, since this is not a decision node. More...
 
const Linear_Expressionparametric_values (Variable var) const
 Returns a parametric expression for the values of problem variable var. More...
 
void ascii_dump (std::ostream &os) const
 Dumps to os an ASCII representation of *this. More...
 
bool ascii_load (std::istream &is)
 Loads from is an ASCII representation (as produced by ascii_dump(std::ostream&) const) and sets *this accordingly. Returns true if successful, false otherwise. More...
 
virtual memory_size_type total_memory_in_bytes () const
 Returns the total size in bytes of the memory occupied by *this. More...
 
virtual memory_size_type external_memory_in_bytes () const
 Returns the size in bytes of the memory managed by *this. More...
 
- Public Member Functions inherited from Parma_Polyhedra_Library::PIP_Tree_Node
virtual ~PIP_Tree_Node ()
 Destructor. More...
 
const Constraint_Systemconstraints () const
 Returns the system of parameter constraints controlling *this. More...
 
Artificial_Parameter_Sequence::const_iterator art_parameter_begin () const
 Returns a const_iterator to the beginning of local artificial parameters. More...
 
Artificial_Parameter_Sequence::const_iterator art_parameter_end () const
 Returns a const_iterator to the end of local artificial parameters. More...
 
dimension_type art_parameter_count () const
 Returns the number of local artificial parameters. More...
 
void print (std::ostream &s, int indent=0) const
 Prints on s the tree rooted in *this. More...
 
void ascii_dump (std::ostream &s) const
 Dumps to s an ASCII representation of *this. More...
 
bool ascii_load (std::istream &s)
 Loads from s an ASCII representation (as produced by ascii_dump(std::ostream&) const) and sets *this accordingly. Returns true if successful, false otherwise. More...
 

Protected Member Functions

 PIP_Solution_Node (const PIP_Solution_Node &y)
 Copy constructor. More...
 
 PIP_Solution_Node (const PIP_Solution_Node &y, No_Constraints)
 Alternative copy constructor. More...
 
virtual void set_owner (const PIP_Problem *owner)
 Sets the pointer to the PIP_Problem owning object. More...
 
virtual bool check_ownership (const PIP_Problem *owner) const
 Returns true if and only if all the nodes in the subtree rooted in *this is owned by *pip. More...
 
virtual void update_tableau (const PIP_Problem &pip, dimension_type external_space_dim, dimension_type first_pending_constraint, const Constraint_Sequence &input_cs, const Variables_Set &parameters)
 Implements pure virtual method PIP_Tree_Node::update_tableau. More...
 
void update_solution (const std::vector< bool > &pip_dim_is_param) const
 Update the solution values. More...
 
void update_solution () const
 Helper method. More...
 
virtual PIP_Tree_Nodesolve (const PIP_Problem &pip, bool check_feasible_context, const Matrix< Row > &context, const Variables_Set &params, dimension_type space_dim, int indent_level)
 Implements pure virtual method PIP_Tree_Node::solve. More...
 
void generate_cut (dimension_type index, Variables_Set &parameters, Matrix< Row > &context, dimension_type &space_dimension, int indent_level)
 Generate a Gomory cut using non-integer tableau row index. More...
 
virtual void print_tree (std::ostream &s, int indent, const std::vector< bool > &pip_dim_is_param, dimension_type first_art_dim) const
 Prints on s the tree rooted in *this. More...
 
- Protected Member Functions inherited from Parma_Polyhedra_Library::PIP_Tree_Node
 PIP_Tree_Node (const PIP_Problem *owner)
 Constructor: builds a node owned by *owner. More...
 
 PIP_Tree_Node (const PIP_Tree_Node &y)
 Copy constructor. More...
 
const PIP_Problemget_owner () const
 Returns a pointer to the PIP_Problem owning object. More...
 
const PIP_Decision_Nodeparent () const
 Returns a pointer to this node's parent. More...
 
void set_parent (const PIP_Decision_Node *p)
 Set this node's parent to *p. More...
 
void add_constraint (const Row &row, const Variables_Set &parameters)
 Inserts a new parametric constraint in internal row format. More...
 
void parent_merge ()
 Merges parent's artificial parameters into *this. More...
 

Private Types

enum  Row_Sign {
  UNKNOWN, ZERO, POSITIVE, NEGATIVE,
  MIXED
}
 The possible values for the sign of a parametric linear expression. More...
 

Static Private Member Functions

static Row_Sign row_sign (const Row &x, dimension_type big_dimension)
 Returns the sign of row x. More...
 

Private Attributes

Tableau tableau
 The parametric simplex tableau. More...
 
std::vector< bool > basis
 A boolean vector for identifying the basic variables. More...
 
std::vector< dimension_typemapping
 A mapping between the tableau rows/columns and the original variables. More...
 
std::vector< dimension_typevar_row
 The variable identifiers associated to the rows of the simplex tableau. More...
 
std::vector< dimension_typevar_column
 The variable identifiers associated to the columns of the simplex tableau. More...
 
dimension_type special_equality_row
 The variable number of the special inequality used for modeling equality constraints. More...
 
dimension_type big_dimension
 The column index in the parametric part of the simplex tableau corresponding to the big parameter; not_a_dimension() if not set. More...
 
std::vector< Row_Signsign
 A cache for computed sign values of constraint parametric RHS. More...
 
std::vector< Linear_Expressionsolution
 Parametric values for the solution. More...
 
bool solution_valid
 An indicator for solution validity. More...
 

Friends

bool PIP_Problem::ascii_load (std::istream &s)
 

Additional Inherited Members

- Public Types inherited from Parma_Polyhedra_Library::PIP_Tree_Node
typedef Sparse_Row Row
 
typedef std::vector< Artificial_ParameterArtificial_Parameter_Sequence
 A type alias for a sequence of Artificial_Parameter's. More...
 
- Protected Types inherited from Parma_Polyhedra_Library::PIP_Tree_Node
typedef std::vector< ConstraintConstraint_Sequence
 A type alias for a sequence of constraints. More...
 
- Static Protected Member Functions inherited from Parma_Polyhedra_Library::PIP_Tree_Node
static void indent_and_print (std::ostream &s, int indent, const char *str)
 A helper function used when printing PIP trees. More...
 
static bool compatibility_check (Matrix< Row > &s)
 Checks whether a context matrix is satisfiable. More...
 
static bool compatibility_check (const Matrix< Row > &context, const Row &row)
 Helper method: checks for satisfiability of the restricted context obtained by adding row to context. More...
 
- Protected Attributes inherited from Parma_Polyhedra_Library::PIP_Tree_Node
const PIP_Problemowner_
 A pointer to the PIP_Problem object owning this node. More...
 
const PIP_Decision_Nodeparent_
 A pointer to the parent of *this, null if *this is the root. More...
 
Constraint_System constraints_
 The local system of parameter constraints. More...
 
Artificial_Parameter_Sequence artificial_parameters
 The local sequence of expressions for local artificial parameters. More...
 

Detailed Description

A tree node representing part of the space of solutions.

Definition at line 360 of file PIP_Tree_defs.hh.

Member Enumeration Documentation

The possible values for the sign of a parametric linear expression.

Enumerator
UNKNOWN 

Not computed yet (default).

ZERO 

All row coefficients are zero.

POSITIVE 

All nonzero row coefficients are positive.

NEGATIVE 

All nonzero row coefficients are negative.

MIXED 

The row contains both positive and negative coefficients.

Definition at line 593 of file PIP_Tree_defs.hh.

593  {
595  UNKNOWN,
597  ZERO,
599  POSITIVE,
601  NEGATIVE,
603  MIXED
604  };
The row contains both positive and negative coefficients.
All nonzero row coefficients are negative.
All nonzero row coefficients are positive.

Constructor & Destructor Documentation

Parma_Polyhedra_Library::PIP_Solution_Node::PIP_Solution_Node ( const PIP_Problem owner)
explicit

Constructor: builds a solution node owned by *owner.

Definition at line 1036 of file PIP_Tree.cc.

Referenced by Parma_Polyhedra_Library::PIP_Decision_Node::ascii_load(), clone(), and solve().

1037  : PIP_Tree_Node(owner),
1038  tableau(),
1039  basis(),
1040  mapping(),
1041  var_row(),
1042  var_column(),
1045  sign(),
1046  solution(),
1047  solution_valid(false) {
1048 }
std::vector< dimension_type > var_column
The variable identifiers associated to the columns of the simplex tableau.
Tableau tableau
The parametric simplex tableau.
dimension_type not_a_dimension()
Returns a value that does not designate a valid dimension.
dimension_type special_equality_row
The variable number of the special inequality used for modeling equality constraints.
PIP_Tree_Node(const PIP_Problem *owner)
Constructor: builds a node owned by *owner.
Definition: PIP_Tree.cc:916
dimension_type big_dimension
The column index in the parametric part of the simplex tableau corresponding to the big parameter; no...
bool solution_valid
An indicator for solution validity.
std::vector< dimension_type > var_row
The variable identifiers associated to the rows of the simplex tableau.
std::vector< dimension_type > mapping
A mapping between the tableau rows/columns and the original variables.
std::vector< Linear_Expression > solution
Parametric values for the solution.
std::vector< bool > basis
A boolean vector for identifying the basic variables.
std::vector< Row_Sign > sign
A cache for computed sign values of constraint parametric RHS.
Parma_Polyhedra_Library::PIP_Solution_Node::~PIP_Solution_Node ( )
virtual

Destructor.

Definition at line 1079 of file PIP_Tree.cc.

1079  {
1080 }
Parma_Polyhedra_Library::PIP_Solution_Node::PIP_Solution_Node ( const PIP_Solution_Node y)
protected

Copy constructor.

Definition at line 1050 of file PIP_Tree.cc.

1051  : PIP_Tree_Node(y),
1052  tableau(y.tableau),
1053  basis(y.basis),
1054  mapping(y.mapping),
1055  var_row(y.var_row),
1056  var_column(y.var_column),
1057  special_equality_row(y.special_equality_row),
1058  big_dimension(y.big_dimension),
1059  sign(y.sign),
1060  solution(y.solution),
1061  solution_valid(y.solution_valid) {
1062 }
std::vector< dimension_type > var_column
The variable identifiers associated to the columns of the simplex tableau.
Tableau tableau
The parametric simplex tableau.
dimension_type special_equality_row
The variable number of the special inequality used for modeling equality constraints.
PIP_Tree_Node(const PIP_Problem *owner)
Constructor: builds a node owned by *owner.
Definition: PIP_Tree.cc:916
dimension_type big_dimension
The column index in the parametric part of the simplex tableau corresponding to the big parameter; no...
bool solution_valid
An indicator for solution validity.
std::vector< dimension_type > var_row
The variable identifiers associated to the rows of the simplex tableau.
std::vector< dimension_type > mapping
A mapping between the tableau rows/columns and the original variables.
std::vector< Linear_Expression > solution
Parametric values for the solution.
std::vector< bool > basis
A boolean vector for identifying the basic variables.
std::vector< Row_Sign > sign
A cache for computed sign values of constraint parametric RHS.
Parma_Polyhedra_Library::PIP_Solution_Node::PIP_Solution_Node ( const PIP_Solution_Node y,
No_Constraints   
)
protected

Alternative copy constructor.

This constructor differs from the default copy constructor in that it will not copy the constraint system, nor the artificial parameters.

Definition at line 1064 of file PIP_Tree.cc.

1066  : PIP_Tree_Node(y.owner_), // NOTE: only copy owner.
1067  tableau(y.tableau),
1068  basis(y.basis),
1069  mapping(y.mapping),
1070  var_row(y.var_row),
1071  var_column(y.var_column),
1072  special_equality_row(y.special_equality_row),
1073  big_dimension(y.big_dimension),
1074  sign(y.sign),
1075  solution(y.solution),
1076  solution_valid(y.solution_valid) {
1077 }
std::vector< dimension_type > var_column
The variable identifiers associated to the columns of the simplex tableau.
Tableau tableau
The parametric simplex tableau.
dimension_type special_equality_row
The variable number of the special inequality used for modeling equality constraints.
PIP_Tree_Node(const PIP_Problem *owner)
Constructor: builds a node owned by *owner.
Definition: PIP_Tree.cc:916
dimension_type big_dimension
The column index in the parametric part of the simplex tableau corresponding to the big parameter; no...
bool solution_valid
An indicator for solution validity.
std::vector< dimension_type > var_row
The variable identifiers associated to the rows of the simplex tableau.
std::vector< dimension_type > mapping
A mapping between the tableau rows/columns and the original variables.
std::vector< Linear_Expression > solution
Parametric values for the solution.
std::vector< bool > basis
A boolean vector for identifying the basic variables.
std::vector< Row_Sign > sign
A cache for computed sign values of constraint parametric RHS.

Member Function Documentation

const PIP_Decision_Node * Parma_Polyhedra_Library::PIP_Solution_Node::as_decision ( ) const
virtual

Returns 0, since this is not a decision node.

Implements Parma_Polyhedra_Library::PIP_Tree_Node.

Definition at line 1153 of file PIP_Tree.cc.

1153  {
1154  return 0;
1155 }
const PIP_Solution_Node * Parma_Polyhedra_Library::PIP_Solution_Node::as_solution ( ) const
virtual

Returns this.

Implements Parma_Polyhedra_Library::PIP_Tree_Node.

Definition at line 1163 of file PIP_Tree.cc.

Referenced by Parma_Polyhedra_Library::PIP_Problem::ascii_dump(), and Parma_Polyhedra_Library::PIP_Decision_Node::ascii_dump().

1163  {
1164  return this;
1165 }
void Parma_Polyhedra_Library::PIP_Solution_Node::ascii_dump ( std::ostream &  os) const

Dumps to os an ASCII representation of *this.

Definition at line 1909 of file PIP_Tree.cc.

References Parma_Polyhedra_Library::PIP_Tree_Node::ascii_dump(), big_dimension, MIXED, NEGATIVE, POSITIVE, sign, solution, solution_valid, special_equality_row, UNKNOWN, var_column, var_row, and ZERO.

Referenced by Parma_Polyhedra_Library::PIP_Problem::ascii_dump(), Parma_Polyhedra_Library::PIP_Decision_Node::ascii_dump(), and Parma_Polyhedra_Library::PIP_Tree_Node::OK().

1909  {
1911 
1912  os << "\ntableau\n";
1913  tableau.ascii_dump(os);
1914 
1915  os << "\nbasis ";
1916  const dimension_type basis_size = basis.size();
1917  os << basis_size;
1918  for (dimension_type i = 0; i < basis_size; ++i) {
1919  os << (basis[i] ? " true" : " false");
1920  }
1921 
1922  os << "\nmapping ";
1923  const dimension_type mapping_size = mapping.size();
1924  os << mapping_size;
1925  for (dimension_type i = 0; i < mapping_size; ++i) {
1926  os << " " << mapping[i];
1927  }
1928 
1929  os << "\nvar_row ";
1930  const dimension_type var_row_size = var_row.size();
1931  os << var_row_size;
1932  for (dimension_type i = 0; i < var_row_size; ++i) {
1933  os << " " << var_row[i];
1934  }
1935 
1936  os << "\nvar_column ";
1937  const dimension_type var_column_size = var_column.size();
1938  os << var_column_size;
1939  for (dimension_type i = 0; i < var_column_size; ++i) {
1940  os << " " << var_column[i];
1941  }
1942 
1943  os << "\n";
1944 
1945  os << "special_equality_row " << special_equality_row << "\n";
1946  os << "big_dimension " << big_dimension << "\n";
1947 
1948  os << "sign ";
1949  const dimension_type sign_size = sign.size();
1950  os << sign_size;
1951  for (dimension_type i = 0; i < sign_size; ++i) {
1952  os << " ";
1953  switch (sign[i]) {
1954  case UNKNOWN:
1955  os << "UNKNOWN";
1956  break;
1957  case ZERO:
1958  os << "ZERO";
1959  break;
1960  case POSITIVE:
1961  os << "POSITIVE";
1962  break;
1963  case NEGATIVE:
1964  os << "NEGATIVE";
1965  break;
1966  case MIXED:
1967  os << "MIXED";
1968  break;
1969  }
1970  }
1971  os << "\n";
1972 
1973  const dimension_type solution_size = solution.size();
1974  os << "solution " << solution_size << "\n";
1975  for (dimension_type i = 0; i < solution_size; ++i) {
1976  solution[i].ascii_dump(os);
1977  }
1978  os << "\n";
1979 
1980  os << "solution_valid " << (solution_valid ? "true" : "false") << "\n";
1981 }
std::vector< dimension_type > var_column
The variable identifiers associated to the columns of the simplex tableau.
size_t dimension_type
An unsigned integral type for representing space dimensions.
Tableau tableau
The parametric simplex tableau.
void ascii_dump(std::ostream &os) const
Dumps to os an ASCII representation of *this.
Definition: PIP_Tree.cc:1873
dimension_type special_equality_row
The variable number of the special inequality used for modeling equality constraints.
dimension_type big_dimension
The column index in the parametric part of the simplex tableau corresponding to the big parameter; no...
bool solution_valid
An indicator for solution validity.
The row contains both positive and negative coefficients.
All nonzero row coefficients are negative.
std::vector< dimension_type > var_row
The variable identifiers associated to the rows of the simplex tableau.
void ascii_dump(std::ostream &s) const
Dumps to s an ASCII representation of *this.
Definition: PIP_Tree.cc:1818
std::vector< dimension_type > mapping
A mapping between the tableau rows/columns and the original variables.
All nonzero row coefficients are positive.
std::vector< Linear_Expression > solution
Parametric values for the solution.
std::vector< bool > basis
A boolean vector for identifying the basic variables.
std::vector< Row_Sign > sign
A cache for computed sign values of constraint parametric RHS.
bool Parma_Polyhedra_Library::PIP_Solution_Node::ascii_load ( std::istream &  is)

Loads from is an ASCII representation (as produced by ascii_dump(std::ostream&) const) and sets *this accordingly. Returns true if successful, false otherwise.

Definition at line 1984 of file PIP_Tree.cc.

References Parma_Polyhedra_Library::PIP_Tree_Node::ascii_load(), Parma_Polyhedra_Library::Linear_Expression::ascii_load(), big_dimension, MIXED, NEGATIVE, OK(), POSITIVE, sign, solution, solution_valid, special_equality_row, UNKNOWN, var_column, var_row, and ZERO.

Referenced by Parma_Polyhedra_Library::PIP_Problem::ascii_load(), and Parma_Polyhedra_Library::PIP_Decision_Node::ascii_load().

1984  {
1985  if (!PIP_Tree_Node::ascii_load(is)) {
1986  return false;
1987  }
1988 
1989  std::string str;
1990  if (!(is >> str) || str != "tableau") {
1991  return false;
1992  }
1993  if (!tableau.ascii_load(is)) {
1994  return false;
1995  }
1996  if (!(is >> str) || str != "basis") {
1997  return false;
1998  }
1999  dimension_type basis_size;
2000  if (!(is >> basis_size)) {
2001  return false;
2002  }
2003  basis.clear();
2004  for (dimension_type i = 0; i < basis_size; ++i) {
2005  if (!(is >> str)) {
2006  return false;
2007  }
2008  bool val = false;
2009  if (str == "true") {
2010  val = true;
2011  }
2012  else if (str != "false") {
2013  return false;
2014  }
2015  basis.push_back(val);
2016  }
2017 
2018  if (!(is >> str) || str != "mapping") {
2019  return false;
2020  }
2021  dimension_type mapping_size;
2022  if (!(is >> mapping_size)) {
2023  return false;
2024  }
2025  mapping.clear();
2026  for (dimension_type i = 0; i < mapping_size; ++i) {
2027  dimension_type val;
2028  if (!(is >> val)) {
2029  return false;
2030  }
2031  mapping.push_back(val);
2032  }
2033 
2034  if (!(is >> str) || str != "var_row") {
2035  return false;
2036  }
2037  dimension_type var_row_size;
2038  if (!(is >> var_row_size)) {
2039  return false;
2040  }
2041  var_row.clear();
2042  for (dimension_type i = 0; i < var_row_size; ++i) {
2043  dimension_type val;
2044  if (!(is >> val)) {
2045  return false;
2046  }
2047  var_row.push_back(val);
2048  }
2049 
2050  if (!(is >> str) || str != "var_column") {
2051  return false;
2052  }
2053  dimension_type var_column_size;
2054  if (!(is >> var_column_size)) {
2055  return false;
2056  }
2057  var_column.clear();
2058  for (dimension_type i = 0; i < var_column_size; ++i) {
2059  dimension_type val;
2060  if (!(is >> val)) {
2061  return false;
2062  }
2063  var_column.push_back(val);
2064  }
2065 
2066  if (!(is >> str) || str != "special_equality_row") {
2067  return false;
2068  }
2069  if (!(is >> special_equality_row)) {
2070  return false;
2071  }
2072 
2073  if (!(is >> str) || str != "big_dimension") {
2074  return false;
2075  }
2076  if (!(is >> big_dimension)) {
2077  return false;
2078  }
2079 
2080  if (!(is >> str) || str != "sign") {
2081  return false;
2082  }
2083  dimension_type sign_size;
2084  if (!(is >> sign_size)) {
2085  return false;
2086  }
2087 
2088  sign.clear();
2089  for (dimension_type i = 0; i < sign_size; ++i) {
2090  if (!(is >> str)) {
2091  return false;
2092  }
2093  Row_Sign val;
2094  if (str == "UNKNOWN") {
2095  val = UNKNOWN;
2096  }
2097  else if (str == "ZERO") {
2098  val = ZERO;
2099  }
2100  else if (str == "POSITIVE") {
2101  val = POSITIVE;
2102  }
2103  else if (str == "NEGATIVE") {
2104  val = NEGATIVE;
2105  }
2106  else if (str == "MIXED") {
2107  val = MIXED;
2108  }
2109  else {
2110  return false;
2111  }
2112  sign.push_back(val);
2113  }
2114 
2115  if (!(is >> str) || str != "solution") {
2116  return false;
2117  }
2118  dimension_type solution_size;
2119  if (!(is >> solution_size)) {
2120  return false;
2121  }
2122  solution.clear();
2123  for (dimension_type i = 0; i < solution_size; ++i) {
2124  Linear_Expression val;
2125  if (!val.ascii_load(is)) {
2126  return false;
2127  }
2128  solution.push_back(val);
2129  }
2130 
2131  if (!(is >> str) || str != "solution_valid") {
2132  return false;
2133  }
2134  if (!(is >> str)) {
2135  return false;
2136  }
2137  if (str == "true") {
2138  solution_valid = true;
2139  }
2140  else if (str == "false") {
2141  solution_valid = false;
2142  }
2143  else {
2144  return false;
2145  }
2146 
2147  PPL_ASSERT(OK());
2148  return true;
2149 }
std::vector< dimension_type > var_column
The variable identifiers associated to the columns of the simplex tableau.
size_t dimension_type
An unsigned integral type for representing space dimensions.
bool ascii_load(std::istream &s)
Loads from s an ASCII representation (as produced by ascii_dump(std::ostream&) const) and sets *this ...
Definition: PIP_Tree.cc:1830
virtual bool OK() const
Returns true if and only if *this is well formed.
Definition: PIP_Tree.cc:1263
Tableau tableau
The parametric simplex tableau.
dimension_type special_equality_row
The variable number of the special inequality used for modeling equality constraints.
dimension_type big_dimension
The column index in the parametric part of the simplex tableau corresponding to the big parameter; no...
bool solution_valid
An indicator for solution validity.
The row contains both positive and negative coefficients.
All nonzero row coefficients are negative.
std::vector< dimension_type > var_row
The variable identifiers associated to the rows of the simplex tableau.
std::vector< dimension_type > mapping
A mapping between the tableau rows/columns and the original variables.
All nonzero row coefficients are positive.
std::vector< Linear_Expression > solution
Parametric values for the solution.
std::vector< bool > basis
A boolean vector for identifying the basic variables.
Row_Sign
The possible values for the sign of a parametric linear expression.
std::vector< Row_Sign > sign
A cache for computed sign values of constraint parametric RHS.
bool ascii_load(std::istream &is)
Loads from is an ASCII representation (as produced by ascii_dump(std::ostream&) const) and sets *this...
Definition: PIP_Tree.cc:1882
bool Parma_Polyhedra_Library::PIP_Solution_Node::check_ownership ( const PIP_Problem owner) const
protectedvirtual

Returns true if and only if all the nodes in the subtree rooted in *this is owned by *pip.

Implements Parma_Polyhedra_Library::PIP_Tree_Node.

Definition at line 1136 of file PIP_Tree.cc.

References Parma_Polyhedra_Library::PIP_Tree_Node::get_owner().

1136  {
1137  return get_owner() == owner;
1138 }
const PIP_Problem * get_owner() const
Returns a pointer to the PIP_Problem owning object.
PIP_Tree_Node * Parma_Polyhedra_Library::PIP_Solution_Node::clone ( ) const
virtual

Returns a pointer to a dynamically-allocated copy of *this.

Implements Parma_Polyhedra_Library::PIP_Tree_Node.

Definition at line 1863 of file PIP_Tree.cc.

References PIP_Solution_Node().

1863  {
1864  return new PIP_Solution_Node(*this);
1865 }
PIP_Solution_Node(const PIP_Problem *owner)
Constructor: builds a solution node owned by *owner.
Definition: PIP_Tree.cc:1036
memory_size_type Parma_Polyhedra_Library::PIP_Solution_Node::external_memory_in_bytes ( ) const
virtual

Returns the size in bytes of the memory managed by *this.

Implements Parma_Polyhedra_Library::PIP_Tree_Node.

Definition at line 3778 of file PIP_Tree.cc.

References Parma_Polyhedra_Library::Checked::bool, Parma_Polyhedra_Library::PIP_Tree_Node::external_memory_in_bytes(), sign, solution, var_column, and var_row.

Referenced by Parma_Polyhedra_Library::PIP_Tree_Node::Artificial_Parameter::total_memory_in_bytes(), total_memory_in_bytes(), and Parma_Polyhedra_Library::PIP_Decision_Node::total_memory_in_bytes().

3778  {
3781  // FIXME: size of std::vector<bool> ?
3782  n += basis.capacity() * sizeof(bool);
3783  n += sizeof(dimension_type)
3784  * (mapping.capacity() + var_row.capacity() + var_column.capacity());
3785  n += sign.capacity() * sizeof(Row_Sign);
3786  // FIXME: Adding the external memory for `solution'.
3787  n += solution.capacity() * sizeof(Linear_Expression);
3788  for (std::vector<Linear_Expression>::const_iterator
3789  i = solution.begin(), i_end = solution.end();
3790  i != i_end; ++i) {
3791  n += (i->external_memory_in_bytes());
3792  }
3793 
3794  return n;
3795 }
std::vector< dimension_type > var_column
The variable identifiers associated to the columns of the simplex tableau.
size_t dimension_type
An unsigned integral type for representing space dimensions.
Tableau tableau
The parametric simplex tableau.
virtual memory_size_type external_memory_in_bytes() const =0
Returns the size in bytes of the memory managed by *this.
Definition: PIP_Tree.cc:3741
std::vector< dimension_type > var_row
The variable identifiers associated to the rows of the simplex tableau.
std::vector< dimension_type > mapping
A mapping between the tableau rows/columns and the original variables.
std::vector< Linear_Expression > solution
Parametric values for the solution.
memory_size_type external_memory_in_bytes() const
Returns the size in bytes of the memory managed by *this.
Definition: PIP_Tree.cc:3771
std::vector< bool > basis
A boolean vector for identifying the basic variables.
Row_Sign
The possible values for the sign of a parametric linear expression.
size_t memory_size_type
An unsigned integral type for representing memory size in bytes.
std::vector< Row_Sign > sign
A cache for computed sign values of constraint parametric RHS.
void Parma_Polyhedra_Library::PIP_Solution_Node::generate_cut ( dimension_type  index,
Variables_Set parameters,
Matrix< Row > &  context,
dimension_type space_dimension,
int  indent_level 
)
protected

Generate a Gomory cut using non-integer tableau row index.

Parameters
indexRow index in simplex tableau from which the cut is generated.
parametersA std::set of the current parameter dimensions (including artificials); to be updated if a new artificial parameter is to be created.
contextA set of linear inequalities on the parameters, in matrix form; to be updated if a new artificial parameter is to be created.
space_dimensionThe current space dimension, including variables and all parameters; to be updated if an extra parameter is to be created.
indent_levelThe indentation level (for debugging output only).

Definition at line 3463 of file PIP_Tree.cc.

References Parma_Polyhedra_Library::add_mul_assign(), Parma_Polyhedra_Library::Matrix< Row >::add_zero_columns(), Parma_Polyhedra_Library::Matrix< Row >::add_zero_rows(), Parma_Polyhedra_Library::PIP_Tree_Node::artificial_parameters, Parma_Polyhedra_Library::Sparse_Row::begin(), Parma_Polyhedra_Library::Sparse_Row::end(), Parma_Polyhedra_Library::Sparse_Row::get(), Parma_Polyhedra_Library::CO_Tree::const_iterator::index(), Parma_Polyhedra_Library::CO_Tree::iterator::index(), Parma_Polyhedra_Library::Variables_Set::insert(), Parma_Polyhedra_Library::Sparse_Row::insert(), Parma_Polyhedra_Library::neg_assign(), NEGATIVE, Parma_Polyhedra_Library::not_a_dimension(), Parma_Polyhedra_Library::Matrix< Row >::num_rows(), Parma_Polyhedra_Library::PIP_Tree_Node::parent(), PPL_DIRTY_TEMP_COEFFICIENT, PPL_USED, sign, var_row, WEIGHT_ADD, and WEIGHT_BEGIN.

Referenced by solve().

3467  {
3468  PPL_ASSERT(indent_level >= 0);
3469 #ifdef NOISY_PIP
3470  std::cerr << std::setw(2 * indent_level) << ""
3471  << "Row " << index << " requires cut generation.\n";
3472 #else
3473  PPL_USED(indent_level);
3474 #endif // #ifdef NOISY_PIP
3475 
3476  const dimension_type num_rows = tableau.t.num_rows();
3477  PPL_ASSERT(index < num_rows);
3478  const dimension_type num_vars = tableau.s.num_columns();
3479  const dimension_type num_params = tableau.t.num_columns();
3480  PPL_ASSERT(num_params == 1 + parameters.size());
3481  Coefficient_traits::const_reference denom = tableau.denominator();
3482 
3485 
3486  // Test if cut to be generated must be parametric or not.
3487  bool generate_parametric_cut = false;
3488  {
3489  // Limiting the scope of reference row_t (may be later invalidated).
3490  const Row& row_t = tableau.t[index];
3491  Row::const_iterator j = row_t.begin();
3492  Row::const_iterator j_end = row_t.end();
3493  // Skip the element with index 0.
3494  if (j != j_end && j.index() == 0) {
3495  ++j;
3496  }
3497  WEIGHT_BEGIN();
3498  for ( ; j != j_end; ++j) {
3499  WEIGHT_ADD(7);
3500  if (*j % denom != 0) {
3501  generate_parametric_cut = true;
3502  break;
3503  }
3504  }
3505  }
3506 
3507  // Column index of already existing Artificial_Parameter.
3508  dimension_type ap_column = not_a_dimension();
3509 
3510  if (generate_parametric_cut) {
3511  // Fractional parameter coefficient found: generate parametric cut.
3512  bool reuse_ap = false;
3513  Linear_Expression expr;
3514 
3515  // Limiting the scope of reference row_t (may be later invalidated).
3516  {
3517  const Row& row_t = tableau.t[index];
3518  Row::const_iterator j = row_t.begin();
3519  Row::const_iterator j_end = row_t.end();
3520  if (j != j_end && j.index() == 0) {
3521  pos_rem_assign(mod, *j, denom);
3522  ++j;
3523  if (mod != 0) {
3524  // Optimizing computation: expr += (denom - mod);
3525  expr += denom;
3526  expr -= mod;
3527  }
3528  }
3529  if (!parameters.empty()) {
3530  // To avoid reallocations of expr.
3531  add_mul_assign(expr, 0, Variable(*(parameters.rbegin())));
3532  Variables_Set::const_iterator p_j = parameters.begin();
3533  dimension_type last_index = 1;
3534  WEIGHT_BEGIN();
3535  for ( ; j != j_end; ++j) {
3536  WEIGHT_ADD(69);
3537  pos_rem_assign(mod, *j, denom);
3538  if (mod != 0) {
3539  // Optimizing computation: expr += (denom - mod) * Variable(*p_j);
3540  WEIGHT_ADD(164);
3541  coeff = denom - mod;
3542  PPL_ASSERT(last_index <= j.index());
3543  std::advance(p_j, j.index() - last_index);
3544  last_index = j.index();
3545  add_mul_assign(expr, coeff, Variable(*p_j));
3546  }
3547  }
3548  }
3549  }
3550  // Generate new artificial parameter.
3551  const Artificial_Parameter ap(expr, denom);
3552 
3553  // Search if the Artificial_Parameter has already been generated.
3554  ap_column = space_dimension;
3555  const PIP_Tree_Node* node = this;
3556  do {
3557  for (dimension_type j = node->artificial_parameters.size(); j-- > 0; ) {
3558  --ap_column;
3559  if (node->artificial_parameters[j] == ap) {
3560  reuse_ap = true;
3561  break;
3562  }
3563  }
3564  node = node->parent();
3565  } while (!reuse_ap && node != 0);
3566 
3567  if (reuse_ap) {
3568  // We can re-use an existing Artificial_Parameter.
3569 #ifdef NOISY_PIP
3570  using namespace IO_Operators;
3571  std::cerr << std::setw(2 * indent_level) << ""
3572  << "Re-using parameter " << Variable(ap_column)
3573  << " = " << ap << std::endl;
3574 #endif // #ifdef NOISY_PIP
3575  ap_column = ap_column - num_vars + 1;
3576  }
3577  else {
3578  // Here reuse_ap == false: the Artificial_Parameter does not exist yet.
3579  // Beware: possible reallocation invalidates row references.
3580  tableau.t.add_zero_columns(1);
3581  context.add_zero_columns(1);
3582  artificial_parameters.push_back(ap);
3583  parameters.insert(space_dimension);
3584 #ifdef NOISY_PIP
3585  using namespace IO_Operators;
3586  std::cerr << std::setw(2 * indent_level) << ""
3587  << "New parameter " << Variable(space_dimension)
3588  << " = " << ap << std::endl;
3589 #endif // #ifdef NOISY_PIP
3590  ++space_dimension;
3591  ap_column = num_params;
3592 
3593  // Update current context with constraints on the new parameter.
3594  const dimension_type ctx_num_rows = context.num_rows();
3595  context.add_zero_rows(2);
3596  Row& ctx1 = context[ctx_num_rows];
3597  Row& ctx2 = context[ctx_num_rows+1];
3598  // Recompute row reference after possible reallocation.
3599  const Row& row_t = tableau.t[index];
3600  {
3601  Row::const_iterator j = row_t.begin();
3602  Row::const_iterator j_end = row_t.end();
3603  Row::iterator itr1 = ctx1.end();
3604  Row::iterator itr2 = ctx2.end();
3605  if (j != j_end && j.index() == 0) {
3606  pos_rem_assign(mod, *j, denom);
3607  if (mod != 0) {
3608  itr1 = ctx1.insert(0, denom);
3609  *itr1 -= mod;
3610  itr2 = ctx2.insert(0, *itr1);
3611  neg_assign(*itr2);
3612  // Compute <CODE> ctx2[0] += denom-1; </CODE>
3613  *itr2 += denom;
3614  --(*itr2);
3615  }
3616  else {
3617  // Compute <CODE> ctx2[0] += denom-1; </CODE>
3618  itr2 = ctx2.insert(0, denom);
3619  --(*itr2);
3620  }
3621  ++j;
3622  }
3623  else {
3624  // Compute <CODE> ctx2[0] += denom-1; </CODE>
3625  itr2 = ctx2.insert(0, denom);
3626  --(*itr2);
3627  }
3628  WEIGHT_BEGIN();
3629  for ( ; j != j_end; ++j) {
3630  pos_rem_assign(mod, *j, denom);
3631  if (mod != 0) {
3632  const dimension_type j_index = j.index();
3633  itr1 = ctx1.insert(itr1, j_index, denom);
3634  *itr1 -= mod;
3635  itr2 = ctx2.insert(itr2, j_index, *itr1);
3636  neg_assign(*itr2);
3637  WEIGHT_ADD(294);
3638  }
3639  }
3640  itr1 = ctx1.insert(itr1, num_params, denom);
3641  neg_assign(*itr1);
3642  itr2 = ctx2.insert(itr2, num_params, denom);
3643  WEIGHT_ADD(122);
3644  }
3645 
3646 #ifdef NOISY_PIP
3647  {
3648  using namespace IO_Operators;
3649  Variables_Set::const_iterator p = parameters.begin();
3650  Linear_Expression expr1(ctx1.get(0));
3651  Linear_Expression expr2(ctx2.get(0));
3652  for (dimension_type j = 1; j <= num_params; ++j, ++p) {
3653  add_mul_assign(expr1, ctx1.get(j), Variable(*p));
3654  add_mul_assign(expr2, ctx2.get(j), Variable(*p));
3655  }
3656  std::cerr << std::setw(2 * indent_level) << ""
3657  << "Adding to context: "
3658  << Constraint(expr1 >= 0) << " ; "
3659  << Constraint(expr2 >= 0) << std::endl;
3660  }
3661 #endif // #ifdef NOISY_PIP
3662  }
3663  }
3664 
3665  // Generate new cut.
3666  tableau.s.add_zero_rows(1);
3667  tableau.t.add_zero_rows(1);
3668  Row& cut_s = tableau.s[num_rows];
3669  Row& cut_t = tableau.t[num_rows];
3670  // Recompute references after possible reallocation.
3671  const Row& row_s = tableau.s[index];
3672  const Row& row_t = tableau.t[index];
3673  WEIGHT_BEGIN();
3674  {
3675  Row::iterator itr = cut_s.end();
3676  for (Row::const_iterator
3677  j = row_s.begin(), j_end = row_s.end(); j != j_end; ++j) {
3678  WEIGHT_ADD(55);
3679  itr = cut_s.insert(itr, j.index(), *j);
3680  pos_rem_assign(*itr, *itr, denom);
3681  }
3682  }
3683  {
3684  Row::iterator cut_t_itr = cut_t.end();
3685  for (Row::const_iterator
3686  j = row_t.begin(), j_end = row_t.end(); j!=j_end; ++j) {
3687  WEIGHT_ADD(37);
3688  pos_rem_assign(mod, *j, denom);
3689  if (mod != 0) {
3690  WEIGHT_ADD(108);
3691  cut_t_itr = cut_t.insert(cut_t_itr, j.index(), mod);
3692  *cut_t_itr -= denom;
3693  }
3694  }
3695  }
3696  if (ap_column != not_a_dimension()) {
3697  // If we re-use an existing Artificial_Parameter
3698  cut_t[ap_column] = denom;
3699  }
3700 #ifdef NOISY_PIP
3701  {
3702  using namespace IO_Operators;
3703  Linear_Expression expr;
3704  dimension_type ti = 1;
3705  dimension_type si = 0;
3706  for (dimension_type j = 0; j < space_dimension; ++j) {
3707  if (parameters.count(j) == 1) {
3708  add_mul_assign(expr, cut_t.get(ti), Variable(j));
3709  ++ti;
3710  }
3711  else {
3712  add_mul_assign(expr, cut_s.get(si), Variable(j));
3713  ++si;
3714  }
3715  }
3716  std::cerr << std::setw(2 * indent_level) << ""
3717  << "Adding cut: "
3718  << Constraint(expr + cut_t.get(0) >= 0)
3719  << std::endl;
3720  }
3721 #endif // #ifdef NOISY_PIP
3722  var_row.push_back(num_rows + num_vars);
3723  basis.push_back(false);
3724  mapping.push_back(num_rows);
3725  sign.push_back(NEGATIVE);
3726 }
size_t dimension_type
An unsigned integral type for representing space dimensions.
Tableau tableau
The parametric simplex tableau.
#define PPL_DIRTY_TEMP_COEFFICIENT(id)
Declare a local variable named id, of type Coefficient, and containing an unknown initial value...
dimension_type not_a_dimension()
Returns a value that does not designate a valid dimension.
CO_Tree::iterator iterator
An iterator on the row elements.
void add_mul_assign(GMP_Integer &x, const GMP_Integer &y, const GMP_Integer &z)
PIP_Tree_Node(const PIP_Problem *owner)
Constructor: builds a node owned by *owner.
Definition: PIP_Tree.cc:916
#define WEIGHT_ADD(delta)
Definition: globals_defs.hh:83
All nonzero row coefficients are negative.
std::vector< dimension_type > var_row
The variable identifiers associated to the rows of the simplex tableau.
Coefficient_traits::const_reference denominator() const
Returns the value of the denominator.
std::vector< dimension_type > mapping
A mapping between the tableau rows/columns and the original variables.
#define WEIGHT_BEGIN()
Definition: globals_defs.hh:81
void neg_assign(GMP_Integer &x)
Artificial_Parameter_Sequence artificial_parameters
The local sequence of expressions for local artificial parameters.
std::vector< bool > basis
A boolean vector for identifying the basic variables.
Matrix< Row > t
The matrix of parameter coefficients.
#define PPL_USED(v)
No-op macro that allows to avoid unused variable warnings from the compiler.
Definition: compiler.hh:39
Matrix< Row > s
The matrix of simplex coefficients.
CO_Tree::const_iterator const_iterator
A const iterator on the row elements.
std::vector< Row_Sign > sign
A cache for computed sign values of constraint parametric RHS.
bool Parma_Polyhedra_Library::PIP_Solution_Node::OK ( ) const
virtual

Returns true if and only if *this is well formed.

Implements Parma_Polyhedra_Library::PIP_Tree_Node.

Definition at line 1263 of file PIP_Tree.cc.

References Parma_Polyhedra_Library::PIP_Tree_Node::OK(), var_column, and var_row.

Referenced by ascii_load(), Parma_Polyhedra_Library::PIP_Solution_Node::Tableau::ascii_load(), Parma_Polyhedra_Library::PIP_Decision_Node::ascii_load(), Parma_Polyhedra_Library::PIP_Tree_Node::parent_merge(), solve(), Parma_Polyhedra_Library::PIP_Decision_Node::solve(), update_tableau(), and Parma_Polyhedra_Library::PIP_Decision_Node::update_tableau().

1263  {
1264 #ifndef NDEBUG
1265  using std::cerr;
1266 #endif
1267  if (!PIP_Tree_Node::OK()) {
1268  return false;
1269  }
1270 
1271  // Check that every member used is OK.
1272 
1273  if (!tableau.OK()) {
1274  return false;
1275  }
1276 
1277  // Check coherency of basis, mapping, var_row and var_column
1278  if (basis.size() != mapping.size()) {
1279 #ifndef NDEBUG
1280  cerr << "The PIP_Solution_Node::basis and PIP_Solution_Node::mapping "
1281  << "vectors do not have the same number of elements.\n";
1282 #endif
1283  return false;
1284  }
1285  if (basis.size() != var_row.size() + var_column.size()) {
1286 #ifndef NDEBUG
1287  cerr << "The sum of number of elements in the PIP_Solution_Node::var_row "
1288  << "and PIP_Solution_Node::var_column vectors is different from the "
1289  << "number of elements in the PIP_Solution_Node::basis vector.\n";
1290 #endif
1291  return false;
1292  }
1293  if (var_column.size() != tableau.s.num_columns()) {
1294 #ifndef NDEBUG
1295  cerr << "The number of elements in the PIP_Solution_Node::var_column "
1296  << "vector is different from the number of columns in the "
1297  << "PIP_Solution_Node::tableau.s matrix.\n";
1298 #endif
1299  return false;
1300  }
1301  if (var_row.size() != tableau.s.num_rows()) {
1302 #ifndef NDEBUG
1303  cerr << "The number of elements in the PIP_Solution_Node::var_row "
1304  << "vector is different from the number of rows in the "
1305  << "PIP_Solution_Node::tableau.s matrix.\n";
1306 #endif
1307  return false;
1308  }
1309  for (dimension_type i = mapping.size(); i-- > 0; ) {
1310  const dimension_type row_column = mapping[i];
1311  if (basis[i] && var_column[row_column] != i) {
1312 #ifndef NDEBUG
1313  cerr << "Variable " << i << " is basic and corresponds to column "
1314  << row_column << " but PIP_Solution_Node::var_column["
1315  << row_column << "] does not correspond to variable " << i
1316  << ".\n";
1317 #endif
1318  return false;
1319  }
1320  if (!basis[i] && var_row[row_column] != i) {
1321 #ifndef NDEBUG
1322  cerr << "Variable " << i << " is nonbasic and corresponds to row "
1323  << row_column << " but PIP_Solution_Node::var_row["
1324  << row_column << "] does not correspond to variable " << i
1325  << ".\n";
1326 #endif
1327  return false;
1328  }
1329  }
1330  // All checks passed.
1331  return true;
1332 }
std::vector< dimension_type > var_column
The variable identifiers associated to the columns of the simplex tableau.
size_t dimension_type
An unsigned integral type for representing space dimensions.
Tableau tableau
The parametric simplex tableau.
std::vector< dimension_type > var_row
The variable identifiers associated to the rows of the simplex tableau.
bool OK() const
Returns true if and only if *this is well formed.
Definition: PIP_Tree.cc:1168
virtual bool OK() const =0
Returns true if and only if *this is well formed.
Definition: PIP_Tree.cc:1197
std::vector< dimension_type > mapping
A mapping between the tableau rows/columns and the original variables.
std::vector< bool > basis
A boolean vector for identifying the basic variables.
Matrix< Row > s
The matrix of simplex coefficients.
const Linear_Expression & Parma_Polyhedra_Library::PIP_Solution_Node::parametric_values ( Variable  var) const

Returns a parametric expression for the values of problem variable var.

The returned linear expression may involve problem parameters as well as artificial parameters.

Parameters
varThe problem variable which is queried about.
Exceptions
std::invalid_argumentThrown if var is dimension-incompatible with the PIP_Problem owning this solution node, or if var is a problem parameter.

Definition at line 3920 of file PIP_Tree.cc.

References Parma_Polyhedra_Library::PIP_Tree_Node::get_owner(), Parma_Polyhedra_Library::Variable::id(), Parma_Polyhedra_Library::PIP_Problem::parameter_space_dimensions(), solution, Parma_Polyhedra_Library::Variable::space_dimension(), Parma_Polyhedra_Library::PIP_Problem::space_dimension(), and update_solution().

3920  {
3921  const PIP_Problem* const pip = get_owner();
3922  PPL_ASSERT(pip != 0);
3923 
3924  const dimension_type space_dim = pip->space_dimension();
3925  if (var.space_dimension() > space_dim) {
3926  std::ostringstream s;
3927  s << "PPL::PIP_Solution_Node::parametric_values(v):\n"
3928  << "v.space_dimension() == " << var.space_dimension()
3929  << " is incompatible with the owning PIP_Problem "
3930  << " (space dim == " << space_dim << ").";
3931  throw std::invalid_argument(s.str());
3932  }
3933 
3934  dimension_type solution_index = var.id();
3935  const Variables_Set& params = pip->parameter_space_dimensions();
3936  for (Variables_Set::const_iterator p = params.begin(),
3937  p_end = params.end(); p != p_end; ++p) {
3938  const dimension_type param_index = *p;
3939  if (param_index < var.id()) {
3940  --solution_index;
3941  }
3942  else if (param_index == var.id()) {
3943  throw std::invalid_argument("PPL::PIP_Solution_Node"
3944  "::parametric_values(v):\n"
3945  "v is a problem parameter.");
3946  }
3947  else {
3948  break;
3949  }
3950  }
3951 
3952  update_solution();
3953  return solution[solution_index];
3954 }
size_t dimension_type
An unsigned integral type for representing space dimensions.
const PIP_Problem * get_owner() const
Returns a pointer to the PIP_Problem owning object.
std::vector< Linear_Expression > solution
Parametric values for the solution.
void update_solution() const
Helper method.
Definition: PIP_Tree.cc:3958
void Parma_Polyhedra_Library::PIP_Solution_Node::print_tree ( std::ostream &  s,
int  indent,
const std::vector< bool > &  pip_dim_is_param,
dimension_type  first_art_dim 
) const
protectedvirtual

Prints on s the tree rooted in *this.

Implements Parma_Polyhedra_Library::PIP_Tree_Node.

Definition at line 3887 of file PIP_Tree.cc.

References Parma_Polyhedra_Library::PIP_Tree_Node::constraints_, Parma_Polyhedra_Library::Constraint_System::empty(), Parma_Polyhedra_Library::PIP_Tree_Node::indent_and_print(), Parma_Polyhedra_Library::PIP_Tree_Node::print_tree(), solution, and update_solution().

Referenced by Parma_Polyhedra_Library::PIP_Tree_Node::print().

3889  {
3890  // Print info common to decision and solution nodes.
3891  PIP_Tree_Node::print_tree(s, indent, pip_dim_is_param, first_art_dim);
3892 
3893  // Print info specific of solution nodes:
3894  // first update solution if needed ...
3895  update_solution(pip_dim_is_param);
3896  // ... and then actually print it.
3897  const bool no_constraints = constraints_.empty();
3898  indent_and_print(s, indent + (no_constraints ? 0 : 1), "{");
3899  const dimension_type pip_space_dim = pip_dim_is_param.size();
3900  for (dimension_type i = 0, num_var = 0; i < pip_space_dim; ++i) {
3901  if (pip_dim_is_param[i]) {
3902  continue;
3903  }
3904  if (num_var > 0) {
3905  s << " ; ";
3906  }
3907  using namespace IO_Operators;
3908  s << solution[num_var];
3909  ++num_var;
3910  }
3911  s << "}\n";
3912 
3913  if (!no_constraints) {
3914  indent_and_print(s, indent, "else\n");
3915  indent_and_print(s, indent+1, "_|_\n");
3916  }
3917 }
size_t dimension_type
An unsigned integral type for representing space dimensions.
virtual void print_tree(std::ostream &s, int indent, const std::vector< bool > &pip_dim_is_param, dimension_type first_art_dim) const =0
Prints on s the tree rooted in *this.
Definition: PIP_Tree.cc:3831
bool empty() const
Returns true if and only if *this has no constraints.
std::vector< Linear_Expression > solution
Parametric values for the solution.
void update_solution() const
Helper method.
Definition: PIP_Tree.cc:3958
Constraint_System constraints_
The local system of parameter constraints.
static void indent_and_print(std::ostream &s, int indent, const char *str)
A helper function used when printing PIP trees.
Definition: PIP_Tree.cc:3803
PIP_Solution_Node::Row_Sign Parma_Polyhedra_Library::PIP_Solution_Node::row_sign ( const Row x,
dimension_type  big_dimension 
)
staticprivate

Returns the sign of row x.

Definition at line 2152 of file PIP_Tree.cc.

References Parma_Polyhedra_Library::Sparse_Row::begin(), Parma_Polyhedra_Library::Sparse_Row::end(), Parma_Polyhedra_Library::Sparse_Row::get(), MIXED, NEGATIVE, Parma_Polyhedra_Library::not_a_dimension(), POSITIVE, sign, and ZERO.

Referenced by solve(), and update_tableau().

2153  {
2154  if (big_dimension != not_a_dimension()) {
2155  // If a big parameter has been set and its coefficient is not zero,
2156  // then return the sign of the coefficient.
2157  Coefficient_traits::const_reference x_big = x.get(big_dimension);
2158  if (x_big > 0) {
2159  return POSITIVE;
2160  }
2161  if (x_big < 0) {
2162  return NEGATIVE;
2163  }
2164  // Otherwise x_big == 0, then no big parameter involved.
2165  }
2166 
2168  for (Row::const_iterator i = x.begin(), i_end = x.end(); i != i_end; ++i) {
2169  Coefficient_traits::const_reference x_i = *i;
2170  if (x_i > 0) {
2171  if (sign == NEGATIVE) {
2172  return MIXED;
2173  }
2174  sign = POSITIVE;
2175  }
2176  else if (x_i < 0) {
2177  if (sign == POSITIVE) {
2178  return MIXED;
2179  }
2180  sign = NEGATIVE;
2181  }
2182  }
2183  return sign;
2184 }
dimension_type not_a_dimension()
Returns a value that does not designate a valid dimension.
dimension_type big_dimension
The column index in the parametric part of the simplex tableau corresponding to the big parameter; no...
The row contains both positive and negative coefficients.
All nonzero row coefficients are negative.
All nonzero row coefficients are positive.
Row_Sign
The possible values for the sign of a parametric linear expression.
CO_Tree::const_iterator const_iterator
A const iterator on the row elements.
std::vector< Row_Sign > sign
A cache for computed sign values of constraint parametric RHS.
void Parma_Polyhedra_Library::PIP_Solution_Node::set_owner ( const PIP_Problem owner)
protectedvirtual

Sets the pointer to the PIP_Problem owning object.

Implements Parma_Polyhedra_Library::PIP_Tree_Node.

Definition at line 1120 of file PIP_Tree.cc.

References Parma_Polyhedra_Library::PIP_Tree_Node::owner_.

Referenced by Parma_Polyhedra_Library::PIP_Problem::ascii_load().

1120  {
1121  owner_ = owner;
1122 }
const PIP_Problem * owner_
A pointer to the PIP_Problem object owning this node.
PIP_Tree_Node * Parma_Polyhedra_Library::PIP_Solution_Node::solve ( const PIP_Problem pip,
bool  check_feasible_context,
const Matrix< Row > &  context,
const Variables_Set params,
dimension_type  space_dim,
int  indent_level 
)
protectedvirtual

Implements pure virtual method PIP_Tree_Node::solve.

Implements Parma_Polyhedra_Library::PIP_Tree_Node.

Definition at line 2605 of file PIP_Tree.cc.

References Parma_Polyhedra_Library::PIP_Tree_Node::add_constraint(), Parma_Polyhedra_Library::add_mul_assign(), Parma_Polyhedra_Library::Matrix< Row >::add_row(), Parma_Polyhedra_Library::PIP_Tree_Node::artificial_parameters, Parma_Polyhedra_Library::Matrix< Row >::ascii_dump(), Parma_Polyhedra_Library::Constraint_System::begin(), Parma_Polyhedra_Library::Sparse_Row::begin(), big_dimension, Parma_Polyhedra_Library::PIP_Tree_Node::compatibility_check(), Parma_Polyhedra_Library::PIP_Tree_Node::constraints_, Parma_Polyhedra_Library::PIP_Problem::control_parameters, Parma_Polyhedra_Library::PIP_Problem::CUTTING_STRATEGY, Parma_Polyhedra_Library::PIP_Problem::CUTTING_STRATEGY_ALL, Parma_Polyhedra_Library::PIP_Problem::CUTTING_STRATEGY_DEEPEST, Parma_Polyhedra_Library::PIP_Problem::CUTTING_STRATEGY_FIRST, Parma_Polyhedra_Library::Constraint_System::empty(), Parma_Polyhedra_Library::Constraint_System::end(), Parma_Polyhedra_Library::Sparse_Row::end(), Parma_Polyhedra_Library::exact_div_assign(), Parma_Polyhedra_Library::PIP_Decision_Node::false_child, Parma_Polyhedra_Library::Sparse_Row::find(), Parma_Polyhedra_Library::gcd_assign(), generate_cut(), Parma_Polyhedra_Library::Sparse_Row::get(), Parma_Polyhedra_Library::PIP_Tree_Node::get_owner(), Parma_Polyhedra_Library::PIP_Tree_Node::indent_and_print(), Parma_Polyhedra_Library::CO_Tree::iterator::index(), Parma_Polyhedra_Library::Constraint_System::insert(), Parma_Polyhedra_Library::Sparse_Row::insert(), Parma_Polyhedra_Library::Sparse_Row::m_swap(), Parma_Polyhedra_Library::maybe_abandon(), MIXED, NEGATIVE, Parma_Polyhedra_Library::not_a_dimension(), Parma_Polyhedra_Library::Matrix< Row >::num_rows(), OK(), Parma_Polyhedra_Library::PIP_Tree_Node::parent(), Parma_Polyhedra_Library::PIP_Tree_Node::PIP_Decision_Node, PIP_Solution_Node(), Parma_Polyhedra_Library::PIP_Problem::PIVOT_ROW_STRATEGY, Parma_Polyhedra_Library::PIP_Problem::PIVOT_ROW_STRATEGY_FIRST, POSITIVE, PPL_DIRTY_TEMP_COEFFICIENT, PPL_USED, row_sign(), sign, solution_valid, Parma_Polyhedra_Library::PIP_Tree_Node::solve(), Parma_Polyhedra_Library::swap(), UNKNOWN, var_column, var_row, WEIGHT_ADD, WEIGHT_BEGIN, and ZERO.

2610  {
2611  PPL_ASSERT(indent_level >= 0);
2612 #ifdef NOISY_PIP_TREE_STRUCTURE
2613  indent_and_print(std::cerr, indent_level, "=== SOLVING NODE\n");
2614 #else
2615  PPL_USED(indent_level);
2616 #endif
2617  // Reset current solution as invalid.
2618  solution_valid = false;
2619 
2620  Matrix<Row> ctx(context);
2621  Variables_Set all_params(params);
2622  const dimension_type num_art_params = artificial_parameters.size();
2623  add_artificial_parameters(ctx, all_params, space_dim, num_art_params);
2624  merge_assign(ctx, constraints_, all_params);
2625 
2626  // If needed, (re-)check feasibility of context.
2627  if (check_feasible_context) {
2628  Matrix<Row> ctx_copy(ctx);
2629  if (!compatibility_check(ctx_copy)) {
2630  delete this;
2631  return 0;
2632  }
2633  }
2634 
2635  const dimension_type not_a_dim = not_a_dimension();
2636 
2637  // Main loop of the simplex algorithm.
2638  while (true) {
2639  // Check if the client has requested abandoning all expensive
2640  // computations. If so, the exception specified by the client
2641  // is thrown now.
2642  maybe_abandon();
2643 
2644  PPL_ASSERT(OK());
2645 
2646  const dimension_type num_rows = tableau.t.num_rows();
2647  const dimension_type num_vars = tableau.s.num_columns();
2648  const dimension_type num_params = tableau.t.num_columns();
2649  Coefficient_traits::const_reference tableau_denom = tableau.denominator();
2650 
2651 #ifdef VERY_NOISY_PIP
2652  tableau.ascii_dump(std::cerr);
2653  std::cerr << "context ";
2654  ctx.ascii_dump(std::cerr);
2655 #endif // #ifdef VERY_NOISY_PIP
2656 
2657  // (Re-) Compute parameter row signs.
2658  // While at it, keep track of the first parameter rows
2659  // having negative and mixed sign.
2660  dimension_type first_negative = not_a_dim;
2661  dimension_type first_mixed = not_a_dim;
2662  for (dimension_type i = 0; i < num_rows; ++i) {
2663  Row_Sign& sign_i = sign[i];
2664  if (sign_i == UNKNOWN || sign_i == MIXED) {
2665  sign_i = row_sign(tableau.t[i], big_dimension);
2666  }
2667 
2668  if (sign_i == NEGATIVE && first_negative == not_a_dim) {
2669  first_negative = i;
2670  }
2671  else if (sign_i == MIXED && first_mixed == not_a_dim) {
2672  first_mixed = i;
2673  }
2674  }
2675 
2676  // If no negative parameter row was found, try to refine the sign of
2677  // mixed rows using compatibility checks with the current context.
2678  if (first_negative == not_a_dim && first_mixed != not_a_dim) {
2679  for (dimension_type i = first_mixed; i < num_rows; ++i) {
2680  // Consider mixed sign parameter rows only.
2681  if (sign[i] != MIXED) {
2682  continue;
2683  }
2684  const Row& t_i = tableau.t[i];
2685  Row_Sign new_sign = ZERO;
2686  // Check compatibility for constraint t_i(z) >= 0.
2687  if (compatibility_check(ctx, t_i)) {
2688  new_sign = POSITIVE;
2689  }
2690  // Check compatibility for constraint t_i(z) < 0,
2691  // i.e., -t_i(z) - 1 >= 0.
2692  Row t_i_complement(num_params);
2693  complement_assign(t_i_complement, t_i, tableau_denom);
2694  if (compatibility_check(ctx, t_i_complement)) {
2695  new_sign = (new_sign == POSITIVE) ? MIXED : NEGATIVE;
2696  }
2697  // Update sign for parameter row i.
2698  sign[i] = new_sign;
2699  // Maybe update first_negative and first_mixed.
2700  if (new_sign == NEGATIVE && first_negative == not_a_dim) {
2701  first_negative = i;
2702  if (i == first_mixed) {
2703  first_mixed = not_a_dim;
2704  }
2705  }
2706  else if (new_sign == MIXED) {
2707  if (first_mixed == not_a_dim) {
2708  first_mixed = i;
2709  }
2710  }
2711  else if (i == first_mixed) {
2712  first_mixed = not_a_dim;
2713  }
2714  }
2715  }
2716 
2717  // If there still is no negative parameter row and a mixed sign
2718  // parameter row (first_mixed) such that:
2719  // - it has at least one positive variable coefficient;
2720  // - constraint t_i(z) > 0 is not compatible with the context;
2721  // then this parameter row can be considered negative.
2722  if (first_negative == not_a_dim && first_mixed != not_a_dim) {
2723  WEIGHT_BEGIN();
2724  for (dimension_type i = first_mixed; i < num_rows; ++i) {
2725  // Consider mixed sign parameter rows only.
2726  if (sign[i] != MIXED) {
2727  continue;
2728  }
2729  // Check for a positive variable coefficient.
2730  const Row& s_i = tableau.s[i];
2731  bool has_positive = false;
2732  {
2733  for (Row::const_iterator
2734  j = s_i.begin(), j_end = s_i.end(); j != j_end; ++j) {
2735  if (*j > 0) {
2736  has_positive = true;
2737  break;
2738  }
2739  }
2740  }
2741  if (!has_positive) {
2742  continue;
2743  }
2744  // Check compatibility of constraint t_i(z) > 0.
2745  Row row(tableau.t[i]);
2747  Coefficient& row0 = row[0];
2748  pos_rem_assign(mod, row0, tableau_denom);
2749  row0 -= (mod == 0) ? tableau_denom : mod;
2750  WEIGHT_ADD(210);
2751  const bool compatible = compatibility_check(ctx, row);
2752  // Maybe update sign (and first_* indices).
2753  if (compatible) {
2754  // Sign is still mixed.
2755  if (first_mixed == not_a_dim) {
2756  first_mixed = i;
2757  }
2758  }
2759  else {
2760  // Sign becomes negative (i.e., no longer mixed).
2761  sign[i] = NEGATIVE;
2762  if (first_negative == not_a_dim) {
2763  first_negative = i;
2764  }
2765  if (first_mixed == i) {
2766  first_mixed = not_a_dim;
2767  }
2768  }
2769  }
2770  }
2771 
2772 #ifdef VERY_NOISY_PIP
2773  std::cerr << "sign =";
2774  for (dimension_type i = 0; i < sign.size(); ++i)
2775  std::cerr << " " << "?0+-*"[sign[i]];
2776  std::cerr << std::endl;
2777 #endif // #ifdef VERY_NOISY_PIP
2778 
2779  // If we have found a negative parameter row, then
2780  // either the problem is unfeasible, or a pivoting step is required.
2781  if (first_negative != not_a_dim) {
2782 
2783  // Search for the best pivot row.
2784  dimension_type pi = not_a_dim;
2785  dimension_type pj = not_a_dim;
2786  for (dimension_type i = first_negative; i < num_rows; ++i) {
2787  if (sign[i] != NEGATIVE) {
2788  continue;
2789  }
2790  dimension_type j;
2791  if (!find_lexico_minimal_column(tableau.s, mapping, basis,
2792  tableau.s[i], 0, j)) {
2793  // No positive s_ij was found: problem is unfeasible.
2794 #ifdef NOISY_PIP_TREE_STRUCTURE
2795  indent_and_print(std::cerr, indent_level,
2796  "No positive pivot: Solution = _|_\n");
2797 #endif // #ifdef NOISY_PIP_TREE_STRUCTURE
2798  delete this;
2799  return 0;
2800  }
2801  if (pj == not_a_dim
2802  || tableau.is_better_pivot(mapping, basis, i, j, pi, pj)) {
2803  // Update pivot indices.
2804  pi = i;
2805  pj = j;
2806  if (pip.control_parameters[PIP_Problem::PIVOT_ROW_STRATEGY]
2808  // Stop at first valid row.
2809  break;
2810  }
2811  }
2812  }
2813 
2814 #ifdef VERY_NOISY_PIP
2815  std::cerr << "Pivot (pi, pj) = (" << pi << ", " << pj << ")\n";
2816 #endif // #ifdef VERY_NOISY_PIP
2817 
2818  // Normalize the tableau before pivoting.
2819  tableau.normalize();
2820 
2821  // Perform pivot operation.
2822 
2823  // Update basis.
2824  {
2825  const dimension_type var_pi = var_row[pi];
2826  const dimension_type var_pj = var_column[pj];
2827  var_row[pi] = var_pj;
2828  var_column[pj] = var_pi;
2829  basis[var_pi] = true;
2830  basis[var_pj] = false;
2831  mapping[var_pi] = pj;
2832  mapping[var_pj] = pi;
2833  }
2834 
2835  PPL_DIRTY_TEMP_COEFFICIENT(product);
2837  PPL_DIRTY_TEMP_COEFFICIENT(scale_factor);
2838 
2839  // Creating identity rows corresponding to basic variable pj:
2840  // 1. add them to tableau so as to have proper size and capacity;
2841  tableau.s.add_zero_rows(1);
2842  tableau.t.add_zero_rows(1);
2843  // 2. swap the rows just added with empty ones.
2844  Row s_pivot(0);
2845  Row t_pivot(0);
2846  swap(s_pivot, tableau.s[num_rows]);
2847  swap(t_pivot, tableau.t[num_rows]);
2848  // 3. drop rows previously added at end of tableau.
2849  tableau.s.remove_trailing_rows(1);
2850  tableau.t.remove_trailing_rows(1);
2851 
2852  // Save current pivot denominator.
2853  PPL_DIRTY_TEMP_COEFFICIENT(pivot_denom);
2854  pivot_denom = tableau.denominator();
2855  // Let the (scaled) pivot coordinate be 1.
2856  s_pivot[pj] = pivot_denom;
2857 
2858  // Swap identity row with the pivot row previously found.
2859  s_pivot.m_swap(tableau.s[pi]);
2860  t_pivot.m_swap(tableau.t[pi]);
2861  sign[pi] = ZERO;
2862 
2863  PPL_DIRTY_TEMP_COEFFICIENT(s_pivot_pj);
2864  s_pivot_pj = s_pivot.get(pj);
2865 
2866  // Compute columns s[*][j]:
2867  //
2868  // <CODE>
2869  // s[i][j] -= s[i][pj] * s_pivot[j] / s_pivot_pj;
2870  // </CODE>
2871  for (dimension_type i = num_rows; i-- > 0; ) {
2872  Row& s_i = tableau.s[i];
2874  s_i_pj = s_i.get(pj);
2875 
2876  if (s_i_pj == 0) {
2877  continue;
2878  }
2879 
2880  WEIGHT_BEGIN();
2881  Row::iterator itr = s_i.end();
2882  for (Row::const_iterator
2883  j = s_pivot.begin(), j_end = s_pivot.end(); j != j_end; ++j) {
2884  if (j.index() != pj) {
2885  Coefficient_traits::const_reference s_pivot_j = *j;
2886  // Do nothing if the j-th pivot element is zero.
2887  if (s_pivot_j != 0) {
2888  product = s_pivot_j * s_i_pj;
2889  if (product % s_pivot_pj != 0) {
2890  // Must scale matrix to stay in integer case.
2891  gcd_assign(gcd, product, s_pivot_pj);
2892  exact_div_assign(scale_factor, s_pivot_pj, gcd);
2893  tableau.scale(scale_factor);
2894  s_i_pj *= scale_factor;
2895  product *= scale_factor;
2896  WEIGHT_ADD(102);
2897  }
2898  PPL_ASSERT(product % s_pivot_pj == 0);
2899  exact_div_assign(product, product, s_pivot_pj);
2900  WEIGHT_ADD(130);
2901  if (product != 0) {
2902  itr = s_i.insert(itr, j.index());
2903  *itr -= product;
2904  WEIGHT_ADD(34);
2905  }
2906  }
2907  }
2908  }
2909  }
2910 
2911  // Compute columns t[*][j]:
2912  //
2913  // <CODE>
2914  // t[i][j] -= s[i][pj] * t_pivot[j] / s_pivot_pj;
2915  // </CODE>
2916  for (dimension_type i = num_rows; i-- > 0; ) {
2917  Row& s_i = tableau.s[i];
2918  Row& t_i = tableau.t[i];
2919 
2920  Row::iterator s_i_pj_itr = s_i.find(pj);
2921 
2922  if (s_i_pj_itr == s_i.end()) {
2923  continue;
2924  }
2925 
2926  // FIXME: the following comment does not make sense.
2927  // NOTE: This is a Coefficient& instead of a
2928  // Coefficient_traits::const_reference, because scale() may silently
2929  // modify it.
2930  const Coefficient& s_i_pj = *s_i_pj_itr;
2931 
2932  if (s_i_pj == 0) {
2933  continue;
2934  }
2935 
2936  WEIGHT_BEGIN();
2937  Row::iterator k = t_i.end();
2938  for (Row::const_iterator
2939  j = t_pivot.begin(), j_end = t_pivot.end(); j != j_end; ++j) {
2940  Coefficient_traits::const_reference t_pivot_j = *j;
2941  // Do nothing if the j-th pivot element is zero.
2942  if (t_pivot_j != 0) {
2943  product = t_pivot_j * s_i_pj;
2944  if (product % s_pivot_pj != 0) {
2945  // Must scale matrix to stay in integer case.
2946  gcd_assign(gcd, product, s_pivot_pj);
2947  exact_div_assign(scale_factor, s_pivot_pj, gcd);
2948  tableau.scale(scale_factor);
2949  product *= scale_factor;
2950  WEIGHT_ADD(261);
2951  }
2952  PPL_ASSERT(product % s_pivot_pj == 0);
2953  exact_div_assign(product, product, s_pivot_pj);
2954  WEIGHT_ADD(115);
2955  if (product != 0) {
2956  k = t_i.insert(k, j.index());
2957  *k -= product;
2958  WEIGHT_ADD(41);
2959  }
2960 
2961  // Update row sign.
2962  Row_Sign& sign_i = sign[i];
2963  switch (sign_i) {
2964  case ZERO:
2965  if (product > 0) {
2966  sign_i = NEGATIVE;
2967  }
2968  else if (product < 0) {
2969  sign_i = POSITIVE;
2970  }
2971  break;
2972  case POSITIVE:
2973  if (product > 0) {
2974  sign_i = MIXED;
2975  }
2976  break;
2977  case NEGATIVE:
2978  if (product < 0) {
2979  sign_i = MIXED;
2980  }
2981  break;
2982  default:
2983  break;
2984  }
2985  }
2986  }
2987  }
2988 
2989  // Compute column s[*][pj]: s[i][pj] /= s_pivot_pj;
2990  // Update column only if pivot coordinate != 1.
2991  if (s_pivot_pj != pivot_denom) {
2992  WEIGHT_BEGIN();
2993  Row::iterator itr;
2994  for (dimension_type i = num_rows; i-- > 0; ) {
2995  Row& s_i = tableau.s[i];
2996  itr = s_i.find(pj);
2997  if (itr == s_i.end()) {
2998  continue;
2999  }
3000  WEIGHT_ADD(43);
3001  product = *itr * pivot_denom;
3002  if (product % s_pivot_pj != 0) {
3003  // As above, perform matrix scaling.
3004  gcd_assign(gcd, product, s_pivot_pj);
3005  exact_div_assign(scale_factor, s_pivot_pj, gcd);
3006  tableau.scale(scale_factor);
3007  product *= scale_factor;
3008  WEIGHT_ADD(177);
3009  }
3010  PPL_ASSERT(product % s_pivot_pj == 0);
3011  if (product != 0 || *itr != 0) {
3012  WEIGHT_ADD(106);
3013  exact_div_assign(*itr, product, s_pivot_pj);
3014  }
3015  }
3016  }
3017 
3018  // Pivoting process ended: jump to next iteration.
3019  continue;
3020  } // if (first_negative != not_a_dim)
3021 
3022 
3023  PPL_ASSERT(first_negative == not_a_dim);
3024  // If no negative parameter row was found,
3025  // but a mixed parameter row was found ...
3026  if (first_mixed != not_a_dim) {
3027  // Look for a constraint (i_neg):
3028  // - having mixed parameter sign;
3029  // - having no positive variable coefficient;
3030  // - minimizing the score (sum of parameter coefficients).
3031  dimension_type i_neg = not_a_dim;
3032  PPL_DIRTY_TEMP_COEFFICIENT(best_score);
3034  for (dimension_type i = first_mixed; i < num_rows; ++i) {
3035  // Mixed parameter sign.
3036  if (sign[i] != MIXED) {
3037  continue;
3038  }
3039  // No positive variable coefficient.
3040  bool has_positive = false;
3041  {
3042  const Row& s_i = tableau.s[i];
3043  for (Row::const_iterator
3044  j = s_i.begin(), j_end = s_i.end(); j != j_end; ++j) {
3045  if (*j > 0) {
3046  has_positive = true;
3047  break;
3048  }
3049  }
3050  }
3051  if (has_positive) {
3052  continue;
3053  }
3054  // Minimize parameter coefficient score,
3055  // eliminating implicated tautologies (if any).
3056  score = 0;
3057  {
3058  WEIGHT_BEGIN();
3059  const Row& t_i = tableau.t[i];
3060  for (Row::const_iterator
3061  j = t_i.begin(), j_end = t_i.end(); j != j_end; ++j) {
3062  WEIGHT_ADD(55);
3063  score += *j;
3064  }
3065  }
3066  if (i_neg == not_a_dim || score < best_score) {
3067  i_neg = i;
3068  best_score = score;
3069  }
3070  }
3071 
3072  if (i_neg != not_a_dim) {
3073  Row tautology = tableau.t[i_neg];
3074  /* Simplify tautology by exploiting integrality. */
3075  integral_simplification(tautology);
3076  ctx.add_row(tautology);
3077  add_constraint(tautology, all_params);
3078  sign[i_neg] = POSITIVE;
3079 #ifdef NOISY_PIP
3080  {
3081  Linear_Expression expr = Linear_Expression(tautology.get(0));
3082  dimension_type j = 1;
3083  for (Variables_Set::const_iterator p = all_params.begin(),
3084  p_end = all_params.end(); p != p_end; ++p, ++j)
3085  add_mul_assign(expr, tautology.get(j), Variable(*p));
3086  using namespace IO_Operators;
3087  std::cerr << std::setw(2 * indent_level) << ""
3088  << "Row " << i_neg
3089  << ": mixed param sign, negative var coeffs\n";
3090  std::cerr << std::setw(2 * indent_level) << ""
3091  << "==> adding tautology: "
3092  << Constraint(expr >= 0) << ".\n";
3093  }
3094 #endif // #ifdef NOISY_PIP
3095  // Jump to next iteration.
3096  continue;
3097  }
3098 
3099  PPL_ASSERT(i_neg == not_a_dim);
3100  // Heuristically choose "best" (mixed) pivoting row.
3101  dimension_type best_i = not_a_dim;
3102  for (dimension_type i = first_mixed; i < num_rows; ++i) {
3103  if (sign[i] != MIXED) {
3104  continue;
3105  }
3106  score = 0;
3107  {
3108  WEIGHT_BEGIN();
3109  const Row& t_i = tableau.t[i];
3110  for (Row::const_iterator
3111  j = t_i.begin(), j_end = t_i.end(); j != j_end; ++j) {
3112  WEIGHT_ADD(51);
3113  score += *j;
3114  }
3115  }
3116  if (best_i == not_a_dim || score < best_score) {
3117  best_score = score;
3118  best_i = i;
3119  }
3120  }
3121 
3122  Row t_test(tableau.t[best_i]);
3123  /* Simplify t_test by exploiting integrality. */
3124  integral_simplification(t_test);
3125 
3126 #ifdef NOISY_PIP
3127  {
3128  Linear_Expression expr = Linear_Expression(t_test.get(0));
3129  dimension_type j = 1;
3130  for (Variables_Set::const_iterator p = all_params.begin(),
3131  p_end = all_params.end(); p != p_end; ++p, ++j)
3132  add_mul_assign(expr, t_test.get(j), Variable(*p));
3133  using namespace IO_Operators;
3134  std::cerr << std::setw(2 * indent_level) << ""
3135  << "Row " << best_i << ": mixed param sign\n";
3136  std::cerr << std::setw(2 * indent_level) << ""
3137  << "==> depends on sign of " << expr << ".\n";
3138  }
3139 #endif // #ifdef NOISY_PIP
3140 
3141  // Create a solution node for the "true" version of current node.
3142  PIP_Tree_Node* t_node = new PIP_Solution_Node(*this, No_Constraints());
3143  // Protect it from exception safety issues via std::auto_ptr.
3144  std::auto_ptr<PIP_Tree_Node> wrapped_node(t_node);
3145 
3146  // Add parametric constraint to context.
3147  ctx.add_row(t_test);
3148  // Recursively solve true node with respect to updated context.
3149 #ifdef NOISY_PIP_TREE_STRUCTURE
3150  indent_and_print(std::cerr, indent_level, "=== SOLVING THEN CHILD\n");
3151 #endif
3152  t_node = t_node->solve(pip, check_feasible_context,
3153  ctx, all_params, space_dim,
3154  indent_level + 1);
3155  // Resolution may have changed t_node: in case, re-wrap it.
3156  if (t_node != wrapped_node.get()) {
3157  wrapped_node.release();
3158  wrapped_node.reset(t_node);
3159  }
3160 
3161  // Modify *this in place to become the "false" version of current node.
3162  PIP_Tree_Node* f_node = this;
3163  // Swap aside constraints and artificial parameters
3164  // (these will be later restored if needed).
3165  Constraint_System cs;
3167  swap(cs, f_node->constraints_);
3168  swap(aps, f_node->artificial_parameters);
3169  // Compute the complement of the constraint used for the "true" node.
3170  Row& f_test = ctx[ctx.num_rows() - 1];
3171  complement_assign(f_test, t_test, 1);
3172 
3173  // Recursively solve false node with respect to updated context.
3174 #ifdef NOISY_PIP_TREE_STRUCTURE
3175  indent_and_print(std::cerr, indent_level, "=== SOLVING ELSE CHILD\n");
3176 #endif
3177  f_node = f_node->solve(pip, check_feasible_context,
3178  ctx, all_params, space_dim,
3179  indent_level + 1);
3180 
3181  // Case analysis on recursive resolution calls outcome.
3182  if (t_node == 0) {
3183  if (f_node == 0) {
3184  // Both t_node and f_node unfeasible.
3185 #ifdef NOISY_PIP_TREE_STRUCTURE
3186  indent_and_print(std::cerr, indent_level,
3187  "=== EXIT: BOTH BRANCHES UNFEASIBLE: _|_\n");
3188 #endif
3189  return 0;
3190  }
3191  else {
3192  // t_node unfeasible, f_node feasible:
3193  // restore cs and aps into f_node (i.e., this).
3194  PPL_ASSERT(f_node == this);
3195  swap(f_node->constraints_, cs);
3196  swap(f_node->artificial_parameters, aps);
3197  // Add f_test to constraints.
3198  f_node->add_constraint(f_test, all_params);
3199 #ifdef NOISY_PIP_TREE_STRUCTURE
3200  indent_and_print(std::cerr, indent_level,
3201  "=== EXIT: THEN BRANCH UNFEASIBLE: SWAP BRANCHES\n");
3202 #endif
3203  return f_node;
3204  }
3205  }
3206  else if (f_node == 0) {
3207  // t_node feasible, f_node unfeasible.
3208 #ifdef NOISY_PIP_TREE_STRUCTURE
3209  indent_and_print(std::cerr, indent_level,
3210  "=== EXIT: THEN BRANCH FEASIBLE\n");
3211 #endif
3212  // NOTE: in principle, we could merge t_node into its parent.
3213  // However, if t_node is a decision node having both children,
3214  // then we would obtain a node violating the PIP_Decision_Node
3215  // invariant saying that t_node should have a single constraint:
3216  // it will have, at least, the two splitting constraints.
3217  const PIP_Decision_Node* const decision_node_p
3218  = dynamic_cast<PIP_Decision_Node*>(t_node);
3219  if (decision_node_p != 0 && decision_node_p->false_child != 0) {
3220  // Do NOT merge: create a new decision node.
3221  PIP_Tree_Node* const parent
3222  = new PIP_Decision_Node(t_node->get_owner(), 0, t_node);
3223  // Previously wrapped 't_node' is now safe: release it
3224  // and protect new 'parent' node from exception safety issues.
3225  wrapped_node.release();
3226  wrapped_node.reset(parent);
3227  // Restore into parent `cs' and `aps'.
3228  swap(parent->constraints_, cs);
3229  swap(parent->artificial_parameters, aps);
3230  // Add t_test to parent's constraints.
3231  parent->add_constraint(t_test, all_params);
3232  // It is now safe to release previously wrapped parent pointer
3233  // and return it to caller.
3234  return wrapped_node.release();
3235  }
3236  else {
3237  // Merge t_node with its parent:
3238  // a) append into `cs' the constraints of t_node;
3240  i = t_node->constraints_.begin(),
3241  i_end = t_node->constraints_.end(); i != i_end; ++i) {
3242  cs.insert(*i);
3243  }
3244  // b) append into `aps' the parameters of t_node;
3245  aps.insert(aps.end(),
3246  t_node->artificial_parameters.begin(),
3247  t_node->artificial_parameters.end());
3248  // c) swap the updated `cs' and `aps' into t_node.
3249  swap(cs, t_node->constraints_);
3250  swap(aps, t_node->artificial_parameters);
3251  // d) add t_test to t_nodes's constraints.
3252  t_node->add_constraint(t_test, all_params);
3253  // It is now safe to release previously wrapped t_node pointer
3254  // and return it to caller.
3255  return wrapped_node.release();
3256  }
3257  }
3258 
3259  // Here both t_node and f_node are feasible:
3260  // create a new decision node.
3261 #ifdef NOISY_PIP_TREE_STRUCTURE
3262  indent_and_print(std::cerr, indent_level,
3263  "=== EXIT: BOTH BRANCHES FEASIBLE: NEW DECISION NODE\n");
3264 #endif
3265  PIP_Tree_Node* parent
3266  = new PIP_Decision_Node(f_node->get_owner(), f_node, t_node);
3267  // Previously wrapped 't_node' is now safe: release it
3268  // and protect new 'parent' node from exception safety issues.
3269  wrapped_node.release();
3270  wrapped_node.reset(parent);
3271 
3272  // Add t_test to the constraints of the new decision node.
3273  parent->add_constraint(t_test, all_params);
3274 
3275  if (!cs.empty()) {
3276 #ifdef NOISY_PIP_TREE_STRUCTURE
3277  indent_and_print(std::cerr, indent_level,
3278  "=== NODE HAS BOTH BRANCHES AND TAUTOLOGIES:\n");
3279  indent_and_print(std::cerr, indent_level,
3280  "=== CREATE NEW PARENT FOR TAUTOLOGIES\n");
3281 #endif
3282  // If node to be solved had tautologies,
3283  // store them in a new decision node.
3284  parent = new PIP_Decision_Node(parent->get_owner(), 0, parent);
3285  // Previously wrapped 'parent' node is now safe: release it
3286  // and protect new 'parent' node from exception safety issues.
3287  wrapped_node.release();
3288  wrapped_node.reset(parent);
3289  swap(parent->constraints_, cs);
3290  }
3291  swap(parent->artificial_parameters, aps);
3292  // It is now safe to release previously wrapped decision node
3293  // and return it to the caller.
3294  return wrapped_node.release();
3295  } // if (first_mixed != not_a_dim)
3296 
3297 
3298  PPL_ASSERT(first_negative == not_a_dim);
3299  PPL_ASSERT(first_mixed == not_a_dim);
3300  // Here all parameters are positive: we have found a continuous
3301  // solution. If the solution happens to be integer, then it is the
3302  // solution of the integer problem. Otherwise, we may need to generate
3303  // a new cut to try and get back into the integer case.
3304 #ifdef NOISY_PIP
3305  indent_and_print(std::cerr, indent_level,
3306  "All parameters are positive.\n");
3307 #endif // #ifdef NOISY_PIP
3308  tableau.normalize();
3309 
3310  // Look for any row having non integer parameter coefficients.
3311  Coefficient_traits::const_reference denom = tableau.denominator();
3312  for (dimension_type k = 0; k < num_vars; ++k) {
3313  if (basis[k]) {
3314  // Basic variable = 0, hence integer.
3315  continue;
3316  }
3317  const dimension_type i = mapping[k];
3318  const Row& t_i = tableau.t[i];
3319  WEIGHT_BEGIN();
3320  for (Row::const_iterator
3321  j = t_i.begin(), j_end = t_i.end(); j != j_end; ++j) {
3322  WEIGHT_ADD(27);
3323  if (*j % denom != 0) {
3324  goto non_integer;
3325  }
3326  }
3327  }
3328  // The goto was not taken, the solution is integer.
3329 #ifdef NOISY_PIP_TREE_STRUCTURE
3330  indent_and_print(std::cerr, indent_level,
3331  "EXIT: solution found.\n");
3332 #endif // #ifdef NOISY_PIP
3333  return this;
3334 
3335  non_integer:
3336  // The solution is non-integer: generate a cut.
3338  dimension_type best_i = not_a_dim;
3339  dimension_type best_pcount = not_a_dim;
3340 
3341  const PIP_Problem::Control_Parameter_Value cutting_strategy
3342  = pip.control_parameters[PIP_Problem::CUTTING_STRATEGY];
3343 
3344  if (cutting_strategy == PIP_Problem::CUTTING_STRATEGY_FIRST) {
3345  // Find the first row with simplest parametric part.
3346  for (dimension_type k = 0; k < num_vars; ++k) {
3347  if (basis[k]) {
3348  continue;
3349  }
3350  const dimension_type i = mapping[k];
3351  // Count the number of non-integer parameter coefficients.
3352  WEIGHT_BEGIN();
3353  dimension_type pcount = 0;
3354  const Row& t_i = tableau.t[i];
3355  for (Row::const_iterator
3356  j = t_i.begin(), j_end = t_i.end(); j != j_end; ++j) {
3357  WEIGHT_ADD(18);
3358  pos_rem_assign(mod, *j, denom);
3359  if (mod != 0) {
3360  ++pcount;
3361  }
3362  }
3363  if (pcount > 0 && (best_i == not_a_dim || pcount < best_pcount)) {
3364  best_pcount = pcount;
3365  best_i = i;
3366  }
3367  }
3368  // Generate cut using 'best_i'.
3369  generate_cut(best_i, all_params, ctx, space_dim, indent_level);
3370  }
3371  else {
3372  PPL_ASSERT(cutting_strategy == PIP_Problem::CUTTING_STRATEGY_DEEPEST
3373  || cutting_strategy == PIP_Problem::CUTTING_STRATEGY_ALL);
3374  // Find the row with simplest parametric part
3375  // which will generate the "deepest" cut.
3376  PPL_DIRTY_TEMP_COEFFICIENT(best_score);
3377  best_score = 0;
3379  PPL_DIRTY_TEMP_COEFFICIENT(s_score);
3380  std::vector<dimension_type> all_best_is;
3381 
3382  for (dimension_type k = 0; k < num_vars; ++k) {
3383  if (basis[k]) {
3384  continue;
3385  }
3386  const dimension_type i = mapping[k];
3387  // Compute score and pcount.
3388  score = 0;
3389  dimension_type pcount = 0;
3390  {
3391  WEIGHT_BEGIN();
3392  const Row& t_i = tableau.t[i];
3393  for (Row::const_iterator
3394  j = t_i.begin(), j_end = t_i.end(); j != j_end; ++j) {
3395  WEIGHT_ADD(46);
3396  pos_rem_assign(mod, *j, denom);
3397  if (mod != 0) {
3398  WEIGHT_ADD(94);
3399  score += denom;
3400  score -= mod;
3401  ++pcount;
3402  }
3403  }
3404  }
3405 
3406  // Compute s_score.
3407  s_score = 0;
3408  {
3409  WEIGHT_BEGIN();
3410  const Row& s_i = tableau.s[i];
3411  for (Row::const_iterator
3412  j = s_i.begin(), j_end = s_i.end(); j != j_end; ++j) {
3413  WEIGHT_ADD(94);
3414  pos_rem_assign(mod, *j, denom);
3415  s_score += denom;
3416  s_score -= mod;
3417  }
3418  }
3419  // Combine 'score' and 's_score'.
3420  score *= s_score;
3421  /*
3422  Select row i if it is non integer AND
3423  - no row has been chosen yet; OR
3424  - it has fewer non-integer parameter coefficients; OR
3425  - it has the same number of non-integer parameter coefficients,
3426  but its score is greater.
3427  */
3428  if (pcount != 0
3429  && (best_i == not_a_dim
3430  || pcount < best_pcount
3431  || (pcount == best_pcount && score > best_score))) {
3432  if (pcount < best_pcount) {
3433  all_best_is.clear();
3434  }
3435  best_i = i;
3436  best_pcount = pcount;
3437  best_score = score;
3438  }
3439  if (pcount > 0) {
3440  all_best_is.push_back(i);
3441  }
3442  }
3443  if (cutting_strategy == PIP_Problem::CUTTING_STRATEGY_DEEPEST) {
3444  generate_cut(best_i, all_params, ctx, space_dim, indent_level);
3445  }
3446  else {
3447  PPL_ASSERT(cutting_strategy == PIP_Problem::CUTTING_STRATEGY_ALL);
3448  for (dimension_type k = all_best_is.size(); k-- > 0; ) {
3449  generate_cut(all_best_is[k], all_params, ctx,
3450  space_dim, indent_level);
3451  }
3452  }
3453  } // End of processing for non-integer solutions.
3454 
3455  } // Main loop of the simplex algorithm
3456 
3457  // This point should be unreachable.
3458  PPL_UNREACHABLE;
3459  return 0;
3460 }
std::vector< dimension_type > var_column
The variable identifiers associated to the columns of the simplex tableau.
static bool compatibility_check(Matrix< Row > &s)
Checks whether a context matrix is satisfiable.
Definition: PIP_Tree.cc:2195
void swap(CO_Tree &x, CO_Tree &y)
void generate_cut(dimension_type index, Variables_Set &parameters, Matrix< Row > &context, dimension_type &space_dimension, int indent_level)
Generate a Gomory cut using non-integer tableau row index.
Definition: PIP_Tree.cc:3463
size_t dimension_type
An unsigned integral type for representing space dimensions.
virtual bool OK() const
Returns true if and only if *this is well formed.
Definition: PIP_Tree.cc:1263
const PIP_Decision_Node * parent() const
Returns a pointer to this node's parent.
Tableau tableau
The parametric simplex tableau.
#define PPL_DIRTY_TEMP_COEFFICIENT(id)
Declare a local variable named id, of type Coefficient, and containing an unknown initial value...
dimension_type not_a_dimension()
Returns a value that does not designate a valid dimension.
CO_Tree::iterator iterator
An iterator on the row elements.
void add_mul_assign(GMP_Integer &x, const GMP_Integer &y, const GMP_Integer &z)
void ascii_dump(std::ostream &os) const
Dumps to os an ASCII representation of *this.
Definition: PIP_Tree.cc:1873
static Row_Sign row_sign(const Row &x, dimension_type big_dimension)
Returns the sign of row x.
Definition: PIP_Tree.cc:2152
PIP_Tree_Node(const PIP_Problem *owner)
Constructor: builds a node owned by *owner.
Definition: PIP_Tree.cc:916
dimension_type big_dimension
The column index in the parametric part of the simplex tableau corresponding to the big parameter; no...
Choose the first row with negative parameter sign.
#define WEIGHT_ADD(delta)
Definition: globals_defs.hh:83
PIP_Solution_Node(const PIP_Problem *owner)
Constructor: builds a solution node owned by *owner.
Definition: PIP_Tree.cc:1036
bool solution_valid
An indicator for solution validity.
void exact_div_assign(Checked_Number< T, Policy > &x, const Checked_Number< T, Policy > &y, const Checked_Number< T, Policy > &z)
The row contains both positive and negative coefficients.
All nonzero row coefficients are negative.
std::vector< Artificial_Parameter > Artificial_Parameter_Sequence
A type alias for a sequence of Artificial_Parameter's.
std::vector< dimension_type > var_row
The variable identifiers associated to the rows of the simplex tableau.
Control_Parameter_Value
Possible values for PIP_Problem control parameters.
Coefficient_traits::const_reference denominator() const
Returns the value of the denominator.
std::vector< dimension_type > mapping
A mapping between the tableau rows/columns and the original variables.
All nonzero row coefficients are positive.
void scale(Coefficient_traits::const_reference ratio)
Multiplies all coefficients and denominator with ratio.
Definition: PIP_Tree.cc:1714
PPL_COEFFICIENT_TYPE Coefficient
An alias for easily naming the type of PPL coefficients.
#define WEIGHT_BEGIN()
Definition: globals_defs.hh:81
Artificial_Parameter_Sequence artificial_parameters
The local sequence of expressions for local artificial parameters.
void normalize()
Normalizes the modulo of coefficients so that they are mutually prime.
Definition: PIP_Tree.cc:1654
std::vector< bool > basis
A boolean vector for identifying the basic variables.
Row_Sign
The possible values for the sign of a parametric linear expression.
void add_constraint(const Row &row, const Variables_Set &parameters)
Inserts a new parametric constraint in internal row format.
Definition: PIP_Tree.cc:1222
Matrix< Row > t
The matrix of parameter coefficients.
void gcd_assign(GMP_Integer &x, const GMP_Integer &y, const GMP_Integer &z)
#define PPL_USED(v)
No-op macro that allows to avoid unused variable warnings from the compiler.
Definition: compiler.hh:39
bool is_better_pivot(const std::vector< dimension_type > &mapping, const std::vector< bool > &basis, const dimension_type row_0, const dimension_type col_0, const dimension_type row_1, const dimension_type col_1) const
Compares two pivot row and column pairs before pivoting.
Definition: PIP_Tree.cc:1733
Constraint_System constraints_
The local system of parameter constraints.
Matrix< Row > s
The matrix of simplex coefficients.
CO_Tree::const_iterator const_iterator
A const iterator on the row elements.
static void indent_and_print(std::ostream &s, int indent, const char *str)
A helper function used when printing PIP trees.
Definition: PIP_Tree.cc:3803
std::vector< Row_Sign > sign
A cache for computed sign values of constraint parametric RHS.
Constraint_System_const_iterator const_iterator
memory_size_type Parma_Polyhedra_Library::PIP_Solution_Node::total_memory_in_bytes ( ) const
virtual

Returns the total size in bytes of the memory occupied by *this.

Implements Parma_Polyhedra_Library::PIP_Tree_Node.

Definition at line 3798 of file PIP_Tree.cc.

References external_memory_in_bytes().

3798  {
3799  return sizeof(*this) + external_memory_in_bytes();
3800 }
virtual memory_size_type external_memory_in_bytes() const
Returns the size in bytes of the memory managed by *this.
Definition: PIP_Tree.cc:3778
void Parma_Polyhedra_Library::PIP_Solution_Node::update_solution ( const std::vector< bool > &  pip_dim_is_param) const
protected

Update the solution values.

Parameters
pip_dim_is_paramA vector of Boolean flags telling which PIP problem dimensions are problem parameters. The size of the vector is equal to the PIP problem internal space dimension (i.e., no artificial parameters).

Definition at line 3977 of file PIP_Tree.cc.

References Parma_Polyhedra_Library::add_mul_assign(), Parma_Polyhedra_Library::Sparse_Row::begin(), Parma_Polyhedra_Library::Sparse_Row::end(), Parma_Polyhedra_Library::Sparse_Row::get(), Parma_Polyhedra_Library::CO_Tree::const_iterator::index(), PPL_DIRTY_TEMP_COEFFICIENT, solution, and solution_valid.

3977  {
3978  // Avoid doing useless work.
3979  if (solution_valid) {
3980  return;
3981  }
3982 
3983  // const_cast required so as to refresh the solution cache.
3984  PIP_Solution_Node& x = const_cast<PIP_Solution_Node&>(*this);
3985 
3986  const dimension_type num_pip_dims = pip_dim_is_param.size();
3987  const dimension_type num_pip_vars = tableau.s.num_columns();
3988  const dimension_type num_pip_params = num_pip_dims - num_pip_vars;
3989  const dimension_type num_all_params = tableau.t.num_columns() - 1;
3990  const dimension_type num_art_params = num_all_params - num_pip_params;
3991 
3992  if (solution.size() != num_pip_vars) {
3993  x.solution.resize(num_pip_vars);
3994  }
3995 
3996  // Compute external "names" (i.e., indices) for all parameters.
3997  std::vector<dimension_type> all_param_names(num_all_params);
3998 
3999  // External indices for problem parameters.
4000  for (dimension_type i = 0, p_index = 0; i < num_pip_dims; ++i) {
4001  if (pip_dim_is_param[i]) {
4002  all_param_names[p_index] = i;
4003  ++p_index;
4004  }
4005  }
4006  // External indices for artificial parameters.
4007  for (dimension_type i = 0; i < num_art_params; ++i) {
4008  all_param_names[num_pip_params + i] = num_pip_dims + i;
4009  }
4010 
4011 
4012  PPL_DIRTY_TEMP_COEFFICIENT(norm_coeff);
4013  Coefficient_traits::const_reference denom = tableau.denominator();
4014  for (dimension_type i = num_pip_vars; i-- > 0; ) {
4015  Linear_Expression& sol_i = x.solution[i];
4016  sol_i = Linear_Expression(0);
4017  if (basis[i]) {
4018  continue;
4019  }
4020  const Row& row = tableau.t[mapping[i]];
4021 
4022  // Start from index 1 to skip the inhomogeneous term.
4023  Row::const_iterator j = row.begin();
4024  Row::const_iterator j_end = row.end();
4025  // Skip the element with index 0.
4026  if (j != j_end && j.index() == 0) {
4027  ++j;
4028  }
4029  for ( ; j != j_end; ++j) {
4030  Coefficient_traits::const_reference coeff = *j;
4031  if (coeff == 0) {
4032  continue;
4033  }
4034  norm_coeff = coeff / denom;
4035  if (norm_coeff != 0) {
4036  add_mul_assign(sol_i, norm_coeff,
4037  Variable(all_param_names[j.index() - 1]));
4038  }
4039  }
4040  norm_coeff = row.get(0) / denom;
4041  sol_i += norm_coeff;
4042  }
4043 
4044  // Mark solution as valid.
4045  x.solution_valid = true;
4046 }
size_t dimension_type
An unsigned integral type for representing space dimensions.
Tableau tableau
The parametric simplex tableau.
#define PPL_DIRTY_TEMP_COEFFICIENT(id)
Declare a local variable named id, of type Coefficient, and containing an unknown initial value...
void add_mul_assign(GMP_Integer &x, const GMP_Integer &y, const GMP_Integer &z)
PIP_Solution_Node(const PIP_Problem *owner)
Constructor: builds a solution node owned by *owner.
Definition: PIP_Tree.cc:1036
bool solution_valid
An indicator for solution validity.
Coefficient_traits::const_reference denominator() const
Returns the value of the denominator.
std::vector< dimension_type > mapping
A mapping between the tableau rows/columns and the original variables.
std::vector< Linear_Expression > solution
Parametric values for the solution.
std::vector< bool > basis
A boolean vector for identifying the basic variables.
Matrix< Row > t
The matrix of parameter coefficients.
Matrix< Row > s
The matrix of simplex coefficients.
CO_Tree::const_iterator const_iterator
A const iterator on the row elements.
void Parma_Polyhedra_Library::PIP_Solution_Node::update_solution ( ) const
protected

Helper method.

Definition at line 3958 of file PIP_Tree.cc.

References Parma_Polyhedra_Library::PIP_Tree_Node::get_owner(), Parma_Polyhedra_Library::PIP_Problem::parameter_space_dimensions(), solution_valid, and Parma_Polyhedra_Library::PIP_Problem::space_dimension().

Referenced by parametric_values(), and print_tree().

3958  {
3959  // Avoid doing useless work.
3960  if (solution_valid) {
3961  return;
3962  }
3963  const PIP_Problem* const pip = get_owner();
3964  PPL_ASSERT(pip != 0);
3965  std::vector<bool> pip_dim_is_param(pip->space_dimension());
3966  const Variables_Set& params = pip->parameter_space_dimensions();
3967  for (Variables_Set::const_iterator p = params.begin(),
3968  p_end = params.end(); p != p_end; ++p) {
3969  pip_dim_is_param[*p] = true;
3970  }
3971 
3972  update_solution(pip_dim_is_param);
3973 }
const PIP_Problem * get_owner() const
Returns a pointer to the PIP_Problem owning object.
bool solution_valid
An indicator for solution validity.
void update_solution() const
Helper method.
Definition: PIP_Tree.cc:3958
void Parma_Polyhedra_Library::PIP_Solution_Node::update_tableau ( const PIP_Problem pip,
dimension_type  external_space_dim,
dimension_type  first_pending_constraint,
const Constraint_Sequence input_cs,
const Variables_Set parameters 
)
protectedvirtual

Implements pure virtual method PIP_Tree_Node::update_tableau.

Implements Parma_Polyhedra_Library::PIP_Tree_Node.

Definition at line 2406 of file PIP_Tree.cc.

References Parma_Polyhedra_Library::add_mul_assign(), Parma_Polyhedra_Library::Expression_Adapter< T >::begin(), big_dimension, Parma_Polyhedra_Library::PIP_Problem::big_parameter_dimension, Parma_Polyhedra_Library::Expression_Hide_Last< T >::end(), Parma_Polyhedra_Library::Constraint::expression(), Parma_Polyhedra_Library::PIP_Problem::external_space_dim, Parma_Polyhedra_Library::Constraint::inhomogeneous_term(), Parma_Polyhedra_Library::Variables_Set::insert(), Parma_Polyhedra_Library::Sparse_Row::insert(), Parma_Polyhedra_Library::PIP_Problem::internal_space_dim, Parma_Polyhedra_Library::Constraint::is_equality(), Parma_Polyhedra_Library::Constraint::is_strict_inequality(), Parma_Polyhedra_Library::neg_assign(), Parma_Polyhedra_Library::not_a_dimension(), Parma_Polyhedra_Library::nth_iter(), OK(), row_sign(), sign, Parma_Polyhedra_Library::Expression_Hide_Last< T >::space_dimension(), special_equality_row, Parma_Polyhedra_Library::Boundary_NS::sub_assign(), var_column, var_row, WEIGHT_ADD, WEIGHT_BEGIN, and ZERO.

2410  {
2411 
2412  // Make sure a parameter column exists, for the inhomogeneous term.
2413  if (tableau.t.num_columns() == 0) {
2414  tableau.t.add_zero_columns(1);
2415  }
2416 
2417  // NOTE: here 'params' stands for problem (i.e., non artificial) parameters.
2418  const dimension_type old_num_vars = tableau.s.num_columns();
2419  const dimension_type old_num_params
2420  = pip.internal_space_dim - old_num_vars;
2421  const dimension_type num_added_dims
2422  = pip.external_space_dim - pip.internal_space_dim;
2423  const dimension_type new_num_params = parameters.size();
2424  const dimension_type num_added_params = new_num_params - old_num_params;
2425  const dimension_type num_added_vars = num_added_dims - num_added_params;
2426 
2427  // Resize the two tableau matrices.
2428  if (num_added_vars > 0) {
2429  tableau.s.add_zero_columns(num_added_vars);
2430  }
2431 
2432  if (num_added_params > 0) {
2433  tableau.t.add_zero_columns(num_added_params, old_num_params + 1);
2434  }
2435 
2436  dimension_type new_var_column = old_num_vars;
2437  const dimension_type initial_space_dim = old_num_vars + old_num_params;
2438  for (dimension_type i = initial_space_dim; i < external_space_dim; ++i) {
2439  if (parameters.count(i) == 0) {
2440  // A new problem variable.
2441  if (tableau.s.num_rows() == 0) {
2442  // No rows have been added yet
2443  basis.push_back(true);
2444  mapping.push_back(new_var_column);
2445  }
2446  else {
2447  /*
2448  Need to insert the original variable id
2449  before the slack variable id's to respect variable ordering.
2450  */
2451  basis.insert(nth_iter(basis, new_var_column), true);
2452  mapping.insert(nth_iter(mapping, new_var_column), new_var_column);
2453  // Update variable id's of slack variables.
2454  for (dimension_type j = var_row.size(); j-- > 0; ) {
2455  if (var_row[j] >= new_var_column) {
2456  ++var_row[j];
2457  }
2458  }
2459  for (dimension_type j = var_column.size(); j-- > 0; ) {
2460  if (var_column[j] >= new_var_column) {
2461  ++var_column[j];
2462  }
2463  }
2464  if (special_equality_row > 0) {
2466  }
2467  }
2468  var_column.push_back(new_var_column);
2469  ++new_var_column;
2470  }
2471  }
2472 
2474  && pip.big_parameter_dimension != not_a_dimension()) {
2475  // Compute the column number of big parameter in tableau.t matrix.
2476  Variables_Set::const_iterator pos
2477  = parameters.find(pip.big_parameter_dimension);
2478  big_dimension = 1U
2479  + static_cast<dimension_type>(std::distance(parameters.begin(), pos));
2480  }
2481 
2482  Coefficient_traits::const_reference denom = tableau.denominator();
2483 
2484  for (Constraint_Sequence::const_iterator
2485  c_iter = nth_iter(input_cs, first_pending_constraint),
2486  c_end = input_cs.end(); c_iter != c_end; ++c_iter) {
2487  const Constraint& constraint = *c_iter;
2488  // (Tentatively) Add new rows to s and t matrices.
2489  // These will be removed at the end if they turn out to be useless.
2490  const dimension_type row_id = tableau.s.num_rows();
2491  tableau.s.add_zero_rows(1);
2492  tableau.t.add_zero_rows(1);
2493  Row& v_row = tableau.s[row_id];
2494  Row& p_row = tableau.t[row_id];
2495 
2496  {
2497  dimension_type p_index = 1;
2498  dimension_type v_index = 0;
2499  // Setting the inhomogeneous term.
2500  if (constraint.inhomogeneous_term() != 0) {
2501  Coefficient& p_row0 = p_row[0];
2502  p_row0 = constraint.inhomogeneous_term();
2503  if (constraint.is_strict_inequality()) {
2504  // Transform (expr > 0) into (expr - 1 >= 0).
2505  --p_row0;
2506  }
2507  p_row0 *= denom;
2508  }
2509  else {
2510  if (constraint.is_strict_inequality()) {
2511  // Transform (expr > 0) into (expr - 1 >= 0).
2512  neg_assign(p_row[0], denom);
2513  }
2514  }
2515  WEIGHT_BEGIN();
2516  dimension_type last_dim = 0;
2517  const Constraint::expr_type e = constraint.expression();
2519  i = e.begin(), i_end = e.end(); i != i_end; ++i) {
2520  const dimension_type dim = i.variable().space_dimension();
2521  if (dim != last_dim + 1) {
2522  // We have skipped some zero coefficients.
2523  // Update p_index and v_index accordingly.
2524  const dimension_type n
2525  = std::distance(parameters.lower_bound(last_dim),
2526  parameters.lower_bound(dim - 1));
2527  const dimension_type num_skipped = dim - last_dim - 1;
2528  p_index += n;
2529  v_index += (num_skipped - n);
2530  }
2531  PPL_ASSERT(p_index + v_index == i.variable().id() + 1);
2532  const bool is_parameter = (1 == parameters.count(dim - 1));
2533  Coefficient_traits::const_reference coeff_i = *i;
2534 
2535  WEIGHT_ADD(140);
2536  if (is_parameter) {
2537  p_row.insert(p_index, coeff_i * denom);
2538  ++p_index;
2539  }
2540  else {
2541  const dimension_type mv = mapping[v_index];
2542  if (basis[v_index]) {
2543  // Basic variable: add coeff_i * x_i
2544  add_mul_assign(v_row[mv], coeff_i, denom);
2545  }
2546  else {
2547  // Non-basic variable: add coeff_i * row_i
2548  add_mul_assign_row(v_row, coeff_i, tableau.s[mv]);
2549  add_mul_assign_row(p_row, coeff_i, tableau.t[mv]);
2550  }
2551  ++v_index;
2552  }
2553 
2554  last_dim = dim;
2555  }
2556  }
2557 
2558  if (row_sign(v_row, not_a_dimension()) == ZERO) {
2559  // Parametric-only constraints have already been inserted in
2560  // initial context, so no need to insert them in the tableau.
2561  tableau.s.remove_trailing_rows(1);
2562  tableau.t.remove_trailing_rows(1);
2563  }
2564  else {
2565  const dimension_type var_id = mapping.size();
2566  sign.push_back(row_sign(p_row, big_dimension));
2567  basis.push_back(false);
2568  mapping.push_back(row_id);
2569  var_row.push_back(var_id);
2570  if (constraint.is_equality()) {
2571  // Handle equality constraints.
2572  // After having added the f_i(x,p) >= 0 constraint,
2573  // we must add -f_i(x,p) to the special equality row.
2575  // The special constraint has not been created yet
2576  // FIXME: for now, we do not handle the case where the variable
2577  // is basic, and we just create a new row.
2578  // This might be faster however.
2579  tableau.s.add_zero_rows(1);
2580  tableau.t.add_zero_rows(1);
2581  // NOTE: addition of rows invalidates references v_row and p_row
2582  // due to possible matrix reallocations: recompute them.
2583  neg_assign_row(tableau.s[1 + row_id], tableau.s[row_id]);
2584  neg_assign_row(tableau.t[1 + row_id], tableau.t[row_id]);
2585  sign.push_back(row_sign(tableau.t[1 + row_id], big_dimension));
2586  special_equality_row = mapping.size();
2587  basis.push_back(false);
2588  mapping.push_back(1 + row_id);
2589  var_row.push_back(1 + var_id);
2590  }
2591  else {
2592  // The special constraint already exists and is nonbasic.
2594  sub_assign(tableau.s[m_eq], v_row);
2595  sub_assign(tableau.t[m_eq], p_row);
2596  sign[m_eq] = row_sign(tableau.t[m_eq], big_dimension);
2597  }
2598  }
2599  }
2600  }
2601  PPL_ASSERT(OK());
2602 }
Expression_Hide_Last< Linear_Expression > expr_type
The type of the (adapted) internal expression.
std::vector< dimension_type > var_column
The variable identifiers associated to the columns of the simplex tableau.
size_t dimension_type
An unsigned integral type for representing space dimensions.
virtual bool OK() const
Returns true if and only if *this is well formed.
Definition: PIP_Tree.cc:1263
Tableau tableau
The parametric simplex tableau.
dimension_type not_a_dimension()
Returns a value that does not designate a valid dimension.
void add_mul_assign(GMP_Integer &x, const GMP_Integer &y, const GMP_Integer &z)
static Row_Sign row_sign(const Row &x, dimension_type big_dimension)
Returns the sign of row x.
Definition: PIP_Tree.cc:2152
dimension_type special_equality_row
The variable number of the special inequality used for modeling equality constraints.
dimension_type big_dimension
The column index in the parametric part of the simplex tableau corresponding to the big parameter; no...
#define WEIGHT_ADD(delta)
Definition: globals_defs.hh:83
RA_Container::iterator nth_iter(RA_Container &cont, dimension_type n)
std::vector< dimension_type > var_row
The variable identifiers associated to the rows of the simplex tableau.
Coefficient_traits::const_reference denominator() const
Returns the value of the denominator.
std::vector< dimension_type > mapping
A mapping between the tableau rows/columns and the original variables.
Result sub_assign(Boundary_Type to_type, To &to, To_Info &to_info, Boundary_Type type1, const T1 &x1, const Info1 &info1, Boundary_Type type2, const T2 &x2, const Info2 &info2)
PPL_COEFFICIENT_TYPE Coefficient
An alias for easily naming the type of PPL coefficients.
#define WEIGHT_BEGIN()
Definition: globals_defs.hh:81
void neg_assign(GMP_Integer &x)
std::vector< bool > basis
A boolean vector for identifying the basic variables.
Matrix< Row > t
The matrix of parameter coefficients.
base_type::const_iterator const_iterator
The type of const iterators on coefficients.
Matrix< Row > s
The matrix of simplex coefficients.
std::vector< Row_Sign > sign
A cache for computed sign values of constraint parametric RHS.

Friends And Related Function Documentation

bool PIP_Problem::ascii_load ( std::istream &  s)
friend

Member Data Documentation

std::vector<bool> Parma_Polyhedra_Library::PIP_Solution_Node::basis
private

A boolean vector for identifying the basic variables.

Variable identifiers are numbered from 0 to n+m-1, where n is the number of columns in the simplex tableau corresponding to variables, and m is the number of rows.

Indices from 0 to n-1 correspond to the original variables.

Indices from n to n+m-1 correspond to the slack variables associated to the internal constraints, which do not strictly correspond to original constraints, since these may have been transformed to fit the standard form of the dual simplex.

The value for basis[i] is:

  • true if variable i is basic,
  • false if variable i is nonbasic.

Definition at line 543 of file PIP_Tree_defs.hh.

Referenced by Parma_Polyhedra_Library::PIP_Tree_Node::compatibility_check().

dimension_type Parma_Polyhedra_Library::PIP_Solution_Node::big_dimension
private

The column index in the parametric part of the simplex tableau corresponding to the big parameter; not_a_dimension() if not set.

Definition at line 590 of file PIP_Tree_defs.hh.

Referenced by ascii_dump(), ascii_load(), solve(), and update_tableau().

std::vector<dimension_type> Parma_Polyhedra_Library::PIP_Solution_Node::mapping
private

A mapping between the tableau rows/columns and the original variables.

The value of mapping[i] depends of the value of basis[i].

  • If basis[i] is true, mapping[i] encodes the column index of variable i in the s matrix of the tableau.
  • If basis[i] is false, mapping[i] encodes the row index of variable i in the tableau.

Definition at line 555 of file PIP_Tree_defs.hh.

Referenced by Parma_Polyhedra_Library::PIP_Tree_Node::compatibility_check().

std::vector<Row_Sign> Parma_Polyhedra_Library::PIP_Solution_Node::sign
private

A cache for computed sign values of constraint parametric RHS.

Definition at line 607 of file PIP_Tree_defs.hh.

Referenced by ascii_dump(), ascii_load(), external_memory_in_bytes(), generate_cut(), row_sign(), solve(), and update_tableau().

std::vector<Linear_Expression> Parma_Polyhedra_Library::PIP_Solution_Node::solution
private

Parametric values for the solution.

Definition at line 610 of file PIP_Tree_defs.hh.

Referenced by ascii_dump(), ascii_load(), external_memory_in_bytes(), parametric_values(), print_tree(), and update_solution().

bool Parma_Polyhedra_Library::PIP_Solution_Node::solution_valid
private

An indicator for solution validity.

Definition at line 613 of file PIP_Tree_defs.hh.

Referenced by ascii_dump(), ascii_load(), solve(), and update_solution().

dimension_type Parma_Polyhedra_Library::PIP_Solution_Node::special_equality_row
private

The variable number of the special inequality used for modeling equality constraints.

The subset of equality constraints in a specific problem can be expressed as: $f_i(x,p) = 0 ; 1 \leq i \leq n$. As the dual simplex standard form requires constraints to be inequalities, the following constraints can be modeled as follows:

  • $f_i(x,p) \geq 0 ; 1 \leq i \leq n$
  • $\sum\limits_{i=1}^n f_i(x,p) \leq 0$

The special_equality_row value stores the variable number of the specific constraint which is used to model the latter sum of constraints. If no such constraint exists, the value is set to 0.

Definition at line 584 of file PIP_Tree_defs.hh.

Referenced by ascii_dump(), ascii_load(), and update_tableau().

Tableau Parma_Polyhedra_Library::PIP_Solution_Node::tableau
private

The parametric simplex tableau.

Definition at line 523 of file PIP_Tree_defs.hh.

std::vector<dimension_type> Parma_Polyhedra_Library::PIP_Solution_Node::var_column
private

The variable identifiers associated to the columns of the simplex tableau.

Definition at line 565 of file PIP_Tree_defs.hh.

Referenced by ascii_dump(), ascii_load(), Parma_Polyhedra_Library::PIP_Tree_Node::compatibility_check(), external_memory_in_bytes(), OK(), solve(), and update_tableau().

std::vector<dimension_type> Parma_Polyhedra_Library::PIP_Solution_Node::var_row
private

The variable identifiers associated to the rows of the simplex tableau.

Definition at line 560 of file PIP_Tree_defs.hh.

Referenced by ascii_dump(), ascii_load(), Parma_Polyhedra_Library::PIP_Tree_Node::compatibility_check(), external_memory_in_bytes(), generate_cut(), OK(), solve(), and update_tableau().


The documentation for this class was generated from the following files: