Example #1
0
        private static Model NewHelper(out Variable[] variables, Func <int, bool> isIntegerFunc, Func <int, string> columnNameFunc, Func <int, string> rowNameFunc,
                                       double[] colLower, double[] colUpper, string objName, double[] objCoefs, int numberVariables, int numberConstraints, char[] rowSenses, CoinPackedMatrix rowMatrix, double[] rowLowers, double[] rowUppers)
        {
            Model model = new Model();

            variables = new Variable[numberVariables];

            Expression objExpr = new Expression();

            int i = 0;

            for (i = 0; i < numberVariables; i++)
            {
                Variable var = new Variable();
                variables[i] = var;

                double lower     = colLower[i];
                double upper     = colUpper[i];
                bool   isInteger = isIntegerFunc.Invoke(i);

                string name = columnNameFunc.Invoke(i);
                if (!string.IsNullOrEmpty(name))
                {
                    var.Name = name;
                }
                else
                {
                    var.Name = string.Concat("VAR", i);
                }

                var.Lower = lower;
                var.Upper = upper;
                var.Type  = (isInteger) ? VariableType.Integer : VariableType.Continuous;

                objExpr.Add(objCoefs[i], var);
            }

            model.Objective      = new Objective(objName, objExpr);
            model.ObjectiveSense = ObjectiveSense.Minimise;
            // NOTE: MPS DOESNT STORE MAXIMIZATION OR MINIMIZATION!
            // bUT LP always returns Minimization (and transforms objective accordingly if original is max)

            for (int j = 0; j < numberConstraints; j++)
            {
                Expression expr = new Expression();
                CoinShallowPackedVector vector = rowMatrix.getVector(j); // I guess..
                int      nElements             = vector.getNumElements();
                int[]    indices  = vector.getIndices();
                double[] elements = vector.getElements();

                for (int e = 0; e < nElements; e++)
                {
                    int      index = indices[e];
                    Variable var   = variables[index];
                    double   coef  = elements[e];

                    expr.Add(coef, var);
                }

                double lower = rowLowers[j];
                double upper = rowUppers[j];

                string name = rowNameFunc.Invoke(j);
                string conName;
                if (!string.IsNullOrEmpty(name))
                {
                    conName = name;
                }
                else
                {
                    conName = string.Concat("CON", i);
                }

                switch (rowSenses[j])
                {
                case 'L':     //<= constraint and rhs()[i] == rowupper()[i]
                {
                    ConstraintType type      = ConstraintType.LE;
                    Expression     upperExpr = new Expression(upper);
                    Constraint     con       = new Constraint(conName, expr, type, upperExpr);
                    upperExpr.Clear();
                    model.Add(con);
                    break;
                }

                case 'E':     //=  constraint
                {
                    ConstraintType type      = ConstraintType.EQ;
                    Expression     upperExpr = new Expression(upper);
                    Constraint     con       = new Constraint(conName, expr, type, upperExpr);
                    upperExpr.Clear();
                    model.Add(con);
                    break;
                }

                case 'G':     //>= constraint and rhs()[i] == rowlower()[i]
                {
                    ConstraintType type      = ConstraintType.GE;
                    Expression     lowerExpr = new Expression(lower);
                    Constraint     con       = new Constraint(conName, expr, type, lowerExpr);
                    lowerExpr.Clear();
                    model.Add(con);
                    break;
                }

                case 'R':     //ranged constraint
                {
                    RangeConstraint con = new RangeConstraint(conName, lower, expr, upper);
                    model.Add(con);
                    break;
                }

                case 'N':     //free constraint
                {
                    RangeConstraint con = new RangeConstraint(conName, lower, expr, upper);
                    con.Enabled = false;
                    model.Add(con);
                    break;
                }

                default:
                    break;
                }
            }
            return(model);
        }
