/*
Cassowary.net: an incremental constraint solver for .NET
(http://lumumba.uhasselt.be/jo/projects/cassowary.net/)
Copyright (C) 2005 Jo Vermeulen (jo.vermeulen@uhasselt.be)
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public License
as published by the Free Software Foundation; either version 2.1
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
using System;
using System.Collections;
using Cassowary.Utils;
namespace Cassowary
{
public class ClTableau : Cl
{
///
/// Constructor is protected, since this only supports an ADT for
/// the ClSimplexSolver class.
///
protected ClTableau()
{
_columns = new Hashtable();
_rows = new Hashtable();
_infeasibleRows = new Set();
_externalRows = new Set();
_externalParametricVars = new Set();
}
///
/// Variable v has been removed from an expression. If the
/// expression is in a tableau the corresponding basic variable is
/// subject (or if subject is nil then it's in the objective function).
/// Update the column cross-indices.
///
public /*sealed*/ void NoteRemovedVariable(ClAbstractVariable v, ClAbstractVariable subject)
{
if (Trace)
FnEnterPrint(string.Format("NoteRemovedVariable: {0}, {1}", v, subject));
if (subject != null) {
((Set) _columns[v]).Remove(subject);
}
}
///
/// v has been added to the linear expression for subject
/// update column cross indices.
///
public /*sealed*/ void NoteAddedVariable(ClAbstractVariable v, ClAbstractVariable subject)
{
if (Trace)
FnEnterPrint(string.Format("NoteAddedVariable: {0}, {1}", v, subject));
if (subject != null) {
InsertColVar(v, subject);
}
}
///
/// Returns information about the tableau's internals.
///
///
/// Originally from Michael Noth
///
///
/// String containing the information.
///
public virtual string GetInternalInfo() {
string s = "Tableau Information:\n";
s += string.Format("Rows: {0} (= {1} constraints)", _rows.Count, _rows.Count - 1);
s += string.Format("\nColumns: {0}", _columns.Count);
s += string.Format("\nInfeasible Rows: {0}", _infeasibleRows.Count);
s += string.Format("\nExternal basic variables: {0}", _externalRows.Count);
s += string.Format("\nExternal parametric variables: {0}", _externalParametricVars.Count);
return s;
}
public override string ToString()
{
string s = "Tableau:\n";
foreach (ClAbstractVariable clv in _rows.Keys)
{
ClLinearExpression expr = (ClLinearExpression) _rows[clv];
s += string.Format("{0} <==> {1}\n", clv.ToString(), expr.ToString());
}
s += string.Format("\nColumns:\n{0}", _columns.ToString());
s += string.Format("\nInfeasible rows: {0}", _infeasibleRows.ToString());
s += string.Format("\nExternal basic variables: {0}", _externalRows.ToString());
s += string.Format("\nExternal parametric variables: {0}", _externalParametricVars.ToString());
return s;
}
///
/// Convenience function to insert a variable into
/// the set of rows stored at _columns[param_var],
/// creating a new set if needed.
///
private /*sealed*/ void InsertColVar(ClAbstractVariable param_var,
ClAbstractVariable rowvar)
{
Set rowset = (Set) _columns[param_var];
if (rowset == null)
_columns.Add(param_var, rowset = new Set());
rowset.Add(rowvar);
}
// Add v=expr to the tableau, update column cross indices
// v becomes a basic variable
// expr is now owned by ClTableau class,
// and ClTableau is responsible for deleting it
// (also, expr better be allocated on the heap!).
protected /*sealed*/ void AddRow(ClAbstractVariable var, ClLinearExpression expr)
{
if (Trace)
FnEnterPrint("AddRow: " + var + ", " + expr);
// for each variable in expr, add var to the set of rows which
// have that variable in their expression
_rows.Add(var, expr);
// FIXME: check correctness!
foreach (ClAbstractVariable clv in expr.Terms.Keys)
{
InsertColVar(clv, var);
if (clv.IsExternal)
{
_externalParametricVars.Add(clv);
}
}
if (var.IsExternal) {
_externalRows.Add(var);
}
if (Trace)
TracePrint(this.ToString());
}
///
/// Remove v from the tableau -- remove the column cross indices for v
/// and remove v from every expression in rows in which v occurs
///
protected /*sealed*/ void RemoveColumn(ClAbstractVariable var)
{
if (Trace)
FnEnterPrint(string.Format("RemoveColumn: {0}", var));
// remove the rows with the variables in varset
Set rows = (Set) _columns[var];
_columns.Remove(var);
if (rows != null) {
foreach(ClAbstractVariable clv in rows)
{
ClLinearExpression expr = (ClLinearExpression) _rows[clv];
expr.Terms.Remove(var);
}
} else {
if (Trace)
DebugPrint(string.Format("Could not find var {0} in _columns", var));
}
if (var.IsExternal) {
_externalRows.Remove(var);
_externalParametricVars.Remove(var);
}
}
///
/// Remove the basic variable v from the tableau row v=expr
/// Then update column cross indices.
///
protected /*sealed*/ ClLinearExpression RemoveRow(ClAbstractVariable var)
/*throws ExCLInternalError*/
{
if (Trace)
FnEnterPrint(string.Format("RemoveRow: {0}", var));
ClLinearExpression expr = (ClLinearExpression) _rows[var];
Assert(expr != null);
// For each variable in this expression, update
// the column mapping and remove the variable from the list
// of rows it is known to be in.
foreach (ClAbstractVariable clv in expr.Terms.Keys)
{
Set varset = (Set) _columns[clv];
if (varset != null)
{
if (Trace)
DebugPrint(string.Format("removing from varset {0}", var));
varset.Remove(var);
}
}
_infeasibleRows.Remove(var);
if (var.IsExternal) {
_externalRows.Remove(var);
}
_rows.Remove(var);
if (Trace)
FnExitPrint(string.Format("returning {0}", expr));
return expr;
}
///
/// Replace all occurrences of oldVar with expr, and update column cross indices
/// oldVar should now be a basic variable.
///
protected /*sealed*/ void SubstituteOut(ClAbstractVariable oldVar, ClLinearExpression expr)
{
if (Trace)
FnEnterPrint(string.Format("SubstituteOut: {0}", oldVar, expr));
if (Trace)
TracePrint(this.ToString());
Set varset = (Set) _columns[oldVar];
foreach(ClAbstractVariable v in varset)
{
ClLinearExpression row = (ClLinearExpression) _rows[v];
row.SubstituteOut(oldVar, expr, v, this);
if (v.IsRestricted && row.Constant < 0.0)
{
_infeasibleRows.Add(v);
}
}
if (oldVar.IsExternal) {
_externalRows.Add(oldVar);
_externalParametricVars.Remove(oldVar);
}
_columns.Remove(oldVar);
}
protected Hashtable Columns
{
get {
return _columns;
}
}
protected Hashtable Rows
{
get
{
return _rows;
}
}
///
/// Return true if and only if the variable subject is in the columns keys
///
protected /*sealed*/ bool ColumnsHasKey(ClAbstractVariable subject)
{
return _columns.ContainsKey(subject);
}
protected /*sealed*/ ClLinearExpression RowExpression(ClAbstractVariable v)
{
// if (Trace) FnEnterPrint(string.Format("rowExpression: {0}", v));
return (ClLinearExpression) _rows[v];
}
///
/// _columns is a mapping from variables which occur in expressions to the
/// set of basic variables whose expressions contain them
/// i.e., it's a mapping from variables in expressions (a column) to the
/// set of rows that contain them.
///
protected Hashtable _columns; // From ClAbstractVariable to Set of variables
///
/// _rows maps basic variables to the expressions for that row in the tableau.
///
protected Hashtable _rows; // From ClAbstractVariable to ClLinearExpression
///
/// Collection of basic variables that have infeasible rows
/// (used when reoptimizing).
///
protected Set _infeasibleRows; // Set of ClAbstractVariable-s
///
/// Set of rows where the basic variable is external
/// this was added to the Java/C++/C# versions to reduce time in SetExternalVariables().
///
protected Set _externalRows; // Set of ClVariable-s
///
/// Set of external variables which are parametric
/// this was added to the Java/C++/C# versions to reduce time in SetExternalVariables().
///
protected Set _externalParametricVars; // Set of ClVariable-s
}
}