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 }