public ClEditInfo(ClConstraint cn, ClSlackVariable eplus, ClSlackVariable eminus, double prevEditConstant, int i) { _cn = cn; _clvEditPlus = eplus; _clvEditMinus = eminus; _prevEditConstant = prevEditConstant; _i = i; }
/// <summary> /// Suggest a new value for an edit variable. /// </summary> /// <remarks> /// The variable needs to be added as an edit variable and /// BeginEdit() needs to be called before this is called. /// The tableau will not be solved completely until after Resolve() /// has been called. /// </remarks> IEditContext IEditContext.SuggestValue(ClVariable v, double x) { ClEditInfo cei = _editVarMap[v]; if (cei == null) { throw new CassowaryException("SuggestValue for variable " + v + ", but var is not an edit variable\n"); } ClSlackVariable clvEditPlus = cei.ClvEditPlus; ClSlackVariable clvEditMinus = cei.ClvEditMinus; double delta = x - cei.PrevEditConstant; cei.PrevEditConstant = x; DeltaEditConstant(delta, clvEditPlus, clvEditMinus); return(this); }
//// 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> /// Add a constraint to the solver. /// <param name="cn"> /// The constraint to be added. /// </param> /// </summary> public ClSimplexSolver AddConstraint(ClConstraint cn) { List <ClAbstractVariable> eplusEminus = new List <ClAbstractVariable>(2); ClDouble prevEConstant = new ClDouble(); ClLinearExpression expr = NewExpression(cn, /* output to: */ eplusEminus, prevEConstant); bool cAddedOkDirectly = TryAddingDirectly(expr); if (!cAddedOkDirectly) { // could not add directly AddWithArtificialVariable(expr); } _cNeedsSolving = true; if (cn.IsEditConstraint) { int i = _editVarMap.Count; ClEditConstraint cnEdit = (ClEditConstraint)cn; ClSlackVariable clvEplus = (ClSlackVariable)eplusEminus[0]; ClSlackVariable clvEminus = (ClSlackVariable)eplusEminus[1]; _editVarMap.Add(cnEdit.Variable, new ClEditInfo(cnEdit, clvEplus, clvEminus, prevEConstant.Value, i)); } if (_cOptimizeAutomatically) { Optimize(_objective); SetExternalVariables(); } return(this); }
//// 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); }
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; }
private ClLinearExpression NewExpression(ClConstraint cn, ICollection <ClAbstractVariable> eplusEminus, ClDouble prevEConstant) { ClLinearExpression cnExpr = cn.Expression; ClLinearExpression expr = new ClLinearExpression(cnExpr.Constant); ClSlackVariable eminus; var cnTerms = cnExpr.Terms; foreach (ClAbstractVariable v in cnTerms.Keys) { double c = (cnTerms[v]).Value; ClLinearExpression e = RowExpression(v); if (e == null) { expr.AddVariable(v, c); } else { expr.AddExpression(e, c); } } if (cn.IsInequality) { ++_slackCounter; ClSlackVariable slackVar = new ClSlackVariable(_slackCounter, "s"); expr.SetVariable(slackVar, -1); _markerVars.Add(cn, slackVar); if (!cn.Strength.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.Strength.IsRequired) { ++_dummyCounter; ClDummyVariable dummyVar = new ClDummyVariable(_dummyCounter, "d"); expr.SetVariable(dummyVar, 1.0); _markerVars.Add(cn, dummyVar); } else { ++_slackCounter; ClSlackVariable 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(); 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) { eplusEminus.Add(eplus); eplusEminus.Add(eminus); prevEConstant.Value = cnExpr.Constant; } } } if (expr.Constant < 0) { expr.MultiplyMe(-1); } return(expr); }
/// <summary> /// Remove a constraint from the tableau. /// Also remove any error variable associated with it. /// </summary> public ClSimplexSolver RemoveConstraint(ClConstraint cn) /* throws ExClRequiredFailure, ExClInternalError */ { _cNeedsSolving = true; ResetStayConstants(); ClLinearExpression zRow = RowExpression(_objective); HashSet <ClAbstractVariable> eVars; if (_errorVars.TryGetValue(cn, out eVars)) { foreach (ClAbstractVariable clv in eVars) { ClLinearExpression expr = RowExpression(clv); if (expr == null) { zRow.AddVariable(clv, -cn.Weight * cn.Strength.SymbolicWeight.AsDouble(), _objective, this); } else // the error variable was in the basis { zRow.AddExpression(expr, -cn.Weight * cn.Strength.SymbolicWeight.AsDouble(), _objective, this); } } } ClAbstractVariable marker; if (!_markerVars.TryGetValue(cn, out marker)) { throw new CassowaryConstraintNotFoundException(); } _markerVars.Remove(cn); if (RowExpression(marker) == null) { // not in the basis, so need to do some more work var col = Columns[marker]; ClAbstractVariable exitVar = null; double minRatio = 0.0; foreach (ClAbstractVariable v in col) { if (v.IsRestricted) { ClLinearExpression expr = RowExpression(v); double coeff = expr.CoefficientFor(marker); if (coeff < 0.0) { double r = -expr.Constant / coeff; if (exitVar == null || r < minRatio) { minRatio = r; exitVar = v; } } } } if (exitVar == null) { foreach (ClAbstractVariable v in col) { if (v.IsRestricted) { ClLinearExpression expr = RowExpression(v); double coeff = expr.CoefficientFor(marker); double r = expr.Constant / coeff; if (exitVar == null || r < minRatio) { minRatio = r; exitVar = v; } } } } if (exitVar == null) { // exitVar is still null if (col.Count == 0) { RemoveColumn(marker); } else { // put first element in exitVar var colEnum = col.GetEnumerator(); colEnum.MoveNext(); exitVar = colEnum.Current; } } if (exitVar != null) { Pivot(marker, exitVar); } } if (RowExpression(marker) != null) { RemoveRow(marker); } if (eVars != null) { foreach (ClAbstractVariable v in eVars.Where(a => a != marker)) { RemoveColumn(v); } } if (cn.IsStayConstraint) { if (eVars != null) { for (int i = 0; i < _stayPlusErrorVars.Count; i++) { eVars.Remove(_stayPlusErrorVars[i]); eVars.Remove(_stayMinusErrorVars[i]); } } } else if (cn.IsEditConstraint) { Assert(eVars != null, "eVars != null"); ClEditConstraint cnEdit = (ClEditConstraint)cn; ClVariable clv = cnEdit.Variable; ClEditInfo cei = _editVarMap[clv]; ClSlackVariable clvEditMinus = cei.ClvEditMinus; RemoveColumn(clvEditMinus); _editVarMap.Remove(clv); } // FIXME: do the remove at top if (eVars != null) { //_errorVars.Remove(eVars); _errorVars.Remove(cn); } if (_cOptimizeAutomatically) { Optimize(_objective); SetExternalVariables(); } return(this); }