Example #1
0
 public ClEditInfo(ClConstraint cn, ClSlackVariable eplus, 
                   ClSlackVariable eminus, double prevEditConstant,
                   int i)
 {
   _cn = cn;
   _clvEditPlus = eplus;
   _clvEditMinus = eminus;
   _prevEditConstant = prevEditConstant;
   _i = i;
 }
 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);
        }