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:
Inheritance graph
[legend]
Collaboration diagram for Parma_Polyhedra_Library::PIP_Solution_Node:
Collaboration graph
[legend]

List of all members.

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.
virtual PIP_Tree_Nodeclone () const
 Returns a pointer to a dynamically-allocated copy of *this.
virtual ~PIP_Solution_Node ()
 Destructor.
virtual bool OK () const
 Returns true if and only if *this is well formed.
virtual const PIP_Solution_Nodeas_solution () const
 Returns this.
const Linear_Expressionparametric_values (Variable var) const
 Returns a parametric expression for the values of problem variable var.
void ascii_dump (std::ostream &s) const
 Dumps to s an ASCII representation of *this.
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.
virtual memory_size_type total_memory_in_bytes () const
 Returns the total size in bytes of the memory occupied by *this.
virtual memory_size_type external_memory_in_bytes () const
 Returns the size in bytes of the memory managed by *this.

Protected Member Functions

 PIP_Solution_Node (const PIP_Solution_Node &y)
 Copy constructor.
 PIP_Solution_Node (const PIP_Solution_Node &y, No_Constraints)
 Alternative copy constructor.
virtual void set_owner (const PIP_Problem *owner)
 Sets the pointer to the PIP_Problem owning object.
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.
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.
void update_solution (const std::vector< bool > &pip_dim_is_param) const
 Update the solution values.
void update_solution () const
 Helper method.
virtual PIP_Tree_Nodesolve (const PIP_Problem &pip, bool check_feasible_context, const Matrix &context, const Variables_Set &params, dimension_type space_dim, unsigned indent_level)
 Implements pure virtual method PIP_Tree_Node::solve.
void generate_cut (dimension_type i, Variables_Set &parameters, Matrix &context, dimension_type &space_dimension, unsigned indent_level)
 Generate a Gomory cut using non-integer tableau row i.
virtual void print_tree (std::ostream &s, unsigned indent, const std::vector< bool > &pip_dim_is_param, dimension_type first_art_dim) const
 Prints on s the tree rooted in *this.

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.

Private Attributes

Tableau tableau
 The parametric simplex tableau.
std::vector< bool > basis
 A boolean vector for identifying the basic variables.
std::vector< dimension_typemapping
 A mapping between the tableau rows/columns and the original variables.
std::vector< dimension_typevar_row
 The variable identifiers associated to the rows of the simplex tableau.
std::vector< dimension_typevar_column
 The variable identifiers associated to the columns of the simplex tableau.
dimension_type special_equality_row
 The variable number of the special inequality used for modelling equality constraints.
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.
std::vector< Row_Signsign
 A cache for computed sign values of constraint parametric RHS.
std::vector< Linear_Expressionsolution
 Parametric values for the solution.
bool solution_valid
 An indicator for solution validity.

Friends

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

Detailed Description

A tree node representing part of the space of solutions.

Definition at line 344 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 573 of file PIP_Tree.defs.hh.

00573                 {
00575     UNKNOWN,
00577     ZERO,
00579     POSITIVE,
00581     NEGATIVE,
00583     MIXED
00584   };


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 481 of file PIP_Tree.cc.

Referenced by clone(), and solve().

00482   : PIP_Tree_Node(owner),
00483     tableau(),
00484     basis(),
00485     mapping(),
00486     var_row(),
00487     var_column(),
00488     special_equality_row(0),
00489     big_dimension(not_a_dimension()),
00490     sign(),
00491     solution(),
00492     solution_valid(false) {
00493 }

Parma_Polyhedra_Library::PIP_Solution_Node::~PIP_Solution_Node (  )  [virtual]

Destructor.

Definition at line 524 of file PIP_Tree.cc.

00524                                       {
00525 }

Parma_Polyhedra_Library::PIP_Solution_Node::PIP_Solution_Node ( const PIP_Solution_Node y  )  [protected]

Copy constructor.

Definition at line 495 of file PIP_Tree.cc.

00496   : PIP_Tree_Node(y),
00497     tableau(y.tableau),
00498     basis(y.basis),
00499     mapping(y.mapping),
00500     var_row(y.var_row),
00501     var_column(y.var_column),
00502     special_equality_row(y.special_equality_row),
00503     big_dimension(y.big_dimension),
00504     sign(y.sign),
00505     solution(y.solution),
00506     solution_valid(y.solution_valid) {
00507 }

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 509 of file PIP_Tree.cc.

00511   : PIP_Tree_Node(y.owner_), // NOTE: only copy owner.
00512     tableau(y.tableau),
00513     basis(y.basis),
00514     mapping(y.mapping),
00515     var_row(y.var_row),
00516     var_column(y.var_column),
00517     special_equality_row(y.special_equality_row),
00518     big_dimension(y.big_dimension),
00519     sign(y.sign),
00520     solution(y.solution),
00521     solution_valid(y.solution_valid) {
00522 }


Member Function Documentation

const PIP_Solution_Node * Parma_Polyhedra_Library::PIP_Solution_Node::as_solution (  )  const [virtual]

Returns this.

Reimplemented from Parma_Polyhedra_Library::PIP_Tree_Node.

Definition at line 599 of file PIP_Tree.cc.

00599                                      {
00600   return this;
00601 }

void Parma_Polyhedra_Library::PIP_Solution_Node::ascii_dump ( std::ostream &  s  )  const

Dumps to s an ASCII representation of *this.

Reimplemented from Parma_Polyhedra_Library::PIP_Tree_Node.

Definition at line 1262 of file PIP_Tree.cc.

References 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_Decision_Node::ascii_dump(), and Parma_Polyhedra_Library::PIP_Problem::ascii_dump().

01262                                                  {
01263   PIP_Tree_Node::ascii_dump(s);
01264 
01265   s << "\ntableau\n";
01266   tableau.ascii_dump(s);
01267 
01268   s << "\nbasis ";
01269   dimension_type basis_size = basis.size();
01270   s << basis_size;
01271   for (dimension_type i = 0; i < basis_size; ++i)
01272     s << (basis[i] ? " true" : " false");
01273 
01274   s << "\nmapping ";
01275   dimension_type mapping_size = mapping.size();
01276   s << mapping_size;
01277   for (dimension_type i = 0; i < mapping_size; ++i)
01278     s << " " << mapping[i];
01279 
01280   s << "\nvar_row ";
01281   dimension_type var_row_size = var_row.size();
01282   s << var_row_size;
01283   for (dimension_type i = 0; i < var_row_size; ++i)
01284     s << " " << var_row[i];
01285 
01286   s << "\nvar_column ";
01287   dimension_type var_column_size = var_column.size();
01288   s << var_column_size;
01289   for (dimension_type i = 0; i < var_column_size; ++i)
01290     s << " " << var_column[i];
01291   s << "\n";
01292 
01293   s << "special_equality_row " << special_equality_row << "\n";
01294   s << "big_dimension " << big_dimension << "\n";
01295 
01296   s << "sign ";
01297   dimension_type sign_size = sign.size();
01298   s << sign_size;
01299   for (dimension_type i = 0; i < sign_size; ++i) {
01300     s << " ";
01301     switch (sign[i]) {
01302     case UNKNOWN:
01303       s << "UNKNOWN";
01304       break;
01305     case ZERO:
01306       s << "ZERO";
01307       break;
01308     case POSITIVE:
01309       s << "POSITIVE";
01310       break;
01311     case NEGATIVE:
01312       s << "NEGATIVE";
01313       break;
01314     case MIXED:
01315       s << "MIXED";
01316       break;
01317     }
01318   }
01319   s << "\n";
01320 
01321   dimension_type solution_size = solution.size();
01322   s << "solution " << solution_size << "\n";
01323   for (dimension_type i = 0; i < solution_size; ++i)
01324     solution[i].ascii_dump(s);
01325   s << "\n";
01326 
01327   s << "solution_valid " << (solution_valid ? "true" : "false") << "\n";
01328 }

bool Parma_Polyhedra_Library::PIP_Solution_Node::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.

Reimplemented from Parma_Polyhedra_Library::PIP_Tree_Node.

Definition at line 1331 of file PIP_Tree.cc.

References Parma_Polyhedra_Library::Linear_Expression::ascii_load(), Parma_Polyhedra_Library::PIP_Tree_Node::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_Decision_Node::ascii_load(), and Parma_Polyhedra_Library::PIP_Problem::ascii_load().

