/// <remarks>
    /// Constructor initializes the fields, and creaties the objective row.
    /// </remarks>
    public ClSimplexSolver()
    { 
      _stayMinusErrorVars = new ArrayList();
      _stayPlusErrorVars = new ArrayList();
      _errorVars = new Hashtable();
      _markerVars = new Hashtable();

      _resolve_pair = new ArrayList(2);
      _resolve_pair.Add(new ClDouble(0));
      _resolve_pair.Add(new ClDouble(0));

      _objective = new ClObjectiveVariable("Z");

      _editVarMap = new Hashtable();

      _slackCounter = 0;
      _artificialCounter = 0;
      _dummyCounter = 0;
      _epsilon = 1e-8;

      _cOptimizeAutomatically = true;
      _cNeedsSolving = false;

      ClLinearExpression e = new ClLinearExpression();
      _rows.Add(_objective, e);
      _stkCedcns = new Stack();
      _stkCedcns.Push(0);

      if (Trace)
        TracePrint("objective expr == " + RowExpression(_objective));
    }
        /// <summary>
        /// Minimize the value of the objective.
        /// </summary>
        /// <remarks>
        /// The tableau should already be feasible.
        /// </remarks>
        private void Optimize(ClObjectiveVariable zVar)
        /* throws ExClInternalError */
        {
            ClLinearExpression zRow = RowExpression(zVar);

            if (zRow == null)
            {
                throw new CassowaryInternalException("Assertion failed: zRow != null");
            }

            ClAbstractVariable entryVar = null;
            ClAbstractVariable exitVar  = null;

            while (true)
            {
                double objectiveCoeff = 0;
                foreach (var kvp in zRow.Terms)
                {
                    if (kvp.Key.IsPivotable && kvp.Value.Value < objectiveCoeff)
                    {
                        objectiveCoeff = kvp.Value.Value;
                        entryVar       = kvp.Key;
                    }
                }

                if (objectiveCoeff >= -EPSILON || entryVar == null)
                {
                    return;
                }

                double minRatio = Double.MaxValue;
                foreach (ClAbstractVariable v in Columns[entryVar])
                {
                    if (v.IsPivotable)
                    {
                        ClLinearExpression expr  = RowExpression(v);
                        double             coeff = expr.CoefficientFor(entryVar);
                        if (coeff < 0.0)
                        {
                            double r = -expr.Constant / coeff;
                            if (r < minRatio)
                            {
                                minRatio = r;
                                exitVar  = v;
                            }
                        }
                    }
                }
// ReSharper disable CompareOfFloatsByEqualityOperator
                if (minRatio == Double.MaxValue)
// ReSharper restore CompareOfFloatsByEqualityOperator
                {
                    throw new CassowaryInternalException("Objective function is unbounded in Optimize");
                }
                Pivot(entryVar, exitVar);
            }
        }
        //// END PUBLIC INTERFACE ////

        /// <summary>
        /// Add the constraint expr=0 to the inequality tableau using an
        /// artificial variable.
        /// </summary>
        /// <remarks>
        /// To do this, create an artificial variable av and add av=expr
        /// to the inequality tableau, then make av be 0 (raise an exception
        /// if we can't attain av=0).
        /// </remarks>
        private void AddWithArtificialVariable(ClLinearExpression expr)
        /* throws ExClRequiredFailure, ExClInternalError */
        {
            ClSlackVariable     av    = new ClSlackVariable(++_artificialCounter, "a");
            ClObjectiveVariable az    = new ClObjectiveVariable("az");
            ClLinearExpression  azRow = expr.Clone();

            AddRow(az, azRow);
            AddRow(av, expr);

            Optimize(az);

            ClLinearExpression azTableauRow = RowExpression(az);

            if (!Approx(azTableauRow.Constant, 0.0))
            {
                RemoveRow(az);
                RemoveColumn(av);
                throw new CassowaryRequiredFailureException();
            }

            // see if av is a basic variable
            ClLinearExpression e = RowExpression(av);

            if (e != null)
            {
                // find another variable in this row and pivot,
                // so that av becomes parametric
                if (e.IsConstant)
                {
                    // if there isn't another variable in the row
                    // then the tableau contains the equation av=0 --
                    // just delete av's row
                    RemoveRow(av);
                    RemoveRow(az);
                    return;
                }
                ClAbstractVariable entryVar = e.AnyPivotableVariable();
                Pivot(entryVar, av);
            }
            Assert(RowExpression(av) == null, "RowExpression(av) == null)");
            RemoveColumn(av);
            RemoveRow(az);
        }
    //// END PUBLIC INTERFACE ////
    
    /// <summary>
    /// Add the constraint expr=0 to the inequality tableau using an
    /// artificial variable.
    /// </summary>
    /// <remarks>
    /// To do this, create an artificial variable av and add av=expr
    /// to the inequality tableau, then make av be 0 (raise an exception
    /// if we can't attain av=0).
    /// </remarks>
    protected void AddWithArtificialVariable(ClLinearExpression expr)
      /* throws ExClRequiredFailure, ExClInternalError */
    {
      if (Trace)
        FnEnterPrint("AddWithArtificialVariable: " + expr);

      ClSlackVariable av = new ClSlackVariable(++_artificialCounter, "a");
      ClObjectiveVariable az = new ClObjectiveVariable("az");
      ClLinearExpression azRow = (ClLinearExpression) expr.Clone();
      
      if (Trace)
        TracePrint("before AddRows:\n" + this);

      AddRow(az, azRow);
      AddRow(av, expr);

      if (Trace)
        TracePrint("after AddRows:\n" + this);
      
      Optimize(az);

      ClLinearExpression azTableauRow = RowExpression(az);

      if (Trace)
        TracePrint("azTableauRow.Constant == " + azTableauRow.Constant);

      if (!Cl.Approx(azTableauRow.Constant, 0.0))
      {
        RemoveRow(az);
        RemoveColumn(av);
        throw new ExClRequiredFailure();
      }

      // see if av is a basic variable
      ClLinearExpression e = RowExpression(av);

      if (e != null)
      {
        // find another variable in this row and pivot,
        // so that av becomes parametric
        if (e.IsConstant)
        {
          // if there isn't another variable in the row
          // then the tableau contains the equation av=0 --
          // just delete av's row
          RemoveRow(av);
          RemoveRow(az);
          return;
        }
        ClAbstractVariable entryVar = e.AnyPivotableVariable();
        Pivot(entryVar, av);
      }
      Assert(RowExpression(av) == null, "RowExpression(av) == null)");
      RemoveColumn(av);
      RemoveRow(az);
    }
    /// <summary>
    /// Minimize the value of the objective.
    /// </summary>
    /// <remarks>
    /// The tableau should already be feasible.
    /// </remarks>
    protected void Optimize(ClObjectiveVariable zVar)
      /* throws ExClInternalError */
    {
      if (Trace) 
      {
        FnEnterPrint("Optimize: " + zVar);
        TracePrint(this.ToString());
      }

      ClLinearExpression zRow = RowExpression(zVar);
      Assert(zRow != null, "zRow != null");
      ClAbstractVariable entryVar = null;
      ClAbstractVariable exitVar = null;
      while (true)
      {
        double objectiveCoeff = 0;
        Hashtable terms = zRow.Terms;
        foreach (ClAbstractVariable v in terms.Keys)
        {
          double c = ((ClDouble) terms[v]).Value;
          if (v.IsPivotable && c < objectiveCoeff)
          {
            objectiveCoeff = c;
            entryVar = v;
          }
        }
        if (objectiveCoeff >= -_epsilon || entryVar == null)
          return;
        if (Trace)
          TracePrint("entryVar == " + entryVar + ", objectiveCoeff == " + objectiveCoeff);

        double minRatio = Double.MaxValue;
        Set columnVars = (Set) _columns[entryVar];
        double r = 0.0;
        foreach (ClAbstractVariable v in columnVars)
        {
          if (Trace)
            TracePrint("Checking " + v);
          if (v.IsPivotable)
          {
            ClLinearExpression expr = RowExpression(v);
            double coeff = expr.CoefficientFor(entryVar);
            if (Trace)
              TracePrint("pivotable, coeff == " + coeff);
            if (coeff < 0.0)
            {
              r = - expr.Constant / coeff;
              if (r < minRatio)
              {
                if (Trace)
                  TracePrint("New minRatio == " + r);
                minRatio = r;
                exitVar = v;
              }
            }
          }
        }
        if (minRatio == Double.MaxValue)
        {
          throw new ExClInternalError("Objective function is unbounded in Optimize");
        }
        Pivot(entryVar, exitVar);
        if (Trace)
          TracePrint(this.ToString());
      }
    }