Пример #1
0
    static void Main()
    {
        try {
            GRBEnv   env   = new GRBEnv("qp.log");
            GRBModel model = new GRBModel(env);

            // Create variables

            GRBVar x = model.AddVar(0.0, 1.0, 0.0, GRB.CONTINUOUS, "x");
            GRBVar y = model.AddVar(0.0, 1.0, 0.0, GRB.CONTINUOUS, "y");
            GRBVar z = model.AddVar(0.0, 1.0, 0.0, GRB.CONTINUOUS, "z");

            // Set objective

            GRBQuadExpr obj = x * x + x * y + y * y + y * z + z * z + 2 * x;
            model.SetObjective(obj);

            // Add constraint: x + 2 y + 3 z >= 4

            model.AddConstr(x + 2 * y + 3 * z >= 4.0, "c0");

            // Add constraint: x + y >= 1

            model.AddConstr(x + y >= 1.0, "c1");

            // Optimize model

            model.Optimize();

            Console.WriteLine(x.VarName + " " + x.X);
            Console.WriteLine(y.VarName + " " + y.X);
            Console.WriteLine(z.VarName + " " + z.X);

            Console.WriteLine("Obj: " + model.ObjVal + " " + obj.Value);


            // Change variable types to integer

            x.VType = GRB.INTEGER;
            y.VType = GRB.INTEGER;
            z.VType = GRB.INTEGER;

            // Optimize model

            model.Optimize();

            Console.WriteLine(x.VarName + " " + x.X);
            Console.WriteLine(y.VarName + " " + y.X);
            Console.WriteLine(z.VarName + " " + z.X);

            Console.WriteLine("Obj: " + model.ObjVal + " " + obj.Value);

            // Dispose of model and env

            model.Dispose();
            env.Dispose();
        } catch (GRBException e) {
            Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message);
        }
    }
Пример #2
0
        public static GRBQuadExpr SumL2(this GRBVar[] _vars)
        {
            var res = new GRBQuadExpr();

            foreach (var v in _vars)
            {
                res.Add(v * v);
            }
            return(res);
        }
