Commit a029c93e authored by Chinmay Garde's avatar Chinmay Garde

Remove the << overload on solver. Operator precendence rules made it awkward to use anyway

parent 882a17f7
...@@ -14,19 +14,47 @@ class Solver { ...@@ -14,19 +14,47 @@ class Solver {
_Row _artificial = new _Row(0.0); _Row _artificial = new _Row(0.0);
int tick = 0; int tick = 0;
/// Attempts to add the constraints in the list to the solver. If it cannot
/// add any for some reason, a cleanup is attempted so that either all
/// constraints will be added or none.
Result addConstraints(List<Constraint> constraints) {
List<Constraint> added = new List<Constraint>(constraints.length);
bool needsCleanup = false;
Result result = Result.success;
for (Constraint constraint in constraints) {
result = addConstraint(constraint);
if (result == Result.success) {
added.add(constraint);
} else {
needsCleanup = true;
break;
}
}
if (needsCleanup) {
for (Constraint constraint in added) {
removeConstraint(constraint);
}
}
return result;
}
Result addConstraint(Constraint constraint) { Result addConstraint(Constraint constraint) {
if (_constraints.containsKey(constraint)) { if (_constraints.containsKey(constraint)) {
return Result.duplicateConstraint; return Result.duplicateConstraint;
} }
_Tag tag = new _Tag( _Tag tag = new _Tag(new _Symbol(_SymbolType.invalid, 0),
new _Symbol(SymbolType.invalid, 0), new _Symbol(SymbolType.invalid, 0)); new _Symbol(_SymbolType.invalid, 0));
_Row row = _createRow(constraint, tag); _Row row = _createRow(constraint, tag);
_Symbol subject = _chooseSubjectForRow(row, tag); _Symbol subject = _chooseSubjectForRow(row, tag);
if (subject.type == SymbolType.invalid && _allDummiesInRow(row)) { if (subject.type == _SymbolType.invalid && _allDummiesInRow(row)) {
if (!_nearZero(row.constant)) { if (!_nearZero(row.constant)) {
return Result.unsatisfiableConstraint; return Result.unsatisfiableConstraint;
} else { } else {
...@@ -34,7 +62,7 @@ class Solver { ...@@ -34,7 +62,7 @@ class Solver {
} }
} }
if (subject.type == SymbolType.invalid) { if (subject.type == _SymbolType.invalid) {
if (!_addWithArtificialVariableOnRow(row)) { if (!_addWithArtificialVariableOnRow(row)) {
return Result.unsatisfiableConstraint; return Result.unsatisfiableConstraint;
} }
...@@ -64,8 +92,7 @@ class Solver { ...@@ -64,8 +92,7 @@ class Solver {
if (row != null) { if (row != null) {
_rows.remove(tag.marker); _rows.remove(tag.marker);
} else { } else {
_Pair<_Symbol, _Row> rowPair = _Pair<_Symbol, _Row> rowPair = _leavingRowPairForMarkerSymbol(tag.marker);
_leavingRowPairForMarkerSymbol(tag.marker);
if (rowPair == null) { if (rowPair == null) {
return Result.internalSolverError; return Result.internalSolverError;
...@@ -152,8 +179,6 @@ class Solver { ...@@ -152,8 +179,6 @@ class Solver {
} }
} }
Solver operator <<(Constraint c) => this..addConstraint(c);
_Symbol _symbolForVariable(Variable variable) { _Symbol _symbolForVariable(Variable variable) {
_Symbol symbol = _vars[variable]; _Symbol symbol = _vars[variable];
...@@ -161,7 +186,7 @@ class Solver { ...@@ -161,7 +186,7 @@ class Solver {
return symbol; return symbol;
} }
symbol = new _Symbol(SymbolType.external, tick++); symbol = new _Symbol(_SymbolType.external, tick++);
_vars[variable] = symbol; _vars[variable] = symbol;
return symbol; return symbol;
...@@ -192,12 +217,12 @@ class Solver { ...@@ -192,12 +217,12 @@ class Solver {
double coefficient = double coefficient =
constraint.relation == Relation.lessThanOrEqualTo ? 1.0 : -1.0; constraint.relation == Relation.lessThanOrEqualTo ? 1.0 : -1.0;
_Symbol slack = new _Symbol(SymbolType.slack, tick++); _Symbol slack = new _Symbol(_SymbolType.slack, tick++);
tag.marker = slack; tag.marker = slack;
row.insertSymbol(slack, coefficient); row.insertSymbol(slack, coefficient);
if (!constraint.required) { if (!constraint.required) {
_Symbol error = new _Symbol(SymbolType.error, tick++); _Symbol error = new _Symbol(_SymbolType.error, tick++);
tag.other = error; tag.other = error;
row.insertSymbol(error, -coefficient); row.insertSymbol(error, -coefficient);
_objective.insertSymbol(error, constraint.priority); _objective.insertSymbol(error, constraint.priority);
...@@ -206,8 +231,8 @@ class Solver { ...@@ -206,8 +231,8 @@ class Solver {
break; break;
case Relation.equalTo: case Relation.equalTo:
if (!constraint.required) { if (!constraint.required) {
_Symbol errPlus = new _Symbol(SymbolType.error, tick++); _Symbol errPlus = new _Symbol(_SymbolType.error, tick++);
_Symbol errMinus = new _Symbol(SymbolType.error, tick++); _Symbol errMinus = new _Symbol(_SymbolType.error, tick++);
tag.marker = errPlus; tag.marker = errPlus;
tag.other = errMinus; tag.other = errMinus;
row.insertSymbol(errPlus, -1.0); row.insertSymbol(errPlus, -1.0);
...@@ -215,7 +240,7 @@ class Solver { ...@@ -215,7 +240,7 @@ class Solver {
_objective.insertSymbol(errPlus, constraint.priority); _objective.insertSymbol(errPlus, constraint.priority);
_objective.insertSymbol(errMinus, constraint.priority); _objective.insertSymbol(errMinus, constraint.priority);
} else { } else {
_Symbol dummy = new _Symbol(SymbolType.dummy, tick++); _Symbol dummy = new _Symbol(_SymbolType.dummy, tick++);
tag.marker = dummy; tag.marker = dummy;
row.insertSymbol(dummy); row.insertSymbol(dummy);
} }
...@@ -231,31 +256,31 @@ class Solver { ...@@ -231,31 +256,31 @@ class Solver {
_Symbol _chooseSubjectForRow(_Row row, _Tag tag) { _Symbol _chooseSubjectForRow(_Row row, _Tag tag) {
for (_Symbol symbol in row.cells.keys) { for (_Symbol symbol in row.cells.keys) {
if (symbol.type == SymbolType.external) { if (symbol.type == _SymbolType.external) {
return symbol; return symbol;
} }
} }
if (tag.marker.type == SymbolType.slack || if (tag.marker.type == _SymbolType.slack ||
tag.marker.type == SymbolType.error) { tag.marker.type == _SymbolType.error) {
if (row.coefficientForSymbol(tag.marker) < 0.0) { if (row.coefficientForSymbol(tag.marker) < 0.0) {
return tag.marker; return tag.marker;
} }
} }
if (tag.other.type == SymbolType.slack || if (tag.other.type == _SymbolType.slack ||
tag.other.type == SymbolType.error) { tag.other.type == _SymbolType.error) {
if (row.coefficientForSymbol(tag.other) < 0.0) { if (row.coefficientForSymbol(tag.other) < 0.0) {
return tag.other; return tag.other;
} }
} }
return new _Symbol(SymbolType.invalid, 0); return new _Symbol(_SymbolType.invalid, 0);
} }
bool _allDummiesInRow(_Row row) { bool _allDummiesInRow(_Row row) {
for (_Symbol symbol in row.cells.keys) { for (_Symbol symbol in row.cells.keys) {
if (symbol.type != SymbolType.dummy) { if (symbol.type != _SymbolType.dummy) {
return false; return false;
} }
} }
...@@ -263,7 +288,7 @@ class Solver { ...@@ -263,7 +288,7 @@ class Solver {
} }
bool _addWithArtificialVariableOnRow(_Row row) { bool _addWithArtificialVariableOnRow(_Row row) {
_Symbol artificial = new _Symbol(SymbolType.slack, tick++); _Symbol artificial = new _Symbol(_SymbolType.slack, tick++);
_rows[artificial] = new _Row.fromRow(row); _rows[artificial] = new _Row.fromRow(row);
_artificial = new _Row.fromRow(row); _artificial = new _Row.fromRow(row);
...@@ -285,7 +310,7 @@ class Solver { ...@@ -285,7 +310,7 @@ class Solver {
} }
_Symbol entering = _anyPivotableSymbol(foundRow); _Symbol entering = _anyPivotableSymbol(foundRow);
if (entering.type == SymbolType.invalid) { if (entering.type == _SymbolType.invalid) {
return false; return false;
} }
...@@ -304,12 +329,11 @@ class Solver { ...@@ -304,12 +329,11 @@ class Solver {
Result _optimizeObjectiveRow(_Row objective) { Result _optimizeObjectiveRow(_Row objective) {
while (true) { while (true) {
_Symbol entering = _enteringSymbolForObjectiveRow(objective); _Symbol entering = _enteringSymbolForObjectiveRow(objective);
if (entering.type == SymbolType.invalid) { if (entering.type == _SymbolType.invalid) {
return Result.success; return Result.success;
} }
_Pair<_Symbol, _Row> leavingPair = _Pair<_Symbol, _Row> leavingPair = _leavingRowForEnteringSymbol(entering);
_leavingRowForEnteringSymbol(entering);
if (leavingPair == null) { if (leavingPair == null) {
return Result.internalSolverError; return Result.internalSolverError;
...@@ -328,12 +352,12 @@ class Solver { ...@@ -328,12 +352,12 @@ class Solver {
Map<_Symbol, double> cells = objective.cells; Map<_Symbol, double> cells = objective.cells;
for (_Symbol symbol in cells.keys) { for (_Symbol symbol in cells.keys) {
if (symbol.type != SymbolType.dummy && cells[symbol] < 0.0) { if (symbol.type != _SymbolType.dummy && cells[symbol] < 0.0) {
return symbol; return symbol;
} }
} }
return new _Symbol(SymbolType.invalid, 0); return new _Symbol(_SymbolType.invalid, 0);
} }
_Pair<_Symbol, _Row> _leavingRowForEnteringSymbol(_Symbol entering) { _Pair<_Symbol, _Row> _leavingRowForEnteringSymbol(_Symbol entering) {
...@@ -341,7 +365,7 @@ class Solver { ...@@ -341,7 +365,7 @@ class Solver {
_Pair<_Symbol, _Row> result = new _Pair(null, null); _Pair<_Symbol, _Row> result = new _Pair(null, null);
_rows.forEach((symbol, row) { _rows.forEach((symbol, row) {
if (symbol.type != SymbolType.external) { if (symbol.type != _SymbolType.external) {
double temp = row.coefficientForSymbol(entering); double temp = row.coefficientForSymbol(entering);
if (temp < 0.0) { if (temp < 0.0) {
...@@ -366,7 +390,7 @@ class Solver { ...@@ -366,7 +390,7 @@ class Solver {
void _substitute(_Symbol symbol, _Row row) { void _substitute(_Symbol symbol, _Row row) {
_rows.forEach((first, second) { _rows.forEach((first, second) {
second.substitute(symbol, row); second.substitute(symbol, row);
if (first.type != SymbolType.external && second.constant < 0.0) { if (first.type != _SymbolType.external && second.constant < 0.0) {
_infeasibleRows.add(first); _infeasibleRows.add(first);
} }
}); });
...@@ -379,18 +403,19 @@ class Solver { ...@@ -379,18 +403,19 @@ class Solver {
_Symbol _anyPivotableSymbol(_Row row) { _Symbol _anyPivotableSymbol(_Row row) {
for (_Symbol symbol in row.cells.keys) { for (_Symbol symbol in row.cells.keys) {
if (symbol.type == SymbolType.slack || symbol.type == SymbolType.error) { if (symbol.type == _SymbolType.slack ||
symbol.type == _SymbolType.error) {
return symbol; return symbol;
} }
} }
return new _Symbol(SymbolType.invalid, 0); return new _Symbol(_SymbolType.invalid, 0);
} }
void _removeConstraintEffects(Constraint cn, _Tag tag) { void _removeConstraintEffects(Constraint cn, _Tag tag) {
if (tag.marker.type == SymbolType.error) { if (tag.marker.type == _SymbolType.error) {
_removeMarkerEffects(tag.marker, cn.priority); _removeMarkerEffects(tag.marker, cn.priority);
} }
if (tag.other.type == SymbolType.error) { if (tag.other.type == _SymbolType.error) {
_removeMarkerEffects(tag.other, cn.priority); _removeMarkerEffects(tag.other, cn.priority);
} }
} }
...@@ -417,7 +442,7 @@ class Solver { ...@@ -417,7 +442,7 @@ class Solver {
return; return;
} }
if (symbol.type == SymbolType.external) { if (symbol.type == _SymbolType.external) {
third = new _Pair(symbol, row); third = new _Pair(symbol, row);
} else if (c < 0.0) { } else if (c < 0.0) {
double r = -row.constant / c; double r = -row.constant / c;
...@@ -475,7 +500,7 @@ class Solver { ...@@ -475,7 +500,7 @@ class Solver {
double coeff = row.coefficientForSymbol(info.tag.marker); double coeff = row.coefficientForSymbol(info.tag.marker);
if (coeff != 0.0 && if (coeff != 0.0 &&
row.add(delta * coeff) < 0.0 && row.add(delta * coeff) < 0.0 &&
symbol.type != SymbolType.external) { symbol.type != _SymbolType.external) {
_infeasibleRows.add(symbol); _infeasibleRows.add(symbol);
} }
} }
...@@ -489,7 +514,7 @@ class Solver { ...@@ -489,7 +514,7 @@ class Solver {
if (row != null && row.constant < 0.0) { if (row != null && row.constant < 0.0) {
_Symbol entering = _dualEnteringSymbolForRow(row); _Symbol entering = _dualEnteringSymbolForRow(row);
if (entering.type == SymbolType.invalid) { if (entering.type == _SymbolType.invalid) {
return Result.internalSolverError; return Result.internalSolverError;
} }
...@@ -513,7 +538,7 @@ class Solver { ...@@ -513,7 +538,7 @@ class Solver {
for (_Symbol symbol in rowCells.keys) { for (_Symbol symbol in rowCells.keys) {
double value = rowCells[symbol]; double value = rowCells[symbol];
if (value > 0.0 && symbol.type != SymbolType.dummy) { if (value > 0.0 && symbol.type != _SymbolType.dummy) {
double coeff = _objective.coefficientForSymbol(symbol); double coeff = _objective.coefficientForSymbol(symbol);
double r = coeff / value; double r = coeff / value;
if (r < ratio) { if (r < ratio) {
...@@ -523,7 +548,7 @@ class Solver { ...@@ -523,7 +548,7 @@ class Solver {
} }
} }
return _elvis(entering, new _Symbol(SymbolType.invalid, 0)); return _elvis(entering, new _Symbol(_SymbolType.invalid, 0));
} }
} }
......
...@@ -4,10 +4,10 @@ ...@@ -4,10 +4,10 @@
part of cassowary; part of cassowary;
enum SymbolType { invalid, external, slack, error, dummy, } enum _SymbolType { invalid, external, slack, error, dummy, }
class _Symbol { class _Symbol {
final SymbolType type; final _SymbolType type;
int tick; int tick;
_Symbol(this.type, this.tick); _Symbol(this.type, this.tick);
......
...@@ -426,7 +426,7 @@ void main() { ...@@ -426,7 +426,7 @@ void main() {
test('single_item', () { test('single_item', () {
var left = new Param(-20.0); var left = new Param(-20.0);
Solver s = new Solver(); Solver s = new Solver();
s << (left >= CM(0.0)); s.addConstraint(left >= CM(0.0));
s.flushVariableUpdates(); s.flushVariableUpdates();
expect(left.value, 0.0); expect(left.value, 0.0);
}); });
...@@ -438,9 +438,10 @@ void main() { ...@@ -438,9 +438,10 @@ void main() {
Solver s = new Solver(); Solver s = new Solver();
s << ((left + right == CM(2.0) * mid) as Constraint); expect(s.addConstraint((left + right == CM(2.0) * mid) as Constraint),
s << (right - left >= CM(100.0)); Result.success);
s << (left >= CM(0.0)); expect(s.addConstraint(right - left >= CM(100.0)), Result.success);
expect(s.addConstraint(left >= CM(0.0)), Result.success);
s.flushVariableUpdates(); s.flushVariableUpdates();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment