/// <summary>
 /// Add an edit constraint for a variable with a given strength.
 /// <param name="v">Variable to add an edit constraint to.</param>
 /// <param name="strength">Strength of the edit constraint.</param>
 /// </summary>
 public ClSimplexSolver AddEditVar(ClVariable v, ClStrength strength)
   /* throws ExClInternalError */
 {
   try 
   {
     ClEditConstraint cnEdit = new ClEditConstraint(v, strength);
     return AddConstraint(cnEdit);
   }
   catch (ExClRequiredFailure)
   {
     // should not get this
     throw new ExClInternalError("Required failure when adding an edit variable");
   }
 }
        /// <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);
        }