1 module cassowary.Tableau;
2 
3 import std.conv;
4 
5 import cassowary.AbstractVariable;
6 import cassowary.LinearExpression;
7 import cassowary.Variable;
8 import cassowary.set;
9 import cassowary.Cl;
10 
11 class ClTableau
12 {
13 	// ctr is protected, since this only supports an ADT for
14 	// the ClSimplexSolved class
15 	protected this()
16 	{
17 		_infeasibleRows = new typeof(_infeasibleRows)();
18 		_externalRows = new typeof(_externalRows)();
19 		_externalParametricVars = new typeof(_externalParametricVars)();
20 	}
21 
22 	// Variable v has been removed from an expression.  If the
23 	// expression is in a tableau the corresponding basic variable is
24 	// subject (or if subject is nil then it's in the objective function).
25 	// Update the column cross-indices.
26 	final void noteRemovedVariable(ClAbstractVariable v, ClAbstractVariable subject)
27 	{
28 		fnenterprint("noteRemovedVariable: " ~ v.toString() ~ ", " ~ subject.toString());
29 		if (subject !is null)
30 		{
31 			_columns[v].remove(subject);
32 		}
33 	}
34 
35 	// v has been added to the linear expression for subject
36 	// update column cross indices
37 	final void noteAddedVariable(ClAbstractVariable v, ClAbstractVariable subject)
38 	{
39 		fnenterprint("noteAddedVariable: " ~ v.toString() ~ ", " ~ subject.toString());
40 		if (subject !is null)
41 		{
42 			insertColVar(v, subject);
43 		}
44 	}
45 
46 	// Originally from Michael Noth <noth@cs>
47 	string getInternalInfo()
48 	{
49 		string res = "Tableau Information:\n";
50 		res ~= "Rows: " ~ _rows.length.to!string();
51 
52 		res ~= " (= " ~ (_rows.length - 1).to!string() ~ " constraints)";
53 		res ~= "\nColumns: " ~ _columns.length.to!string();
54 		res ~= "\nInfeasible Rows: " ~ _infeasibleRows.length.to!string();
55 		res ~= "\nExternal basic variables: " ~ _externalRows.length.to!string();
56 		res ~= "\nExternal parametric variables: ";
57 		res ~= _externalParametricVars.length.to!string();
58 		res ~= "\n";
59 
60 		return res;
61 	}
62 
63 	override string toString() const
64 	{
65 		string res = "Tableau:\n";
66 
67 		foreach(clv, expr; _rows)
68 		{
69 			res ~= clv.toString();
70 
71 			res ~= " <==> ";
72 			res ~= expr.toString();
73 			res ~= "\n";
74 		}
75 
76 		res ~= "\nColumns:\n";
77 		res ~= _columns.to!string();
78 
79 		res ~= "\nInfeasible rows: ";
80 		res ~= _infeasibleRows.toString();
81 
82 		res ~= "External basic variables: ";
83 		res ~= _externalRows.toString();
84 
85 		res ~= "External parametric variables: ";
86 		res ~= _externalParametricVars.toString();
87 
88 		return res;
89 	}
90 
91 	// Convenience function to insert a variable into
92 	// the set of rows stored at _columns[param_var],
93 	// creating a new set if needed
94 	private final void insertColVar(ClAbstractVariable param_var, ClAbstractVariable rowvar)
95 	{
96 		auto rowset = _columns.get(param_var, null);
97 		if (rowset is null)
98 		{
99 			rowset = new typeof(rowset)();
100 			_columns[param_var] = rowset;
101 		}
102 		rowset ~= rowvar;
103 	}
104 
105 	// Add v=expr to the tableau, update column cross indices
106 	// v becomes a basic variable
107 	// expr is now owned by ClTableau class,
108 	// and ClTableauis responsible for deleting it
109 	// (also, expr better be allocated on the heap!)
110 	protected final void addRow(ClAbstractVariable var, ClLinearExpression expr)
111 	{
112 		fnenterprint("addRow: " ~ var.toString() ~ ", " ~ expr.toString());
113 
114 		// for each variable in expr, add var to the set of rows which
115 		// have that variable in their expression
116 		_rows[var] = expr;
117 
118 		foreach(ClAbstractVariable clv, val; expr.terms())
119 		{
120 			insertColVar(clv, var);
121 			if (clv.isExternal())
122 			{
123 				_externalParametricVars ~= clv;
124 			}
125 		}
126 
127 		if (var.isExternal())
128 		{
129 			_externalRows ~= var;
130 		}
131 		traceprint(this.toString());
132 	}
133 
134 	// Remove v from the tableau -- remove the column cross indices for v
135 	// and remove v from every expression in rows in which v occurs
136 	protected final void removeColumn(ClAbstractVariable var)
137 	{
138 		fnenterprint("removeColumn:" ~ var.toString());
139 		// remove the rows with the variables in varset
140 
141 		auto rows = _columns.get(var, null);
142 
143 
144 		if (rows !is null)
145 		{
146 			_columns.remove(var);
147 			foreach(ClAbstractVariable clv; rows)
148 			{
149 				ClLinearExpression expr = _rows[clv];
150 				expr.terms().remove(var);
151 			}
152 		}
153 		else
154 		{
155 			debugprint("Could not find var " ~ var.toString() ~ " in _columns");
156 		}
157 
158 		if (var.isExternal())
159 		{
160 			_externalRows.remove(var);
161 			_externalParametricVars.remove(var);
162 		}
163 	}
164 
165 	// Remove the basic variable v from the tableau row v=expr
166 	// Then update column cross indices
167 	protected final ClLinearExpression removeRow(ClAbstractVariable var)
168 	{
169 		fnenterprint("removeRow:" ~ var.toString());
170 
171 		ClLinearExpression expr = _rows.get(var, null);
172 		assert(expr !is null);
173 
174 		// For each variable in this expression, update
175 		// the column mapping and remove the variable from the list
176 		// of rows it is known to be in
177 		foreach(ClAbstractVariable clv, val; expr.terms())
178 		{
179 			auto varset = _columns.get(clv, null);
180 			if (varset !is null)
181 			{
182 				debugprint("removing from varset " ~ var.toString());
183 				varset.remove(var);
184 			}
185 		}
186 
187 		_infeasibleRows.remove(var);
188 
189 		if (var.isExternal())
190 		{
191 			_externalRows.remove(var);
192 		}
193 		_rows.remove(var);
194 		fnexitprint("returning " ~ expr.toString());
195 		return expr;
196 	}
197 
198 	// Replace all occurrences of oldVar with expr, and update column cross indices
199 	// oldVar should now be a basic variable
200 	protected final void substituteOut(ClAbstractVariable oldVar, ClLinearExpression expr)
201 	{
202 		fnenterprint("substituteOut:" ~ oldVar.toString() ~ ", " ~ expr.toString());
203 		traceprint(this.toString());
204 
205 		auto varset = _columns[oldVar];
206 		foreach (ClAbstractVariable v; varset)
207 		{
208 			ClLinearExpression row = _rows[v];
209 			row.substituteOut(oldVar, expr, v, this);
210 			if (v.isRestricted() && row.constant() < 0.0)
211 			{
212 				_infeasibleRows ~= v;
213 			}
214 		}
215 
216 		if (oldVar.isExternal())
217 		{
218 			_externalRows ~= oldVar;
219 			_externalParametricVars.remove(oldVar);
220 		}
221 		_columns.remove(oldVar);
222 	}
223 
224 	protected final auto columns()
225 	{
226 		return _columns;
227 	}
228 
229 	protected final auto rows()
230 	{
231 		return _rows;
232 	}
233 
234 	// return true iff the variable subject is in the columns keys
235 	protected final bool columnsHasKey(ClAbstractVariable subject)
236 	{
237 		return (subject in _columns) !is null;
238 	}
239 
240 	protected final ClLinearExpression rowExpression(ClAbstractVariable v)
241 	{
242 		// fnenterprint("rowExpression:" + v);
243 		return _rows.get(v, null);
244 	}
245 
246 	// _columns is a mapping from variables which occur in expressions to the
247 	// set of basic variables whose expressions contain them
248 	// i.e., it's a mapping from variables in expressions (a column) to the
249 	// set of rows that contain them
250 	protected Set!(ClAbstractVariable)[ClAbstractVariable] _columns; // From ClAbstractVariable to Set of variables
251 
252 	// _rows maps basic variables to the expressions for that row in the tableau
253 	protected ClLinearExpression[ClAbstractVariable] _rows;  // From ClAbstractVariable to ClLinearExpression
254 
255 	// the collection of basic variables that have infeasible rows
256 	// (used when reoptimizing)
257 	protected Set!(ClAbstractVariable) _infeasibleRows; // Set of ClAbstractVariable-s
258 
259 	// the set of rows where the basic variable is external
260 	// this was added to the Java/C++ versions to reduce time in setExternalVariables()
261 	protected Set!(ClAbstractVariable) _externalRows; // Set of ClVariable-s
262 
263 	// the set of external variables which are parametric
264 	// this was added to the Java/C++ versions to reduce time in setExternalVariables()
265 	protected Set!(ClAbstractVariable) _externalParametricVars; // Set of ClVariable-s
266 }