/// <summary> /// Remove v from the tableau -- remove the column cross indices for v /// and remove v from every expression in rows in which v occurs /// </summary> protected /*sealed*/ void RemoveColumn(ClAbstractVariable var) { if (Trace) { FnEnterPrint(string.Format("RemoveColumn: {0}", var)); } // remove the rows with the variables in varset Set rows = (Set)_columns[var]; _columns.Remove(var); if (rows != null) { foreach (ClAbstractVariable clv in rows) { ClLinearExpression expr = (ClLinearExpression)_rows[clv]; expr.Terms.Remove(var); } } else { if (Trace) { DebugPrint(string.Format("Could not find var {0} in _columns", var)); } } if (var.IsExternal) { _externalRows.Remove(var); _externalParametricVars.Remove(var); } }
public ClLinearEquation(ClLinearExpression cle, ClAbstractVariable clv, ClStrength strength, double weight) : base((ClLinearExpression) cle.Clone(), strength, weight) { _expression.AddVariable(clv, -1.0); }
public ClLinearInequality(ClLinearExpression cle1, byte op_enum, ClLinearExpression cle2, ClStrength strength) : this(cle1, op_enum, cle2, strength, 1.0) /* throws ExClInternalError */ { }
/// <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)); }
public ClEditOrStayConstraint(ClVariable var, ClStrength strength, double weight) : base(strength, weight) { _variable = var; _expression = new ClLinearExpression(_variable, -1.0, _variable.Value); }
public ClLinearInequality(ClLinearExpression cle, byte op_enum, ClAbstractVariable clv, ClStrength strength) : this(cle, op_enum, clv, strength, 1.0) /* throws ExClInternalError */ { }
public ClLinearEquation(ClLinearExpression cle1, ClLinearExpression cle2, ClStrength strength, double weight) : base((ClLinearExpression)cle1.Clone(), strength, weight) { _expression.AddExpression(cle2, -1.0); }
public ClLinearEquation(ClLinearExpression cle, ClAbstractVariable clv, ClStrength strength, double weight) : base((ClLinearExpression)cle.Clone(), strength, weight) { _expression.AddVariable(clv, -1.0); }
/// <summary> /// Replace all occurrences of oldVar with expr, and update column cross indices /// oldVar should now be a basic variable. /// </summary> protected /*sealed*/ void SubstituteOut(ClAbstractVariable oldVar, ClLinearExpression expr) { if (Trace) { FnEnterPrint(string.Format("SubstituteOut: {0}", oldVar, expr)); } if (Trace) { TracePrint(this.ToString()); } Set varset = (Set)_columns[oldVar]; foreach (ClAbstractVariable v in varset) { ClLinearExpression row = (ClLinearExpression)_rows[v]; row.SubstituteOut(oldVar, expr, v, this); if (v.IsRestricted && row.Constant < 0.0) { _infeasibleRows.Add(v); } } if (oldVar.IsExternal) { _externalRows.Add(oldVar); _externalParametricVars.Remove(oldVar); } _columns.Remove(oldVar); }
/// <summary> /// Replace var with a symbolic expression expr that is equal to it. /// If a variable has been added to this expression that wasn't there /// before, or if a variable has been dropped from this expression /// because it now has a coefficient of 0, inform the solver. /// PRECONDITIONS: /// var occurs with a non-zero coefficient in this expression. /// </summary> public void SubstituteOut(ClAbstractVariable var, ClLinearExpression expr, ClAbstractVariable subject, ClTableau solver) { double multiplier = (_terms[var]).Value; _terms.Remove(var); IncrementConstant(multiplier * expr.Constant); foreach (ClAbstractVariable clv in expr.Terms.Keys) { double coeff = (expr.Terms[clv]).Value; ClDouble dOldCoeff; if (_terms.TryGetValue(clv, out dOldCoeff)) { double oldCoeff = dOldCoeff.Value; double newCoeff = oldCoeff + multiplier * coeff; if (Approx(newCoeff, 0.0)) { solver.NoteRemovedVariable(clv, subject); _terms.Remove(clv); } else { dOldCoeff.Value = newCoeff; } } else { // did not have that variable already _terms.Add(clv, new ClDouble(multiplier * coeff)); solver.NoteAddedVariable(clv, subject); } } }
// Add v=expr to the tableau, update column cross indices // v becomes a basic variable // expr is now owned by ClTableau class, // and ClTableau is responsible for deleting it // (also, expr better be allocated on the heap!). protected /*sealed*/ void AddRow(ClAbstractVariable var, ClLinearExpression expr) { if (Trace) { FnEnterPrint("AddRow: " + var + ", " + expr); } // for each variable in expr, add var to the set of rows which // have that variable in their expression _rows.Add(var, expr); // FIXME: check correctness! foreach (ClAbstractVariable clv in expr.Terms.Keys) { InsertColVar(clv, var); if (clv.IsExternal) { _externalParametricVars.Add(clv); } } if (var.IsExternal) { _externalRows.Add(var); } if (Trace) { TracePrint(this.ToString()); } }
/// <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); } }
public /*sealed*/ ClLinearExpression Divide(ClLinearExpression expr) /*throws ExCLNonlinearExpression*/ { if (!expr.IsConstant) { throw new ExClNonlinearExpression(); } return(Divide(expr._constant.Value)); }
public /*sealed*/ ClLinearExpression DivFrom(ClLinearExpression expr) /*throws ExCLNonlinearExpression*/ { if (!IsConstant || Cl.Approx(_constant.Value, 0.0)) { throw new ExClNonlinearExpression(); } return(expr.Divide(_constant.Value)); }
public ClLinearExpression Divide(ClLinearExpression expr) /*throws ExCLNonlinearExpression*/ { if (!expr.IsConstant) { throw new CassowaryNonlinearExpressionException(); } return(Divide(expr._constant.Value)); }
public ClLinearExpression DivFrom(ClLinearExpression expr) /*throws ExCLNonlinearExpression*/ { if (!IsConstant || Approx(_constant.Value, 0.0)) { throw new CassowaryNonlinearExpressionException(); } return(expr.Divide(_constant.Value)); }
/// <summary> /// Add n*expr to this expression from another expression expr. /// </summary> public ClLinearExpression AddExpression(ClLinearExpression expr, double n = 1.0) { IncrementConstant(n * expr.Constant); foreach (ClAbstractVariable clv in expr.Terms.Keys) { double coeff = (expr.Terms[clv]).Value; AddVariable(clv, coeff * n); } return(this); }
/// <summary> /// Add n*expr to this expression from another expression expr. /// Notify the solver if a variable is added or deleted from this /// expression. /// </summary> public /*sealed*/ ClLinearExpression AddExpression(ClLinearExpression expr, double n, ClAbstractVariable subject, ClTableau solver) { IncrementConstant(n * expr.Constant); foreach (ClAbstractVariable clv in expr.Terms.Keys) { double coeff = ((ClDouble)expr.Terms[clv]).Value; AddVariable(clv, coeff * n, subject, solver); } return(this); }
/// <summary> /// Do a pivot. Move entryVar into the basis and move exitVar /// out of the basis. /// </summary> /// <remarks> /// We could for example make entryVar a basic variable and /// make exitVar a parametric variable. /// </remarks> protected void Pivot(ClAbstractVariable entryVar, ClAbstractVariable exitVar) /* throws ExClInternalError */ { // the entryVar might be non-pivotable if we're doing a // RemoveConstraint -- otherwise it should be a pivotable // variable -- enforced at call sites, hopefully ClLinearExpression pexpr = RemoveRow(exitVar); pexpr.ChangeSubject(exitVar, entryVar); SubstituteOut(entryVar, pexpr); AddRow(entryVar, pexpr); }
/// <summary> /// Replace var with a symbolic expression expr that is equal to it. /// If a variable has been added to this expression that wasn't there /// before, or if a variable has been dropped from this expression /// because it now has a coefficient of 0, inform the solver. /// PRECONDITIONS: /// var occurs with a non-zero coefficient in this expression. /// </summary> public /*sealed*/ void SubstituteOut(ClAbstractVariable var, ClLinearExpression expr, ClAbstractVariable subject, ClTableau solver) { if (Trace) { FnEnterPrint(string.Format("CLE:SubstituteOut: {0}, {1}, {2}, ...", var, expr, subject)); } if (Trace) { TracePrint("this = " + this); } double multiplier = ((ClDouble)_terms[var]).Value; _terms.Remove(var); IncrementConstant(multiplier * expr.Constant); foreach (ClAbstractVariable clv in expr.Terms.Keys) { double coeff = ((ClDouble)expr.Terms[clv]).Value; ClDouble d_old_coeff = (ClDouble)_terms[clv]; if (d_old_coeff != null) { double old_coeff = d_old_coeff.Value; double newCoeff = old_coeff + multiplier * coeff; if (Cl.Approx(newCoeff, 0.0)) { solver.NoteRemovedVariable(clv, subject); _terms.Remove(clv); } else { d_old_coeff.Value = newCoeff; } } else { // did not have that variable already _terms.Add(clv, new ClDouble(multiplier * coeff)); solver.NoteAddedVariable(clv, subject); } } if (Trace) { TracePrint("Now this is " + this); } }
public /*sealed*/ ClLinearExpression Times(ClLinearExpression expr) /*throws ExCLNonlinearExpression*/ { if (IsConstant) { return(expr.Times(_constant.Value)); } else if (!expr.IsConstant) { throw new ExClNonlinearExpression(); } return(Times(expr._constant.Value)); }
public ClLinearExpression Times(ClLinearExpression expr) /*throws ExCLNonlinearExpression*/ { if (IsConstant) { return(expr.Times(_constant.Value)); } if (!expr.IsConstant) { throw new CassowaryNonlinearExpressionException(); } return(Times(expr._constant.Value)); }
/// <summary> /// Fix the constants in the equations representing the stays. /// </summary> /// <remarks> /// Each of the non-required stays will be represented by an equation /// of the form /// v = c + eplus - eminus /// where v is the variable with the stay, c is the previous value /// of v, and eplus and eminus are slack variables that hold the error /// in satisfying the stay constraint. We are about to change something, /// and we want to fix the constants in the equations representing the /// stays. If both eplus and eminus are nonbasic they have value 0 /// in the current solution, meaning the previous stay was exactly /// satisfied. In this case nothing needs to be changed. Otherwise one /// of them is basic, and the other must occur only in the expression /// for that basic error variable. Reset the constant of this /// expression to 0. /// </remarks> protected void ResetStayConstants() { for (int i = 0; i < _stayPlusErrorVars.Count; i++) { ClLinearExpression expr = RowExpression(_stayPlusErrorVars[i]); if (expr == null) { expr = RowExpression(_stayMinusErrorVars[i]); } if (expr != null) { expr.Constant = 0.0; } } }
/// <summary> /// Try to add expr directly to the tableau without creating an /// artificial variable. /// </summary> /// <remarks> /// We are trying to add the constraint expr=0 to the appropriate /// tableau. /// </remarks> /// <returns> /// True if successful and false if not. /// </returns> private bool TryAddingDirectly(ClLinearExpression expr) /* throws ExClRequiredFailure */ { ClAbstractVariable subject = ChooseSubject(expr); if (subject == null) { return(false); } expr.NewSubject(subject); if (ColumnsHasKey(subject)) { SubstituteOut(subject, expr); } AddRow(subject, expr); return(true); // succesfully added directly }
/// <summary> /// Remove the basic variable v from the tableau row v=expr /// Then update column cross indices. /// </summary> protected /*sealed*/ ClLinearExpression RemoveRow(ClAbstractVariable var) /*throws ExCLInternalError*/ { if (Trace) { FnEnterPrint(string.Format("RemoveRow: {0}", var)); } ClLinearExpression expr = (ClLinearExpression)_rows[var]; Assert(expr != null); // For each variable in this expression, update // the column mapping and remove the variable from the list // of rows it is known to be in. foreach (ClAbstractVariable clv in expr.Terms.Keys) { Set varset = (Set)_columns[clv]; if (varset != null) { if (Trace) { DebugPrint(string.Format("removing from varset {0}", var)); } varset.Remove(var); } } _infeasibleRows.Remove(var); if (var.IsExternal) { _externalRows.Remove(var); } _rows.Remove(var); if (Trace) { FnExitPrint(string.Format("returning {0}", expr)); } return(expr); }
public override string ToString() { string s = "Tableau:\n"; foreach (ClAbstractVariable clv in _rows.Keys) { ClLinearExpression expr = _rows[clv]; s += string.Format("{0} <==> {1}\n", clv, expr); } s += string.Format("\nColumns:\n{0}", _columns); s += string.Format("\nInfeasible rows: {0}", InfeasibleRows); s += string.Format("\nExternal basic variables: {0}", ExternalRows); s += string.Format("\nExternal parametric variables: {0}", ExternalParametricVars); return(s); }
//// 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); }
/// <summary> /// Fix the constants in the equations representing the edit constraints. /// </summary> /// <remarks> /// Each of the non-required edits will be represented by an equation /// of the form: /// v = c + eplus - eminus /// where v is the variable with the edit, c is the previous edit value, /// and eplus and eminus are slack variables that hold the error in /// satisfying the edit constraint. We are about to change something, /// and we want to fix the constants in the equations representing /// the edit constraints. If one of eplus and eminus is basic, the other /// must occur only in the expression for that basic error variable. /// (They can't both be basic.) Fix the constant in this expression. /// Otherwise they are both non-basic. Find all of the expressions /// in which they occur, and fix the constants in those. See the /// UIST paper for details. /// (This comment was for ResetEditConstants(), but that is now /// gone since it was part of the screwey vector-based interface /// to resolveing. --02/16/99 gjb) /// </remarks> protected void DeltaEditConstant(double delta, ClAbstractVariable plusErrorVar, ClAbstractVariable minusErrorVar) { ClLinearExpression exprPlus = RowExpression(plusErrorVar); if (exprPlus != null) { exprPlus.IncrementConstant(delta); if (exprPlus.Constant < 0.0) { InfeasibleRows.Add(plusErrorVar); } return; } ClLinearExpression exprMinus = RowExpression(minusErrorVar); if (exprMinus != null) { exprMinus.IncrementConstant(-delta); if (exprMinus.Constant < 0.0) { InfeasibleRows.Add(minusErrorVar); } return; } var columnVars = Columns[minusErrorVar]; foreach (ClAbstractVariable basicVar in columnVars) { ClLinearExpression expr = RowExpression(basicVar); //Assert(expr != null, "expr != null"); double c = expr.CoefficientFor(minusErrorVar); expr.IncrementConstant(c * delta); if (basicVar.IsRestricted && expr.Constant < 0.0) { InfeasibleRows.Add(basicVar); } } }
/// <summary> /// Re-optimize using the dual simplex algorithm. /// </summary> /// <remarks> /// We have set new values for the constants in the edit constraints. /// </remarks> protected void DualOptimize() /* throws ExClInternalError */ { ClLinearExpression zRow = RowExpression(_objective); while (InfeasibleRows.Count > 0) { ClAbstractVariable exitVar = InfeasibleRows.First(); InfeasibleRows.Remove(exitVar); ClAbstractVariable entryVar = null; ClLinearExpression expr = RowExpression(exitVar); if (expr != null) { if (expr.Constant < 0.0) { double ratio = Double.MaxValue; var terms = expr.Terms; foreach (ClAbstractVariable v in terms.Keys) { double c = (terms[v]).Value; if (c > 0.0 && v.IsPivotable) { double zc = zRow.CoefficientFor(v); double r = zc / c; if (r < ratio) { entryVar = v; ratio = r; } } } // ReSharper disable CompareOfFloatsByEqualityOperator if (ratio == Double.MaxValue) // ReSharper restore CompareOfFloatsByEqualityOperator { throw new CassowaryInternalException("ratio == nil (Double.MaxValue) in DualOptimize"); } Pivot(entryVar, exitVar); } } } }
/// <summary> /// Replace all occurrences of oldVar with expr, and update column cross indices /// oldVar should now be a basic variable. /// </summary> protected void SubstituteOut(ClAbstractVariable oldVar, ClLinearExpression expr) { var varset = _columns[oldVar]; foreach (var v in varset) { var row = _rows[v]; row.SubstituteOut(oldVar, expr, v, this); if (v.IsRestricted && row.Constant < 0.0) { InfeasibleRows.Add(v); } } if (oldVar.IsExternal) { ExternalRows.Add((ClVariable)oldVar); ExternalParametricVars.Remove((ClVariable)oldVar); } _columns.Remove(oldVar); }
// Add v=expr to the tableau, update column cross indices // v becomes a basic variable // expr is now owned by ClTableau class, // and ClTableau is responsible for deleting it // (also, expr better be allocated on the heap!). protected void AddRow(ClAbstractVariable var, ClLinearExpression expr) { // for each variable in expr, add var to the set of rows which // have that variable in their expression _rows.Add(var, expr); // FIXME: check correctness! foreach (var clv in expr.Terms.Keys) { InsertColVar(clv, var); if (clv.IsExternal) { ExternalParametricVars.Add((ClVariable)clv); } } if (var.IsExternal) { ExternalRows.Add((ClVariable)var); } }
/// <summary> /// Set the external variables known to this solver to their appropriate values. /// </summary> /// <remarks> /// Set each external basic variable to its value, and set each external parametric /// variable to 0. (It isn't clear that we will ever have external parametric /// variables -- every external variable should either have a stay on it, or have an /// equation that defines it in terms of other external variables that do have stays. /// For the moment I'll put this in though.) Variables that are internal to the solver /// don't actually store values -- their values are just implicit in the tableau -- so /// we don't need to set them. /// </remarks> protected void SetExternalVariables() { foreach (var v in ExternalParametricVars) { if (RowExpression(v) != null) { Console.Error.WriteLine(string.Format("Error: variable {0} in _externalParametricVars is basic", v)); } else { v.Value = 0.0; } } foreach (var v in ExternalRows) { ClLinearExpression expr = RowExpression(v); v.Value = expr.Constant; } _cNeedsSolving = false; }
public static ClLinearExpression Plus(ClVariable e1, ClLinearExpression e2) { return (new ClLinearExpression(e1)).Plus(e2); }
public static ClLinearExpression Plus(ClLinearExpression e1, ClLinearExpression e2) { return e1.Plus(e2); }
public static ClLinearExpression Divide(ClLinearExpression e1, ClLinearExpression e2) /*throws ExCLNonlinearExpression*/ { return e1.Divide(e2); }
public ClLinearEquation(ClLinearExpression cle, ClAbstractVariable clv) : this(cle, clv, ClStrength.Required, 1.0) {}
public ClLinearEquation(ClLinearExpression cle1, ClLinearExpression cle2, ClStrength strength, double weight) : base((ClLinearExpression) cle1.Clone(), strength, weight) { _expression.AddExpression(cle2, -1.0); }
public ClLinearEquation(ClLinearExpression cle) : base(cle) {}
public ClLinearEquation(ClLinearExpression cle1, ClLinearExpression cle2) : this(cle1, cle2, ClStrength.Required, 1.0) {}
public ClLinearInequality(ClLinearExpression cle) : base(cle) {}
/// <summary> /// Try to add expr directly to the tableau without creating an /// artificial variable. /// </summary> /// <remarks> /// We are trying to add the constraint expr=0 to the appropriate /// tableau. /// </remarks> /// <returns> /// True if successful and false if not. /// </returns> protected bool TryAddingDirectly(ClLinearExpression expr) /* throws ExClRequiredFailure */ { if (Trace) FnEnterPrint("TryAddingDirectly: " + expr); ClAbstractVariable subject = ChooseSubject(expr); if (subject == null) { if (Trace) FnExitPrint("returning false"); return false; } expr.NewSubject(subject); if (ColumnsHasKey(subject)) { SubstituteOut(subject, expr); } AddRow(subject, expr); if (Trace) FnExitPrint("returning true"); return true; // succesfully added directly }
public ClLinearEquation(ClLinearExpression cle1, ClLinearExpression cle2, ClStrength strength) : this(cle1, cle2, strength, 1.0) {}
public ClLinearEquation(ClLinearExpression cle, ClStrength strength, double weight) : base(cle, strength, weight) {}
public ClLinearEquation(ClLinearExpression cle, ClStrength strength) : base(cle, strength) {}
public static ClLinearExpression Plus(ClLinearExpression e1, ClVariable e2) { return e1.Plus(new ClLinearExpression(e2)); }
protected ClLinearExpression NewExpression(ClConstraint cn, ArrayList eplus_eminus, ClDouble prevEConstant) { if (Trace) { FnEnterPrint("NewExpression: " + cn); TracePrint("cn.IsInequality == " + cn.IsInequality); TracePrint("cn.IsRequired == " + cn.IsRequired); } ClLinearExpression cnExpr = cn.Expression; ClLinearExpression expr = new ClLinearExpression(cnExpr.Constant); ClSlackVariable slackVar = new ClSlackVariable(); ClDummyVariable dummyVar = new ClDummyVariable(); ClSlackVariable eminus = new ClSlackVariable(); ClSlackVariable eplus = new ClSlackVariable(); Hashtable cnTerms = cnExpr.Terms; foreach(ClAbstractVariable v in cnTerms.Keys) { double c = ((ClDouble) cnTerms[v]).Value; ClLinearExpression e = RowExpression(v); if (e == null) expr.AddVariable(v, c); else expr.AddExpression(e, c); } if (cn.IsInequality) { ++_slackCounter; slackVar = new ClSlackVariable (_slackCounter, "s"); expr.SetVariable(slackVar, -1); _markerVars.Add(cn, slackVar); if (!cn.IsRequired) { ++_slackCounter; eminus = new ClSlackVariable(_slackCounter, "em"); expr.SetVariable(eminus, 1.0); ClLinearExpression zRow = RowExpression(_objective); ClSymbolicWeight sw = cn.Strength.SymbolicWeight.Times(cn.Weight); zRow.SetVariable(eminus, sw.AsDouble()); InsertErrorVar(cn, eminus); NoteAddedVariable(eminus, _objective); } } else { // cn is an equality if (cn.IsRequired) { ++_dummyCounter; dummyVar = new ClDummyVariable(_dummyCounter, "d"); expr.SetVariable(dummyVar, 1.0); _markerVars.Add(cn, dummyVar); if (Trace) TracePrint("Adding dummyVar == d" + _dummyCounter); } else { ++_slackCounter; eplus = new ClSlackVariable(_slackCounter, "ep"); eminus = new ClSlackVariable(_slackCounter, "em"); expr.SetVariable(eplus, -1.0); expr.SetVariable(eminus, 1.0); _markerVars.Add(cn, eplus); ClLinearExpression zRow = RowExpression(_objective); ClSymbolicWeight sw = cn.Strength.SymbolicWeight.Times(cn.Weight); double swCoeff = sw.AsDouble(); if (swCoeff == 0) { if (Trace) { TracePrint("sw == " + sw); TracePrint("cn == " + cn); TracePrint("adding " + eplus + " and " + eminus + " with swCoeff == " + swCoeff); } } zRow.SetVariable(eplus, swCoeff); NoteAddedVariable(eplus, _objective); zRow.SetVariable(eminus, swCoeff); NoteAddedVariable(eminus, _objective); InsertErrorVar(cn, eminus); InsertErrorVar(cn, eplus); if (cn.IsStayConstraint) { _stayPlusErrorVars.Add(eplus); _stayMinusErrorVars.Add(eminus); } else if (cn.IsEditConstraint) { eplus_eminus.Add(eplus); eplus_eminus.Add(eminus); prevEConstant.Value = cnExpr.Constant; } } } if (expr.Constant < 0) expr.MultiplyMe(-1); if (Trace) FnExitPrint("returning " + expr); return expr; }
public ClLinearInequality(ClLinearExpression cle, ClStrength strength, double weight) : base(cle, strength, weight) {}
//// 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); }
// Add v=expr to the tableau, update column cross indices // v becomes a basic variable // expr is now owned by ClTableau class, // and ClTableau is responsible for deleting it // (also, expr better be allocated on the heap!). protected /*sealed*/ void AddRow(ClAbstractVariable var, ClLinearExpression expr) { if (Trace) FnEnterPrint("AddRow: " + var + ", " + expr); // for each variable in expr, add var to the set of rows which // have that variable in their expression _rows.Add(var, expr); // FIXME: check correctness! foreach (ClAbstractVariable clv in expr.Terms.Keys) { InsertColVar(clv, var); if (clv.IsExternal) { _externalParametricVars.Add(clv); } } if (var.IsExternal) { _externalRows.Add(var); } if (Trace) TracePrint(this.ToString()); }
/// <summary> /// Try to choose a subject (a variable to become basic) from /// among the current variables in expr. /// </summary> /// <remarks> /// We are trying to add the constraint expr=0 to the tableaux. /// If expr constains any unrestricted variables, then we must choose /// an unrestricted variable as the subject. Also if the subject is /// new to the solver, we won't have to do any substitutions, so we /// prefer new variables to ones that are currently noted as parametric. /// If expr contains only restricted variables, if there is a restricted /// variable with a negative coefficient that is new to the solver we can /// make that the subject. Otherwise we can't find a subject, so return nil. /// (In this last case we have to add an artificial variable and use that /// variable as the subject -- this is done outside this method though.) /// </remarks> protected ClAbstractVariable ChooseSubject(ClLinearExpression expr) /* ExClRequiredFailure */ { if (Trace) FnEnterPrint("ChooseSubject: " + expr); ClAbstractVariable subject = null; // the current best subject, if any bool foundUnrestricted = false; bool foundNewRestricted = false; Hashtable terms = expr.Terms; foreach (ClAbstractVariable v in terms.Keys) { double c = ((ClDouble) terms[v]).Value; if (foundUnrestricted) { if (!v.IsRestricted) { if (!ColumnsHasKey(v)) return v; } } else { // we haven't found an restricted variable yet if (v.IsRestricted) { if (!foundNewRestricted && !v.IsDummy && c < 0.0) { Set col = (Set) _columns[v]; if ( col == null || (col.Count == 1 && ColumnsHasKey(_objective)) ) { subject = v; foundNewRestricted = true; } } } else { subject = v; foundUnrestricted = true; } } } if (subject != null) return subject; double coeff = 0.0; foreach (ClAbstractVariable v in terms.Keys) { double c = ((ClDouble) terms[v]).Value; if (!v.IsDummy) return null; // nope, no luck if (!ColumnsHasKey(v)) { subject = v; coeff = c; } } if (!Cl.Approx(expr.Constant, 0.0)) { throw new ExClRequiredFailure(); } if (coeff > 0.0) { expr.MultiplyMe(-1); } return subject; }
public static ClLinearExpression Minus(double e1, ClLinearExpression e2) { return (new ClLinearExpression(e1)).Minus(e2); }
public ClLinearInequality(ClLinearExpression cle, ClStrength strength) : base(cle, strength) {}
public static ClLinearExpression Minus(ClLinearExpression e1, double e2) { return e1.Minus(new ClLinearExpression(e2)); }
/// <summary> /// Replace all occurrences of oldVar with expr, and update column cross indices /// oldVar should now be a basic variable. /// </summary> protected /*sealed*/ void SubstituteOut(ClAbstractVariable oldVar, ClLinearExpression expr) { if (Trace) FnEnterPrint(string.Format("SubstituteOut: {0}", oldVar, expr)); if (Trace) TracePrint(this.ToString()); Set varset = (Set) _columns[oldVar]; foreach(ClAbstractVariable v in varset) { ClLinearExpression row = (ClLinearExpression) _rows[v]; row.SubstituteOut(oldVar, expr, v, this); if (v.IsRestricted && row.Constant < 0.0) { _infeasibleRows.Add(v); } } if (oldVar.IsExternal) { _externalRows.Add(oldVar); _externalParametricVars.Remove(oldVar); } _columns.Remove(oldVar); }
public static ClLinearExpression Times(ClLinearExpression e1, ClLinearExpression e2) /*throws ExCLNonlinearExpression*/ { return e1.Times(e2); }
public static ClLinearExpression Times(ClLinearExpression e1, double e2) /*throws ExCLNonlinearExpression*/ { return e1.Times(new ClLinearExpression(e2)); }
public static ClLinearExpression Times(double e1, ClLinearExpression e2) /*throws ExCLNonlinearExpression*/ { return (new ClLinearExpression(e1)).Times(e2); }
public static ClLinearExpression Minus(ClLinearExpression e1, ClLinearExpression e2) { return e1.Minus(e2); }
public ClLinearEquation(ClLinearExpression cle, ClAbstractVariable clv, ClStrength strength) : this(cle, clv, strength, 1.0) {}