Пример #3
0
        public void GenerateBaseModel(string datFilePath)
        {
            _constraintModel = DatFileParser.ParseDatFile(datFilePath);
            ExampleName      = new FileInfo(datFilePath).Name;

            try
            {
                var path = @"C:\IJCAI\Output\TestRuns\Logs\";
                if (!Directory.Exists(path))
                {
                    Directory.CreateDirectory(path);
                }

                env = new GRBEnv(path + ExampleName + ".log")
                {
                    LogToConsole  = 0,
                    NodefileStart = 0.5
                };
                _model = new GRBModel(env);

                _k = _constraintModel.K;
                _b = _constraintModel.B;

                // Optimization values
                S = _model.AddVar(0.0, _k - 1, 0.0, GRB.CONTINUOUS, "S"); // Number of interrupted job pairs
                L = _model.AddVar(0.0, _k - 1, 0.0, GRB.CONTINUOUS, "L"); // Longest time a cable resides in storage
                M = _model.AddVar(0.0, _k - 1, 0.0, GRB.CONTINUOUS, "M"); // Maximum number of cables stored simultaneously
                N = _model.AddVar(0.0, _k - 1, 0.0, GRB.CONTINUOUS, "N"); // Number of violated soft atomic constraints

                pfc = CreatePermutationVariable();


                // objective
                var objExpr = new GRBQuadExpr();
                objExpr.AddTerm(Math.Pow(_k, 3), S);
                objExpr.AddTerm(Math.Pow(_k, 2), M);
                objExpr.AddTerm(Math.Pow(_k, 1), L);
                objExpr.AddTerm(Math.Pow(_k, 0), N);

                _model.SetObjective(objExpr);


                _model.Parameters.TimeLimit = 300;  // 300 seconds
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
        }
Пример #4
0
    static void Main()
    {
        try {
            // Sample data
            // Sets of days and workers
            string[] Shifts =
                new string[] { "Mon1", "Tue2", "Wed3", "Thu4", "Fri5", "Sat6",
                               "Sun7", "Mon8", "Tue9", "Wed10", "Thu11", "Fri12", "Sat13",
                               "Sun14" };
            string[] Workers =
                new string[] { "Amy", "Bob", "Cathy", "Dan", "Ed", "Fred", "Gu" };

            int nShifts  = Shifts.Length;
            int nWorkers = Workers.Length;

            // Number of workers required for each shift
            double[] shiftRequirements =
                new double[] { 3, 2, 4, 4, 5, 6, 5, 2, 2, 3, 4, 6, 7, 5 };

            // Worker availability: 0 if the worker is unavailable for a shift
            double[,] availability =
                new double[, ] {
                { 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1 },
                { 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0 },
                { 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1 },
                { 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1 },
                { 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1 },
                { 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1 },
                { 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }
            };

            // Model
            GRBEnv   env   = new GRBEnv();
            GRBModel model = new GRBModel(env);

            model.ModelName = "assignment";

            // Assignment variables: x[w][s] == 1 if worker w is assigned
            // to shift s. This is no longer a pure assignment model, so we must
            // use binary variables.
            GRBVar[,] x = new GRBVar[nWorkers, nShifts];
            for (int w = 0; w < nWorkers; ++w)
            {
                for (int s = 0; s < nShifts; ++s)
                {
                    x[w, s] =
                        model.AddVar(0, availability[w, s], 0, GRB.BINARY,
                                     Workers[w] + "." + Shifts[s]);
                }
            }

            // Slack variables for each shift constraint so that the shifts can
            // be satisfied
            GRBVar[] slacks = new GRBVar[nShifts];
            for (int s = 0; s < nShifts; ++s)
            {
                slacks[s] =
                    model.AddVar(0, GRB.INFINITY, 0, GRB.CONTINUOUS,
                                 Shifts[s] + "Slack");
            }

            // Variable to represent the total slack
            GRBVar totSlack = model.AddVar(0, GRB.INFINITY, 0, GRB.CONTINUOUS,
                                           "totSlack");

            // Variables to count the total shifts worked by each worker
            GRBVar[] totShifts = new GRBVar[nWorkers];
            for (int w = 0; w < nWorkers; ++w)
            {
                totShifts[w] = model.AddVar(0, GRB.INFINITY, 0, GRB.CONTINUOUS,
                                            Workers[w] + "TotShifts");
            }

            GRBLinExpr lhs;

            // Constraint: assign exactly shiftRequirements[s] workers
            // to each shift s, plus the slack
            for (int s = 0; s < nShifts; ++s)
            {
                lhs = new GRBLinExpr();
                lhs.AddTerm(1.0, slacks[s]);
                for (int w = 0; w < nWorkers; ++w)
                {
                    lhs.AddTerm(1.0, x[w, s]);
                }
                model.AddConstr(lhs == shiftRequirements[s], Shifts[s]);
            }

            // Constraint: set totSlack equal to the total slack
            lhs = new GRBLinExpr();
            for (int s = 0; s < nShifts; ++s)
            {
                lhs.AddTerm(1.0, slacks[s]);
            }
            model.AddConstr(lhs == totSlack, "totSlack");

            // Constraint: compute the total number of shifts for each worker
            for (int w = 0; w < nWorkers; ++w)
            {
                lhs = new GRBLinExpr();
                for (int s = 0; s < nShifts; ++s)
                {
                    lhs.AddTerm(1.0, x[w, s]);
                }
                model.AddConstr(lhs == totShifts[w], "totShifts" + Workers[w]);
            }

            // Objective: minimize the total slack
            model.SetObjective(1.0 * totSlack);

            // Optimize
            int status = solveAndPrint(model, totSlack, nWorkers, Workers, totShifts);
            if (status != GRB.Status.OPTIMAL)
            {
                return;
            }

            // Constrain the slack by setting its upper and lower bounds
            totSlack.UB = totSlack.X;
            totSlack.LB = totSlack.X;

            // Variable to count the average number of shifts worked
            GRBVar avgShifts =
                model.AddVar(0, GRB.INFINITY, 0, GRB.CONTINUOUS, "avgShifts");

            // Variables to count the difference from average for each worker;
            // note that these variables can take negative values.
            GRBVar[] diffShifts = new GRBVar[nWorkers];
            for (int w = 0; w < nWorkers; ++w)
            {
                diffShifts[w] = model.AddVar(-GRB.INFINITY, GRB.INFINITY, 0,
                                             GRB.CONTINUOUS, Workers[w] + "Diff");
            }

            // Constraint: compute the average number of shifts worked
            lhs = new GRBLinExpr();
            for (int w = 0; w < nWorkers; ++w)
            {
                lhs.AddTerm(1.0, totShifts[w]);
            }
            model.AddConstr(lhs == nWorkers * avgShifts, "avgShifts");

            // Constraint: compute the difference from the average number of shifts
            for (int w = 0; w < nWorkers; ++w)
            {
                model.AddConstr(totShifts[w] - avgShifts == diffShifts[w],
                                Workers[w] + "Diff");
            }

            // Objective: minimize the sum of the square of the difference from the
            // average number of shifts worked
            GRBQuadExpr qobj = new GRBQuadExpr();
            for (int w = 0; w < nWorkers; ++w)
            {
                qobj.AddTerm(1.0, diffShifts[w], diffShifts[w]);
            }
            model.SetObjective(qobj);

            // Optimize
            status = solveAndPrint(model, totSlack, nWorkers, Workers, totShifts);
            if (status != GRB.Status.OPTIMAL)
            {
                return;
            }

            // Dispose of model and env
            model.Dispose();
            env.Dispose();
        } catch (GRBException e) {
            Console.WriteLine("Error code: " + e.ErrorCode + ". " +
                              e.Message);
        }
    }
Пример #5
0
    protected static bool dense_optimize(GRBEnv    env,
                   int       rows,
                   int       cols,
                   double[]  c,      // linear portion of objective function
                   double[,] Q,      // quadratic portion of objective function
                   double[,] A,      // constraint matrix
                   char[]    sense,  // constraint senses
                   double[]  rhs,    // RHS vector
                   double[]  lb,     // variable lower bounds
                   double[]  ub,     // variable upper bounds
                   char[]    vtype,  // variable types (continuous, binary, etc.)
                   double[]  solution)
    {
        bool success = false;

        try {
          GRBModel model = new GRBModel(env);

          // Add variables to the model

          GRBVar[] vars = model.AddVars(lb, ub, null, vtype, null);
          model.Update();

          // Populate A matrix

          for (int i = 0; i < rows; i++) {
        GRBLinExpr expr = new GRBLinExpr();
        for (int j = 0; j < cols; j++)
          if (A[i,j] != 0)
            expr.AddTerm(A[i,j], vars[j]); // Note: '+=' would be much slower
        model.AddConstr(expr, sense[i], rhs[i], "");
          }

          // Populate objective

          GRBQuadExpr obj = new GRBQuadExpr();
          if (Q != null) {
        for (int i = 0; i < cols; i++)
          for (int j = 0; j < cols; j++)
            if (Q[i,j] != 0)
              obj.AddTerm(Q[i,j], vars[i], vars[j]); // Note: '+=' would be much slower
        for (int j = 0; j < cols; j++)
          if (c[j] != 0)
            obj.AddTerm(c[j], vars[j]); // Note: '+=' would be much slower
        model.SetObjective(obj);
          }

          // Solve model

          model.Optimize();

          // Extract solution

          if (model.Get(GRB.IntAttr.Status) == GRB.Status.OPTIMAL) {
        success = true;

        for (int j = 0; j < cols; j++)
          solution[j] = vars[j].Get(GRB.DoubleAttr.X);
          }

          model.Dispose();

        } catch (GRBException e) {
          Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message);
        }

        return success;
    }