01331                                            {
01332   if (!PIP_Tree_Node::ascii_load(s))
01333     return false;
01334 
01335   std::string str;
01336   if (!(s >> str) || str != "tableau")
01337     return false;
01338   if (!tableau.ascii_load(s))
01339     return false;
01340 
01341   if (!(s >> str) || str != "basis")
01342     return false;
01343   dimension_type basis_size;
01344   if (!(s >> basis_size))
01345     return false;
01346   basis.clear();
01347   for (dimension_type i = 0; i < basis_size; ++i) {
01348     if (!(s >> str))
01349       return false;
01350     bool val = false;
01351     if (str == "true")
01352       val = true;
01353     else if (str != "false")
01354       return false;
01355     basis.push_back(val);
01356   }
01357 
01358   if (!(s >> str) || str != "mapping")
01359     return false;
01360   dimension_type mapping_size;
01361   if (!(s >> mapping_size))
01362     return false;
01363   mapping.clear();
01364   for (dimension_type i = 0; i < mapping_size; ++i) {
01365     dimension_type val;
01366     if (!(s >> val))
01367       return false;
01368     mapping.push_back(val);
01369   }
01370 
01371   if (!(s >> str) || str != "var_row")
01372     return false;
01373   dimension_type var_row_size;
01374   if (!(s >> var_row_size))
01375     return false;
01376   var_row.clear();
01377   for (dimension_type i = 0; i < var_row_size; ++i) {
01378     dimension_type val;
01379     if (!(s >> val))
01380       return false;
01381     var_row.push_back(val);
01382   }
01383 
01384   if (!(s >> str) || str != "var_column")
01385     return false;
01386   dimension_type var_column_size;
01387   if (!(s >> var_column_size))
01388     return false;
01389   var_column.clear();
01390   for (dimension_type i = 0; i < var_column_size; ++i) {
01391     dimension_type val;
01392     if (!(s >> val))
01393       return false;
01394     var_column.push_back(val);
01395   }
01396 
01397   if (!(s >> str) || str != "special_equality_row")
01398     return false;
01399   if (!(s >> special_equality_row))
01400     return false;
01401 
01402   if (!(s >> str) || str != "big_dimension")
01403     return false;
01404   if (!(s >> big_dimension))
01405     return false;
01406 
01407   if (!(s >> str) || str != "sign")
01408     return false;
01409   dimension_type sign_size;
01410   if (!(s >> sign_size))
01411     return false;
01412   sign.clear();
01413   for (dimension_type i = 0; i < sign_size; ++i) {
01414     if (!(s >> str))
01415       return false;
01416     Row_Sign val;
01417     if (str == "UNKNOWN")
01418       val = UNKNOWN;
01419     else if (str == "ZERO")
01420       val = ZERO;
01421     else if (str == "POSITIVE")
01422       val = POSITIVE;
01423     else if (str == "NEGATIVE")
01424       val = NEGATIVE;
01425     else if (str == "MIXED")
01426       val = MIXED;
01427     else
01428       return false;
01429     sign.push_back(val);
01430   }
01431 
01432   if (!(s >> str) || str != "solution")
01433     return false;
01434   dimension_type solution_size;
01435   if (!(s >> solution_size))
01436     return false;
01437   solution.clear();
01438   for (dimension_type i = 0; i < solution_size; ++i) {
01439     Linear_Expression val;
01440     if (!val.ascii_load(s))
01441       return false;
01442     solution.push_back(val);
01443   }
01444 
01445   if (!(s >> str) || str != "solution_valid")
01446     return false;
01447   if (!(s >> str))
01448     return false;
01449   if (str == "true")
01450     solution_valid = true;
01451   else if (str == "false")
01452     solution_valid = false;
01453   else
01454     return false;
01455 
01456   PPL_ASSERT(OK());
01457   return true;
01458 }

bool Parma_Polyhedra_Library::PIP_Solution_Node::check_ownership ( const PIP_Problem owner  )  const [protected, virtual]

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 577 of file PIP_Tree.cc.

References Parma_Polyhedra_Library::PIP_Tree_Node::get_owner().

00577                                                                  {
00578   return get_owner() == owner;
00579 }

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 1222 of file PIP_Tree.cc.

References PIP_Solution_Node().

01222                                {
01223   return new PIP_Solution_Node(*this);
01224 }

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 2885 of file PIP_Tree.cc.

References Parma_Polyhedra_Library::Checked::bool, sign, solution, var_column, and var_row.

Referenced by total_memory_in_bytes().

02885                                                   {
02886   memory_size_type n = PIP_Tree_Node::external_memory_in_bytes();
02887   n += tableau.external_memory_in_bytes();
02888   // FIXME: size of std::vector<bool> ?
02889   n += basis.capacity() * sizeof(bool);
02890   n += sizeof(dimension_type)
02891     * (mapping.capacity() + var_row.capacity() + var_column.capacity());
02892   n += sign.capacity() * sizeof(Row_Sign);
02893   // FIXME: Adding the external memory for `solution'.
02894   n += solution.capacity() * sizeof(Linear_Expression);
02895   for (std::vector<Linear_Expression>::const_iterator
02896          i = solution.begin(), i_end = solution.end(); i != i_end; ++i)
02897     n += (i->external_memory_in_bytes());
02898 
02899   return n;
02900 }

void Parma_Polyhedra_Library::PIP_Solution_Node::generate_cut ( dimension_type  i,
Variables_Set parameters,
Matrix context,
dimension_type space_dimension,
unsigned  indent_level 
) [protected]

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

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

Definition at line 2631 of file PIP_Tree.cc.

References Parma_Polyhedra_Library::add_mul_assign(), Parma_Polyhedra_Library::Matrix::add_zero_columns(), Parma_Polyhedra_Library::Matrix::add_zero_rows(), Parma_Polyhedra_Library::PIP_Tree_Node::artificial_parameters, Parma_Polyhedra_Library::Variables_Set::insert(), Parma_Polyhedra_Library::neg_assign(), NEGATIVE, Parma_Polyhedra_Library::not_a_dimension(), Parma_Polyhedra_Library::Matrix::num_rows(), Parma_Polyhedra_Library::PIP_Tree_Node::parent(), PPL_DIRTY_TEMP_COEFFICIENT, sign, var_row, WEIGHT_ADD, WEIGHT_ADD_MUL, and WEIGHT_BEGIN.

Referenced by solve().

02635                                                              {
02636 #ifdef NOISY_PIP
02637   std::cerr << std::setw(2 * indent_level) << ""
02638             << "Row " << index << " requires cut generation.\n";
02639 #else
02640   used(indent_level);
02641 #endif // #ifdef NOISY_PIP
02642 
02643   const dimension_type num_rows = tableau.t.num_rows();
02644   PPL_ASSERT(index < num_rows);
02645   const dimension_type num_vars = tableau.s.num_columns();
02646   const dimension_type num_params = tableau.t.num_columns();
02647   PPL_ASSERT(num_params == 1 + parameters.size());
02648   const Coefficient& den = tableau.denominator();
02649 
02650   PPL_DIRTY_TEMP_COEFFICIENT(mod);
02651   PPL_DIRTY_TEMP_COEFFICIENT(coeff);
02652 
02653   // Test if cut to be generated must be parametric or not.
02654   bool generate_parametric_cut = false;
02655   {
02656     // Limiting the scope of reference row_t (may be later invalidated).
02657     const Row& row_t = tableau.t[index];
02658     WEIGHT_BEGIN();
02659     for (dimension_type j = 1; j < num_params; ++j) {
02660       WEIGHT_ADD(1);
02661       if (row_t[j] % den != 0) {
02662         generate_parametric_cut = true;
02663         break;
02664       }
02665     }
02666   }
02667 
02668   // Column index of already existing Artificial_Parameter.
02669   dimension_type ap_column = not_a_dimension();
02670   bool reuse_ap = false;
02671 
02672   if (generate_parametric_cut) {
02673     // Fractional parameter coefficient found: generate parametric cut.
02674     Linear_Expression expr;
02675 
02676     // Limiting the scope of reference row_t (may be later invalidated).
02677     {
02678       const Row& row_t = tableau.t[index];
02679       pos_mod_assign(mod, row_t[0], den);
02680       if (mod != 0) {
02681         // Optimizing computation: expr += (den - mod);
02682         expr += den;
02683         expr -= mod;
02684       }
02685       // NOTE: iterating downwards on parameters to avoid reallocations.
02686       Variables_Set::const_reverse_iterator p_j = parameters.rbegin();
02687       // NOTE: index j spans [1..num_params-1] downwards.
02688       WEIGHT_BEGIN();
02689       for (dimension_type j = num_params; j-- > 1; ) {
02690         pos_mod_assign(mod, row_t[j], den);
02691         if (mod != 0) {
02692           // Optimizing computation: expr += (den - mod) * Variable(*p_j);
02693           coeff = den - mod;
02694           add_mul_assign(expr, coeff, Variable(*p_j));
02695         }
02696         // Mode to previous parameter.
02697         ++p_j;
02698       }
02699       WEIGHT_ADD_MUL(2, num_params);
02700     }
02701     // Generate new artificial parameter.
02702     Artificial_Parameter ap(expr, den);
02703 
02704     // Search if the Artificial_Parameter has already been generated.
02705     ap_column = space_dimension;
02706     const PIP_Tree_Node* node = this;
02707     do {
02708       for (dimension_type j = node->artificial_parameters.size(); j-- > 0; ) {
02709         --ap_column;
02710         if (node->artificial_parameters[j] == ap) {
02711           reuse_ap = true;
02712           break;
02713         }
02714       }
02715       node = node->parent();
02716     } while (!reuse_ap && node != 0);
02717 
02718     if (reuse_ap) {
02719       // We can re-use an existing Artificial_Parameter.
02720 #ifdef NOISY_PIP
02721       using namespace IO_Operators;
02722       std::cerr << std::setw(2 * indent_level) << ""
02723                 << "Re-using parameter " << Variable(ap_column)
02724                 << " = " << ap << std::endl;
02725 #endif // #ifdef NOISY_PIP
02726       ap_column = ap_column - num_vars + 1;
02727     }
02728     else {
02729       // Here reuse_ap == false: the Artificial_Parameter does not exist yet.
02730       // Beware: possible reallocation invalidates row references.
02731       tableau.t.add_zero_columns(1);
02732       context.add_zero_columns(1);
02733       artificial_parameters.push_back(ap);
02734       parameters.insert(space_dimension);
02735 #ifdef NOISY_PIP
02736       using namespace IO_Operators;
02737       std::cerr << std::setw(2 * indent_level) << ""
02738                 << "New parameter " << Variable(space_dimension)
02739                 << " = " << ap << std::endl;
02740 #endif // #ifdef NOISY_PIP
02741       ++space_dimension;
02742       ap_column = num_params;
02743 
02744       // Update current context with constraints on the new parameter.
02745       const dimension_type ctx_num_rows = context.num_rows();
02746       context.add_zero_rows(2, Row::Flags());
02747       Row& ctx1 = context[ctx_num_rows];
02748       Row& ctx2 = context[ctx_num_rows+1];
02749       // Recompute row reference after possible reallocation.
02750       WEIGHT_BEGIN();
02751       const Row& row_t = tableau.t[index];
02752       for (dimension_type j = 0; j < num_params; ++j) {
02753         pos_mod_assign(mod, row_t[j], den);
02754         if (mod != 0) {
02755           ctx1[j] = den;
02756           ctx1[j] -= mod;
02757           neg_assign(ctx2[j], ctx1[j]);
02758           WEIGHT_ADD(3);
02759         }
02760       }
02761       WEIGHT_ADD_MUL(1, num_params);
02762       neg_assign(ctx1[num_params], den);
02763       ctx2[num_params] = den;
02764       // ctx2[0] += den-1;
02765       ctx2[0] += den;
02766       --ctx2[0];
02767       WEIGHT_ADD(4);
02768 #ifdef NOISY_PIP
02769       {
02770         using namespace IO_Operators;
02771         Variables_Set::const_iterator p = parameters.begin();
02772         Linear_Expression expr1(ctx1[0]);
02773         Linear_Expression expr2(ctx2[0]);
02774         for (dimension_type j = 1; j <= num_params; ++j, ++p) {
02775           add_mul_assign(expr1, ctx1[j], Variable(*p));
02776           add_mul_assign(expr2, ctx2[j], Variable(*p));
02777         }
02778         std::cerr << std::setw(2 * indent_level) << ""
02779                   << "Adding to context: "
02780                   << Constraint(expr1 >= 0) << " ; "
02781                   << Constraint(expr2 >= 0) << std::endl;
02782       }
02783 #endif // #ifdef NOISY_PIP
02784     }
02785   }
02786 
02787   // Generate new cut.
02788   tableau.s.add_zero_rows(1, Row::Flags());
02789   tableau.t.add_zero_rows(1, Row::Flags());
02790   Row& cut_s = tableau.s[num_rows];
02791   Row& cut_t = tableau.t[num_rows];
02792   // Recompute references after possible reallocation.
02793   WEIGHT_BEGIN();
02794   const Row& row_s = tableau.s[index];
02795   const Row& row_t = tableau.t[index];
02796   for (dimension_type j = 0; j < num_vars; ++j) {
02797     pos_mod_assign(cut_s[j], row_s[j], den);
02798   }
02799   WEIGHT_ADD_MUL(1, num_params);
02800   for (dimension_type j = 0; j < num_params; ++j) {
02801     pos_mod_assign(mod, row_t[j], den);
02802     if (mod != 0) {
02803       cut_t[j] = mod;
02804       cut_t[j] -= den;
02805       WEIGHT_ADD(2);
02806     }
02807   }
02808   WEIGHT_ADD_MUL(1, num_params);
02809   if (ap_column != not_a_dimension())
02810     // If we re-use an existing Artificial_Parameter
02811     cut_t[ap_column] = den;
02812 
02813 #ifdef NOISY_PIP
02814   {
02815     using namespace IO_Operators;
02816     Linear_Expression expr;
02817     dimension_type ti = 1;
02818     dimension_type si = 0;
02819     for (dimension_type j = 0; j < space_dimension; ++j) {
02820       if (parameters.count(j) == 1)
02821         add_mul_assign(expr, cut_t[ti++], Variable(j));
02822       else
02823         add_mul_assign(expr, cut_s[si++], Variable(j));
02824     }
02825     std::cerr << std::setw(2 * indent_level) << ""
02826               << "Adding cut: "
02827               << Constraint(expr + cut_t[0] >= 0)
02828               << std::endl;
02829   }
02830 #endif // #ifdef NOISY_PIP
02831   var_row.push_back(num_rows + num_vars);
02832   basis.push_back(false);
02833   mapping.push_back(num_rows);
02834   sign.push_back(NEGATIVE);
02835 }