Example #2
0
        /// <summary>
        /// Creates a new model from the given file. The name of the model will be the filename.
        /// </summary>
        /// <param name="fileName">The mps or lp file to be imported.</param>
        /// <param name="variables">The full array of variables created for this new model.</param>
        /// <returns>The new model, or an exception if an error occurred.</returns>
        public static Model New(string fileName, out Variable[] variables)
        {
            string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fileName);
            string extension = Path.GetExtension(fileName).ToLower();

            Model model = null;

            if (extension.Equals(".mps"))
            {
                #region New Model from .mps file
                string directoryName = Path.GetDirectoryName(fileName);
                if (directoryName.Length == 0)
                {
                    directoryName = ".";
                }

                string fullPathWithoutExtension = Path.Combine(directoryName, fileNameWithoutExtension);

                // Previously, CoinMpsIO was used but that doesnt read quad info.
                // To read MPS with QUAD info use ClpModel or CoinModel readMps.
                // CoinModel we havent Wrapped yet at all, so more work.
                // ClpModel (ClpSimplex) doesnt do row Sense needed for here, only lb / ub.
                // ClpModel also doesnt save the Objective name.
                // OsiClp can create row sense from lb / ub, but OsiClp uses CoinMpsIO, so cannot read Quad from OsiClp
                // So we use ClpSimplex to read the file, but use an OsiClp of it for rowsense

                ClpSimplex            m      = new ClpSimplex();
                OsiClpSolverInterface osiClp = new OsiClpSolverInterface(m);
                log.PassToClpModel(m);

                int numberErrors = m.readMps(fileName, true, false);
                if (numberErrors != 0)
                {
                    string message = string.Format("Errors occurred when reading the mps file '{0}'.", fileName);
                    SonnetLog.Default.Error(message);
                    throw new SonnetException(message);
                }

                // set objective function offest
                // Skip this: setDblParam(OsiObjOffset,m.objectiveOffset())

                //ClpModel  has ClpObjective which may be an implementatin of ClpQuadObjective.
                // This can be found by obj->type() == 2 (QuadCoef)

                bool             fullQuadraticMatrix = false;
                CoinPackedMatrix quadraticObjective  = null;
                ClpObjective     clpObjective        = m.objectiveAsObject();
                if (clpObjective is ClpQuadraticObjective clpQuadraticObjective)
                {
                    Ensure.IsTrue(clpObjective.type() == 2, $"Quadratic Objective must be type 2 but is {clpObjective.type()}.");
                    fullQuadraticMatrix = clpQuadraticObjective.fullMatrix();
                    quadraticObjective  = clpQuadraticObjective.quadraticObjective();
                }

                model = NewHelper(out variables, m.isInteger, m.columnName, m.rowName,
                                  m.getColLower(), m.getColUpper(), "OBJROW", m.getObjCoefficients(),
                                  m.getNumCols(), m.getNumRows(), osiClp.getRowSense(), osiClp.getMatrixByRow(), m.getRowLower(), m.getRowUpper(), fullQuadraticMatrix, quadraticObjective);

                model.Name = fileNameWithoutExtension;
                #endregion
            }
            else if (extension.Equals(".lp"))
            {
                #region New Model from .lp file
                CoinLpIO m = new CoinLpIO();
                log.PassToCoinLpIO(m);

                m.setInfinity(MathUtils.Infinity);
                // If the original problem is
                // a maximization problem, the objective function is immediadtly
                // flipped to get a minimization problem.
                m.readLp(fileName);

                model = NewHelper(out variables, m.isInteger, m.columnName, m.rowName,
                                  m.getColLower(), m.getColUpper(), m.getObjName(), m.getObjCoefficients(),
                                  m.getNumCols(), m.getNumRows(), m.getRowSense(), m.getMatrixByRow(), m.getRowLower(), m.getRowUpper(), false, null);

                model.Name = fileNameWithoutExtension;
                #endregion
            }
            else
            {
                string message = string.Format("Cannot import file {0} : unknown extension '{1}'.", fileName, extension);
                SonnetLog.Default.Error(message);
                throw new SonnetException(message);
            }

            if (model == null)
            {
                string message = $"An error occured while importing {fileName}. No model created.";
                SonnetLog.Default.Error(message);
                throw new SonnetException(message);
            }

            return(model);
        }