Пример #6
0
        public BalanceOutput BalanceGurobiForGLR(double[] x0, double[,] a, double[,] h, double[] d, double[] technologicLowerBound, double[] technologicUpperBound, double[] metrologicLowerBound, double[] metrologicUpperBound)
        {
            try
            {
                GRBEnv   env     = new GRBEnv();
                GRBModel model   = new GRBModel(env);
                double[] results = new double[x0.Length];
                if (inputData.balanceSettings.balanceSettingsConstraints == BalanceSettings.BalanceSettingsConstraints.TECHNOLOGIC)
                {
                    //Create variables
                    GRBVar[] varsTechnologic = new GRBVar[a.Columns()];
                    for (int i = 0; i < varsTechnologic.Length; i++)
                    {
                        varsTechnologic[i] = model.AddVar(technologicLowerBound[i], technologicUpperBound[i], 0.0, GRB.CONTINUOUS, "x" + i);
                    }
                    //Set objective
                    GRBQuadExpr objTechnologic = new GRBQuadExpr();
                    for (int i = 0; i < varsTechnologic.Length; i++)
                    {
                        objTechnologic.AddTerm(h[i, i] / 2.0, varsTechnologic[i], varsTechnologic[i]);
                    }
                    for (int i = 0; i < varsTechnologic.Length; i++)
                    {
                        objTechnologic.AddTerm(d[i], varsTechnologic[i]);
                    }
                    model.SetObjective(objTechnologic);
                    //Add constraints
                    GRBLinExpr expr;
                    for (int i = 0; i < a.Rows(); i++)
                    {
                        expr = new GRBLinExpr();
                        for (int j = 0; j < a.Columns(); j++)
                        {
                            expr.AddTerm(a[i, j], varsTechnologic[j]);
                        }
                        model.AddConstr(expr, GRB.EQUAL, 0.0, "c" + i);
                    }
                    // Optimize model
                    model.Optimize();
                    //results = new double[varsTechnologic.Length];
                    for (int i = 0; i < results.Length; i++)
                    {
                        results[i] = varsTechnologic[i].Get(GRB.DoubleAttr.X);
                    }
                }
                else
                {
                    //Create variables
                    GRBVar[] varsMetrologic = new GRBVar[a.Columns()];
                    for (int i = 0; i < varsMetrologic.Length; i++)
                    {
                        varsMetrologic[i] = model.AddVar(metrologicLowerBound[i], metrologicUpperBound[i], 0.0, GRB.CONTINUOUS, "x" + i);
                    }
                    //Set objective
                    GRBQuadExpr objMetrologic = new GRBQuadExpr();
                    for (int i = 0; i < varsMetrologic.Length; i++)
                    {
                        objMetrologic.AddTerm(h[i, i] / 2.0, varsMetrologic[i], varsMetrologic[i]);
                    }
                    for (int i = 0; i < varsMetrologic.Length; i++)
                    {
                        objMetrologic.AddTerm(d[i], varsMetrologic[i]);
                    }
                    model.SetObjective(objMetrologic);
                    //Add constraints
                    GRBLinExpr expr;
                    for (int i = 0; i < a.Rows(); i++)
                    {
                        expr = new GRBLinExpr();
                        for (int j = 0; j < a.Columns(); j++)
                        {
                            expr.AddTerm(a[i, j], varsMetrologic[j]);
                        }
                        model.AddConstr(expr, GRB.EQUAL, 0.0, "c" + i);
                    }
                    // Optimize model
                    model.Optimize();
                    //results = new double[varsMetrologic.Length];
                    for (int i = 0; i < results.Length; i++)
                    {
                        results[i] = varsMetrologic[i].Get(GRB.DoubleAttr.X);
                    }
                }

                model.Dispose();
                env.Dispose();

                BalanceOutput outb = new BalanceOutput();
                var           balanceOutputVars = new List <OutputVariables>();
                for (int i = 0; i < measuredValues.Count; i++)
                {
                    InputVariables outputVariable = inputData.BalanceInputVariables[i];
                    balanceOutputVars.Add(new OutputVariables()
                    {
                        id     = outputVariable.id,
                        name   = outputVariable.name,
                        value  = results[i],
                        source = outputVariable.sourceId,
                        target = outputVariable.destinationId
                    });
                }
                outb.balanceOutputVariables = balanceOutputVars;
                outb.GlobaltestValue        = GTR;
                outb.Status = "Success";
                return(outb);
            }
            catch (Exception e)
            {
                return(new BalanceOutput
                {
                    Status = e.Message,
                });
            }
        }