bool Parma_Polyhedra_Library::PIP_Solution_Node::OK (  )  const [virtual]

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

Reimplemented from Parma_Polyhedra_Library::PIP_Tree_Node.

Definition at line 697 of file PIP_Tree.cc.

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

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

00697                             {
00698 #ifndef NDEBUG
00699   using std::cerr;
00700 #endif
00701   if (!PIP_Tree_Node::OK())
00702     return false;
00703 
00704   // Check that every member used is OK.
00705 
00706   if (!tableau.OK())
00707     return false;
00708 
00709   // Check coherency of basis, mapping, var_row and var_column
00710   if (basis.size() != mapping.size()) {
00711 #ifndef NDEBUG
00712     cerr << "The PIP_Solution_Node::basis and PIP_Solution_Node::mapping "
00713          << "vectors do not have the same number of elements.\n";
00714 #endif
00715     return false;
00716   }
00717   if (basis.size() != var_row.size() + var_column.size()) {
00718 #ifndef NDEBUG
00719     cerr << "The sum of number of elements in the PIP_Solution_Node::var_row "
00720          << "and PIP_Solution_Node::var_column vectors is different from the "
00721          << "number of elements in the PIP_Solution_Node::basis vector.\n";
00722 #endif
00723     return false;
00724   }
00725   if (var_column.size() != tableau.s.num_columns()) {
00726 #ifndef NDEBUG
00727     cerr << "The number of elements in the PIP_Solution_Node::var_column "
00728          << "vector is different from the number of columns in the "
00729          << "PIP_Solution_Node::tableau.s Matrix.\n";
00730 #endif
00731     return false;
00732   }
00733   if (var_row.size() != tableau.s.num_rows()) {
00734 #ifndef NDEBUG
00735     cerr << "The number of elements in the PIP_Solution_Node::var_row "
00736          << "vector is different from the number of rows in the "
00737          << "PIP_Solution_Node::tableau.s Matrix.\n";
00738 #endif
00739     return false;
00740   }
00741   for (dimension_type i = mapping.size(); i-- > 0; ) {
00742     const dimension_type rowcol = mapping[i];
00743     if (basis[i] && var_column[rowcol] != i) {
00744 #ifndef NDEBUG
00745       cerr << "Variable " << i << " is basic and corresponds to column "
00746            << rowcol << " but PIP_Solution_Node::var_column[" << rowcol
00747            << "] does not correspond to variable " << i << ".\n";
00748 #endif
00749       return false;
00750     }
00751     if (!basis[i] && var_row[rowcol] != i) {
00752 #ifndef NDEBUG
00753       cerr << "Variable " << i << " is nonbasic and corresponds to row "
00754            << rowcol << " but PIP_Solution_Node::var_row[" << rowcol
00755            << "] does not correspond to variable " << i << ".\n";
00756 #endif
00757       return false;
00758     }
00759   }
00760   // All checks passed.
00761   return true;
00762 }

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:
var The problem variable which is queried about.
Exceptions:
std::invalid_argument Thrown if var is dimension-incompatible with the PIP_Problem owning this solution node, or if var is a problem parameter.

Definition at line 3016 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().

03016                                                              {
03017   const PIP_Problem* pip = get_owner();
03018   PPL_ASSERT(pip);
03019 
03020   const dimension_type space_dim = pip->space_dimension();
03021   if (var.space_dimension() > space_dim) {
03022     std::ostringstream s;
03023     s << "PPL::PIP_Solution_Node::parametric_values(v):\n"
03024       << "v.space_dimension() == " << var.space_dimension()
03025       << " is incompatible with the owning PIP_Problem "
03026       << " (space dim == " << space_dim << ").";
03027     throw std::invalid_argument(s.str());
03028   }
03029 
03030   dimension_type solution_index = var.id();
03031   const Variables_Set& params = pip->parameter_space_dimensions();
03032   for (Variables_Set::const_iterator p = params.begin(),
03033          p_end = params.end(); p != p_end; ++p) {
03034     const dimension_type param_index = *p;
03035     if (param_index < var.id())
03036       --solution_index;
03037     else if (param_index == var.id())
03038       throw std::invalid_argument("PPL::PIP_Solution_Node"
03039                                   "::parametric_values(v):\n"
03040                                   "v is a problem parameter.");
03041     else
03042       break;
03043   }
03044 
03045   update_solution();
03046   return solution[solution_index];
03047 }

void Parma_Polyhedra_Library::PIP_Solution_Node::print_tree ( std::ostream &  s,
unsigned  indent,
const std::vector< bool > &  pip_dim_is_param,
dimension_type  first_art_dim 
) const [protected, virtual]

Prints on s the tree rooted in *this.

Reimplemented from Parma_Polyhedra_Library::PIP_Tree_Node.

Definition at line 2985 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(), solution, and update_solution().

02987                                                                         {
02988   // Print info common to decision and solution nodes.
02989   PIP_Tree_Node::print_tree(s, indent, pip_dim_is_param, first_art_dim);
02990 
02991   // Print info specific of solution nodes:
02992   // first update solution if needed ...
02993   update_solution(pip_dim_is_param);
02994   // ... and then actually print it.
02995   const bool no_constraints = constraints_.empty();
02996   indent_and_print(s, indent + (no_constraints ? 0 : 1), "{");
02997   const dimension_type pip_space_dim = pip_dim_is_param.size();
02998   for (dimension_type i = 0, num_var = 0; i < pip_space_dim; ++i) {
02999     if (pip_dim_is_param[i])
03000       continue;
03001     if (num_var > 0)
03002       s << " ; ";
03003     using namespace IO_Operators;
03004     s << solution[num_var];
03005     ++num_var;
03006   }
03007   s << "}\n";
03008 
03009   if (!no_constraints) {
03010     indent_and_print(s, indent, "else\n");
03011     indent_and_print(s, indent+1, "_|_\n");
03012   }
03013 }

PIP_Solution_Node::Row_Sign Parma_Polyhedra_Library::PIP_Solution_Node::row_sign ( const Row x,
dimension_type  big_dimension 
) [static, private]

Returns the sign of row x.

Definition at line 1461 of file PIP_Tree.cc.

References MIXED, NEGATIVE, Parma_Polyhedra_Library::not_a_dimension(), POSITIVE, sign, Parma_Polyhedra_Library::Row::size(), and ZERO.

Referenced by solve(), and update_tableau().

01462                                                                 {
01463   if (big_dimension != not_a_dimension()) {
01464     // If a big parameter has been set and its coefficient is not zero,
01465     // then return the sign of the coefficient.
01466     const Coefficient& x_big = x[big_dimension];
01467     if (x_big > 0)
01468       return POSITIVE;
01469     if (x_big < 0)
01470       return NEGATIVE;
01471     // Otherwise x_big == 0, then no big parameter involved.
01472   }
01473 
01474   PIP_Solution_Node::Row_Sign sign = ZERO;
01475   for (int i = x.size(); i-- > 0; ) {
01476     const Coefficient& x_i = x[i];
01477     if (x_i > 0) {
01478       if (sign == NEGATIVE)
01479         return MIXED;
01480       sign = POSITIVE;
01481     }
01482     else if (x_i < 0) {
01483       if (sign == POSITIVE)
01484         return MIXED;
01485       sign = NEGATIVE;
01486     }
01487   }
01488   return sign;
01489 }

void Parma_Polyhedra_Library::PIP_Solution_Node::set_owner ( const PIP_Problem owner  )  [protected, virtual]

Sets the pointer to the PIP_Problem owning object.

Implements Parma_Polyhedra_Library::PIP_Tree_Node.

Definition at line 563 of file PIP_Tree.cc.

References Parma_Polyhedra_Library::PIP_Tree_Node::owner_.

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

00563                                                      {
00564   owner_ = owner;
00565 }

PIP_Tree_Node * Parma_Polyhedra_Library::PIP_Solution_Node::solve ( const PIP_Problem pip,
bool  check_feasible_context,
const Matrix context,
const Variables_Set params,
dimension_type  space_dim,
unsigned  indent_level 
) [protected, virtual]

Implements pure virtual method PIP_Tree_Node::solve.

Implements Parma_Polyhedra_Library::PIP_Tree_Node.

Definition at line 1887 of file PIP_Tree.cc.

References Parma_Polyhedra_Library::PIP_Tree_Node::add_constraint(), Parma_Polyhedra_Library::add_mul_assign(), Parma_Polyhedra_Library::Matrix::add_row(), Parma_Polyhedra_Library::PIP_Tree_Node::artificial_parameters, Parma_Polyhedra_Library::Matrix::ascii_dump(), Parma_Polyhedra_Library::Constraint_System::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::exact_div_assign(), Parma_Polyhedra_Library::PIP_Decision_Node::false_child, Parma_Polyhedra_Library::gcd_assign(), generate_cut(), Parma_Polyhedra_Library::PIP_Tree_Node::get_owner(), Parma_Polyhedra_Library::PIP_Tree_Node::indent_and_print(), Parma_Polyhedra_Library::Constraint_System::insert(), Parma_Polyhedra_Library::maybe_abandon(), MIXED, NEGATIVE, Parma_Polyhedra_Library::not_a_dimension(), Parma_Polyhedra_Library::Matrix::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, row_sign(), sign, solution_valid, Parma_Polyhedra_Library::PIP_Tree_Node::solve(), Parma_Polyhedra_Library::Constraint_System::swap(), Parma_Polyhedra_Library::Row::swap(), UNKNOWN, var_column, var_row, WEIGHT_ADD, WEIGHT_ADD_MUL, WEIGHT_BEGIN, and ZERO.

