Implement Solver.suggestValue
diff --git a/lib/solver.dart b/lib/solver.dart index 0a2b960..45eb62b 100644 --- a/lib/solver.dart +++ b/lib/solver.dart
@@ -130,8 +130,14 @@ return _edits.containsKey(variable); } - Result suggestVariable(Variable v, double value) { - return Result.unimplemented; + Result suggestValueForVariable(Variable variable, double value) { + if (!_edits.containsKey(variable)) { + return Result.unknownEditVariable; + } + + _suggestValueForEditInfoWithoutDualOptimization(_edits[variable], value); + + return _dualOptimize(); } void updateVariable() {} @@ -426,6 +432,89 @@ } return third; } + + void _suggestValueForEditInfoWithoutDualOptimization( + EditInfo info, double value) { + double delta = value - info.constant; + info.constant = value; + + { + Symbol symbol = info.tag.marker; + Row row = _rows[info.tag.marker]; + + if (row != null) { + if (row.add(-delta) < 0.0) { + _infeasibleRows.add(symbol); + } + return; + } + + symbol = info.tag.other; + row = _rows[info.tag.other]; + + if (row != null) { + if (row.add(delta) < 0.0) { + _infeasibleRows.add(symbol); + } + return; + } + } + + for (Symbol symbol in _rows.keys) { + Row row = _rows[symbol]; + double coeff = row.coefficientForSymbol(info.tag.marker); + if (coeff != 0.0 && + row.add(delta * coeff) < 0.0 && + symbol.type != SymbolType.external) { + _infeasibleRows.add(symbol); + } + } + } + + Result _dualOptimize() { + while (_infeasibleRows.length != 0) { + Symbol leaving = _infeasibleRows.removeLast(); + Row row = _rows[leaving]; + + if (row != null && row.constant < 0.0) { + Symbol entering = _getDualEnteringSymbolForRow(row); + + if (entering.type == SymbolType.invalid) { + return Result.internalSolverError; + } + + _rows.remove(leaving); + + row.solveForSymbols(leaving, entering); + _substitute(entering, row); + _rows[entering] = row; + } + } + return Result.success; + } + + Symbol _getDualEnteringSymbolForRow(Row row) { + Symbol entering; + + double ratio = double.MAX_FINITE; + + Map<Symbol, double> rowCells = row.cells; + + for (Symbol symbol in rowCells.keys) { + double value = rowCells[symbol]; + + if (value > 0.0 && symbol.type != SymbolType.dummy) { + double coeff = _objective.coefficientForSymbol(symbol); + double r = coeff / value; + if (r < ratio) { + ratio = r; + entering = symbol; + } + } + } + + return _elvis(entering, new Symbol(SymbolType.invalid, 0)); + } } class Tag {