Пример #7
0
        public void BalanceGurobi()
        {
            GRBEnv   env   = new GRBEnv();
            GRBModel model = new GRBModel(env);
            DateTime CalculationTimeStart;
            DateTime CalculationTimeFinish;

            double[] results = new double[measuredValues.ToArray().Length];
            if (inputData.balanceSettings.balanceSettingsConstraints == BalanceSettings.BalanceSettingsConstraints.TECHNOLOGIC)
            {
                //Create variables
                GRBVar[] varsTechnologic = new GRBVar[measuredValues.ToArray().Length];
                for (int i = 0; i < varsTechnologic.Length; i++)
                {
                    varsTechnologic[i] = model.AddVar(technologicRangeLowerBound[i], technologicRangeUpperBound[i], 0.0, GRB.CONTINUOUS, "x" + i);
                }
                //Set objective
                GRBQuadExpr objTechnologic = new GRBQuadExpr();
                for (int i = 0; i < varsTechnologic.Length; i++)
                {
                    objTechnologic.AddTerm(H[i, i] / 2.0, varsTechnologic[i], varsTechnologic[i]);
                }
                for (int i = 0; i < varsTechnologic.Length; i++)
                {
                    objTechnologic.AddTerm(dVector[i], varsTechnologic[i]);
                }
                model.SetObjective(objTechnologic);
                //Add constraints
                GRBLinExpr expr;
                for (int i = 0; i < incidenceMatrix.RowCount; i++)
                {
                    expr = new GRBLinExpr();
                    for (int j = 0; j < incidenceMatrix.ColumnCount; j++)
                    {
                        expr.AddTerm(incidenceMatrix[i, j], varsTechnologic[j]);
                    }
                    model.AddConstr(expr, GRB.EQUAL, 0.0, "c" + i);
                }
                // Optimize model
                CalculationTimeStart = DateTime.Now;
                model.Optimize();
                CalculationTimeFinish = DateTime.Now;
                results = new double[varsTechnologic.Length];
                for (int i = 0; i < results.Length; i++)
                {
                    results[i] = varsTechnologic[i].Get(GRB.DoubleAttr.X);
                }
            }
            else
            {
                //Create variables
                GRBVar[] varsMetrologic = new GRBVar[measuredValues.ToArray().Length];
                for (int i = 0; i < varsMetrologic.Length; i++)
                {
                    if (measureIndicator[i, i] == 0)
                    {
                        varsMetrologic[i] = model.AddVar(technologicRangeLowerBound[i], technologicRangeUpperBound[i], 0.0, GRB.CONTINUOUS, "x" + i);
                    }
                    else
                    {
                        varsMetrologic[i] = model.AddVar(metrologicRangeLowerBound[i], metrologicRangeUpperBound[i], 0.0, GRB.CONTINUOUS, "x" + i);
                    }
                }
                //Set objective
                GRBQuadExpr objMetroologic = new GRBQuadExpr();
                for (int i = 0; i < varsMetrologic.Length; i++)
                {
                    objMetroologic.AddTerm(H[i, i] / 2.0, varsMetrologic[i], varsMetrologic[i]);
                }
                for (int i = 0; i < varsMetrologic.Length; i++)
                {
                    objMetroologic.AddTerm(dVector[i], varsMetrologic[i]);
                }
                model.SetObjective(objMetroologic);
                //Add constraints
                GRBLinExpr expr;
                for (int i = 0; i < incidenceMatrix.RowCount; i++)
                {
                    expr = new GRBLinExpr();
                    for (int j = 0; j < incidenceMatrix.ColumnCount; j++)
                    {
                        expr.AddTerm(incidenceMatrix[i, j], varsMetrologic[j]);
                    }
                    model.AddConstr(expr, GRB.EQUAL, 0.0, "c" + i);
                }
                // Optimize model
                CalculationTimeStart = DateTime.Now;
                model.Optimize();
                CalculationTimeFinish = DateTime.Now;
                results = new double[varsMetrologic.Length];
                for (int i = 0; i < results.Length; i++)
                {
                    results[i] = varsMetrologic[i].Get(GRB.DoubleAttr.X);
                }
            }
            model.Dispose();
            env.Dispose();

            double disbalanceOriginal = incidenceMatrix.Multiply(measuredValues).Subtract(reconciledValues).ToArray().Euclidean();
            double disbalance         = incidenceMatrix.Multiply(SparseVector.OfVector(new DenseVector(results))).Subtract(reconciledValues).ToArray().Euclidean();

            balanceOutput          = new BalanceOutput();
            balanceOutputVariables = new List <OutputVariables>();
            for (int i = 0; i < results.Length; i++)
            {
                InputVariables outputVariable = inputData.BalanceInputVariables[i];
                balanceOutputVariables.Add(new OutputVariables()
                {
                    id         = outputVariable.id,
                    name       = outputVariable.name,
                    value      = results[i],
                    source     = outputVariable.sourceId,
                    target     = outputVariable.destinationId,
                    upperBound = (inputData.balanceSettings.balanceSettingsConstraints == 0 || measureIndicator[i, i] == 0.0) ? technologicRangeUpperBound[i] : metrologicRangeUpperBound[i],
                    lowerBound = (inputData.balanceSettings.balanceSettingsConstraints == 0 || measureIndicator[i, i] == 0.0) ? technologicRangeLowerBound[i] : metrologicRangeLowerBound[i]
                });
            }
            balanceOutput.CalculationTime        = (CalculationTimeFinish - CalculationTimeStart).TotalSeconds;
            balanceOutput.balanceOutputVariables = balanceOutputVariables;
            balanceOutput.DisbalanceOriginal     = disbalanceOriginal;
            balanceOutput.Disbalance             = disbalance;
            balanceOutput.GlobaltestValue        = 0.0;
            balanceOutput.Status = "Success";
        }
    dense_optimize(GRBEnv env,
                   int rows,
                   int cols,
                   double[]  c,      // linear portion of objective function
                   double[,] Q,      // quadratic portion of objective function
                   double[,] A,      // constraint matrix
                   char[]    sense,  // constraint senses
                   double[]  rhs,    // RHS vector
                   double[]  lb,     // variable lower bounds
                   double[]  ub,     // variable upper bounds
                   char[]    vtype,  // variable types (continuous, binary, etc.)
                   double[]  solution)
    {
        bool success = false;

        try {
            GRBModel model = new GRBModel(env);

            // Add variables to the model

            GRBVar[] vars = model.AddVars(lb, ub, null, vtype, null);

            // Populate A matrix

            for (int i = 0; i < rows; i++)
            {
                GRBLinExpr expr = new GRBLinExpr();
                for (int j = 0; j < cols; j++)
                {
                    if (A[i, j] != 0)
                    {
                        expr.AddTerm(A[i, j], vars[j]); // Note: '+=' would be much slower
                    }
                }
                model.AddConstr(expr, sense[i], rhs[i], "");
            }

            // Populate objective

            GRBQuadExpr obj = new GRBQuadExpr();
            if (Q != null)
            {
                for (int i = 0; i < cols; i++)
                {
                    for (int j = 0; j < cols; j++)
                    {
                        if (Q[i, j] != 0)
                        {
                            obj.AddTerm(Q[i, j], vars[i], vars[j]); // Note: '+=' would be much slower
                        }
                    }
                }
                for (int j = 0; j < cols; j++)
                {
                    if (c[j] != 0)
                    {
                        obj.AddTerm(c[j], vars[j]); // Note: '+=' would be much slower
                    }
                }
                model.SetObjective(obj);
            }

            // Solve model

            model.Optimize();

            // Extract solution

            if (model.Status == GRB.Status.OPTIMAL)
            {
                success = true;

                for (int j = 0; j < cols; j++)
                {
                    solution[j] = vars[j].X;
                }
            }

            model.Dispose();
        } catch (GRBException e) {
            Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message);
        }

        return(success);
    }