01892                                                       {
01893 #ifdef NOISY_PIP_TREE_STRUCTURE
01894   indent_and_print(std::cerr, indent_level, "=== SOLVING NODE\n");
01895 #else
01896   used(indent_level);
01897 #endif
01898   // Reset current solution as invalid.
01899   solution_valid = false;
01900 
01901   Matrix context(ctx);
01902   Variables_Set all_params(params);
01903   const dimension_type num_art_params = artificial_parameters.size();
01904   add_artificial_parameters(context, all_params, space_dim, num_art_params);
01905   merge_assign(context, constraints_, all_params);
01906 
01907   // If needed, (re-)check feasibility of context.
01908   if (check_feasible_context) {
01909     Matrix ctx_copy(context);
01910     if (!compatibility_check(ctx_copy)) {
01911       delete this;
01912       return 0;
01913     }
01914   }
01915 
01916   const dimension_type not_a_dim = not_a_dimension();
01917 
01918   // Main loop of the simplex algorithm.
01919   while (true) {
01920     // Check if the client has requested abandoning all expensive
01921     // computations. If so, the exception specified by the client
01922     // is thrown now.
01923     maybe_abandon();
01924 
01925     PPL_ASSERT(OK());
01926 
01927     const dimension_type num_rows = tableau.t.num_rows();
01928     const dimension_type num_vars = tableau.s.num_columns();
01929     const dimension_type num_params = tableau.t.num_columns();
01930     const Coefficient& tableau_den = tableau.denominator();
01931 
01932 #ifdef VERY_NOISY_PIP
01933     tableau.ascii_dump(std::cerr);
01934     std::cerr << "context ";
01935     context.ascii_dump(std::cerr);
01936 #endif // #ifdef VERY_NOISY_PIP
01937 
01938     // (Re-) Compute parameter row signs.
01939     // While at it, keep track of the first parameter rows
01940     // having negative and mixed sign.
01941     dimension_type first_negative = not_a_dim;
01942     dimension_type first_mixed = not_a_dim;
01943     for (dimension_type i = 0; i < num_rows; ++i) {
01944       Row_Sign& sign_i = sign[i];
01945       if (sign_i == UNKNOWN || sign_i == MIXED)
01946         sign_i = row_sign(tableau.t[i], big_dimension);
01947 
01948       if (sign_i == NEGATIVE && first_negative == not_a_dim)
01949         first_negative = i;
01950       else if (sign_i == MIXED && first_mixed == not_a_dim)
01951         first_mixed = i;
01952     }
01953 
01954     // If no negative parameter row was found, try to refine the sign of
01955     // mixed rows using compatibility checks with the current context.
01956     if (first_negative == not_a_dim && first_mixed != not_a_dim) {
01957       for (dimension_type i = first_mixed; i < num_rows; ++i) {
01958         // Consider mixed sign parameter rows only.
01959         if (sign[i] != MIXED)
01960           continue;
01961         const Row& t_i = tableau.t[i];
01962         Row_Sign new_sign = ZERO;
01963         // Check compatibility for constraint t_i(z) >= 0.
01964         if (compatibility_check(context, t_i))
01965           new_sign = POSITIVE;
01966         // Check compatibility for constraint t_i(z) < 0,
01967         // i.e., -t_i(z) - 1 >= 0.
01968         Row t_i_compl(num_params, Row::Flags());
01969         complement_assign(t_i_compl, t_i, tableau_den);
01970         if (compatibility_check(context, t_i_compl))
01971           new_sign = (new_sign == POSITIVE) ? MIXED : NEGATIVE;
01972         // Update sign for parameter row i.
01973         sign[i] = new_sign;
01974         // Maybe update first_negative and first_mixed.
01975         if (new_sign == NEGATIVE && first_negative == not_a_dim) {
01976           first_negative = i;
01977           if (i == first_mixed)
01978             first_mixed = not_a_dim;
01979         }
01980         else if (new_sign == MIXED) {
01981           if (first_mixed == not_a_dim)
01982             first_mixed = i;
01983         }
01984         else if (i == first_mixed)
01985           first_mixed = not_a_dim;
01986       }
01987     }
01988 
01989     // If there still is no negative parameter row and a mixed sign
01990     // parameter row (first_mixed) such that:
01991     //  - it has at least one positive variable coefficient;
01992     //  - constraint t_i(z) > 0 is not compatible with the context;
01993     // then this parameter row can be considered negative.
01994     if (first_negative == not_a_dim && first_mixed != not_a_dim) {
01995       WEIGHT_BEGIN();
01996       for (dimension_type i = first_mixed; i < num_rows; ++i) {
01997         // Consider mixed sign parameter rows only.
01998         if (sign[i] != MIXED)
01999           continue;
02000         // Check for a positive variable coefficient.
02001         const Row& s_i = tableau.s[i];
02002         bool has_positive = false;
02003         for (dimension_type j = num_vars; j-- > 0; )
02004           if (s_i[j] > 0) {
02005             has_positive = true;
02006             break;
02007           }
02008         if (!has_positive)
02009           continue;
02010         // Check compatibility of constraint t_i(z) > 0.
02011         Row row(tableau.t[i]);
02012         PPL_DIRTY_TEMP_COEFFICIENT(mod);
02013         pos_mod_assign(mod, row[0], tableau_den);
02014         row[0] -= (mod == 0) ? tableau_den : mod;
02015         WEIGHT_ADD(2);
02016         const bool compatible = compatibility_check(context, row);
02017         // Maybe update sign (and first_* indices).
02018         if (compatible) {
02019           // Sign is still mixed.
02020           if (first_mixed == not_a_dim)
02021             first_mixed = i;
02022         }
02023         else {
02024           // Sign becomes negative (i.e., no longer mixed).
02025           sign[i] = NEGATIVE;
02026           if (first_negative == not_a_dim)
02027             first_negative = i;
02028           if (first_mixed == i)
02029             first_mixed = not_a_dim;
02030         }
02031       }
02032     }
02033 
02034 #ifdef VERY_NOISY_PIP
02035     std::cerr << "sign =";
02036     for (dimension_type i = 0; i < sign.size(); ++i)
02037       std::cerr << " " << "?0+-*"[sign[i]];
02038     std::cerr << std::endl;
02039 #endif // #ifdef VERY_NOISY_PIP
02040 
02041     // If we have found a negative parameter row, then
02042     // either the problem is unfeasible, or a pivoting step is required.
02043     if (first_negative != not_a_dim) {
02044 
02045       // Search for the best pivot row.
02046       dimension_type pi = not_a_dim;
02047       dimension_type pj = not_a_dim;
02048       for (dimension_type i = first_negative; i < num_rows; ++i) {
02049         if (sign[i] != NEGATIVE)
02050           continue;
02051         dimension_type j;
02052         if (!find_lexico_minimum_column(tableau.s, mapping, basis,
02053                                         tableau.s[i], 0, j)) {
02054           // No positive s_ij was found: problem is unfeasible.
02055 #ifdef NOISY_PIP_TREE_STRUCTURE
02056           indent_and_print(std::cerr, indent_level,
02057                            "No positive pivot: Solution = _|_\n");
02058 #endif // #ifdef NOISY_PIP_TREE_STRUCTURE
02059           delete this;
02060           return 0;
02061         }
02062         if (pj == not_a_dim
02063             || tableau.is_better_pivot(mapping, basis, i, j, pi, pj)) {
02064           // Update pivot indices.
02065           pi = i;
02066           pj = j;
02067           if (pip.control_parameters[PIP_Problem::PIVOT_ROW_STRATEGY]
02068               == PIP_Problem::PIVOT_ROW_STRATEGY_FIRST)
02069             // Stop at first valid row.
02070             break;
02071         }
02072       }
02073 
02074 #ifdef VERY_NOISY_PIP
02075       std::cerr << "Pivot (pi, pj) = (" << pi << ", " << pj << ")\n";
02076 #endif // #ifdef VERY_NOISY_PIP
02077 
02078       // Normalize the tableau before pivoting.
02079       tableau.normalize();
02080 
02081       // Perform pivot operation.
02082 
02083       // Update basis.
02084       {
02085         const dimension_type var_pi = var_row[pi];
02086         const dimension_type var_pj = var_column[pj];
02087         var_row[pi] = var_pj;
02088         var_column[pj] = var_pi;
02089         basis[var_pi] = true;
02090         basis[var_pj] = false;
02091         mapping[var_pi] = pj;
02092         mapping[var_pj] = pi;
02093       }
02094 
02095       PPL_DIRTY_TEMP_COEFFICIENT(product);
02096       PPL_DIRTY_TEMP_COEFFICIENT(gcd);
02097       PPL_DIRTY_TEMP_COEFFICIENT(scale_factor);
02098 
02099       // Creating identity rows corresponding to basic variable pj:
02100       // 1. add them to tableau so as to have proper size and capacity;
02101       tableau.s.add_zero_rows(1, Row::Flags());
02102       tableau.t.add_zero_rows(1, Row::Flags());
02103       // 2. swap the rows just added with empty ones.
02104       Row s_pivot(0, Row::Flags());
02105       Row t_pivot(0, Row::Flags());
02106       s_pivot.swap(tableau.s[num_rows]);
02107       t_pivot.swap(tableau.t[num_rows]);
02108       // 3. drop rows previously added at end of tableau.
02109       tableau.s.erase_to_end(num_rows);
02110       tableau.t.erase_to_end(num_rows);
02111 
02112       // Save current pivot denominator.
02113       PPL_DIRTY_TEMP_COEFFICIENT(pivot_den);
02114       pivot_den = tableau.denominator();
02115       // Let the (scaled) pivot coordinate be 1.
02116       s_pivot[pj] = pivot_den;
02117 
02118       // Swap identity row with the pivot row previously found.
02119       s_pivot.swap(tableau.s[pi]);
02120       t_pivot.swap(tableau.t[pi]);
02121       sign[pi] = ZERO;
02122 
02123       PPL_DIRTY_TEMP_COEFFICIENT(s_pivot_pj);
02124       s_pivot_pj = s_pivot[pj];
02125 
02126       // Compute columns s[*][j] :
02127       // s[i][j] -= s[i][pj] * s_pivot[j] / s_pivot_pj;
02128       for (dimension_type j = num_vars; j-- > 0; ) {
02129         if (j == pj)
02130           continue;
02131         const Coefficient& s_pivot_j = s_pivot[j];
02132         // Do nothing if the j-th pivot element is zero.
02133         if (s_pivot_j == 0)
02134           continue;
02135         WEIGHT_BEGIN();
02136         for (dimension_type i = num_rows; i-- > 0; ) {
02137           Row& s_i = tableau.s[i];
02138           product = s_pivot_j * s_i[pj];
02139           if (product % s_pivot_pj != 0) {
02140             // Must scale matrix to stay in integer case.
02141             gcd_assign(gcd, product, s_pivot_pj);
02142             exact_div_assign(scale_factor, s_pivot_pj, gcd);
02143             tableau.scale(scale_factor);
02144             product *= scale_factor;
02145             WEIGHT_ADD(3);
02146           }
02147           PPL_ASSERT(product % s_pivot_pj == 0);
02148           exact_div_assign(product, product, s_pivot_pj);
02149           s_i[j] -= product;
02150           WEIGHT_ADD(4);
02151         }
02152       }
02153 
02154       // Compute columns t[*][j] :
02155       // t[i][j] -= s[i][pj] * t_pivot[j] / s_pivot_pj;
02156       for (dimension_type j = num_params; j-- > 0; ) {
02157         const Coefficient& t_pivot_j = t_pivot[j];
02158         // Do nothing if the j-th pivot element is zero.
02159         if (t_pivot_j == 0)
02160           continue;
02161         WEIGHT_BEGIN();
02162         for (dimension_type i = num_rows; i-- > 0; ) {
02163           Row& s_i = tableau.s[i];
02164           product = t_pivot_j * s_i[pj];
02165           if (product % s_pivot_pj != 0) {
02166             // Must scale matrix to stay in integer case.
02167             gcd_assign(gcd, product, s_pivot_pj);
02168             exact_div_assign(scale_factor, s_pivot_pj, gcd);
02169             tableau.scale(scale_factor);
02170             product *= scale_factor;
02171             WEIGHT_ADD(3);
02172           }
02173           PPL_ASSERT(product % s_pivot_pj == 0);
02174           exact_div_assign(product, product, s_pivot_pj);
02175           tableau.t[i][j] -= product;
02176           WEIGHT_ADD(4);
02177 
02178           // Update row sign.
02179           Row_Sign& sign_i = sign[i];
02180           switch (sign_i) {
02181           case ZERO:
02182             if (product > 0)
02183               sign_i = NEGATIVE;
02184             else if (product < 0)
02185               sign_i = POSITIVE;
02186             break;
02187           case POSITIVE:
02188             if (product > 0)
02189               sign_i = MIXED;
02190             break;
02191           case NEGATIVE:
02192             if (product < 0)
02193               sign_i = MIXED;
02194             break;
02195           default:
02196             break;
02197           }
02198         }
02199       }
02200 
02201       // Compute column s[*][pj] : s[i][pj] /= s_pivot_pj;
02202       // Update column only if pivot coordinate != 1.
02203       if (s_pivot_pj != pivot_den) {
02204         WEIGHT_BEGIN();
02205         for (dimension_type i = num_rows; i-- > 0; ) {
02206           Row& s_i = tableau.s[i];
02207           Coefficient& s_i_pj = s_i[pj];
02208           product = s_i_pj * pivot_den;
02209           if (product % s_pivot_pj != 0) {
02210             // As above, perform matrix scaling.
02211             gcd_assign(gcd, product, s_pivot_pj);
02212             exact_div_assign(scale_factor, s_pivot_pj, gcd);
02213             tableau.scale(scale_factor);
02214             product *= scale_factor;
02215             WEIGHT_ADD(3);
02216           }
02217           PPL_ASSERT(product % s_pivot_pj == 0);
02218           exact_div_assign(s_i_pj, product, s_pivot_pj);
02219           WEIGHT_ADD(3);
02220         }
02221       }
02222 
02223       // Pivoting process ended: jump to next iteration.
02224       continue;
02225     } // if (first_negative != not_a_dim)
02226 
02227 
02228     PPL_ASSERT(first_negative == not_a_dim);
02229     // If no negative parameter row was found,
02230     // but a mixed parameter row was found ...
02231     if (first_mixed != not_a_dim) {
02232       // Look for a constraint (i_neg):
02233       //  - having mixed parameter sign;
02234       //  - having no positive variable coefficient;
02235       //  - minimizing the score (sum of parameter coefficients).
02236       dimension_type i_neg = not_a_dim;
02237       PPL_DIRTY_TEMP_COEFFICIENT(best_score);
02238       PPL_DIRTY_TEMP_COEFFICIENT(score);
02239       for (dimension_type i = first_mixed; i < num_rows; ++i) {
02240         // Mixed parameter sign.
02241         if (sign[i] != MIXED)
02242           continue;
02243         // No positive variable coefficient.
02244         bool has_positive = false;
02245         const Row& s_i = tableau.s[i];
02246         for (dimension_type j = 0; j < num_vars; ++j)
02247           if (s_i[j] > 0) {
02248             has_positive = true;
02249             break;
02250           }
02251         if (has_positive)
02252           continue;
02253         // Minimize parameter coefficient score,
02254         // eliminating implicated tautologies (if any).
02255         const Row& t_i = tableau.t[i];
02256         score = 0;
02257         WEIGHT_BEGIN();
02258         for (dimension_type j = num_params; j-- > 0; )
02259           score += t_i[j];
02260         WEIGHT_ADD_MUL(1, num_params);
02261         if (i_neg == not_a_dim || score < best_score) {
02262           i_neg = i;
02263           best_score = score;
02264         }
02265       }
02266 
02267       if (i_neg != not_a_dim) {
02268         Row tautology = tableau.t[i_neg];
02269         /* Simplify tautology by exploiting integrality. */
02270         integral_simplification(tautology);
02271         context.add_row(tautology);
02272         add_constraint(tautology, all_params);
02273         sign[i_neg] = POSITIVE;
02274 #ifdef NOISY_PIP
02275         {
02276           Linear_Expression expr = Linear_Expression(tautology[0]);
02277           dimension_type j = 1;
02278           for (Variables_Set::const_iterator p = all_params.begin(),
02279                  p_end = all_params.end(); p != p_end; ++p, ++j)
02280             add_mul_assign(expr, tautology[j], Variable(*p));
02281           using namespace IO_Operators;
02282           std::cerr << std::setw(2 * indent_level) << ""
02283                     << "Row " << i_neg
02284                     << ": mixed param sign, negative var coeffs\n";
02285           std::cerr << std::setw(2 * indent_level) << ""
02286                     << "==> adding tautology: "
02287                     << Constraint(expr >= 0) << ".\n";
02288         }
02289 #endif // #ifdef NOISY_PIP
02290         // Jump to next iteration.
02291         continue;
02292       }
02293 
02294       PPL_ASSERT(i_neg == not_a_dim);
02295       // Heuristically choose "best" (mixed) pivoting row.
02296       dimension_type best_i = not_a_dim;
02297       for (dimension_type i = first_mixed; i < num_rows; ++i) {
02298         if (sign[i] != MIXED)
02299           continue;
02300         const Row& t_i = tableau.t[i];
02301         score = 0;
02302         WEIGHT_BEGIN();
02303         for (dimension_type j = num_params; j-- > 0; )
02304           score += t_i[j];
02305         WEIGHT_ADD_MUL(1, num_params);
02306         if (best_i == not_a_dim || score < best_score) {
02307           best_score = score;
02308           best_i = i;
02309         }
02310       }
02311 
02312       Row t_test(tableau.t[best_i]);
02313       /* Simplify t_test by exploiting integrality. */
02314       integral_simplification(t_test);
02315 #ifdef NOISY_PIP
02316       {
02317         Linear_Expression expr = Linear_Expression(t_test[0]);
02318         dimension_type j = 1;
02319         for (Variables_Set::const_iterator p = all_params.begin(),
02320                p_end = all_params.end(); p != p_end; ++p, ++j)
02321           add_mul_assign(expr, t_test[j], Variable(*p));
02322         using namespace IO_Operators;
02323         std::cerr << std::setw(2 * indent_level) << ""
02324                   << "Row " << best_i << ": mixed param sign\n";
02325         std::cerr << std::setw(2 * indent_level) << ""
02326                   << "==> depends on sign of " << expr << ".\n";
02327       }
02328 #endif // #ifdef NOISY_PIP
02329 
02330       // Create a solution node for the "true" version of current node.
02331       PIP_Tree_Node* t_node = new PIP_Solution_Node(*this, No_Constraints());
02332       // Protect it from exception safety issues via std::auto_ptr.
02333       std::auto_ptr<PIP_Tree_Node> wrapped_node(t_node);
02334 
02335       // Add parametric constraint to context.
02336       context.add_row(t_test);
02337       // Recusively solve true node wrt updated context.
02338 #ifdef NOISY_PIP_TREE_STRUCTURE
02339       indent_and_print(std::cerr, indent_level, "=== SOLVING THEN CHILD\n");
02340 #endif
02341       t_node = t_node->solve(pip, check_feasible_context,
02342                              context, all_params, space_dim,
02343                              indent_level + 1);
02344       // Resolution may have changed t_node: in case, rewrap it.
02345       if (t_node != wrapped_node.get()) {
02346         wrapped_node.release();
02347         wrapped_node.reset(t_node);
02348       }
02349 
02350       // Modify *this in place to become the "false" version of current node.
02351       PIP_Tree_Node* f_node = this;
02352       // Swap aside constraints and artificial parameters
02353       // (these will be later restored if needed).
02354       Constraint_System cs;
02355       Artificial_Parameter_Sequence aps;
02356       cs.swap(f_node->constraints_);
02357       aps.swap(f_node->artificial_parameters);
02358       // Compute the complement of the constraint used for the "true" node.
02359       Row& f_test = context[context.num_rows()-1];
02360       complement_assign(f_test, t_test, 1);
02361 
02362       // Recusively solve false node wrt updated context.
02363 #ifdef NOISY_PIP_TREE_STRUCTURE
02364       indent_and_print(std::cerr, indent_level, "=== SOLVING ELSE CHILD\n");
02365 #endif
02366       f_node = f_node->solve(pip, check_feasible_context,
02367                              context, all_params, space_dim,
02368                              indent_level + 1);
02369 
02370       // Case analysis on recursive resolution calls outcome.
02371       if (t_node == 0) {
02372         if (f_node == 0) {
02373           // Both t_node and f_node unfeasible.
02374 #ifdef NOISY_PIP_TREE_STRUCTURE
02375           indent_and_print(std::cerr, indent_level,
02376                            "=== EXIT: BOTH BRANCHES UNFEASIBLE: _|_\n");
02377 #endif
02378           return 0;
02379         }
02380         else {
02381           // t_node unfeasible, f_node feasible:
02382           // restore cs and aps into f_node (i.e., this).
02383           PPL_ASSERT(f_node == this);
02384           f_node->constraints_.swap(cs);
02385           f_node->artificial_parameters.swap(aps);
02386           // Add f_test to constraints.
02387           f_node->add_constraint(f_test, all_params);
02388 #ifdef NOISY_PIP_TREE_STRUCTURE
02389           indent_and_print(std::cerr, indent_level,
02390                            "=== EXIT: THEN BRANCH UNFEASIBLE: SWAP BRANCHES\n");
02391 #endif
02392           return f_node;
02393         }
02394       }
02395       else if (f_node == 0) {
02396         // t_node feasible, f_node unfeasible.
02397 #ifdef NOISY_PIP_TREE_STRUCTURE
02398         indent_and_print(std::cerr, indent_level,
02399                          "=== EXIT: THEN BRANCH FEASIBLE\n");
02400 #endif
02401         // NOTE: in principle, we could merge t_node into its parent.
02402         // However, if t_node is a decision node having both childs,
02403         // then we would obtain a node violating the PIP_Decision_Node
02404         // invariant saying that t_node should have a single constraint:
02405         // it will have, at least, the two splitting constraints.
02406         PIP_Decision_Node* dn = dynamic_cast<PIP_Decision_Node*>(t_node);
02407         if (dn != 0 && dn->false_child != 0) {
02408           // Do NOT merge: create a new decision node.
02409           PIP_Tree_Node* parent
02410             = new PIP_Decision_Node(t_node->get_owner(), 0, t_node);
02411           // Previously wrapped 't_node' is now safe: release it
02412           // and protect new 'parent' node from exception safety issues.
02413           wrapped_node.release();
02414           wrapped_node.reset(parent);
02415           // Restore into parent `cs' and `aps'.
02416           parent->constraints_.swap(cs);
02417           parent->artificial_parameters.swap(aps);
02418           // Add t_test to parent's constraints.
02419           parent->add_constraint(t_test, all_params);
02420           // It is now safe to release previously wrapped parent pointer
02421           // and return it to caller.
02422           return wrapped_node.release();
02423         }
02424         else {
02425           // Merge t_node with its parent:
02426           // a) append into `cs' the constraints of t_node;
02427           for (Constraint_System::const_iterator
02428                  i = t_node->constraints_.begin(),
02429                  i_end = t_node->constraints_.end(); i != i_end; ++i)
02430             cs.insert(*i);
02431           // b) append into `aps' the parameters of t_node;
02432           aps.insert(aps.end(),
02433                      t_node->artificial_parameters.begin(),
02434                      t_node->artificial_parameters.end());
02435           // c) swap the updated `cs' and `aps' into t_node.
02436           cs.swap(t_node->constraints_);
02437           aps.swap(t_node->artificial_parameters);
02438           // d) add t_test to t_nodes's constraints.
02439           t_node->add_constraint(t_test, all_params);
02440           // It is now safe to release previously wrapped t_node pointer
02441           // and return it to caller.
02442           return wrapped_node.release();
02443         }
02444       }
02445 
02446       // Here both t_node and f_node are feasible:
02447       // create a new decision node.
02448 #ifdef NOISY_PIP_TREE_STRUCTURE
02449       indent_and_print(std::cerr, indent_level,
02450                        "=== EXIT: BOTH BRANCHES FEASIBLE: NEW DECISION NODE\n");
02451 #endif
02452       PIP_Tree_Node* parent
02453         = new PIP_Decision_Node(f_node->get_owner(), f_node, t_node);
02454       // Previously wrapped 't_node' is now safe: release it
02455       // and protect new 'parent' node from exception safety issues.
02456       wrapped_node.release();
02457       wrapped_node.reset(parent);
02458 
02459       // Add t_test to the constraints of the new decision node.
02460       parent->add_constraint(t_test, all_params);
02461 
02462       if (!cs.empty()) {
02463 #ifdef NOISY_PIP_TREE_STRUCTURE
02464         indent_and_print(std::cerr, indent_level,
02465                          "=== NODE HAS BOTH BRANCHES AND TAUTOLOGIES:\n");
02466         indent_and_print(std::cerr, indent_level,
02467                          "=== CREATE NEW PARENT FOR TAUTOLOGIES\n");
02468 #endif
02469         // If node to be solved had tautologies,
02470         // store them in a new decision node.
02471         parent = new PIP_Decision_Node(parent->get_owner(), 0, parent);
02472         // Previously wrapped 'parent' node is now safe: release it
02473         // and protect new 'parent' node from exception safety issues.
02474         wrapped_node.release();
02475         wrapped_node.reset(parent);
02476         parent->constraints_.swap(cs);
02477       }
02478       parent->artificial_parameters.swap(aps);
02479       // It is now safe to release previously wrapped decision node
02480       // and return it to the caller.
02481       return wrapped_node.release();
02482     } // if (first_mixed != not_a_dim)
02483 
02484 
02485     PPL_ASSERT(first_negative == not_a_dim);
02486     PPL_ASSERT(first_mixed == not_a_dim);
02487     // Here all parameters are positive: we have found a continuous
02488     // solution. If the solution happens to be integer, then it is the
02489     // solution of the  integer problem. Otherwise, we may need to generate
02490     // a new cut to try and get back into the integer case.
02491 #ifdef NOISY_PIP
02492     indent_and_print(std::cerr, indent_level,
02493                      "All parameters are positive.\n");
02494 #endif // #ifdef NOISY_PIP
02495     tableau.normalize();
02496 
02497     // Look for any row having non integer parameter coefficients.
02498     const Coefficient& den = tableau.denominator();
02499     for (dimension_type k = 0; k < num_vars; ++k) {
02500       if (basis[k])
02501         // Basic variable = 0, hence integer.
02502         continue;
02503       const dimension_type i = mapping[k];
02504       const Row& t_i = tableau.t[i];
02505       WEIGHT_BEGIN();
02506       for (dimension_type j = num_params; j-- > 0; ) {
02507         WEIGHT_ADD(1);
02508         if (t_i[j] % den != 0)
02509           goto non_integer;
02510       }
02511     }
02512     // The goto was not taken, the solution is integer.
02513 #ifdef NOISY_PIP_TREE_STRUCTURE
02514     indent_and_print(std::cerr, indent_level,
02515                      "EXIT: solution found.\n");
02516 #endif // #ifdef NOISY_PIP
02517     return this;
02518 
02519   non_integer:
02520     // The solution is non-integer: generate a cut.
02521     PPL_DIRTY_TEMP_COEFFICIENT(mod);
02522     dimension_type best_i = not_a_dim;
02523     dimension_type best_pcount = not_a_dim;
02524 
02525     const PIP_Problem::Control_Parameter_Value cutting_strategy
02526       = pip.control_parameters[PIP_Problem::CUTTING_STRATEGY];
02527 
02528     if (cutting_strategy == PIP_Problem::CUTTING_STRATEGY_FIRST) {
02529       // Find the first row with simplest parametric part.
02530       for (dimension_type k = 0; k < num_vars; ++k) {
02531         if (basis[k])
02532           continue;
02533         const dimension_type i = mapping[k];
02534         const Row& t_i = tableau.t[i];
02535         // Count the number of non-integer parameter coefficients.
02536         WEIGHT_BEGIN();
02537         dimension_type pcount = 0;
02538         for (dimension_type j = num_params; j-- > 0; ) {
02539           pos_mod_assign(mod, t_i[j], den);
02540           if (mod != 0)
02541             ++pcount;
02542         }
02543         WEIGHT_ADD_MUL(1, num_params);
02544         if (pcount > 0 && (best_i == not_a_dim || pcount < best_pcount)) {
02545           best_pcount = pcount;
02546           best_i = i;
02547         }
02548       }
02549       // Generate cut using 'best_i'.
02550       generate_cut(best_i, all_params, context, space_dim, indent_level);
02551     }
02552     else {
02553       PPL_ASSERT(cutting_strategy == PIP_Problem::CUTTING_STRATEGY_DEEPEST
02554                  || cutting_strategy == PIP_Problem::CUTTING_STRATEGY_ALL);
02555       // Find the row with simplest parametric part
02556       // which will generate the "deepest" cut.
02557       PPL_DIRTY_TEMP_COEFFICIENT(best_score);
02558       best_score = 0;
02559       PPL_DIRTY_TEMP_COEFFICIENT(score);
02560       PPL_DIRTY_TEMP_COEFFICIENT(s_score);
02561       std::vector<dimension_type> all_best_is;
02562 
02563       for (dimension_type k = 0; k < num_vars; ++k) {
02564         if (basis[k])
02565           continue;
02566         const dimension_type i = mapping[k];
02567         // Compute score and pcount.
02568         WEIGHT_BEGIN();
02569         score = 0;
02570         dimension_type pcount = 0;
02571         const Row& t_i = tableau.t[i];
02572         for (dimension_type j = num_params; j-- > 0; ) {
02573           pos_mod_assign(mod, t_i[j], den);
02574           if (mod != 0) {
02575             score += den;
02576             score -= mod;
02577             ++pcount;
02578           }
02579         }
02580         WEIGHT_ADD_MUL(3, num_params);
02581 
02582         // Compute s_score.
02583         WEIGHT_BEGIN();
02584         s_score = 0;
02585         const Row& s_i = tableau.s[i];
02586         for (dimension_type j = num_vars; j-- > 0; ) {
02587           pos_mod_assign(mod, s_i[j], den);
02588           s_score += den;
02589           s_score -= mod;
02590         }
02591         WEIGHT_ADD_MUL(3, num_vars);
02592         // Combine 'score' and 's_score'.
02593         score *= s_score;
02594         /*
02595           Select row i if it is non integer AND
02596             - no row has been chosen yet; OR
02597             - it has fewer non-integer parameter coefficients; OR
02598             - it has the same number of non-integer parameter coefficients,
02599               but its score is greater.
02600         */
02601         if (pcount != 0
02602             && (best_i == not_a_dim
02603                 || pcount < best_pcount
02604                 || (pcount == best_pcount && score > best_score))) {
02605           if (pcount < best_pcount)
02606             all_best_is.clear();
02607           best_i = i;
02608           best_pcount = pcount;
02609           best_score = score;
02610         }
02611         if (pcount > 0)
02612           all_best_is.push_back(i);
02613       }
02614       if (cutting_strategy == PIP_Problem::CUTTING_STRATEGY_DEEPEST)
02615         generate_cut(best_i, all_params, context, space_dim, indent_level);
02616       else {
02617         PPL_ASSERT(cutting_strategy == PIP_Problem::CUTTING_STRATEGY_ALL);
02618         for (dimension_type k = all_best_is.size(); k-- > 0; )
02619           generate_cut(all_best_is[k], all_params, context,
02620                        space_dim, indent_level);
02621       }
02622     } // End of processing for non-integer solutions.
02623 
02624   } // Main loop of the simplex algorithm
02625 
02626   // This point should be unreachable.
02627   throw std::runtime_error("PPL internal error");
02628 }

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 2903 of file PIP_Tree.cc.

