summaryrefslogtreecommitdiff
path: root/libs/cassowary/ClSimplexSolver.cc
diff options
context:
space:
mode:
Diffstat (limited to 'libs/cassowary/ClSimplexSolver.cc')
-rw-r--r--libs/cassowary/ClSimplexSolver.cc1631
1 files changed, 0 insertions, 1631 deletions
diff --git a/libs/cassowary/ClSimplexSolver.cc b/libs/cassowary/ClSimplexSolver.cc
deleted file mode 100644
index 32ea59df74..0000000000
--- a/libs/cassowary/ClSimplexSolver.cc
+++ /dev/null
@@ -1,1631 +0,0 @@
-// $Id$
-//
-// Cassowary Incremental Constraint Solver
-// Original Smalltalk Implementation by Alan Borning
-// This C++ Implementation by Greg J. Badros, <gjb@cs.washington.edu>
-// http://www.cs.washington.edu/homes/gjb
-// (C) 1998, 1999 Greg J. Badros and Alan Borning
-// See ../LICENSE for legal details regarding this software
-//
-// ClSimplexSolver.cc
-
-using namespace std;
-
-#include <cassowary/debug.h>
-#include <cassowary/ClSimplexSolver.h>
-#include <cassowary/ClErrors.h>
-#include <cassowary/ClVariable.h>
-#include <cassowary/ClPoint.h>
-#include <cassowary/ClSlackVariable.h>
-#include <cassowary/ClObjectiveVariable.h>
-#include <cassowary/ClDummyVariable.h>
-#include <cassowary/cl_auto_ptr.h>
-
-#include <algorithm>
-#include <float.h>
-#include <sstream>
-#include <queue>
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#define CONFIG_H_INCLUDED
-#endif
-
-// Need to delete all expressions
-// and all slack and dummy variables
-// See NewExpression -- all allocation is done in there
-ClSimplexSolver::~ClSimplexSolver()
-{
-#ifdef CL_SOLVER_STATS
- cerr << "_slackCounter == " << _slackCounter
- << "\n_artificialCounter == " << _artificialCounter
- << "\n_dummyCounter == " << _dummyCounter << endl;
- cerr << "stayMinusErrorVars " << _stayMinusErrorVars.size() << ", "
- << "stayPlusErrorVars " << _stayPlusErrorVars.size() << ", "
- << "errorVars " << _errorVars.size() << ", "
- << "markerVars " << _markerVars.size() << endl;
-#endif
- // Cannot print *this here, since local ClVariable-s may have been
- // destructed already
-}
-
-// Add the constraint cn to the tableau
-ClSimplexSolver &
-ClSimplexSolver::AddConstraint(ClConstraint *const pcn)
-{
-#ifdef CL_TRACE
- Tracer TRACER(__FUNCTION__);
- cerr << "(" << *pcn << ")" << endl;
-#endif
-
- if (!pcn->FIsOkayForSimplexSolver()) {
- throw ExCLTooDifficultSpecial("SimplexSolver cannot handle this constraint object");
- }
-
- if (pcn->IsStrictInequality()) {
- // cannot handle strict inequalities
- throw ExCLStrictInequalityNotAllowed();
- }
-
- if (pcn->ReadOnlyVars().size() > 0) {
- // cannot handle read-only vars
- throw ExCLReadOnlyNotAllowed();
- }
-
- if (pcn->IsEditConstraint())
- {
- ClEditConstraint *pcnEdit = dynamic_cast<ClEditConstraint *>(pcn);
- const ClVariable &v = pcnEdit->variable();
- if (!v.IsExternal() ||
- (!FIsBasicVar(v) && !ColumnsHasKey(v)))
- {
- // we could try to make this case work,
- // but it'd be unnecessarily inefficient --
- // and probably easier for the client application
- // to deal with
- throw ExCLEditMisuse("(ExCLEditMisuse) Edit constraint on variable not in tableau.");
- }
- ClEditInfo *pcei = PEditInfoFromClv(v);
- if (pcei)
- {
- // we need to only add a partial _editInfoList entry for this
- // edit constraint since the variable is already being edited.
- // otherwise a more complete entry is added later in this function
- _editInfoList.push_back(new ClEditInfo(v, NULL, clvNil, clvNil, 0));
- return *this;
- }
- }
-
- ClVariable clvEplus, clvEminus;
- Number prevEConstant;
- ClLinearExpression *pexpr = NewExpression(pcn, /* output to: */
- clvEplus,clvEminus,
- prevEConstant);
- bool fAddedOkDirectly = false;
-
- try
- {
- // If possible Add expr directly to the appropriate tableau by
- // choosing a subject for expr (a variable to become basic) from
- // among the current variables in expr. If this doesn't work use an
- // artificial variable. After adding expr re-Optimize.
- fAddedOkDirectly = TryAddingDirectly(*pexpr);
- }
- catch (ExCLRequiredFailure &error)
- {
-#ifdef CL_TRACE
- cerr << "could not Add directly -- caught ExCLRequiredFailure error" << endl;
-#endif
- RemoveConstraintInternal(pcn);
- throw;
- }
-
- if (!fAddedOkDirectly)
- { // could not Add directly
- ExCLRequiredFailureWithExplanation e;
- if (!AddWithArtificialVariable(*pexpr, e))
- {
-#ifdef CL_DEBUG_FAILURES
- cerr << "Failed solve! Could not Add constraint.\n"
- << *this << endl;
-#endif
- RemoveConstraintInternal(pcn);
- if (FIsExplaining())
- throw e;
- else
- throw ExCLRequiredFailure();
- }
- }
-
- _fNeedsSolving = true;
-
- if (pcn->IsEditConstraint())
- {
- ClEditConstraint *pcnEdit = dynamic_cast<ClEditConstraint *>(pcn);
- ClVariable clv = pcnEdit->variable();
- _editInfoList.push_back(new ClEditInfo(clv, pcnEdit, clvEplus, clvEminus,
- prevEConstant));
- }
-
- if (_fAutosolve)
- {
- Optimize(_objective);
- SetExternalVariables();
- }
-
- pcn->addedTo(*this);
- return *this;
-}
-
-// Add weak stays to the x and y parts of each point. These have
-// increasing weights so that the solver will try to satisfy the x
-// and y stays on the same point, rather than the x stay on one and
-// the y stay on another.
-ClSimplexSolver &
-ClSimplexSolver::AddPointStays(const vector<const ClPoint *> &listOfPoints,
- const ClStrength &strength)
-{
-#ifdef CL_TRACE
- Tracer TRACER(__FUNCTION__);
-#endif
-
- vector<const ClPoint *>::const_iterator it = listOfPoints.begin();
- double weight = 1.0;
- static const double multiplier = 2.0;
- for ( ; it != listOfPoints.end(); ++it )
- {
- AddPointStay((*it)->X(),(*it)->Y(),strength,weight);
- weight *= multiplier;
- }
- return *this;
-}
-
-ClSimplexSolver &
-ClSimplexSolver::AddPointStay(const ClPoint &clp, const ClStrength &strength, double weight)
-{
- AddPointStay(clp.X(),clp.Y(),strength,weight);
- return *this;
-}
-
-
-ClSimplexSolver &
-ClSimplexSolver::RemoveEditVarsTo(unsigned int n)
-{
- queue<ClVariable> qclv;
- ClVarSet sclvStillEditing; // Set of edit variables that we need to *not* remove
-#ifdef DEBUG_NESTED_EDITS
- cerr << __FUNCTION__ << " " << n << endl;
-#endif
- unsigned int i = 0;
- for ( ClEditInfoList::const_iterator it = _editInfoList.begin();
- (it != _editInfoList.end() && _editInfoList.size() != static_cast<unsigned int>(n));
- ++it, ++i )
- {
- const ClEditInfo *pcei = (*it);
- assert(pcei);
-#ifdef DEBUG_NESTED_EDITS
- cerr << __FUNCTION__ << "Checking " << pcei->_clv
- << ", index = " << i << endl;
-#endif
- if (i >= n)
- qclv.push(pcei->_clv);
- else
- sclvStillEditing.insert(pcei->_clv);
- }
- while (!qclv.empty())
- {
- ClVariable clv = qclv.front();
- // only remove the variable if it's not in the set of variable
- // from a previous nested outer edit
- // e.g., if I do:
- // Edit x,y
- // Edit w,h,x,y
- // EndEdit
- // The end edit needs to only get rid of the edits on w,h
- // not the ones on x,y
- if (sclvStillEditing.find(clv) == sclvStillEditing.end())
- {
-#ifdef DEBUG_NESTED_EDITS
- cerr << __FUNCTION__ << ": Removing " << clv << endl;
-#endif
- RemoveEditVar(clv);
- }
-#ifdef DEBUG_NESTED_EDITS
- else
- {
- cerr << __FUNCTION__ << ": Not removing " << clv << endl;
- }
-#endif
- qclv.pop();
- }
- while (_editInfoList.size() > n) {
- _editInfoList.pop_back();
- }
-
- return *this;
-}
-
-
-/* A predicate used for remove_if */
-class VarInVarSet : public unary_function<ClVariable,bool> {
-public:
- VarInVarSet(const ClVarSet &clvset) :
- _set(clvset),
- _setEnd(clvset.end())
- { }
-
- bool operator ()(ClVariable clv) const {
- return (_set.find(clv) != _setEnd);
- }
-
-private:
- const ClVarSet &_set;
- const ClVarSet::iterator _setEnd;
-};
-
-
-
-// Remove the constraint cn from the tableau
-// Also remove any error variable associated with cn
-ClSimplexSolver &
-ClSimplexSolver::RemoveConstraintInternal(const ClConstraint *const pcn)
-{
-#ifdef CL_TRACE
- Tracer TRACER(__FUNCTION__);
- cerr << "(" << *pcn << ")" << endl;
-#endif
-
- // We are about to remove a constraint. There may be some stay
- // constraints that were unsatisfied previously -- if we just
- // removed the constraint these could come into play. Instead,
- // Reset all of the stays so that things should stay where they are
- // at the moment.
- _fNeedsSolving = true;
-
- ResetStayConstants();
-
- // remove any error variables from the objective function
- ClLinearExpression *pzRow = RowExpression(_objective);
-
-#ifdef CL_TRACE
- cerr << _errorVars << endl << endl;
-#endif
-
- ClConstraintToVarSetMap::iterator
- it_eVars = _errorVars.find(pcn);
- bool fFoundErrorVar = (it_eVars != _errorVars.end());
-
- if (fFoundErrorVar)
- {
- ClVarSet &eVars = (*it_eVars).second;
- ClVarSet::iterator it = eVars.begin();
- for ( ; it != eVars.end(); ++it )
- {
- const ClLinearExpression *pexpr = RowExpression(*it);
- if (pexpr == NULL )
- {
- pzRow->AddVariable(*it,-pcn->weight() * pcn->strength().symbolicWeight().AsDouble(),
- _objective,*this);
- }
- else
- { // the error variable was in the basis
- pzRow->AddExpression(*pexpr,-pcn->weight() * pcn->strength().symbolicWeight().AsDouble(),
- _objective,*this);
- }
- }
- }
-
- ClConstraintToVarMap::iterator
- it_marker = _markerVars.find(pcn);
- if (it_marker == _markerVars.end())
- { // could not find the constraint
- throw ExCLConstraintNotFound();
- }
- // try to make the marker variable basic if it isn't already
- const ClVariable marker = (*it_marker).second;
- _markerVars.erase(it_marker);
- _constraintsMarked.erase(marker);
-#ifdef CL_TRACE
- cerr << "Looking to remove var " << marker << endl;
-#endif
- if (!FIsBasicVar(marker))
- { // not in the basis, so need to do some work
- // first choose which variable to move out of the basis
- // only consider restricted basic variables
- ClVarSet &col = _columns[marker];
- ClVarSet::iterator it_col = col.begin();
-#ifdef CL_TRACE
- cerr << "Must Pivot -- columns are " << col << endl;
-#endif
-
- ClVariable exitVar = clvNil;
- bool fExitVarSet = false;
- double minRatio = 0.0;
- for ( ; it_col != col.end(); ++it_col)
- {
- const ClVariable &v = *it_col;
- if (v.IsRestricted() )
- {
- const ClLinearExpression *pexpr = RowExpression(v);
- assert(pexpr != NULL );
- Number coeff = pexpr->CoefficientFor(marker);
-#ifdef CL_TRACE
- cerr << "Marker " << marker << "'s coefficient in " << *pexpr << " is "
- << coeff << endl;
-#endif
- // only consider negative coefficients
- if (coeff < 0.0)
- {
- Number r = - pexpr->Constant() / coeff;
- if (!fExitVarSet || r < minRatio)
- {
- minRatio = r;
- exitVar = v;
- fExitVarSet = true;
- }
- }
- }
- }
- // if we didn't set exitvar above, then either the marker
- // variable has a positive coefficient in all equations, or it
- // only occurs in equations for unrestricted variables. If it
- // does occur in an equation for a restricted variable, pick the
- // equation that gives the smallest ratio. (The row with the
- // marker variable will become infeasible, but all the other rows
- // will still be feasible; and we will be dropping the row with
- // the marker variable. In effect we are removing the
- // non-negativity restriction on the marker variable.)
- if (!fExitVarSet)
- {
-#ifdef CL_TRACE
- cerr << "exitVar did not get set" << endl;
-#endif
- it_col = col.begin();
- for ( ; it_col != col.end(); ++it_col)
- {
- ClVariable v = *it_col;
- if (v.IsRestricted() )
- {
- const ClLinearExpression *pexpr = RowExpression(v);
- assert(pexpr != NULL);
- Number coeff = pexpr->CoefficientFor(marker);
- Number r = pexpr->Constant() / coeff;
- if (!fExitVarSet || r < minRatio)
- {
- minRatio = r;
- exitVar = v;
- fExitVarSet = true;
- }
- }
- }
- }
-
- if (!fExitVarSet)
- { // exitVar is still nil
- // If col is empty, then exitVar doesn't occur in any equations,
- // so just remove it. Otherwise pick an exit var from among the
- // unrestricted variables whose equation involves the marker var
- if (col.size() == 0)
- {
- RemoveColumn(marker);
- }
- else
- {
- // A. Beurive' Tue Sep 14 18:26:05 CEST 1999
- // Don't pick the objective, or it will be removed!
- it_col = col.begin();
- for ( ; it_col != col.end(); ++it_col)
- {
- ClVariable v = *it_col;
- if (v != _objective)
- {
- exitVar = v;
- fExitVarSet = true;
- break;
- }
- }
- assert(fExitVarSet == true);
- }
- }
-
- if (fExitVarSet)
- {
- Pivot(marker,exitVar);
- }
- }
-
- if (FIsBasicVar(marker))
- {
- ClLinearExpression *pexpr = RemoveRow(marker);
-#ifdef CL_TRACE
- cerr << "delete@ " << pexpr << endl;
-#endif
- delete pexpr;
- }
-
- // Delete any error variables. If cn is an inequality, it also
- // contains a slack variable; but we use that as the marker variable
- // and so it has been deleted when we removed its row.
- if (fFoundErrorVar)
- {
- ClVarSet &eVars = (*it_eVars).second;
- ClVarSet::iterator it = eVars.begin();
- for ( ; it != eVars.end(); ++it )
- {
- ClVariable v = (*it);
- if (v != marker)
- {
- RemoveColumn(v);
- }
- }
- }
-
- if (pcn->isStayConstraint())
- {
- // iterate over the stay{Plus,Minus}ErrorVars and remove those
- // variables v in those vectors that are also in set eVars
- if (fFoundErrorVar)
- {
- ClVarSet &eVars = (*it_eVars).second;
- _stayPlusErrorVars
- .erase(remove_if(_stayPlusErrorVars.begin(),_stayPlusErrorVars.end(),
- VarInVarSet(eVars)),
- _stayPlusErrorVars.end());
- _stayMinusErrorVars
- .erase(remove_if(_stayMinusErrorVars.begin(),_stayMinusErrorVars.end(),
- VarInVarSet(eVars)),
- _stayMinusErrorVars.end());
- }
- }
- else if (pcn->IsEditConstraint())
- {
- const ClEditConstraint *pcnEdit = dynamic_cast<const ClEditConstraint *>(pcn);
- const ClVariable clv = pcnEdit->variable();
- ClEditInfo *pcei = PEditInfoFromClv(clv);
- assert(pcei);
- ClVariable clvEditMinus = pcei->_clvEditMinus;
- RemoveColumn(clvEditMinus); // clvEditPlus is a marker var and gets removed later
- delete pcei;
- _editInfoList.remove(pcei);
- }
-
- if (fFoundErrorVar)
- {
- // This code is not needed since the variables are deleted
- // when they are removed from the row --
- // leaving it in results in double deletions
- // delete the constraint's error variables
- // ClVarSet &evars_set = (*it_eVars).second;
- // ClVarSet::const_iterator it_set = evars_set.begin();
- // for ( ; it_set != evars_set.end(); ++it_set)
- // {
- // delete *it_set;
- // }
- _errorVars.erase((*it_eVars).first);
- }
-
- if (_fAutosolve)
- {
- Optimize(_objective);
- SetExternalVariables();
- }
-
- return *this;
-}
-
-
-// Re-initialize this solver from the original constraints, thus
-// getting rid of any accumulated numerical problems. (Actually,
-// Alan hasn't observed any such problems yet, but here's the method
-// anyway.)
-void
-ClSimplexSolver::Reset()
-{
-#ifdef CL_TRACE
- Tracer TRACER(__FUNCTION__);
- cerr << "()" << endl;
-#endif
- // FIXGJB -- can postpone writing this for a while
- // gotta be careful, though, as it's a likely place for
- // a memory leak to sneak in
- assert(false);
-}
-
-
-// Re-solve the cuurent collection of constraints, given the new
-// values for the edit variables that have already been
-// suggested (see SuggestValue() method)
-void
-ClSimplexSolver::Resolve()
-{ // CODE DUPLICATED ABOVE
-#ifdef CL_TRACE
- Tracer TRACER(__FUNCTION__);
-#endif
- DualOptimize();
- SetExternalVariables();
- _infeasibleRows.clear();
- if (_fResetStayConstantsAutomatically)
- ResetStayConstants();
-}
-
-ClSimplexSolver &
-ClSimplexSolver::SuggestValue(ClVariable v, Number x)
-{
-#ifdef CL_TRACE
- Tracer TRACER(__FUNCTION__);
-#endif
- ClEditInfo *pcei = PEditInfoFromClv(v);
- if (NULL == pcei)
- {
-#ifndef CL_NO_IO
- std::stringstream ss;
- ss << "SuggestValue for variable " << v << ", but var is not an edit variable" << ends;
- throw ExCLEditMisuse(ss.str().c_str());
-#else
- throw ExCLEditMisuse(v.Name().c_str());
-#endif
- }
- ClVariable clvEditPlus = pcei->_clvEditPlus;
- ClVariable clvEditMinus = pcei->_clvEditMinus;
- Number delta = x - pcei->_prevEditConstant;
- pcei->_prevEditConstant = x;
- DeltaEditConstant(delta,clvEditPlus,clvEditMinus);
- return *this;
-}
-
-// Re-solve the cuurent collection of constraints, given the new
-// values for the edit variables that have already been
-// suggested (see SuggestValue() method)
-// This is not guaranteed to work if you remove an edit constraint
-// from the middle of the edit constraints you added
-// (e.g., edit A, edit B, edit C, remove B -> this will fail!)
-// DEPRECATED
-void
-ClSimplexSolver::Resolve(const vector<Number> &newEditConstants)
-{
- ClEditInfoList::iterator it = _editInfoList.begin();
- unsigned int i = 0;
- for (; i < newEditConstants.size() && it != _editInfoList.end(); ++it, ++i)
- {
- ClEditInfo *pcei = (*it);
- SuggestValue(pcei->_clv,newEditConstants[i]);
- }
- Resolve();
-}
-
-
-//// protected
-
-// Add the constraint expr=0 to the inequality tableau using an
-// artificial variable. To do this, create an artificial variable
-// av and Add av=expr to the inequality tableau, then make av be 0.
-// (Raise an exception if we can't attain av=0 -- and prepare explanation)
-bool
-ClSimplexSolver::AddWithArtificialVariable(ClLinearExpression &expr,
- ExCLRequiredFailureWithExplanation &e)
-{
-#ifdef CL_TRACE
- Tracer TRACER(__FUNCTION__);
- cerr << "(" << expr << ")" << endl;
-#endif
-
- // Allocate the objects on the heap because the objects
- // will remain in the tableau if we throw an exception,
- // and that will result in the destructor cleaning up
- // after us
- ClSlackVariable *pav = new ClSlackVariable(++_artificialCounter,"a");
- ClObjectiveVariable *paz = new ClObjectiveVariable("az");
- ClLinearExpression *pazRow = new ClLinearExpression(expr);
- // the artificial objective is av, which we know is equal to expr
- // (which contains only parametric variables)
-
-#ifdef CL_FIND_LEAK
- cerr << "aC = " << _artificialCounter
- << "\nDeletes = " << _cArtificialVarsDeleted << endl;
-#endif
-#ifdef CL_TRACE
- cerr << __FUNCTION__ << " before addRow-s:\n"
- << (*this) << endl;
-#endif
-
- // the artificial objective is av, which we know is equal to expr
- // (which contains only parametric variables)
-
- // objective is treated as a row in the tableau,
- // so do the substitution for its value (we are minimizing
- // the artificial variable)
- // this row will be removed from the tableau after optimizing
- addRow(*paz,*pazRow);
-
- // now Add the normal row to the tableau -- when artifical
- // variable is minimized to 0 (if possible)
- // this row remains in the tableau to maintain the constraint
- // we are trying to Add
- addRow(*pav,expr);
-
-#ifdef CL_TRACE
- cerr << __FUNCTION__ << " after addRow-s:\n"
- << (*this) << endl;
-#endif
-
- // try to Optimize az to 0
- // note we are *not* optimizing the real objective, but optimizing
- // the artificial objective to see if the error in the constraint
- // we are adding can be set to 0
- Optimize(*paz);
-
- // Careful, we want to get the Expression that is in
- // the tableau, not the one we initialized it with!
- ClLinearExpression *pazTableauRow = RowExpression(*paz);
-#ifdef CL_TRACE
- cerr << "pazTableauRow->Constant() == " << pazTableauRow->Constant() << endl;
-#endif
-
- // Check that we were able to make the objective value 0
- // If not, the original constraint was not satisfiable
- if (!ClApprox(pazTableauRow->Constant(),0.0))
- {
- BuildExplanation(e, paz, pazTableauRow);
- // remove the artificial objective row that we just
- // added temporarily
- delete RemoveRow(*paz);
- // and delete the artificial objective variable that we also added above
- delete paz;
- return false;
- }
-
- // see if av is a basic variable
- const ClLinearExpression *pe = RowExpression(*pav);
- if (pe != NULL)
- {
- // FIXGJB: do we ever even get here?
- // Find another variable in this row and Pivot, so that av becomes parametric
- // If there isn't another variable in the row then
- // the tableau contains the equation av = 0 -- just delete av's row
- if (pe->IsConstant())
- {
- // FIXGJB: do we ever get here?
- assert(ClApprox(pe->Constant(),0.0));
- delete RemoveRow(*pav);
- // remove the temporary objective function
- // FIXGJB may need this too: delete RemoveRow(*paz);
- delete pav;
-#ifdef CL_FIND_LEAK
- ++_cArtificialVarsDeleted;
-#endif
- return true;
- }
- ClVariable entryVar = pe->AnyPivotableVariable();
- if (entryVar.IsNil())
- {
- BuildExplanation(e, *pav, pe);
- return false; /* required failure */
- }
- Pivot(entryVar, *pav);
- }
- // now av should be parametric
- assert(RowExpression(*pav) == NULL);
- RemoveColumn(*pav);
- delete pav;
-#ifdef CL_FIND_LEAK
- ++_cArtificialVarsDeleted;
-#endif
- // remove the temporary objective function
- delete RemoveRow(*paz);
- delete paz;
- return true;
-}
-
-
-// Using the given equation (av = cle) build an explanation which
-// implicates all constraints used to construct the equation. That
-// is, everything for which the variables in the equation are markers.
-void ClSimplexSolver::BuildExplanation(ExCLRequiredFailureWithExplanation &e,
- ClVariable av,
- const ClLinearExpression *pcle)
-{
- ClVarToConstraintMap::iterator it_cn;
- it_cn = _constraintsMarked.find(av);
- if (it_cn != _constraintsMarked.end())
- {
- e.AddConstraint((*it_cn).second);
- }
-
- assert(pcle != NULL);
-
- const ClVarToNumberMap & terms = pcle->Terms();
- ClVarToNumberMap::const_iterator it_term;
- for (it_term = terms.begin(); it_term != terms.end(); it_term++)
- {
- it_cn = _constraintsMarked.find((*it_term).first);
- if (it_cn != _constraintsMarked.end())
- {
- e.AddConstraint((*it_cn).second);
- }
- }
-}
-
-
-
-// We are trying to Add the constraint expr=0 to the appropriate
-// tableau. Try to Add expr directly to the tableaus without
-// creating an artificial variable. Return true if successful and
-// false if not.
-bool
-ClSimplexSolver::TryAddingDirectly(ClLinearExpression &expr)
-{
-#ifdef CL_TRACE
- Tracer TRACER(__FUNCTION__);
- cerr << "(" << expr << ")" << endl;
-#endif
- ClVariable subject = ChooseSubject(expr);
- if (subject.get_pclv() == NULL )
- {
-#ifdef CL_TRACE
- cerr << "- returning false" << endl;
-#endif
- return false;
- }
- expr.NewSubject(subject);
- if (ColumnsHasKey(subject))
- {
- SubstituteOut(subject,expr);
- }
- addRow(subject,expr);
-#ifdef CL_TRACE
- cerr << "- returning true" << endl;
-#endif
- return true; // successfully added directly
-}
-
-
-// We are trying to Add the constraint expr=0 to the tableaux. Try
-// to choose a subject (a variable to become basic) from among the
-// current variables in expr. If expr contains any unrestricted
-// variables, then we must choose an unrestricted variable as the
-// subject. Also, if the subject is new to the solver we won't have
-// to do any substitutions, so we prefer new variables to ones that
-// are currently noted as parametric. If expr contains only
-// restricted variables, if there is a restricted variable with a
-// negative coefficient that is new to the solver we can make that
-// the subject. Otherwise we can't find a subject, so return nil.
-// (In this last case we have to Add an artificial variable and use
-// that variable as the subject -- this is done outside this method
-// though.)
-//
-// Note: in checking for variables that are new to the solver, we
-// ignore whether a variable occurs in the objective function, since
-// new slack variables are added to the objective function by
-// 'NewExpression:', which is called before this method.
-ClVariable
-ClSimplexSolver::ChooseSubject(ClLinearExpression &expr)
-{
-#ifdef CL_TRACE
- Tracer TRACER(__FUNCTION__);
- cerr << "(" << expr << ")" << endl;
-#endif
- ClVariable subject(clvNil); // the current best subject, if any
-
- // true iff we have found a subject that is an unrestricted variable
- bool foundUnrestricted = false;
-
- // true iff we have found a restricted variable that is new to the
- // solver (except for being in the obj. function) and that has a
- // negative coefficient
- bool foundNewRestricted = false;
-
- const ClVarToNumberMap &terms = expr.Terms();
- ClVarToNumberMap::const_iterator it = terms.begin();
- for ( ; it != terms.end(); ++it )
- {
- ClVariable v = (*it).first;
- Number c = (*it).second;
-
- if (foundUnrestricted)
- {
- // We have already found an unrestricted variable. The only
- // time we will want to use v instead of the current choice
- // 'subject' is if v is unrestricted and new to the solver and
- // 'subject' isn't new. If this is the case just pick v
- // immediately and return.
- if (!v.IsRestricted())
- {
- if (!ColumnsHasKey(v))
- return v;
- }
- }
- else
- { // we haven't found an restricted variable yet
- if (v.IsRestricted())
- {
- // v is restricted. If we have already found a suitable
- // restricted variable just stick with that. Otherwise, if v
- // is new to the solver and has a negative coefficient pick
- // it. Regarding being new to the solver -- if the variable
- // occurs only in the objective function we regard it as being
- // new to the solver, since error variables are added to the
- // objective function when we make the Expression. We also
- // never pick a dummy variable here.
- if (!foundNewRestricted && !v.IsDummy() && c < 0.0)
- {
- const ClTableauColumnsMap &col = Columns();
- ClTableauColumnsMap::const_iterator it_col = col.find(v);
- if (it_col == col.end() ||
- ( col.size() == 1 && ColumnsHasKey(_objective) ) )
- {
- subject = v;
- foundNewRestricted = true;
- }
- }
- }
- else
- {
- // v is unrestricted.
- // If v is also new to the solver just pick it now
- subject = v;
- foundUnrestricted = true;
- }
- }
- }
- if (!subject.IsNil())
- return subject;
-
- // subject is nil.
- // Make one last check -- if all of the variables in expr are dummy
- // variables, then we can pick a dummy variable as the subject
- Number coeff = 0;
- it = terms.begin();
- for ( ; it != terms.end(); ++it )
- {
- ClVariable v = (*it).first;
- Number c = (*it).second;
- if (!v.IsDummy())
- return clvNil; // nope, no luck
- // if v is new to the solver, tentatively make it the subject
- if (!ColumnsHasKey(v))
- {
- subject = v;
- coeff = c;
- }
- }
-
- // If we get this far, all of the variables in the Expression should
- // be dummy variables. If the Constant is nonzero we are trying to
- // Add an unsatisfiable required constraint. (Remember that dummy
- // variables must take on a value of 0.) Otherwise, if the Constant
- // is Zero, multiply by -1 if necessary to make the coefficient for
- // the subject negative."
- if (!ClApprox(expr.Constant(),0.0))
- {
-#ifdef CL_DEBUG_FAILURES
- cerr << "required failure in choose subject:\n"
- << *this << endl;
-#endif
- if (FIsExplaining())
- {
- ExCLRequiredFailureWithExplanation e;
- BuildExplanation(e, clvNil, &expr);
- throw e;
- }
- else
- throw ExCLRequiredFailure();
- }
- if (coeff > 0.0)
- {
- expr.MultiplyMe(-1);
- }
- return subject;
-}
-
-// Each of the non-required edits will be represented by an equation
-// of the form
-// v = c + eplus - eminus
-// where v is the variable with the edit, c is the previous edit
-// value, and eplus and eminus are slack variables that hold the
-// error in satisfying the edit constraint. We are about to change
-// something, and we want to fix the constants in the equations
-// representing the edit constraints. If one of eplus and eminus is
-// basic, the other must occur only in the Expression for that basic
-// error variable. (They can't both be basic.) Fix the Constant in
-// this Expression. Otherwise they are both nonbasic. Find all of
-// the expressions in which they occur, and fix the constants in
-// those. See the UIST paper for details.
-// (This comment was for resetEditConstants(), but that is now
-// gone since it was part of the screwey vector-based interface
-// to resolveing. --02/15/99 gjb)
-void
-ClSimplexSolver::DeltaEditConstant(Number delta,
- ClVariable plusErrorVar,
- ClVariable minusErrorVar)
-{
-#ifdef CL_TRACE
- Tracer TRACER(__FUNCTION__);
- cerr << "(" << delta << ", " << plusErrorVar << ", " << minusErrorVar << ")" << endl;
-#endif
- // first check if the plusErrorVar is basic
- ClLinearExpression *pexprPlus = RowExpression(plusErrorVar);
- if (pexprPlus != NULL )
- {
- pexprPlus->IncrementConstant(delta);
- // error variables are always restricted
- // so the row is infeasible if the Constant is negative
- if (pexprPlus->Constant() < 0.0)
- {
- _infeasibleRows.insert(plusErrorVar);
- }
- return;
- }
- // check if minusErrorVar is basic
- ClLinearExpression *pexprMinus = RowExpression(minusErrorVar);
- if (pexprMinus != NULL)
- {
- pexprMinus->IncrementConstant(-delta);
- if (pexprMinus->Constant() < 0.0)
- {
- _infeasibleRows.insert(minusErrorVar);
- }
- return;
- }
- // Neither is basic. So they must both be nonbasic, and will both
- // occur in exactly the same expressions. Find all the expressions
- // in which they occur by finding the column for the minusErrorVar
- // (it doesn't matter whether we look for that one or for
- // plusErrorVar). Fix the constants in these expressions.
- ClVarSet &columnVars = _columns[minusErrorVar];
- ClVarSet::iterator it = columnVars.begin();
- for (; it != columnVars.end(); ++it)
- {
- ClVariable basicVar = *it;
- ClLinearExpression *pexpr = RowExpression(basicVar);
- assert(pexpr != NULL );
- double c = pexpr->CoefficientFor(minusErrorVar);
- pexpr->IncrementConstant(c*delta);
- if (basicVar.IsRestricted() && pexpr->Constant() < 0.0)
- {
- _infeasibleRows.insert(basicVar);
- }
- }
-}
-
-// We have set new values for the constants in the edit constraints.
-// Re-Optimize using the dual simplex algorithm.
-void
-ClSimplexSolver::DualOptimize()
-{
-#ifdef CL_TRACE
- Tracer TRACER(__FUNCTION__);
- cerr << "()" << endl;
-#endif
- const ClLinearExpression *pzRow = RowExpression(_objective);
- // need to handle infeasible rows
- while (!_infeasibleRows.empty())
- {
- ClVarSet::iterator it_exitVar = _infeasibleRows.begin();
- ClVariable exitVar = *it_exitVar;
- _infeasibleRows.erase(it_exitVar);
- ClVariable entryVar;
- // exitVar might have become basic after some other pivoting
- // so allow for the case of its not being there any longer
- ClLinearExpression *pexpr = RowExpression(exitVar);
- if (pexpr != NULL )
- {
- // make sure the row is still not feasible
- if (pexpr->Constant() < 0.0)
- {
- double ratio = DBL_MAX;
- double r;
- ClVarToNumberMap &terms = pexpr->Terms();
- ClVarToNumberMap::iterator it = terms.begin();
- for ( ; it != terms.end(); ++it )
- {
- ClVariable v = (*it).first;
- Number c = (*it).second;
- if (c > 0.0 && v.IsPivotable())
- {
- Number zc = pzRow->CoefficientFor(v);
- r = zc/c; // FIXGJB r:= zc/c or Zero, as ClSymbolicWeight-s
- if (r < ratio)
- {
- entryVar = v;
- ratio = r;
- }
- }
- }
- if (ratio == DBL_MAX)
- {
- stringstream ss;
- ss << "ratio == nil (DBL_MAX)" << ends;
- throw ExCLInternalError(ss.str().c_str());
- }
- Pivot(entryVar,exitVar);
- }
- }
- }
-}
-
-// Make a new linear Expression representing the constraint cn,
-// replacing any basic variables with their defining expressions.
-// Normalize if necessary so that the Constant is non-negative. If
-// the constraint is non-required give its error variables an
-// appropriate weight in the objective function.
-ClLinearExpression *
-ClSimplexSolver::NewExpression(const ClConstraint *pcn,
- /* output to */
- ClVariable &clvEplus,
- ClVariable &clvEminus,
- Number &prevEConstant)
-{
-#ifdef CL_TRACE
- Tracer TRACER(__FUNCTION__);
- cerr << "(" << *pcn << ")" << endl;
- cerr << "cn.IsInequality() == " << pcn->IsInequality() << endl;
- cerr << "cn.IsRequired() == " << pcn->IsRequired() << endl;
-#endif
- const ClLinearExpression &cnExpr = pcn->Expression();
- cl_auto_ptr<ClLinearExpression> pexpr ( new ClLinearExpression(cnExpr.Constant()) );
- cl_auto_ptr<ClSlackVariable> pslackVar;
- cl_auto_ptr<ClDummyVariable> pdummyVar;
- cl_auto_ptr<ClSlackVariable> peminus(0);
- cl_auto_ptr<ClSlackVariable> peplus(0);
- const ClVarToNumberMap &cnTerms = cnExpr.Terms();
- ClVarToNumberMap::const_iterator it = cnTerms.begin();
- for ( ; it != cnTerms.end(); ++it)
- {
- ClVariable v = (*it).first;
- Number c = (*it).second;
- const ClLinearExpression *pe = RowExpression(v);
- if (pe == NULL)
- {
- pexpr->AddVariable(v,c);
- }
- else
- {
- pexpr->AddExpression(*pe,c);
- }
- }
-
- // Add slack and error variables as needed
- if (pcn->IsInequality())
- {
- // cn is an inequality, so Add a slack variable. The original
- // constraint is expr>=0, so that the resulting equality is
- // expr-slackVar=0. If cn is also non-required Add a negative
- // error variable, giving
- // expr-slackVar = -errorVar, in other words
- // expr-slackVar+errorVar=0.
- // Since both of these variables are newly created we can just Add
- // them to the Expression (they can't be basic).
- ++_slackCounter;
- ReinitializeAutoPtr(pslackVar,new ClSlackVariable (_slackCounter, "s"));
- pexpr->setVariable(*pslackVar,-1);
- // index the constraint under its slack variable and vice-versa
- _markerVars[pcn] = pslackVar.get();
- _constraintsMarked[pslackVar.get()] = pcn;
-
- if (!pcn->IsRequired())
- {
- ++_slackCounter;
- ReinitializeAutoPtr(peminus,new ClSlackVariable (_slackCounter, "em"));
- pexpr->setVariable(*peminus,1.0);
- // Add emnius to the objective function with the appropriate weight
- ClLinearExpression *pzRow = RowExpression(_objective);
- // FIXGJB: pzRow->AddVariable(eminus,pcn->strength().symbolicWeight() * pcn->weight());
- ClSymbolicWeight sw = pcn->strength().symbolicWeight().Times(pcn->weight());
- pzRow->setVariable(*peminus,sw.AsDouble());
- _errorVars[pcn].insert(peminus.get());
- NoteAddedVariable(*peminus,_objective);
- }
- }
- else
- { // cn is an equality
- if (pcn->IsRequired())
- {
- // Add a dummy variable to the Expression to serve as a marker
- // for this constraint. The dummy variable is never allowed to
- // enter the basis when pivoting.
- ++_dummyCounter;
- ReinitializeAutoPtr(pdummyVar,new ClDummyVariable (_dummyCounter, "d"));
- pexpr->setVariable(*pdummyVar,1.0);
- _markerVars[pcn] = pdummyVar.get();
- _constraintsMarked[pdummyVar.get()] = pcn;
-#ifdef CL_TRACE
- cerr << "Adding dummyVar == d" << _dummyCounter << endl;
-#endif
- }
- else
- {
- // cn is a non-required equality. Add a positive and a negative
- // error variable, making the resulting constraint
- // expr = eplus - eminus,
- // in other words: expr-eplus+eminus=0
- ++_slackCounter;
- ReinitializeAutoPtr(peplus,new ClSlackVariable (_slackCounter, "ep"));
- ReinitializeAutoPtr(peminus,new ClSlackVariable (_slackCounter, "em"));
-
- pexpr->setVariable(*peplus,-1.0);
- pexpr->setVariable(*peminus,1.0);
- // index the constraint under one of the error variables
- _markerVars[pcn] = peplus.get();
- _constraintsMarked[peplus.get()] = pcn;
-
- ClLinearExpression *pzRow = RowExpression(_objective);
- // FIXGJB: pzRow->AddVariable(eplus,pcn->strength().symbolicWeight() * pcn->weight());
- ClSymbolicWeight sw = pcn->strength().symbolicWeight().Times(pcn->weight());
- double swCoeff = sw.AsDouble();
-#ifdef CL_TRACE
- if (swCoeff == 0)
- {
- cerr << "sw == " << sw << endl
- << "cn == " << *pcn << endl;
- cerr << "adding " << *peplus << " and " << *peminus
- << " with swCoeff == " << swCoeff << endl;
- }
-#endif
- pzRow->setVariable(*peplus,swCoeff);
- NoteAddedVariable(*peplus,_objective);
- // FIXGJB: pzRow->AddVariable(eminus,pcn->strength().symbolicWeight() * pcn->weight());
- pzRow->setVariable(*peminus,swCoeff);
- NoteAddedVariable(*peminus,_objective);
- _errorVars[pcn].insert(peminus.get());
- _errorVars[pcn].insert(peplus.get());
- if (pcn->isStayConstraint())
- {
- _stayPlusErrorVars.push_back(peplus.get());
- _stayMinusErrorVars.push_back(peminus.get());
- }
- else if (pcn->IsEditConstraint())
- {
- clvEplus = peplus.get();
- clvEminus = peminus.get();
- prevEConstant = cnExpr.Constant();
- }
- }
- }
-
- // the Constant in the Expression should be non-negative.
- // If necessary normalize the Expression by multiplying by -1
- if (pexpr->Constant() < 0)
- {
-#ifdef CL_TRACE
- cerr << "NewExpression's Constant is " << pexpr->Constant() << ", < 0, so flipping" << endl;
-#endif
- pexpr->MultiplyMe(-1);
- }
-#ifdef CL_TRACE
- cerr << "- returning " << *pexpr << endl;
-#endif
- // Terrible Name -- release() does *not* delete the object,
- // only makes sure that the destructor won't delete the object
- // (it releases the cl_auto_ptr from the responsibility of deleting the object)
- pslackVar.release();
- pdummyVar.release();
- peminus.release();
- peplus.release();
- return pexpr.release();
-}
-
-// Minimize the value of the objective. (The tableau should already
-// be feasible.)
-void
-ClSimplexSolver::Optimize(ClVariable zVar)
-{
-#ifdef CL_TRACE
- Tracer TRACER(__FUNCTION__);
- cerr << "(" << zVar << ")\n"
- << *this << endl;
-#endif
- ClLinearExpression *pzRow = RowExpression(zVar);
- assert(pzRow != NULL);
- ClVariable entryVar = clvNil;
- ClVariable exitVar = clvNil;
- while (true)
- {
- Number objectiveCoeff = 0;
- // Find the most negative coefficient in the objective function
- // (ignoring the non-pivotable dummy variables). If all
- // coefficients are positive we're done
- ClVarToNumberMap &terms = pzRow->Terms();
- ClVarToNumberMap::iterator it = terms.begin();
- for (; it != terms.end(); ++it)
- {
- ClVariable v = (*it).first;
- Number c = (*it).second;
- if (v.IsPivotable() && c < objectiveCoeff)
- {
- objectiveCoeff = c;
- entryVar = v;
- // A. Beurive' Tue Jul 13 23:03:05 CEST 1999 Why the most
- // negative? I encountered unending cycles of pivots!
- break;
- }
- }
- // if all coefficients were positive (or if the objective
- // function has no pivotable variables)
- // we are at an optimum
- if (objectiveCoeff >= -_epsilon)
- return;
-#ifdef CL_TRACE
- cerr << "entryVar == " << entryVar << ", "
- << "objectiveCoeff == " << objectiveCoeff
- << endl;
-#endif
-
- // choose which variable to move out of the basis
- // Only consider pivotable basic variables
- // (i.e. restricted, non-dummy variables)
- double minRatio = DBL_MAX;
- ClVarSet &columnVars = _columns[entryVar];
- ClVarSet::iterator it_rowvars = columnVars.begin();
- Number r = 0.0;
- for (; it_rowvars != columnVars.end(); ++it_rowvars)
- {
- ClVariable v = *it_rowvars;
-#ifdef CL_TRACE
- cerr << "Checking " << v << endl;
-#endif
- if (v.IsPivotable())
- {
- const ClLinearExpression *pexpr = RowExpression(v);
- Number coeff = pexpr->CoefficientFor(entryVar);
- // only consider negative coefficients
- if (coeff < 0.0)
- {
- r = - pexpr->Constant() / coeff;
- if (r < minRatio)
- {
-#ifdef CL_TRACE
- cerr << "New minRatio == " << r << endl;
-#endif
- minRatio = r;
- exitVar = v;
- }
- }
- }
- }
- // If minRatio is still nil at this point, it means that the
- // objective function is unbounded, i.e. it can become
- // arbitrarily negative. This should never happen in this
- // application.
- if (minRatio == DBL_MAX)
- {
- stringstream ss;
- ss << "objective function is unbounded!" << ends;
- throw ExCLInternalError(ss.str().c_str());
- }
- Pivot(entryVar, exitVar);
-#ifdef CL_TRACE
- cerr << "After Optimize:\n"
- << *this << endl;
-#endif
- }
-}
-
-// Do a Pivot. Move entryVar into the basis (i.e. make it a basic variable),
-// and move exitVar out of the basis (i.e., make it a parametric variable)
-void
-ClSimplexSolver::Pivot(ClVariable entryVar, ClVariable exitVar)
-{
-#ifdef CL_TRACE
- Tracer TRACER(__FUNCTION__);
- cerr << "(" << entryVar << ", " << exitVar << ")" << endl;
-#endif
-
- // the entryVar might be non-pivotable if we're doing a RemoveConstraint --
- // otherwise it should be a pivotable variable -- enforced at call sites,
- // hopefully
-
- // expr is the Expression for the exit variable (about to leave the basis) --
- // so that the old tableau includes the equation:
- // exitVar = expr
- ClLinearExpression *pexpr = RemoveRow(exitVar);
-
- // Compute an Expression for the entry variable. Since expr has
- // been deleted from the tableau we can destructively modify it to
- // build this Expression.
- pexpr->ChangeSubject(exitVar,entryVar);
- SubstituteOut(entryVar,*pexpr);
-
- if (entryVar.IsExternal())
- {
- // entry var is no longer a parametric variable since we're moving
- // it into the basis
- _externalParametricVars.erase(entryVar);
- }
- addRow(entryVar,*pexpr);
-}
-
-
-
-// Each of the non-required stays will be represented by an equation
-// of the form
-// v = c + eplus - eminus
-// where v is the variable with the stay, c is the previous value of
-// v, and eplus and eminus are slack variables that hold the error
-// in satisfying the stay constraint. We are about to change
-// something, and we want to fix the constants in the equations
-// representing the stays. If both eplus and eminus are nonbasic
-// they have value 0 in the current solution, meaning the previous
-// stay was exactly satisfied. In this case nothing needs to be
-// changed. Otherwise one of them is basic, and the other must
-// occur only in the Expression for that basic error variable.
-// Reset the Constant in this Expression to 0.
-void
-ClSimplexSolver::ResetStayConstants()
-{
-#ifdef CL_TRACE
- Tracer TRACER(__FUNCTION__);
- cerr << "()" << endl;
-#endif
- ClVarVector::const_iterator
- itStayPlusErrorVars = _stayPlusErrorVars.begin();
- ClVarVector::const_iterator
- itStayMinusErrorVars = _stayMinusErrorVars.begin();
-
- for ( ; itStayPlusErrorVars != _stayPlusErrorVars.end();
- ++itStayPlusErrorVars, ++itStayMinusErrorVars )
- {
- ClLinearExpression *pexpr = RowExpression(*itStayPlusErrorVars);
- if (pexpr == NULL )
- {
- pexpr = RowExpression(*itStayMinusErrorVars);
- }
- if (pexpr != NULL)
- {
- pexpr->Set_constant(0.0);
- }
- }
-}
-
-// Set the external variables known to this solver to their appropriate values.
-// Set each external basic variable to its value, and set each
-// external parametric variable to 0. (It isn't clear that we will
-// ever have external parametric variables -- every external
-// variable should either have a stay on it, or have an equation
-// that defines it in terms of other external variables that do have
-// stays. For the moment I'll put this in though.) Variables that
-// are internal to the solver don't actually store values -- their
-// values are just implicit in the tableu -- so we don't need to set
-// them."
-void
-ClSimplexSolver::SetExternalVariables()
-{
-#ifdef CL_TRACE
- Tracer TRACER(__FUNCTION__);
- cerr << "()\n"
- << *this << endl;
-#endif
-
- // FIXGJB -- oughta check some invariants here
-
- // Set external parametric variables first
- // in case I've screwed up
- ClVarSet::iterator itParVars = _externalParametricVars.begin();
- for ( ; itParVars != _externalParametricVars.end(); ++itParVars )
- {
- ClVariable v = *itParVars;
-#ifndef NDEBUG
- // defensively skip it if it is basic -- ChangeValue is virtual
- // so don't want to call it twice; this should never
- // happen
- if (FIsBasicVar(v))
- {
-#ifndef CL_NO_IO
- // WARNING
- cerr << __FUNCTION__ << "Error: variable " << v
- << " in _externalParametricVars is basic" << endl;
- cerr << "Row is: " << *RowExpression(v) << endl;
-#endif
- continue;
- }
-#endif
- ChangeClv(v,0.0);
- }
-
- // Only iterate over the rows w/ external variables
- ClVarSet::iterator itRowVars = _externalRows.begin();
- for ( ; itRowVars != _externalRows.end() ; ++itRowVars )
- {
- ClVariable v = *itRowVars;
- ClLinearExpression *pexpr = RowExpression(v);
- ChangeClv(v,pexpr->Constant());
- }
-
- _fNeedsSolving = false;
- if (_pfnResolveCallback)
- _pfnResolveCallback(this);
-}
-
-#ifndef CL_NO_IO
-ostream &
-PrintTo(ostream &xo, const ClVarVector &varlist)
-{
- ClVarVector::const_iterator it = varlist.begin();
- xo << varlist.size() << ":" << "[ ";
- if (it != varlist.end())
- {
- xo << *it;
- ++it;
- }
- for (; it != varlist.end(); ++it)
- {
- xo << ", " << *it;
- }
- xo << " ]";
- return xo;
-}
-
-ostream &operator<<(ostream &xo, const ClVarVector &varlist)
-{ return PrintTo(xo,varlist); }
-
-
-ostream &
-PrintTo(ostream &xo, const ClConstraintToVarSetMap &mapCnToVarSet)
-{
- ClConstraintToVarSetMap::const_iterator it = mapCnToVarSet.begin();
- for ( ; it != mapCnToVarSet.end(); ++it) {
- const ClConstraint *pcn = (*it).first;
- const ClVarSet &set = (*it).second;
- xo << "CN: " << pcn << *pcn << ":: " << set << endl;
- }
- return xo;
-}
-
-ostream &operator <<(ostream &xo, const ClConstraintToVarSetMap &mapCnToVarSet)
-{ return PrintTo(xo,mapCnToVarSet); }
-
-
-
-ostream &
-ClSimplexSolver::PrintOn(ostream &xo) const
-{
- ClTableau::PrintOn(xo);
-
- xo << "_stayPlusErrorVars: "
- << _stayPlusErrorVars << endl;
- xo << "_stayMinusErrorVars: "
- << _stayMinusErrorVars << endl;
- xo << "_editInfoList:\n"
- << _editInfoList << endl;
- return xo;
-}
-
-
-ostream &
-ClSimplexSolver::PrintInternalInfo(ostream &xo) const
-{
- ClTableau::PrintInternalInfo(xo);
- xo << "; edvars: " << _editInfoList.size();
- xo << endl;
- printExternalVariablesTo(xo);
- return xo;
-}
-
-ostream &operator<<(ostream &xo, const ClSimplexSolver &clss)
-{
- return clss.PrintOn(xo);
-}
-
-#endif
-
-bool
-ClSimplexSolver::FIsConstraintSatisfied(const ClConstraint *const pcn) const
-{
- ClConstraintToVarMap::const_iterator it_marker = _markerVars.find(pcn);
- if (it_marker == _markerVars.end())
- { // could not find the constraint
- throw ExCLConstraintNotFound();
- }
-
-#ifndef CL_NO_IO
- bool fCnsays = pcn->FIsSatisfied();
-#endif
-
- ClConstraintToVarSetMap::const_iterator it_eVars = _errorVars.find(pcn);
-
- if (it_eVars != _errorVars.end())
- {
- const ClVarSet &eVars = (*it_eVars).second;
- ClVarSet::const_iterator it = eVars.begin();
- for ( ; it != eVars.end(); ++it )
- {
- const ClLinearExpression *pexpr = RowExpression(*it);
- if (pexpr != NULL && !ClApprox(pexpr->Constant(),0.0))
- {
-#ifndef CL_NO_IO
- if (fCnsays)
- cerr << __FUNCTION__ << ": constraint says satisfiable, but solver does not" << endl;
-#endif
- return false;
- }
- }
- }
-
-#ifndef CL_NO_IO
- if (!fCnsays)
- cerr << __FUNCTION__ << ": solver says satisfiable, but constraint does not" << endl;
-#endif
- return true;
-}
-
-
-
-#ifndef CL_NO_ID
-
-ostream &PrintTo(ostream &xo, const ClSimplexSolver::ClEditInfoList &listPEditInfo)
-{
- ClSimplexSolver::ClEditInfoList::const_iterator it = listPEditInfo.begin();
- for ( ; it != listPEditInfo.end(); ++it) {
- const ClSimplexSolver::ClEditInfo *pcei = (*it);
- xo << *pcei << endl;
- }
- return xo;
-}
-
-
-ostream &operator<<(ostream &xo, const ClSimplexSolver::ClEditInfoList &listPEditInfo)
-{ return PrintTo(xo,listPEditInfo); }
-
-#endif
-
-// A. Beurive' Tue Jul 6 17:03:32 CEST 1999
-void
-ClSimplexSolver::ChangeStrengthAndWeight(ClConstraint *pcn, const ClStrength &strength, double weight)
-{
- ClConstraintToVarSetMap::iterator it_eVars = _errorVars.find(pcn);
- // Only for constraints that already have error variables (i.e. non-required constraints)
- assert(it_eVars != _errorVars.end());
-
- ClLinearExpression *pzRow = RowExpression(_objective);
-
- Number old_coeff = pcn->weight() * pcn->strength().symbolicWeight().AsDouble();
- pcn->setStrength(strength);
- pcn->setWeight(weight);
- Number new_coeff = pcn->weight() * pcn->strength().symbolicWeight().AsDouble();
-
- if (new_coeff != old_coeff)
- {
-#ifdef CL_TRACE
- cerr << "Changing strength and/or weight for constraint: " << endl << *pcn << endl;
- cerr << "Updating objective row from:" << endl << *pzRow << endl;
-#endif
- ClVarSet &eVars = (*it_eVars).second;
- ClVarSet::iterator it = eVars.begin();
- for ( ; it != eVars.end(); ++it )
- {
- const ClLinearExpression *pexpr = RowExpression(*it);
- if (pexpr == NULL )
- {
- pzRow->AddVariable(*it,-old_coeff,_objective,*this);
- pzRow->AddVariable(*it,new_coeff,_objective,*this);
- }
- else
- {
- pzRow->AddExpression(*pexpr,-old_coeff,_objective,*this);
- pzRow->AddExpression(*pexpr,new_coeff,_objective,*this);
- }
- }
-#ifdef CL_TRACE
- cerr << "to: " << endl << *pzRow << endl;
-#endif
-
- if (_fAutosolve)
- {
- Optimize(_objective);
- SetExternalVariables();
- }
- }
-}
-
-// A. Beurive' Tue Jul 6 17:03:42 CEST 1999
-void
-ClSimplexSolver::ChangeStrength(ClConstraint *pcn, const ClStrength &strength)
-{
- ChangeStrengthAndWeight(pcn,strength,pcn->weight());
-}
-
-// A. Beurive' Tue Jul 6 17:03:42 CEST 1999
-void
-ClSimplexSolver::ChangeWeight(ClConstraint *pcn, double weight)
-{
- ChangeStrengthAndWeight(pcn,pcn->strength(),weight);
-}