Пример #9
0
        public GurobiSolver(Crossword crossword)
        {
            var wordLengthHistogram = new Dictionary <int, int>()
            {
                { 3, 18 },
                { 4, 24 },
                { 5, 20 },
                { 6, 18 },
                { 7, 12 },
                { 8, 4 },
                { 9, 4 },
            };

            const int maxWordLength = 9;

            int sizeY = crossword.Grid.GetLength(0);
            int sizeX = crossword.Grid.GetLength(1);

            int amountQuestions = (int)Math.Round(0.22 * sizeX * sizeY);


            GRBEnv   env = new GRBEnv();
            GRBModel m   = new GRBModel(env);

            // 0 = letter, 1 = question
            GRBVar[,] fields = new GRBVar[sizeY, sizeX];
            // 0 = right, 1 = down
            GRBVar[,] questionType = new GRBVar[sizeY, sizeX];


            for (int y = 0; y < sizeY; y++)
            {
                for (int x = 0; x < sizeX; x++)
                {
                    // create a var for every non-blocked field
                    if (!(crossword.Grid[y, x] is Blocked))
                    {
                        fields[y, x]       = m.AddVar(0, 1, 0, GRB.BINARY, "Field" + x + "_" + y);
                        questionType[y, x] = m.AddVar(0, 1, 0, GRB.BINARY, "QType" + x + "_" + y);
                    }
                }
            }

            GRBLinExpr allFieldsSum = new GRBLinExpr();

            // count word lengths (to compare with histogram)
            var lengths = new Dictionary <int, GRBLinExpr>();

            foreach (var l in wordLengthHistogram.Keys)
            {
                lengths.Add(l, new GRBLinExpr());
            }

            var partOfAWord = new GRBLinExpr[sizeY, sizeX];

            for (int y = 0; y < sizeY; y++)
            {
                for (int x = 0; x < sizeX; x++)
                {
                    partOfAWord[y, x] = new GRBLinExpr();
                }
            }

            for (int y = 0; y < sizeY; y++)
            {
                for (int x = 0; x < sizeX; x++)
                {
                    allFieldsSum += fields[y, x];

                    foreach (var l in wordLengthHistogram.Keys)
                    {
                        if (x + l < sizeX)
                        {
                            // + 1 if the following fields are all words and the last one is not a word (question or outside grid)
                            var wordCount = new GRBLinExpr();
                            for (int i = 1; i <= l; i++)
                            {
                                wordCount += fields[y, x + i];
                            }

                            // last field is question or outside?
                            var lastFieldIsNoWord = m.AddVar(0, 1, 0, GRB.BINARY, "lastFieldIsNoWord" + y + "_" + x + "_" + l);
                            if (x + l + 1 < sizeX)
                            {
                                m.AddConstr(lastFieldIsNoWord == fields[y, x + l + 1], "lastFieldIsInGridAndIsQuestion" + y + "_" + x + "_" + l);
                            }
                            else
                            {
                                m.AddConstr(lastFieldIsNoWord == 1, "lastFieldOutsideGrid" + y + "_" + x + "_" + l);
                            }

                            // https://cs.stackexchange.com/questions/51025/cast-to-boolean-for-integer-linear-programming
                            var hasCorrectWordCount = m.AddVar(0, 1, 0, GRB.BINARY, "hasCorrect" + y + "_" + x + "_" + l);
                            var hcTemp   = m.AddVar(0, 1, 0, GRB.BINARY, "hasCorrectTemp" + y + "_" + x + "_" + l);
                            var worddiff = wordCount - l;
                            m.AddConstr(-sizeX * hasCorrectWordCount <= worddiff, "ToBoolean" + y + "_" + x + "_" + l + "_1");
                            m.AddConstr(worddiff <= sizeX * hasCorrectWordCount, "ToBoolean" + y + "_" + x + "_" + l + "_2");
                            m.AddConstr(0.001 * hasCorrectWordCount - (sizeX + 0.001) * hcTemp <= worddiff, "ToBoolean" + y + "_" + x + "_" + l + "_3");
                            m.AddConstr(worddiff <= -0.001 * hasCorrectWordCount + (sizeX + 0.001) * (1 - hcTemp), "ToBoolean" + y + "_" + x + "_" + l + "_4");

                            // firstFieldIsQuestion AND questionIsHorizontal AND hasCorrectWordCount AND lastFieldIsNoWord
                            var allConditionsMet = m.AddVar(0, 1, 0, GRB.BINARY, "allCondsMet" + y + "_" + x + "_" + l);
                            var condVal          = fields[y, x] + (1 - questionType[y, x]) + hasCorrectWordCount + lastFieldIsNoWord - 3;
                            m.AddConstr(allConditionsMet >= condVal, "AllConditionsAND" + y + "_" + x + "_" + l + "_1");
                            m.AddConstr(allConditionsMet <= fields[y, x], "AllConditionsAND" + y + "_" + x + "_" + l + "_2");
                            m.AddConstr(allConditionsMet <= (1 - questionType[y, x]), "AllConditionsAND" + y + "_" + x + "_" + l + "_3");
                            m.AddConstr(allConditionsMet <= hasCorrectWordCount, "AllConditionsAND" + y + "_" + x + "_" + l + "_4");
                            m.AddConstr(allConditionsMet <= lastFieldIsNoWord, "AllConditionsAND" + y + "_" + x + "_" + l + "_5");
                            lengths[l] += allConditionsMet;

                            // If all conditions are met, all letters are part of a word
                            for (int i = 1; i <= l; i++)
                            {
                                partOfAWord[y, x + i] += allConditionsMet;
                            }
                        }

                        if (y + l < sizeY)
                        {
                            // + 1 if the following fields are all words and the last one is not a word (question or outside grid)
                            var wordCount = new GRBLinExpr();
                            for (int i = 1; i <= l; i++)
                            {
                                wordCount += fields[y + i, x];
                            }

                            // last field is question or outside?
                            var lastFieldIsNoWord = m.AddVar(0, 1, 0, GRB.BINARY, "lastFieldIsNoWord" + y + "_" + x + "_" + l);
                            if (y + l + 1 < sizeY)
                            {
                                m.AddConstr(lastFieldIsNoWord == fields[y + l + 1, x], "lastFieldIsInGridAndIsQuestion" + y + "_" + x + "_" + l);
                            }
                            else
                            {
                                m.AddConstr(lastFieldIsNoWord == 1, "lastFieldOutsideGrid" + y + "_" + x + "_" + l);
                            }

                            // https://cs.stackexchange.com/questions/51025/cast-to-boolean-for-integer-linear-programming
                            var hasCorrectWordCount = m.AddVar(0, 1, 0, GRB.BINARY, "hasCorrect" + y + "_" + x + "_" + l);
                            var hcTemp   = m.AddVar(0, 1, 0, GRB.BINARY, "hasCorrectTemp" + y + "_" + x + "_" + l);
                            var worddiff = wordCount - l;
                            m.AddConstr(-sizeY * hasCorrectWordCount <= worddiff, "ToBoolean" + y + "_" + x + "_" + l + "_1");
                            m.AddConstr(worddiff <= sizeY * hasCorrectWordCount, "ToBoolean" + y + "_" + x + "_" + l + "_2");
                            m.AddConstr(0.001 * hasCorrectWordCount - (sizeY + 0.001) * hcTemp <= worddiff, "ToBoolean" + y + "_" + x + "_" + l + "_3");
                            m.AddConstr(worddiff <= -0.001 * hasCorrectWordCount + (sizeY + 0.001) * (1 - hcTemp), "ToBoolean" + y + "_" + x + "_" + l + "_4");

                            // firstFieldIsQuestion AND questionIsHorizontal AND hasCorrectWordCount AND lastFieldIsNoWord
                            var allConditionsMet = m.AddVar(0, 1, 0, GRB.BINARY, "allCondsMet" + y + "_" + x + "_" + l);
                            var condVal          = fields[y, x] + (questionType[y, x]) + hasCorrectWordCount + lastFieldIsNoWord - 3;
                            m.AddConstr(allConditionsMet >= condVal, "AllConditionsAND" + y + "_" + x + "_" + l + "_1");
                            m.AddConstr(allConditionsMet <= fields[y, x], "AllConditionsAND" + y + "_" + x + "_" + l + "_2");
                            m.AddConstr(allConditionsMet <= (questionType[y, x]), "AllConditionsAND" + y + "_" + x + "_" + l + "_3");
                            m.AddConstr(allConditionsMet <= hasCorrectWordCount, "AllConditionsAND" + y + "_" + x + "_" + l + "_4");
                            m.AddConstr(allConditionsMet <= lastFieldIsNoWord, "AllConditionsAND" + y + "_" + x + "_" + l + "_5");
                            lengths[l] += allConditionsMet;

                            // If all conditions are met, all letters are part of a word
                            for (int i = 1; i <= l; i++)
                            {
                                partOfAWord[y + i, x] += allConditionsMet;
                            }
                        }
                    }

                    // max word count
                    if (x + maxWordLength < sizeX)
                    {
                        var maxWordCount = new GRBLinExpr();
                        var range        = maxWordLength + 1;
                        if (x + range == sizeX)
                        {
                            range--;
                        }
                        for (int i = 0; i < maxWordLength + 1; i++)
                        {
                            maxWordCount += 1 - fields[y, x + i];
                        }
                        m.AddConstr(maxWordCount <= maxWordLength, "maxWordsX" + y + "_" + x);
                    }
                    if (y + maxWordLength < sizeY)
                    {
                        var maxWordCount = new GRBLinExpr();
                        var range        = maxWordLength + 1;
                        if (y + range == sizeY)
                        {
                            range--;
                        }
                        for (int i = 0; i < maxWordLength + 1; i++)
                        {
                            maxWordCount += 1 - fields[y + i, x];
                        }
                        m.AddConstr(maxWordCount <= maxWordLength, "maxWordsY" + y + "_" + x);
                    }
                }
            }


            // All non-question fields have to belong to a word
            for (int y = 0; y < sizeY; y++)
            {
                for (int x = 0; x < sizeX; x++)
                {
                    m.AddConstr(1 - fields[y, x] <= partOfAWord[y, x], "NonQuestionsToWords" + y + "_" + x + "_1");
                    m.AddConstr(1 - fields[y, x] >= partOfAWord[y, x] * 0.5, "NonQuestionsToWords" + y + "_" + x + "_2");
                }
            }

            // after a question, no word of length 1 or 2 is allowed
            for (int y = 0; y < sizeY; y++)
            {
                for (int x = 0; x < sizeX; x++)
                {
                    if (x < sizeX - 3)
                    {
                        // if there's a question AND it's pointing right THEN sum(fields[y, x+1/2/3]) = 0
                        var minLetters = 3 - (fields[y, x + 1] + fields[y, x + 2] + fields[y, x + 3]);
                        m.AddConstr(fields[y, x] + (1 - questionType[y, x]) - 1 <= minLetters * (1d / 3d), "AfterRightQuestionMin2Letters" + y + "_" + x);
                    }
                    else
                    {
                        m.AddConstr(questionType[y, x] == 1, "NoRightQuestionAtRightBorder" + y + "_" + x);
                    }

                    if (y < sizeY - 3)
                    {
                        // if there's a question AND it's pointing down THEN sum(fields[y+1/2/3, x]) = 0
                        var minLetters = 3 - (fields[y + 1, x] + fields[y + 2, x] + fields[y + 3, x]);
                        m.AddConstr(fields[y, x] + questionType[y, x] - 1 <= minLetters * (1d / 3d), "AfterDownQuestionMin2Letters" + y + "_" + x);
                    }
                    else if (x < sizeX - 3)
                    {
                        m.AddConstr(questionType[y, x] == 0, "NoDownQuestionAtBottomBorder" + y + "_" + x);
                    }
                    else
                    {
                        m.AddConstr(fields[y, x] == 0, "OnlyWordsInBottomrightCorner" + y + "_" + x);
                    }
                }
            }

            // Objective:
            // questions should be around ~22% (allFieldsSum ~= amountQuestions)
            var amountOfQuestionsRating   = m.AddVar(0, sizeX * sizeY - amountQuestions, 0, GRB.INTEGER, "amountOfQuestionsRating");
            var amountOfQuestionsAbsInput = m.AddVar(-amountQuestions, sizeX * sizeY - amountQuestions, 0, GRB.INTEGER, "amountOfQuestionsAbsInput");

            m.AddConstr(amountOfQuestionsAbsInput == allFieldsSum - amountQuestions);
            m.AddGenConstrAbs(amountOfQuestionsRating, amountOfQuestionsAbsInput, "amountOfQuestionsAbs");

            /*int tolerance = (int)(amountQuestions * 0.1);
             * m.AddConstr(allFieldsSum - amountQuestions >= -tolerance);
             * m.AddConstr(allFieldsSum - amountQuestions <= tolerance);*/

            // as many partOfAWord == 2 as possible
            var manyCrossedWords = new GRBLinExpr();

            for (int y = 0; y < sizeY; y++)
            {
                for (int x = 0; x < sizeX; x++)
                {
                    manyCrossedWords += partOfAWord[y, x];
                }
            }

            // ideal histogram comparison
            var wordHistogramDifferences = new GRBQuadExpr();

            foreach (var wl in wordLengthHistogram.Keys)
            {
                var diff = (wordLengthHistogram[wl] - lengths[wl]) * 2;
                wordHistogramDifferences += diff * diff;
            }

            // question field clusters
            var clusterPenalty = new GRBLinExpr();

            for (int y = 0; y < sizeY - 2; y++)
            {
                for (int x = 0; x < sizeX - 2; x++)
                {
                    var clusterTotal = new GRBLinExpr();
                    for (int i = 0; i < 3; i++)
                    {
                        for (int j = 0; j < 3; j++)
                        {
                            clusterTotal += fields[y + i, x + j];
                        }
                    }
                    var varClusterTotalPenalty = m.AddVar(0, 7, 0, GRB.INTEGER, "varClusterTotalPenalty" + y + "_" + x);
                    m.AddConstr(varClusterTotalPenalty >= clusterTotal - 2);
                    clusterPenalty += varClusterTotalPenalty;
                }
            }

            //amountOfQuestionsRating * (100d / sizeX / sizeY) + manyCrossedWords +  + wordHistogramDifferences
            // clusterPenalty * 100
            m.SetObjective(amountOfQuestionsRating * (100d / sizeX / sizeY) + clusterPenalty * 100 + wordHistogramDifferences + manyCrossedWords, GRB.MINIMIZE);

            m.SetCallback(new GRBMipSolCallback(crossword, fields, questionType, null));

            m.Optimize();
            m.ComputeIIS();
            m.Write("model.ilp");

            m.Dispose();
            env.Dispose();
        }