References external_memory_in_bytes().

02903                                                {
02904   return sizeof(*this) + external_memory_in_bytes();
02905 }

void Parma_Polyhedra_Library::PIP_Solution_Node::update_solution (  )  const [protected]

Helper method.

Definition at line 3051 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().

03051                                          {
03052   // Avoid doing useless work.
03053   if (solution_valid)
03054     return;
03055 
03056   const PIP_Problem* pip = get_owner();
03057   PPL_ASSERT(pip);
03058   std::vector<bool> pip_dim_is_param(pip->space_dimension());
03059   const Variables_Set& params = pip->parameter_space_dimensions();
03060   for (Variables_Set::const_iterator p = params.begin(),
03061          p_end = params.end(); p != p_end; ++p)
03062     pip_dim_is_param[*p] = true;
03063 
03064   update_solution(pip_dim_is_param);
03065 }

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_param A 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 3069 of file PIP_Tree.cc.

References Parma_Polyhedra_Library::add_mul_assign(), PPL_DIRTY_TEMP_COEFFICIENT, solution, and solution_valid.

03069                                                                {
03070   // Avoid doing useless work.
03071   if (solution_valid)
03072     return;
03073 
03074   // const_cast required so as to refresh the solution cache.
03075   PIP_Solution_Node& x = const_cast<PIP_Solution_Node&>(*this);
03076 
03077   const dimension_type num_pip_dims = pip_dim_is_param.size();
03078   const dimension_type num_pip_vars = tableau.s.num_columns();
03079   const dimension_type num_pip_params = num_pip_dims - num_pip_vars;
03080   const dimension_type num_all_params = tableau.t.num_columns() - 1;
03081   const dimension_type num_art_params = num_all_params - num_pip_params;
03082 
03083   if (solution.size() != num_pip_vars)
03084     x.solution.resize(num_pip_vars);
03085 
03086   // Compute external "names" (i.e., indices) for all parameters.
03087   std::vector<dimension_type> all_param_names(num_all_params);
03088 
03089   // External indices for problem parameters.
03090   for (dimension_type i = 0, p_index = 0; i < num_pip_dims; ++i)
03091     if (pip_dim_is_param[i]) {
03092       all_param_names[p_index] = i;
03093       ++p_index;
03094     }
03095   // External indices for artificial parameters.
03096   for (dimension_type i = 0; i < num_art_params; ++i)
03097     all_param_names[num_pip_params + i] = num_pip_dims + i;
03098 
03099 
03100   PPL_DIRTY_TEMP_COEFFICIENT(norm_coeff);
03101   const Coefficient& den = tableau.denominator();
03102   for (dimension_type i = num_pip_vars; i-- > 0; ) {
03103     Linear_Expression& sol_i = x.solution[i];
03104     sol_i = Linear_Expression(0);
03105     if (basis[i])
03106       continue;
03107     const Row& row = tableau.t[mapping[i]];
03108 
03109     for (dimension_type j = num_all_params; j-- > 0; ) {
03110       // NOTE: add 1 to column index to account for inhomogenous term.
03111       const Coefficient& coeff = row[j+1];
03112       if (coeff == 0)
03113         continue;
03114       norm_coeff = coeff / den;
03115       if (norm_coeff != 0)
03116         add_mul_assign(sol_i, norm_coeff, Variable(all_param_names[j]));
03117     }
03118     norm_coeff = row[0] / den;
03119     sol_i += norm_coeff;
03120   }
03121 
03122   // Mark solution as valid.
03123   x.solution_valid = true;
03124 }

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 
) [protected, virtual]

Implements pure virtual method PIP_Tree_Node::update_tableau.

Implements Parma_Polyhedra_Library::PIP_Tree_Node.

Definition at line 1703 of file PIP_Tree.cc.

References Parma_Polyhedra_Library::add_mul_assign(), big_dimension, Parma_Polyhedra_Library::PIP_Problem::big_parameter_dimension, Parma_Polyhedra_Library::Constraint::coefficient(), Parma_Polyhedra_Library::PIP_Problem::external_space_dim, Parma_Polyhedra_Library::Constraint::inhomogeneous_term(), Parma_Polyhedra_Library::PIP_Problem::internal_space_dim, Parma_Polyhedra_Library::Constraint::is_equality(), Parma_Polyhedra_Library::Constraint::is_strict_inequality(), Parma_Polyhedra_Library::not_a_dimension(), OK(), row_sign(), sign, Parma_Polyhedra_Library::Constraint::space_dimension(), special_equality_row, var_column, var_row, WEIGHT_ADD, WEIGHT_BEGIN, and ZERO.

01707                                                                    {
01708   // Make sure a parameter column exists, for the inhomogeneous term.
01709   if (tableau.t.num_columns() == 0)
01710     tableau.t.add_zero_columns(1);
01711 
01712   // NOTE: here 'params' stands for problem (i.e., non artificial) parameters.
01713   const dimension_type old_num_vars = tableau.s.num_columns();
01714   const dimension_type old_num_params
01715     = pip.internal_space_dim - old_num_vars;
01716   const dimension_type num_added_dims
01717     = pip.external_space_dim - pip.internal_space_dim;
01718   const dimension_type new_num_params = parameters.size();
01719   const dimension_type num_added_params = new_num_params - old_num_params;
01720   const dimension_type num_added_vars = num_added_dims - num_added_params;
01721 
01722   const dimension_type old_num_art_params
01723     = tableau.t.num_columns() - 1 - old_num_params;
01724 
01725   // Resize the two tableau matrices.
01726   if (num_added_vars > 0)
01727     tableau.s.add_zero_columns(num_added_vars);
01728   if (num_added_params > 0)
01729     tableau.t.add_zero_columns(num_added_params);
01730 
01731   if (num_added_params > 0 && old_num_art_params > 0) {
01732     // Shift to the right the columns of artificial parameters.
01733     std::vector<dimension_type> swaps;
01734     swaps.reserve(3*old_num_art_params);
01735     const dimension_type first_ap = 1 + old_num_params;
01736     for (dimension_type i = 0; i < old_num_art_params; ++i) {
01737       dimension_type old_ap = first_ap + i;
01738       dimension_type new_ap = old_ap + num_added_params;
01739       swaps.push_back(old_ap);
01740       swaps.push_back(new_ap);
01741       swaps.push_back(0);
01742     }
01743     tableau.t.permute_columns(swaps);
01744   }
01745 
01746   dimension_type new_var_column = old_num_vars;
01747   const dimension_type initial_space_dim = old_num_vars + old_num_params;
01748   for (dimension_type i = initial_space_dim; i < external_space_dim; ++i) {
01749     if (parameters.count(i) == 0) {
01750       // A new problem variable.
01751       if (tableau.s.num_rows() == 0) {
01752         // No rows have been added yet
01753         basis.push_back(true);
01754         mapping.push_back(new_var_column);
01755       }
01756       else {
01757         /*
01758           Need to insert the original variable id
01759           before the slack variable id's to respect variable ordering.
01760         */
01761         basis.insert(basis.begin() + new_var_column, true);
01762         mapping.insert(mapping.begin() + new_var_column, new_var_column);
01763         // Update variable id's of slack variables.
01764         for (dimension_type j = var_row.size(); j-- > 0; )
01765           if (var_row[j] >= new_var_column)
01766             ++var_row[j];
01767         for (dimension_type j = var_column.size(); j-- > 0; )
01768           if (var_column[j] >= new_var_column)
01769             ++var_column[j];
01770         if (special_equality_row > 0)
01771           ++special_equality_row;
01772       }
01773       var_column.push_back(new_var_column);
01774       ++new_var_column;
01775     }
01776   }
01777 
01778   if (big_dimension == not_a_dimension()
01779       && pip.big_parameter_dimension != not_a_dimension()) {
01780     // Compute the column number of big parameter in tableau.t matrix.
01781     Variables_Set::const_iterator pos
01782       = parameters.find(pip.big_parameter_dimension);
01783     big_dimension = std::distance(parameters.begin(), pos) + 1;
01784   }
01785 
01786   const Coefficient& denom = tableau.denominator();
01787   for (Constraint_Sequence::const_iterator
01788          c_iter = input_cs.begin() + first_pending_constraint,
01789          c_end = input_cs.end(); c_iter != c_end; ++c_iter) {
01790     const Constraint& constraint = *c_iter;
01791     // (Tentatively) Add new rows to s and t matrices.
01792     // These will be removed at the end if they turn out to be useless.
01793     const dimension_type row_id = tableau.s.num_rows();
01794     tableau.s.add_zero_rows(1,  Row::Flags());
01795     tableau.t.add_zero_rows(1,  Row::Flags());
01796     Row& v_row = tableau.s[row_id];
01797     Row& p_row = tableau.t[row_id];
01798 
01799     // Setting the inhomogeneus term.
01800     p_row[0] = constraint.inhomogeneous_term();
01801     if (constraint.is_strict_inequality())
01802       // Transform (expr > 0) into (expr - 1 >= 0).
01803       --p_row[0];
01804     p_row[0] *= denom;
01805 
01806     WEIGHT_BEGIN();
01807     dimension_type p_index = 1;
01808     dimension_type v_index = 0;
01809     for (dimension_type i = 0,
01810            i_end = constraint.space_dimension(); i != i_end; ++i) {
01811       const bool is_parameter = (1 == parameters.count(i));
01812       const Coefficient& coeff_i = constraint.coefficient(Variable(i));
01813       if (coeff_i == 0) {
01814         // Optimize computation below: only update p/v index.
01815         if (is_parameter)
01816           ++p_index;
01817         else
01818           ++v_index;
01819         // Jump to next iteration.
01820         continue;
01821       }
01822 
01823       WEIGHT_ADD(1);
01824       if (is_parameter) {
01825         p_row[p_index] = coeff_i * denom;
01826         ++p_index;
01827       }
01828       else {
01829         const dimension_type mv = mapping[v_index];
01830         if (basis[v_index])
01831           // Basic variable : add coeff_i * x_i
01832           add_mul_assign(v_row[mv], coeff_i, denom);
01833         else {
01834           // Non-basic variable : add coeff_i * row_i
01835           add_mul_assign_row(v_row, coeff_i, tableau.s[mv]);
01836           add_mul_assign_row(p_row, coeff_i, tableau.t[mv]);
01837         }
01838         ++v_index;
01839       }
01840     }
01841 
01842     if (row_sign(v_row, not_a_dimension()) == ZERO) {
01843       // Parametric-only constraints have already been inserted in
01844       // initial context, so no need to insert them in the tableau.
01845       tableau.s.erase_to_end(row_id);
01846       tableau.t.erase_to_end(row_id);
01847     }
01848     else {
01849       const dimension_type var_id = mapping.size();
01850       sign.push_back(row_sign(p_row, big_dimension));
01851       basis.push_back(false);
01852       mapping.push_back(row_id);
01853       var_row.push_back(var_id);
01854       if (constraint.is_equality()) {
01855         // Handle equality constraints.
01856         // After having added the f_i(x,p) >= 0 constraint,
01857         // we must add -f_i(x,p) to the special equality row.
01858         if (special_equality_row == 0 || basis[special_equality_row]) {
01859           // The special constraint has not been created yet
01860           // FIXME: for now, we don't handle the case where the variable
01861           // is basic, and we just create a new row.
01862           // This might be faster however.
01863           tableau.s.add_zero_rows(1, Row::Flags());
01864           tableau.t.add_zero_rows(1, Row::Flags());
01865           // NOTE: addition of rows invalidates references v_row and p_row
01866           // due to possible matrix reallocations: recompute them.
01867           neg_assign_row(tableau.s[1 + row_id], tableau.s[row_id]);
01868           neg_assign_row(tableau.t[1 + row_id], tableau.t[row_id]);
01869           sign.push_back(row_sign(tableau.t[1 + row_id], big_dimension));
01870           special_equality_row = mapping.size();
01871           basis.push_back(false);
01872           mapping.push_back(1 + row_id);
01873           var_row.push_back(1 + var_id);
01874         } else {
01875           // The special constraint already exists and is nonbasic.
01876           const dimension_type m_eq = mapping[special_equality_row];
01877           sub_assign(tableau.s[m_eq], v_row);
01878           sub_assign(tableau.t[m_eq], p_row);
01879         }
01880       }
01881     }
01882   }
01883   PPL_ASSERT(OK());
01884 }


Friends And Related Function Documentation

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

Member Data Documentation

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 523 of file PIP_Tree.defs.hh.

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 570 of file PIP_Tree.defs.hh.

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

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 535 of file PIP_Tree.defs.hh.

A cache for computed sign values of constraint parametric RHS.

Definition at line 587 of file PIP_Tree.defs.hh.

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

Parametric values for the solution.

Definition at line 590 of file PIP_Tree.defs.hh.

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

An indicator for solution validity.

Definition at line 593 of file PIP_Tree.defs.hh.

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

The variable number of the special inequality used for modelling 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 modelized the following way:

  • $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 modelize the latter sum of constraints. If no such constraint exists, the value is set to 0.

Definition at line 564 of file PIP_Tree.defs.hh.

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

The parametric simplex tableau.

Definition at line 503 of file PIP_Tree.defs.hh.

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

Definition at line 545 of file PIP_Tree.defs.hh.

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

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

Definition at line 540 of file PIP_Tree.defs.hh.

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


The documentation for this class was generated from the following files:
Generated on Sun Feb 27 16:20:32 2011 for PPL by  doxygen 1.6.3