public ClLinearEquation(ClAbstractVariable clv, double val, ClStrength strength, double weight) : base(new ClLinearExpression(val), strength, weight) { _expression.AddVariable(clv, -1.0); }
/// <summary> /// Add a term c*v to this expression. If the expression already /// contains a term involving v, add c to the existing coefficient. /// If the new coefficient is approximately 0, delete v. /// </summary> public /*sealed*/ ClLinearExpression AddVariable(ClAbstractVariable v, double c) { // body largely duplicated below if (Trace) { FnEnterPrint(string.Format("AddVariable: {0}, {1}", v, c)); } ClDouble coeff = (ClDouble)_terms[v]; if (coeff != null) { double new_coefficient = coeff.Value + c; if (Cl.Approx(new_coefficient, 0.0)) { _terms.Remove(v); } else { coeff.Value = new_coefficient; } } else { if (!Cl.Approx(c, 0.0)) { _terms.Add(v, new ClDouble(c)); } } return(this); }
public ClLinearEquation(ClLinearExpression cle, ClAbstractVariable clv, ClStrength strength, double weight) : base((ClLinearExpression) cle.Clone(), strength, weight) { _expression.AddVariable(clv, -1.0); }
/// <summary> /// Variable v has been removed from an expression. If the /// expression is in a tableau the corresponding basic variable is /// subject (or if subject is nil then it's in the objective function). /// Update the column cross-indices. /// </summary> public void NoteRemovedVariable(ClAbstractVariable v, ClAbstractVariable subject) { if (subject != null) { _columns[v].Remove(subject); } }
/// <summary> /// Remove the basic variable v from the tableau row v=expr /// Then update column cross indices. /// </summary> protected ClLinearExpression RemoveRow(ClAbstractVariable var) /*throws ExCLInternalError*/ { var expr = _rows[var]; if (expr == null) { throw new CassowaryInternalException("linear expression is 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 (var varset in expr.Terms.Keys.Select(clv => _columns[clv]).Where(varset => varset != null)) { varset.Remove(var); } InfeasibleRows.Remove(var); if (var.IsExternal) { ExternalRows.Remove((ClVariable)var); } _rows.Remove(var); return(expr); }
public ClLinearInequality(ClLinearExpression cle, byte op_enum, ClAbstractVariable clv, ClStrength strength) : this(cle, op_enum, clv, strength, 1.0) /* throws ExClInternalError */ { }
/// <summary> /// v has been added to the linear expression for subject /// update column cross indices. /// </summary> public void NoteAddedVariable(ClAbstractVariable v, ClAbstractVariable subject) { if (subject != null) { InsertColVar(v, subject); } }
public ClLinearEquation(ClLinearExpression cle, ClAbstractVariable clv, ClStrength strength, double weight) : base((ClLinearExpression)cle.Clone(), strength, weight) { _expression.AddVariable(clv, -1.0); }
/// <summary> /// Add a term c*v to this expression. If the expression already /// contains a term involving v, add c to the existing coefficient. /// If the new coefficient is approximately 0, delete v. /// </summary> public ClLinearExpression AddVariable(ClAbstractVariable v, double c = 1.0) { ClDouble coeff; if (_terms.TryGetValue(v, out coeff)) { double newCoefficient = coeff.Value + c; if (Approx(newCoefficient, 0.0)) { _terms.Remove(v); } else { coeff.Value = newCoefficient; } } else { if (!Approx(c, 0.0)) { _terms.Add(v, new ClDouble(c)); } } return(this); }
/// <summary> /// Add a term c*v to this expression. If the expression already /// contains a term involving v, add c to the existing coefficient. /// If the new coefficient is approximately 0, delete v. Notify the /// solver if v appears or disappears from this expression. /// </summary> public ClLinearExpression AddVariable(ClAbstractVariable v, double c, ClAbstractVariable subject, ClTableau solver) { ClDouble coeff = _terms[v]; if (coeff != null) { double newCoefficient = coeff.Value + c; if (Approx(newCoefficient, 0.0)) { solver.NoteRemovedVariable(v, subject); _terms.Remove(v); } else { coeff.Value = newCoefficient; } } else { if (!Approx(c, 0.0)) { _terms.Add(v, new ClDouble(c)); solver.NoteAddedVariable(v, subject); } } return(this); }
/// <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); } } }
/// <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> /// 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); } }
// 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()); } }
public override string ToString() { String s = ""; IDictionaryEnumerator e = _terms.GetEnumerator(); if (!Approx(_constant.Value, 0.0) || _terms.Count == 0) { s += _constant.ToString(); } else { if (_terms.Count == 0) { return(s); } e.MoveNext(); // go to first element ClAbstractVariable clv = (ClAbstractVariable)e.Key; ClDouble coeff = _terms[clv]; s += string.Format("{0}*{1}", coeff, clv); } while (e.MoveNext()) { ClAbstractVariable clv = (ClAbstractVariable)e.Key; ClDouble coeff = _terms[clv]; s += string.Format(" + {0}*{1}", coeff, clv); } return(s); }
/// <summary> /// v has been added to the linear expression for subject /// update column cross indices. /// </summary> public /*sealed*/ void NoteAddedVariable(ClAbstractVariable v, ClAbstractVariable subject) { if (Trace) FnEnterPrint(string.Format("NoteAddedVariable: {0}, {1}", v, subject)); if (subject != null) { InsertColVar(v, subject); } }
protected ClLinearExpression RowExpression(ClAbstractVariable v) { // if (Trace) FnEnterPrint(string.Format("rowExpression: {0}", v)); ClLinearExpression exp; _rows.TryGetValue(v, out exp); return(exp); }
/// <summary> /// Variable v has been removed from an expression. If the /// expression is in a tableau the corresponding basic variable is /// subject (or if subject is nil then it's in the objective function). /// Update the column cross-indices. /// </summary> public /*sealed*/ void NoteRemovedVariable(ClAbstractVariable v, ClAbstractVariable subject) { if (Trace) FnEnterPrint(string.Format("NoteRemovedVariable: {0}, {1}", v, subject)); if (subject != null) { ((Set) _columns[v]).Remove(subject); } }
/// <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); } }
/// <summary> /// Protected convenience function to insert an error variable /// into the _errorVars set, creating the mapping with Add as necessary. /// </summary> protected void InsertErrorVar(ClConstraint cn, ClAbstractVariable var) { HashSet <ClAbstractVariable> cnset; if (!_errorVars.TryGetValue(cn, out cnset)) { _errorVars.Add(cn, cnset = new HashSet <ClAbstractVariable>()); } cnset.Add(var); }
public ClLinearExpression(ClAbstractVariable clv, double value = 1, double constant = 0) { _constant = new ClDouble(constant); _terms = new Dictionary <ClAbstractVariable, ClDouble>(); if (clv != null) { _terms.Add(clv, new ClDouble(value)); } }
/// <summary> /// v has been added to the linear expression for subject /// update column cross indices. /// </summary> public /*sealed*/ void NoteAddedVariable(ClAbstractVariable v, ClAbstractVariable subject) { if (Trace) { FnEnterPrint(string.Format("NoteAddedVariable: {0}, {1}", v, subject)); } if (subject != null) { InsertColVar(v, subject); } }
/// <summary> /// Convenience function to insert a variable into /// the set of rows stored at _columns[param_var], /// creating a new set if needed. /// </summary> private void InsertColVar(ClAbstractVariable paramVar, ClAbstractVariable rowvar) { HashSet <ClAbstractVariable> rowset; if (!_columns.TryGetValue(paramVar, out rowset)) { _columns.Add(paramVar, rowset = new HashSet <ClAbstractVariable>()); } rowset.Add(rowvar); }
/// <summary> /// This linear expression currently represents the equation self=0. Destructively modify it so /// that subject=self represents an equivalent equation. /// /// Precondition: subject must be one of the variables in this expression. /// NOTES /// Suppose this expression is /// c + a*subject + a1*v1 + ... + an*vn /// representing /// c + a*subject + a1*v1 + ... + an*vn = 0 /// The modified expression will be /// subject = -c/a - (a1/a)*v1 - ... - (an/a)*vn /// representing /// subject = -c/a - (a1/a)*v1 - ... - (an/a)*vn /// /// Note that the term involving subject has been dropped. /// Returns the reciprocal, so changeSubject can use it, too /// </summary> public double NewSubject(ClAbstractVariable subject) { ClDouble coeff = _terms[subject]; _terms.Remove(subject); double reciprocal = 1.0 / coeff.Value; MultiplyMe(-reciprocal); return(reciprocal); }
/// <summary> /// Variable v has been removed from an expression. If the /// expression is in a tableau the corresponding basic variable is /// subject (or if subject is nil then it's in the objective function). /// Update the column cross-indices. /// </summary> public /*sealed*/ void NoteRemovedVariable(ClAbstractVariable v, ClAbstractVariable subject) { if (Trace) { FnEnterPrint(string.Format("NoteRemovedVariable: {0}, {1}", v, subject)); } if (subject != null) { ((Set)_columns[v]).Remove(subject); } }
/// <summary> /// Convenience function to insert a variable into /// the set of rows stored at _columns[param_var], /// creating a new set if needed. /// </summary> private /*sealed*/ void InsertColVar(ClAbstractVariable param_var, ClAbstractVariable rowvar) { Set rowset = (Set)_columns[param_var]; if (rowset == null) { _columns.Add(param_var, rowset = new Set()); } rowset.Add(rowvar); }
/// <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 ClLinearExpression AddExpression(ClLinearExpression expr, double n, ClAbstractVariable subject, ClTableau solver) { IncrementConstant(n * expr.Constant); foreach (ClAbstractVariable clv in expr.Terms.Keys) { double coeff = (expr.Terms[clv]).Value; AddVariable(clv, coeff * n, subject, solver); } return(this); }
/// <summary> /// This linear expression currently represents the equation /// oldSubject=self. Destructively modify it so that it represents /// the equation newSubject=self. /// /// Precondition: newSubject currently has a nonzero coefficient in /// this expression. /// /// NOTES /// Suppose this expression is c + a*newSubject + a1*v1 + ... + an*vn. /// /// Then the current equation is /// oldSubject = c + a*newSubject + a1*v1 + ... + an*vn. /// The new equation will be /// newSubject = -c/a + oldSubject/a - (a1/a)*v1 - ... - (an/a)*vn. /// Note that the term involving newSubject has been dropped. /// </summary> public /*sealed*/ void ChangeSubject(ClAbstractVariable old_subject, ClAbstractVariable new_subject) { ClDouble cld = (ClDouble)_terms[old_subject]; if (cld != null) { cld.Value = NewSubject(new_subject); } else { _terms.Add(old_subject, new ClDouble(NewSubject(new_subject))); } }
/// <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> /// Return the coefficient corresponding to variable var, i.e., /// the 'ci' corresponding to the 'vi' that var is: /// v1*c1 + v2*c2 + .. + vn*cn + c /// </summary> public double CoefficientFor(ClAbstractVariable var) { ClDouble coeff; if (_terms.TryGetValue(var, out coeff) && coeff != null) { return(coeff.Value); } else { return(0.0); } }
public ClLinearExpression(ClAbstractVariable clv, double value, double constant) { if (Cl.GC) { Console.Error.WriteLine("new ClLinearExpression"); } _constant = new ClDouble(constant); _terms = new Hashtable(1); if (clv != null) _terms.Add(clv, new ClDouble(value)); }
/// <summary> /// Return the coefficient corresponding to variable var, i.e., /// the 'ci' corresponding to the 'vi' that var is: /// v1*c1 + v2*c2 + .. + vn*cn + c /// </summary> public double CoefficientFor(ClAbstractVariable var) { ClDouble coeff = _terms[var]; if (coeff != null) { return(coeff.Value); } else { return(0.0); } }
/// <summary> /// This linear expression currently represents the equation /// oldSubject=self. Destructively modify it so that it represents /// the equation newSubject=self. /// /// Precondition: newSubject currently has a nonzero coefficient in /// this expression. /// /// NOTES /// Suppose this expression is c + a*newSubject + a1*v1 + ... + an*vn. /// /// Then the current equation is /// oldSubject = c + a*newSubject + a1*v1 + ... + an*vn. /// The new equation will be /// newSubject = -c/a + oldSubject/a - (a1/a)*v1 - ... - (an/a)*vn. /// Note that the term involving newSubject has been dropped. /// </summary> public void ChangeSubject(ClAbstractVariable oldSubject, ClAbstractVariable newSubject) { ClDouble cld; if (_terms.TryGetValue(oldSubject, out cld)) { cld.Value = NewSubject(newSubject); } else { _terms.Add(oldSubject, new ClDouble(NewSubject(newSubject))); } }
/// <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); } }
/// <summary> /// Convenience function for creating a linear inequality constraint. /// </summary> public ClSimplexSolver AddUpperBound(ClAbstractVariable v, double upper) /* throws ExClRequiredFailure, ExClInternalError */ { ClLinearInequality cn = new ClLinearInequality(v, Cl.LEQ, new ClLinearExpression(upper)); return AddConstraint(cn); }
/// <summary> /// Convenience function for creating a pair of linear inequality constraints. /// </summary> public ClSimplexSolver AddBounds(ClAbstractVariable v, double lower, double upper) /* throws ExClRequiredFailure, ExClInternalError */ { AddLowerBound(v, lower); AddUpperBound(v, upper); return this; }
/// <summary> /// Convenience function to insert a variable into /// the set of rows stored at _columns[param_var], /// creating a new set if needed. /// </summary> private /*sealed*/ void InsertColVar(ClAbstractVariable param_var, ClAbstractVariable rowvar) { Set rowset = (Set) _columns[param_var]; if (rowset == null) _columns.Add(param_var, rowset = new Set()); rowset.Add(rowvar); }
public ClLinearEquation(ClLinearExpression cle, ClAbstractVariable clv) : this(cle, clv, ClStrength.Required, 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> /// 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); } }
/// <summary> /// This linear expression currently represents the equation /// oldSubject=self. Destructively modify it so that it represents /// the equation newSubject=self. /// /// Precondition: newSubject currently has a nonzero coefficient in /// this expression. /// /// NOTES /// Suppose this expression is c + a*newSubject + a1*v1 + ... + an*vn. /// /// Then the current equation is /// oldSubject = c + a*newSubject + a1*v1 + ... + an*vn. /// The new equation will be /// newSubject = -c/a + oldSubject/a - (a1/a)*v1 - ... - (an/a)*vn. /// Note that the term involving newSubject has been dropped. /// </summary> public /*sealed*/ void ChangeSubject(ClAbstractVariable old_subject, ClAbstractVariable new_subject) { ClDouble cld = (ClDouble) _terms[old_subject]; if (cld != null) cld.Value = NewSubject(new_subject); else _terms.Add(old_subject, new ClDouble(NewSubject(new_subject))); }
/// <summary> /// Add a term c*v to this expression. If the expression already /// contains a term involving v, add c to the existing coefficient. /// If the new coefficient is approximately 0, delete v. Notify the /// solver if v appears or disappears from this expression. /// </summary> public /*sealed*/ ClLinearExpression AddVariable(ClAbstractVariable v, double c, ClAbstractVariable subject, ClTableau solver) { // body largely duplicated above if (Trace) FnEnterPrint(string.Format("AddVariable: {0}, {1}, {2}, ...", v, c, subject)); ClDouble coeff = (ClDouble) _terms[v]; if (coeff != null) { double new_coefficient = coeff.Value + c; if (Cl.Approx(new_coefficient, 0.0)) { solver.NoteRemovedVariable(v, subject); _terms.Remove(v); } else { coeff.Value = new_coefficient; } } else { if (!Cl.Approx(c, 0.0)) { _terms.Add(v, new ClDouble(c)); solver.NoteAddedVariable(v, subject); } } return this; }
/// <summary> /// This linear expression currently represents the equation self=0. Destructively modify it so /// that subject=self represents an equivalent equation. /// /// Precondition: subject must be one of the variables in this expression. /// NOTES /// Suppose this expression is /// c + a*subject + a1*v1 + ... + an*vn /// representing /// c + a*subject + a1*v1 + ... + an*vn = 0 /// The modified expression will be /// subject = -c/a - (a1/a)*v1 - ... - (an/a)*vn /// representing /// subject = -c/a - (a1/a)*v1 - ... - (an/a)*vn /// /// Note that the term involving subject has been dropped. /// Returns the reciprocal, so changeSubject can use it, too /// </summary> public /*sealed*/ double NewSubject(ClAbstractVariable subject) { if (Trace) FnEnterPrint(string.Format("newSubject: {0}", subject)); ClDouble coeff = (ClDouble) _terms[subject]; _terms.Remove(subject); double reciprocal = 1.0 / coeff.Value; MultiplyMe(-reciprocal); return reciprocal; }
public ClLinearEquation(ClAbstractVariable clv, double val, ClStrength strength) : this(clv, val, strength, 1.0) {}
public ClLinearEquation(ClAbstractVariable clv, double val) : this(clv, val, ClStrength.Required, 1.0) {}
public ClLinearExpression(ClAbstractVariable clv, double value) : this(clv, value, 0.0) {}
/// <summary> /// Return the coefficient corresponding to variable var, i.e., /// the 'ci' corresponding to the 'vi' that var is: /// v1*c1 + v2*c2 + .. + vn*cn + c /// </summary> public /*sealed*/ double CoefficientFor(ClAbstractVariable var) { ClDouble coeff = (ClDouble) _terms[var]; if (coeff != null) return coeff.Value; else return 0.0; }
public ClLinearInequality(ClLinearExpression cle, byte op_enum, ClAbstractVariable clv, ClStrength strength, double weight) : base((ClLinearExpression) cle.Clone(), strength, weight) /* throws ExClInternalError */ { switch (op_enum) { case Cl.LEQ: _expression.MultiplyMe(-1.0); _expression.AddVariable(clv); break; case Cl.GEQ: _expression.AddVariable(clv, -1.0); break; default: // invalid operator throw new ExClInternalError("Invalid operator in ClLinearInequality constructor"); } }
/// <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); }
protected /*sealed*/ ClLinearExpression RowExpression(ClAbstractVariable v) { // if (Trace) FnEnterPrint(string.Format("rowExpression: {0}", v)); return (ClLinearExpression) _rows[v]; }
public ClLinearExpression(ClAbstractVariable clv) : this(clv, 1, 0) {}
/// <summary> /// Return true if and only if the variable subject is in the columns keys /// </summary> protected /*sealed*/ bool ColumnsHasKey(ClAbstractVariable subject) { return _columns.ContainsKey(subject); }
/// <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) { if (Trace) FnEnterPrint("DeltaEditConstant :" + delta + ", " + plusErrorVar + ", " + 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; } Set columnVars = (Set) _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> /// 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; }
/// <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 */ { if (Trace) FnEnterPrint("Pivot: " + entryVar + ", " + exitVar); // 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); }
// 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> /// Protected convenience function to insert an error variable /// into the _errorVars set, creating the mapping with Add as necessary. /// </summary> protected void InsertErrorVar(ClConstraint cn, ClAbstractVariable var) { if (Trace) FnEnterPrint("InsertErrorVar: " + cn + ", " + var); Set cnset = (Set) _errorVars[cn]; if (cnset == null) _errorVars.Add(cn, cnset = new Set()); cnset.Add(var); }
public ClLinearInequality(ClLinearExpression cle, byte op_enum, ClAbstractVariable clv) : this(cle, op_enum, clv, ClStrength.Required, 1.0) /* throws ExClInternalError */ {}
public ClLinearEquation(ClLinearExpression cle, ClAbstractVariable clv, ClStrength strength) : this(cle, clv, strength, 1.0) {}