Пример #10
0
        private static bool GurobiSolve(GRBEnv env, int rows, int cols,
                                        double[]  c,     // linear portion of objective function
                                        double[,] Q,     // quadratic portion of objective function
                                        double[,] A,     // constraint matrix
                                        double[]  rhs,   // RHS vector
                                        double[]  lb,    // variable lower bounds
                                        double[]  ub,    // variable upper bounds
                                        char[]    vtype, // variable types (continuous, binary, etc.)
                                        double[]  solution,
                                        ref double val)
        {
            bool success = false;

            try {
                GRBModel model = new GRBModel(env);

                // Add variables to the model

                GRBVar[] vars = model.AddVars(lb, ub, null, null, null);
                model.Update();

                // Populate A matrix

                for (int i = 0; i < rows; i++)
                {
                    GRBLinExpr expr = new GRBLinExpr();
                    for (int j = 0; j < cols; j++)
                    {
                        if (A[i, j] != 0)
                        {
                            expr.AddTerm(A[i, j], vars[j]); // Note: '+=' would be much slower
                        }
                    }
                    model.AddConstr(expr, '>', rhs[i], "");
                }

                // Populate objective

                GRBQuadExpr obj = new GRBQuadExpr();
                if (Q != null)
                {
                    for (int i = 0; i < cols; i++)
                    {
                        for (int j = 0; j < cols; j++)
                        {
                            if (Q[i, j] != 0)
                            {
                                obj.AddTerm(Q[i, j], vars[i], vars[j]); // Note: '+=' would be much slower
                            }
                        }
                    }
                    for (int j = 0; j < cols; j++)
                    {
                        if (c[j] != 0)
                        {
                            obj.AddTerm(c[j], vars[j]); // Note: '+=' would be much slower
                        }
                    }
                    model.SetObjective(obj, GRB.MAXIMIZE);
                }

                // Solve model

                model.Optimize();

                // Extract solution

                if (model.Get(GRB.IntAttr.Status) == GRB.Status.OPTIMAL)
                {
                    success = true;

                    for (int j = 0; j < cols; j++)
                    {
                        solution[j] = vars[j].Get(GRB.DoubleAttr.X);
                    }
                }
                else
                {
                    success = false;
                }
                val = obj.Value;
                model.Dispose();
            } catch (GRBException e) {
                return(false);
            }

            return(success);
        }