/// <remarks> /// Constructor initializes the fields, and creaties the objective row. /// </remarks> public ClSimplexSolver() { _stayMinusErrorVars = new ArrayList(); _stayPlusErrorVars = new ArrayList(); _errorVars = new Hashtable(); _markerVars = new Hashtable(); _resolve_pair = new ArrayList(2); _resolve_pair.Add(new ClDouble(0)); _resolve_pair.Add(new ClDouble(0)); _objective = new ClObjectiveVariable("Z"); _editVarMap = new Hashtable(); _slackCounter = 0; _artificialCounter = 0; _dummyCounter = 0; _epsilon = 1e-8; _cOptimizeAutomatically = true; _cNeedsSolving = false; ClLinearExpression e = new ClLinearExpression(); _rows.Add(_objective, e); _stkCedcns = new Stack(); _stkCedcns.Push(0); if (Trace) TracePrint("objective expr == " + RowExpression(_objective)); }
/// <summary> /// Minimize the value of the objective. /// </summary> /// <remarks> /// The tableau should already be feasible. /// </remarks> private void Optimize(ClObjectiveVariable zVar) /* throws ExClInternalError */ { ClLinearExpression zRow = RowExpression(zVar); if (zRow == null) { throw new CassowaryInternalException("Assertion failed: zRow != null"); } ClAbstractVariable entryVar = null; ClAbstractVariable exitVar = null; while (true) { double objectiveCoeff = 0; foreach (var kvp in zRow.Terms) { if (kvp.Key.IsPivotable && kvp.Value.Value < objectiveCoeff) { objectiveCoeff = kvp.Value.Value; entryVar = kvp.Key; } } if (objectiveCoeff >= -EPSILON || entryVar == null) { return; } double minRatio = Double.MaxValue; foreach (ClAbstractVariable v in Columns[entryVar]) { if (v.IsPivotable) { ClLinearExpression expr = RowExpression(v); double coeff = expr.CoefficientFor(entryVar); if (coeff < 0.0) { double r = -expr.Constant / coeff; if (r < minRatio) { minRatio = r; exitVar = v; } } } } // ReSharper disable CompareOfFloatsByEqualityOperator if (minRatio == Double.MaxValue) // ReSharper restore CompareOfFloatsByEqualityOperator { throw new CassowaryInternalException("Objective function is unbounded in Optimize"); } Pivot(entryVar, exitVar); } }
//// END PUBLIC INTERFACE //// /// <summary> /// Add the constraint expr=0 to the inequality tableau using an /// artificial variable. /// </summary> /// <remarks> /// To do this, create an artificial variable av and add av=expr /// to the inequality tableau, then make av be 0 (raise an exception /// if we can't attain av=0). /// </remarks> private void AddWithArtificialVariable(ClLinearExpression expr) /* throws ExClRequiredFailure, ExClInternalError */ { ClSlackVariable av = new ClSlackVariable(++_artificialCounter, "a"); ClObjectiveVariable az = new ClObjectiveVariable("az"); ClLinearExpression azRow = expr.Clone(); AddRow(az, azRow); AddRow(av, expr); Optimize(az); ClLinearExpression azTableauRow = RowExpression(az); if (!Approx(azTableauRow.Constant, 0.0)) { RemoveRow(az); RemoveColumn(av); throw new CassowaryRequiredFailureException(); } // see if av is a basic variable ClLinearExpression e = RowExpression(av); if (e != null) { // find another variable in this row and pivot, // so that av becomes parametric if (e.IsConstant) { // if there isn't another variable in the row // then the tableau contains the equation av=0 -- // just delete av's row RemoveRow(av); RemoveRow(az); return; } ClAbstractVariable entryVar = e.AnyPivotableVariable(); Pivot(entryVar, av); } Assert(RowExpression(av) == null, "RowExpression(av) == null)"); RemoveColumn(av); RemoveRow(az); }
//// END PUBLIC INTERFACE //// /// <summary> /// Add the constraint expr=0 to the inequality tableau using an /// artificial variable. /// </summary> /// <remarks> /// To do this, create an artificial variable av and add av=expr /// to the inequality tableau, then make av be 0 (raise an exception /// if we can't attain av=0). /// </remarks> protected void AddWithArtificialVariable(ClLinearExpression expr) /* throws ExClRequiredFailure, ExClInternalError */ { if (Trace) FnEnterPrint("AddWithArtificialVariable: " + expr); ClSlackVariable av = new ClSlackVariable(++_artificialCounter, "a"); ClObjectiveVariable az = new ClObjectiveVariable("az"); ClLinearExpression azRow = (ClLinearExpression) expr.Clone(); if (Trace) TracePrint("before AddRows:\n" + this); AddRow(az, azRow); AddRow(av, expr); if (Trace) TracePrint("after AddRows:\n" + this); Optimize(az); ClLinearExpression azTableauRow = RowExpression(az); if (Trace) TracePrint("azTableauRow.Constant == " + azTableauRow.Constant); if (!Cl.Approx(azTableauRow.Constant, 0.0)) { RemoveRow(az); RemoveColumn(av); throw new ExClRequiredFailure(); } // see if av is a basic variable ClLinearExpression e = RowExpression(av); if (e != null) { // find another variable in this row and pivot, // so that av becomes parametric if (e.IsConstant) { // if there isn't another variable in the row // then the tableau contains the equation av=0 -- // just delete av's row RemoveRow(av); RemoveRow(az); return; } ClAbstractVariable entryVar = e.AnyPivotableVariable(); Pivot(entryVar, av); } Assert(RowExpression(av) == null, "RowExpression(av) == null)"); RemoveColumn(av); RemoveRow(az); }
/// <summary> /// Minimize the value of the objective. /// </summary> /// <remarks> /// The tableau should already be feasible. /// </remarks> protected void Optimize(ClObjectiveVariable zVar) /* throws ExClInternalError */ { if (Trace) { FnEnterPrint("Optimize: " + zVar); TracePrint(this.ToString()); } ClLinearExpression zRow = RowExpression(zVar); Assert(zRow != null, "zRow != null"); ClAbstractVariable entryVar = null; ClAbstractVariable exitVar = null; while (true) { double objectiveCoeff = 0; Hashtable terms = zRow.Terms; foreach (ClAbstractVariable v in terms.Keys) { double c = ((ClDouble) terms[v]).Value; if (v.IsPivotable && c < objectiveCoeff) { objectiveCoeff = c; entryVar = v; } } if (objectiveCoeff >= -_epsilon || entryVar == null) return; if (Trace) TracePrint("entryVar == " + entryVar + ", objectiveCoeff == " + objectiveCoeff); double minRatio = Double.MaxValue; Set columnVars = (Set) _columns[entryVar]; double r = 0.0; foreach (ClAbstractVariable v in columnVars) { if (Trace) TracePrint("Checking " + v); if (v.IsPivotable) { ClLinearExpression expr = RowExpression(v); double coeff = expr.CoefficientFor(entryVar); if (Trace) TracePrint("pivotable, coeff == " + coeff); if (coeff < 0.0) { r = - expr.Constant / coeff; if (r < minRatio) { if (Trace) TracePrint("New minRatio == " + r); minRatio = r; exitVar = v; } } } } if (minRatio == Double.MaxValue) { throw new ExClInternalError("Objective function is unbounded in Optimize"); } Pivot(entryVar, exitVar); if (Trace) TracePrint(this.ToString()); } }