Exemple #1
0
    static void Main(string[] args)
    {
        if (args.Length < 1) {
          Console.Out.WriteLine("Usage: feasopt_cs filename");
          return;
        }

        try {
          GRBEnv env = new GRBEnv();
          GRBModel feasmodel = new GRBModel(env, args[0]);

          // Create a copy to use FeasRelax feature later */
          GRBModel feasmodel1 = new GRBModel(feasmodel);

          // Clear objective
          feasmodel.SetObjective(new GRBLinExpr());

          // Add slack variables
          GRBConstr[] c = feasmodel.GetConstrs();
          for (int i = 0; i < c.Length; ++i) {
        char sense = c[i].Get(GRB.CharAttr.Sense);
        if (sense != '>') {
          GRBConstr[] constrs = new GRBConstr[] { c[i] };
          double[] coeffs = new double[] { -1 };
          feasmodel.AddVar(0.0, GRB.INFINITY, 1.0, GRB.CONTINUOUS, constrs,
                           coeffs, "ArtN_" + c[i].Get(GRB.StringAttr.ConstrName));
        }
        if (sense != '<') {
          GRBConstr[] constrs = new GRBConstr[] { c[i] };
          double[] coeffs = new double[] { 1 };
          feasmodel.AddVar(0.0, GRB.INFINITY, 1.0, GRB.CONTINUOUS, constrs,
                           coeffs, "ArtP_" +
                               c[i].Get(GRB.StringAttr.ConstrName));
        }
          }
          feasmodel.Update();

          // Optimize modified model
          feasmodel.Write("feasopt.lp");
          feasmodel.Optimize();

          // Use FeasRelax feature */
          feasmodel1.FeasRelax(GRB.FEASRELAX_LINEAR, true, false, true);
          feasmodel1.Write("feasopt1.lp");
          feasmodel1.Optimize();

          // Dispose of model and env
          feasmodel1.Dispose();
          feasmodel.Dispose();
          env.Dispose();

        } catch (GRBException e) {
          Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message);
        }
    }
Exemple #2
0
    static void Main()
    {
        try {
          GRBEnv    env   = new GRBEnv("mip1.log");
          GRBModel  model = new GRBModel(env);

          // Create variables

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

          // Integrate new variables

          model.Update();

          // Set objective: maximize x + y + 2 z

          model.SetObjective(x + y + 2 * z, GRB.MAXIMIZE);

          // 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.Get(GRB.StringAttr.VarName)
                         + " " + x.Get(GRB.DoubleAttr.X));
          Console.WriteLine(y.Get(GRB.StringAttr.VarName)
                         + " " + y.Get(GRB.DoubleAttr.X));
          Console.WriteLine(z.Get(GRB.StringAttr.VarName)
                         + " " + z.Get(GRB.DoubleAttr.X));

          Console.WriteLine("Obj: " + model.Get(GRB.DoubleAttr.ObjVal));

          // Dispose of model and env

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

        } catch (GRBException e) {
          Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message);
        }
    }
Exemple #3
0
    public static void Main(String[] args)
    {
        if (args.Length < 1)
        {
            Console.WriteLine("Usage: tsp_cs nnodes");
            return;
        }

        int n = Convert.ToInt32(args[0]);

        try {
            GRBEnv   env   = new GRBEnv();
            GRBModel model = new GRBModel(env);

            // Must set LazyConstraints parameter when using lazy constraints

            model.Parameters.LazyConstraints = 1;

            double[] x = new double[n];
            double[] y = new double[n];

            Random r = new Random();
            for (int i = 0; i < n; i++)
            {
                x[i] = r.NextDouble();
                y[i] = r.NextDouble();
            }

            // Create variables

            GRBVar[,] vars = new GRBVar[n, n];

            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j <= i; j++)
                {
                    vars[i, j] = model.AddVar(0.0, 1.0, distance(x, y, i, j),
                                              GRB.BINARY, "x" + i + "_" + j);
                    vars[j, i] = vars[i, j];
                }
            }

            // Degree-2 constraints

            for (int i = 0; i < n; i++)
            {
                GRBLinExpr expr = 0;
                for (int j = 0; j < n; j++)
                {
                    expr.AddTerm(1.0, vars[i, j]);
                }
                model.AddConstr(expr == 2.0, "deg2_" + i);
            }

            // Forbid edge from node back to itself

            for (int i = 0; i < n; i++)
            {
                vars[i, i].UB = 0.0;
            }

            model.SetCallback(new tsp_cs(vars));
            model.Optimize();

            if (model.SolCount > 0)
            {
                int[] tour = findsubtour(model.Get(GRB.DoubleAttr.X, vars));

                Console.Write("Tour: ");
                for (int i = 0; i < tour.Length; i++)
                {
                    Console.Write(tour[i] + " ");
                }
                Console.WriteLine();
            }

            // Dispose of model and environment
            model.Dispose();
            env.Dispose();
        } catch (GRBException e) {
            Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message);
            Console.WriteLine(e.StackTrace);
        }
    }
Exemple #4
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,
                });
            }
        }
Exemple #5
0
        static void Main(string[] args)
        {
            //Deserializar o arquivo Json para o c#
            //JavaScriptSerializer serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
            var        json      = File.ReadAllText("C:\\Users\\ruany\\Documents\\dissertacao\\gerador-instancias\\instanciaT11E8D10F6.json");
            Parametros instancia = JsonConvert.DeserializeObject <Parametros>(json);

            // matrizes que irão guardar as soluções do Relax and Fix
            double[,,] matriz_RaF_x = new double[instancia.crew, instancia.task, instancia.date];
            double[,] matriz_RaF_x3 = new double[instancia.task, instancia.date];
            double[,] matriz_RaF_x2 = new double[instancia.task, instancia.date];
            double[] matriz_RaF_x4 = new double[instancia.task];
            double[,,] matriz_RaF_x5 = new double[instancia.crew, instancia.task, instancia.date];
            double[,] matriz_RaF_x6  = new double[instancia.task, instancia.date];
            double[,] matriz_RaF_y   = new double[instancia.crew, instancia.date];
            double[,,] matriz_RaF_z  = new double[instancia.crew, instancia.task, instancia.date];
            double[,] matriz_RaF_z1  = new double[instancia.crew, instancia.task];
            double[,,] matriz_RaF_w  = new double[instancia.crew, instancia.technical_place, instancia.date];
            double[,,,] matriz_RaF_v = new double[instancia.crew, instancia.technical_place, instancia.technical_place, instancia.date];
            double[,,] matriz_RaF_w1 = new double[instancia.crew, instancia.technical_place, instancia.date];
            double[,,] matriz_RaF_w2 = new double[instancia.crew, instancia.technical_place, instancia.date];

            //tempo por iteração
            double tempo_iteracao, tempo_total;
            //status de cada iteração
            int status_RF;
            //lista
            List <double> lista_RF = new List <double>();
            double        soma_RF  = 0;

            //função Relax and Fix
            void modelo_RelaxAndFixData(int iteracao)
            {
                //Modelo
                GRBEnv   ambiente = new GRBEnv();
                GRBModel modelo   = new GRBModel(ambiente);

                //número grande
                int M = 1000;

                //Variáveis

                //fração da tarefa i que o membro de equipe n completa na data j
                GRBVar[,,] x = new GRBVar[instancia.crew, instancia.task, instancia.date];
                for (int n = 0; n < instancia.crew; n++)
                {
                    for (int i = 0; i < instancia.task; i++)
                    {
                        for (int j = 0; j < instancia.date; j++)
                        {
                            x[n, i, j] = modelo.AddVar(0, 1, 0, GRB.CONTINUOUS, "x_" + n + "_" + i + "_" + j);
                        }
                    }
                }
                //fração da tarefa i que é completada na data j
                GRBVar[,] x3 = new GRBVar[instancia.task, instancia.date];
                for (int i = 0; i < instancia.task; i++)
                {
                    for (int j = 0; j < instancia.date; j++)
                    {
                        x3[i, j] = modelo.AddVar(0, 1, 0, GRB.CONTINUOUS, "x3_" + i + "_" + j);
                    }
                }
                //1 se alguma tarefa i é completada na data j
                GRBVar[,] x2 = new GRBVar[instancia.task, instancia.date];
                for (int i = 0; i < instancia.task; i++)
                {
                    for (int j = 0; j < instancia.date; j++)
                    {
                        x2[i, j] = modelo.AddVar(0, 1, 0, GRB.CONTINUOUS, "x2_" + i + "_" + j);
                    }
                }
                //1 se a tarefa i é concluída dentro do horizonte de planejamento
                GRBVar[] x4 = new GRBVar[instancia.task];
                for (int i = 0; i < instancia.task; i++)
                {
                    x4[i] = modelo.AddVar(0, 1, instancia.c[i] * 2, GRB.CONTINUOUS, "x4_" + i);
                }
                //variável fantasma
                GRBVar[] vf = new GRBVar[instancia.task];
                for (int i = 0; i < instancia.task; i++)
                {
                    vf[i] = modelo.AddVar(1, 1, instancia.c[i] * 2, GRB.BINARY, "vf_" + i);
                }
                //1 se o membro de equipe n está trabalhando na tarefa i na data j mas não na data j+1
                GRBVar[,,] x5 = new GRBVar[instancia.crew, instancia.task, instancia.date];
                for (int n = 0; n < instancia.crew; n++)
                {
                    for (int i = 0; i < instancia.task; i++)
                    {
                        for (int j = 0; j < instancia.date; j++)
                        {
                            x5[n, i, j] = modelo.AddVar(0, 1, 0.1, GRB.CONTINUOUS, "x5_" + n + "_" + i + "_" + j);
                        }
                    }
                }
                //1 se parte da tarefa i é completada na data j mas não na data j+1
                GRBVar[,] x6 = new GRBVar[instancia.task, instancia.date];
                for (int i = 0; i < instancia.task; i++)
                {
                    for (int j = 0; j < instancia.date; j++)
                    {
                        x6[i, j] = modelo.AddVar(0, 1, 0.9, GRB.CONTINUOUS, "x6_" + i + "_" + j);
                    }
                }
                //1 se o membro da equipe n vai trabalhar na data j
                GRBVar[,] y = new GRBVar[instancia.crew, instancia.date];
                for (int n = 0; n < instancia.crew; n++)
                {
                    for (int j = 0; j < instancia.date; j++)
                    {
                        y[n, j] = modelo.AddVar(0, 1, instancia.hours_per_shift, GRB.CONTINUOUS, "y_" + n + "_" + j);
                    }
                }
                //1 se membro da equipe n trabalha na tarefa i na data j
                GRBVar[,,] z = new GRBVar[instancia.crew, instancia.task, instancia.date];
                for (int n = 0; n < instancia.crew; n++)
                {
                    for (int i = 0; i < instancia.task; i++)
                    {
                        for (int j = 0; j < instancia.date; j++)
                        {
                            z[n, i, j] = modelo.AddVar(0, 1, 0.5, GRB.CONTINUOUS, "z_" + n + "_" + i + "_" + j);
                        }
                    }
                }
                //1 se o membro de equipe n trabalha na tarefa i
                GRBVar[,] z1 = new GRBVar[instancia.crew, instancia.task];
                for (int n = 0; n < instancia.crew; n++)
                {
                    for (int i = 0; i < instancia.task; i++)
                    {
                        z1[n, i] = modelo.AddVar(0, 1, 0.1, GRB.CONTINUOUS, "z1_" + n + "_" + i);
                    }
                }
                //1 se o membro de equipe n trabalha no local técnico p na data j
                GRBVar[,,] w = new GRBVar[instancia.crew, instancia.technical_place, instancia.date];
                for (int n = 0; n < instancia.crew; n++)
                {
                    for (int p = 0; p < instancia.technical_place; p++)
                    {
                        for (int j = 0; j < instancia.date; j++)
                        {
                            w[n, p, j] = modelo.AddVar(0, 1, 0, GRB.CONTINUOUS, "w_" + n + "_" + p + "_" + j);
                        }
                    }
                }
                //1 se o membro de equipe n precisa de transporte entre o local técnico o e o local q na instancia.date j
                GRBVar[,,,] v = new GRBVar[instancia.crew, instancia.technical_place, instancia.technical_place, instancia.date];
                for (int n = 0; n < instancia.crew; n++)
                {
                    for (int p = 0; p < instancia.technical_place; p++)
                    {
                        for (int q = 0; q < instancia.technical_place; q++)
                        {
                            for (int j = 0; j < instancia.date; j++)
                            {
                                v[n, p, q, j] = modelo.AddVar(0, 1, 0, GRB.CONTINUOUS, "v_" + n + "_" + p + "_" + q + "_" + j);
                            }
                        }
                    }
                }
                //se a equipe n precisa de transporte para o local técnico p de outro local técnico na data j
                GRBVar[,,] w1 = new GRBVar[instancia.crew, instancia.technical_place, instancia.date];
                for (int n = 0; n < instancia.crew; n++)
                {
                    for (int p = 0; p < instancia.technical_place; p++)
                    {
                        for (int j = 0; j < instancia.date; j++)
                        {
                            w1[n, p, j] = modelo.AddVar(0, 1, 0, GRB.CONTINUOUS, "w1_" + n + "_" + p + "_" + j);
                        }
                    }
                }
                //se a equipe n precisa de transporte do local técnico p para outro local técnico
                GRBVar[,,] w2 = new GRBVar[instancia.crew, instancia.technical_place, instancia.date];
                for (int n = 0; n < instancia.crew; n++)
                {
                    for (int p = 0; p < instancia.technical_place; p++)
                    {
                        for (int j = 0; j < instancia.date; j++)
                        {
                            w2[n, p, j] = modelo.AddVar(0, 1, 0, GRB.CONTINUOUS, "w2_" + n + "_" + p + "_" + j);
                        }
                    }
                }

                //Função objetivo
                modelo.ModelSense = GRB.MINIMIZE;


                //Restrições
                GRBLinExpr exp  = 0.0;
                GRBLinExpr exp2 = 0.0;
                GRBLinExpr exp3 = 0.0;

                //Restrições com relação a tarefa

                //restrição 2
                //a tarefa deve ser concluída dentro do horizonte de planejamento
                for (int i = 0; i < instancia.task; i++)
                {
                    exp.Clear();
                    for (int n = 0; n < instancia.crew; n++)
                    {
                        for (int j = 0; j < instancia.date; j++)
                        {
                            exp.AddTerm(1, x[n, i, j]);
                        }
                    }
                    modelo.AddConstr(exp == x4[i], "R2_" + i);
                }
                //restrição 3
                //o número total de horas por turno não deve ser excedido
                for (int j = 0; j < instancia.date; j++)
                {
                    for (int n = 0; n < instancia.crew; n++)
                    {
                        exp.Clear();
                        exp2.Clear();
                        exp3.Clear();
                        for (int i = 0; i < instancia.task; i++)
                        {
                            exp.AddTerm(instancia.c[i], x[n, i, j]);
                        }
                        for (int p = 0; p < instancia.technical_place; p++)
                        {
                            exp2.AddTerm(2 * instancia.tm[p], w[n, p, j]);
                            exp2.AddTerm(-instancia.tm[p], w1[n, p, j]);
                            exp2.AddTerm(-instancia.tm[p], w2[n, p, j]);
                        }
                        for (int p = 0; p < instancia.technical_place; p++)
                        {
                            for (int q = 0; q < instancia.technical_place; q++)
                            {
                                exp3.AddTerm(instancia.tr[p, q], v[n, p, q, j]);
                            }
                        }
                        modelo.AddConstr(exp + exp2 + exp3 <= instancia.hours_per_shift, "R3_" + j + "_" + n);
                    }
                }
                //restrição 4
                //a soma das frações das tarefas locadas  não pode exceder o total para completar a tarefa
                for (int i = 0; i < instancia.task; i++)
                {
                    for (int j = 0; j < instancia.date; j++)
                    {
                        exp.Clear();
                        for (int n = 0; n < instancia.crew; n++)
                        {
                            exp.AddTerm(1, x[n, i, j]);
                        }
                        modelo.AddConstr(x2[i, j] >= exp, "R4_" + i + "_" + j);
                    }
                }
                //restrição 5
                //soma de das frações dos membros e equipe num dado dia deve ser igual a x3
                for (int i = 0; i < instancia.task; i++)
                {
                    for (int j = 0; j < instancia.date; j++)
                    {
                        exp.Clear();
                        for (int n = 0; n < instancia.crew; n++)
                        {
                            exp.AddTerm(1, x[n, i, j]);
                        }
                        modelo.AddConstr(x3[i, j] == exp, "R5_" + i + "_" + j);
                    }
                }
                //restrição 6
                //a tarefa i deve ser completada dentro do horizonte de planejamento se gi=1
                for (int i = 0; i < instancia.task; i++)
                {
                    modelo.AddConstr(x4[i] >= instancia.g[i], "R6_" + i);
                }
                //restrição 7
                //fração da tarefa que é completada num dado dia não deve exceder X4
                for (int n = 0; n < instancia.crew; n++)
                {
                    for (int i = 0; i < instancia.task; i++)
                    {
                        for (int j = 0; j < instancia.date; j++)
                        {
                            modelo.AddConstr(x4[i] >= x[n, i, j], "R7_" + n + "_" + i + "_" + j);
                        }
                    }
                }
                //restrição 8
                //um membro de equipe não pode ser locado a uma tarefa em um dia em que ele não trabalha
                for (int n = 0; n < instancia.crew; n++)
                {
                    for (int i = 0; i < instancia.task; i++)
                    {
                        for (int j = 0; j < instancia.date; j++)
                        {
                            modelo.AddConstr(y[n, j] >= z[n, i, j], "R8_" + n + "_" + i + "_" + j);
                        }
                    }
                }
                //restrição 9
                //se o membro de equipe é locado para uma tarefa então z=1
                for (int n = 0; n < instancia.crew; n++)
                {
                    for (int i = 0; i < instancia.task; i++)
                    {
                        for (int j = 0; j < instancia.date; j++)
                        {
                            modelo.AddConstr(z[n, i, j] >= x[n, i, j], "R9_" + n + "_" + i + "_" + j);
                        }
                    }
                }
                //restrição 10
                //a variável z não pode ser 1 se a equipe n não trabalha num dado dia
                for (int n = 0; n < instancia.crew; n++)
                {
                    for (int i = 0; i < instancia.task; i++)
                    {
                        for (int j = 0; j < instancia.date; j++)
                        {
                            modelo.AddConstr(z[n, i, j] <= M * x[n, i, j], "R10_" + n + "_" + i + "_" + j);
                        }
                    }
                }
                //restrição 11
                for (int n = 0; n < instancia.crew; n++)
                {
                    for (int i = 0; i < instancia.task; i++)
                    {
                        for (int j = 0; j < instancia.date; j++)
                        {
                            modelo.AddConstr(z1[n, i] >= z[n, i, j], "R11_" + n + "_" + i + "_" + j);
                        }
                    }
                }

                //Restrições de gerenciemanto

                //restrição 12
                //preferencalmente uma tarefa deve concluida pela mesma pessoa que começou trabalhando nela
                for (int n = 0; n < instancia.crew; n++)
                {
                    for (int i = 0; i < instancia.task; i++)
                    {
                        for (int j = 0; j < instancia.date - 1; j++)
                        {
                            modelo.AddConstr(x5[n, i, j] >= z[n, i, j] - z[n, i, j + 1], "R12_" + n + "_" + i + "_" + j);
                        }
                    }
                }
                //restrição 13
                //uma penalidade será dada ao planejamento se a tarefa i é completada em dias não consecutivos
                for (int i = 0; i < instancia.task; i++)
                {
                    for (int j = 0; j < instancia.date - 1; j++)
                    {
                        modelo.AddConstr(x6[i, j] >= x2[i, j] - x2[i, j + 1], "R13_" + i + "_" + j);
                    }
                }
                //restrição 14
                //o número mínimo de membros de equipe que podem trabalhar simultaneamente em uma tarefa
                for (int i = 0; i < instancia.task; i++)
                {
                    for (int j = 0; j < instancia.date; j++)
                    {
                        exp.Clear();
                        for (int n = 0; n < instancia.crew; n++)
                        {
                            exp.AddTerm(1, z[n, i, j]);
                        }
                        modelo.AddConstr(exp >= instancia.d1[i] * x2[i, j], "R14_" + i + "_" + j);
                    }
                }
                //restrição 15
                //o número máximo de membros de equipe que podem trablhar simultaneamente em uma tarefa
                for (int i = 0; i < instancia.task; i++)
                {
                    for (int j = 0; j < instancia.date; j++)
                    {
                        exp.Clear();
                        for (int n = 0; n < instancia.crew; n++)
                        {
                            exp.AddTerm(1, z[n, i, j]);
                        }
                        modelo.AddConstr(exp <= instancia.d2[i] * x2[i, j], "R15_" + i + "_" + j);
                    }
                }
                //restrição 16
                //número mínimo de membros para trabalhar em um tarefa deve ser respeitado
                for (int n = 0; n < instancia.crew; n++)
                {
                    for (int i = 0; i < instancia.task; i++)
                    {
                        for (int j = 0; j < instancia.date; j++)
                        {
                            modelo.AddConstr(x[n, i, j] <= x3[i, j] / instancia.d1[i], "R16_" + n + "_" + i + "_" + j);
                        }
                    }
                }
                //restrição 17
                //membros de equipe não podem trabalhar em dias em que eles não estão disponíveis
                for (int n = 0; n < instancia.crew; n++)
                {
                    for (int i = 0; i < instancia.task; i++)
                    {
                        for (int j = 0; j < instancia.date; j++)
                        {
                            modelo.AddConstr(z[n, i, j] <= instancia.e[n, j], "R17_" + n + "_" + i + "_" + j);
                        }
                    }
                }

                //Restrições com relação a competência

                //restrição 18
                //a combinação do nível de competencias de todos os membros
                //de equipe deve ser suficiente para cada tarefa
                for (int i = 0; i < instancia.task; i++)
                {
                    for (int j = 0; j < instancia.date; j++)
                    {
                        for (int k = 0; k < instancia.competencies; k++)
                        {
                            exp.Clear();
                            for (int n = 0; n < instancia.crew; n++)
                            {
                                exp.AddTerm(instancia.bm3[n, k], z[n, i, j]);
                            }
                            modelo.AddConstr(exp >= x2[i, j] * instancia.bo[i, k] * instancia.level_total, "R18_" + i + "_" + j + "_" + k);
                        }
                    }
                }
                //restrição 19
                //pelo menos um membro de equipe deve ter nível 3 de competencia para a tarefa i
                for (int i = 0; i < instancia.task; i++)
                {
                    for (int j = 0; j < instancia.date; j++)
                    {
                        for (int k = 0; k < instancia.competencies; k++)
                        {
                            exp.Clear();
                            for (int n = 0; n < instancia.crew; n++)
                            {
                                exp.AddTerm(instancia.bm[n, k], z[n, i, j]);
                            }
                            modelo.AddConstr(exp >= x2[i, j] * instancia.bo[i, k], "R19_" + i + "_" + j + "_" + k);
                        }
                    }
                }
                //restrição 20
                //pelo menos um mebro de equipe tem nível de competencia 3 se vários membros de equipe trabalham na mesma tarefa
                for (int i = 0; i < instancia.task; i++)
                {
                    for (int j = 0; j < instancia.date; j++)
                    {
                        for (int k = 0; k < instancia.competencies; k++)
                        {
                            exp.Clear();
                            exp2.Clear();
                            for (int n = 0; n < instancia.crew; n++)
                            {
                                exp.AddTerm(instancia.bm[n, k], x[n, i, j]);
                                exp2.AddTerm(instancia.bm2[n, k], x[n, i, j]);
                            }
                            modelo.AddConstr(exp >= exp2 * (double)(1 / instancia.d1[i]), "R20_" + i + "_" + j + "_" + k);
                        }
                    }
                }

                //Restrições com relação ao transporte

                //restrição 21
                //cada membro de equipe trabalha em um local técnico em que a tarefa está localizada
                for (int n = 0; n < instancia.crew; n++)
                {
                    for (int p = 0; p < instancia.technical_place; p++)
                    {
                        for (int j = 0; j < instancia.date; j++)
                        {
                            exp.Clear();
                            for (int i = 0; i < instancia.task; i++)
                            {
                                exp.AddTerm(instancia.tp[i, p], z[n, i, j]);
                            }
                            modelo.AddConstr(w[n, p, j] <= exp, "R21_" + n + "_" + p + "_" + j);
                        }
                    }
                }
                //restrição 22
                for (int n = 0; n < instancia.crew; n++)
                {
                    for (int p = 0; p < instancia.technical_place; p++)
                    {
                        for (int j = 0; j < instancia.date; j++)
                        {
                            exp.Clear();
                            for (int i = 0; i < instancia.task; i++)
                            {
                                exp.AddTerm(instancia.tp[i, p], z[n, i, j]);
                            }
                            modelo.AddConstr(w[n, p, j] * M >= exp, "R22_" + n + "_" + p + "_" + j);
                        }
                    }
                }
                //restrição 23
                //o membro de equipe só é transportado entre os locais técnicos que as tarefas dele estão localizadas
                for (int n = 0; n < instancia.crew; n++)
                {
                    for (int p = 0; p < instancia.technical_place; p++)
                    {
                        for (int j = 0; j < instancia.date; j++)
                        {
                            exp.Clear();
                            for (int q = 0; q < instancia.technical_place; q++)
                            {
                                exp.AddTerm(1, v[n, p, q, j]);
                            }
                            modelo.AddConstr(exp <= w[n, p, j] * M, "R23_" + n + "_" + p + "_" + j);
                        }
                    }
                }
                //restrição 24
                for (int n = 0; n < instancia.crew; n++)
                {
                    for (int q = 0; q < instancia.technical_place; q++)
                    {
                        for (int j = 0; j < instancia.date; j++)
                        {
                            exp.Clear();
                            for (int p = 0; p < instancia.technical_place; p++)
                            {
                                exp.AddTerm(1, v[n, p, q, j]);
                            }
                            modelo.AddConstr(exp <= w[n, q, j] * M, "R24_" + n + "_" + q + "_" + j);
                        }
                    }
                }
                //restrição 25
                //se o membro de equipe trabalha em mais do que um local técninco durante o turno
                for (int n = 0; n < instancia.crew; n++)
                {
                    for (int q = 0; q < instancia.technical_place; q++)
                    {
                        for (int j = 0; j < instancia.date; j++)
                        {
                            exp.Clear();
                            for (int p = 0; p < instancia.technical_place; p++)
                            {
                                exp.AddTerm(1, v[n, p, q, j]);
                            }
                            modelo.AddConstr(w1[n, q, j] == exp, "R25_" + n + "_" + q + "_" + j);
                        }
                    }
                }
                //restrição 26
                for (int n = 0; n < instancia.crew; n++)
                {
                    for (int p = 0; p < instancia.technical_place; p++)
                    {
                        for (int j = 0; j < instancia.date; j++)
                        {
                            exp.Clear();
                            for (int q = 0; q < instancia.technical_place; q++)
                            {
                                exp.AddTerm(1, v[n, p, q, j]);
                            }
                            modelo.AddConstr(w2[n, p, j] == exp, "R26_" + n + "_" + p + "_" + j);
                        }
                    }
                }
                //restrição 27
                //cada membro de equipe pode apenas ser transportado de e para cada local técnico uma vez por dia
                for (int n = 0; n < instancia.crew; n++)
                {
                    for (int p = 0; p < instancia.technical_place; p++)
                    {
                        for (int j = 0; j < instancia.date; j++)
                        {
                            modelo.AddConstr(w1[n, p, j] <= 1, "R27_" + n + "_" + p + "_" + j);
                        }
                    }
                }

                //restrição 28
                for (int n = 0; n < instancia.crew; n++)
                {
                    for (int p = 0; p < instancia.technical_place; p++)
                    {
                        for (int j = 0; j < instancia.date; j++)
                        {
                            modelo.AddConstr(w2[n, p, j] <= 1, "R28_" + n + "_" + p + "_" + j);
                        }
                    }
                }
                //restrição 29
                //funcionário será transportado apenas uma vez do e para o depósito
                for (int n = 0; n < instancia.crew; n++)
                {
                    for (int j = 0; j < instancia.date; j++)
                    {
                        exp.Clear();
                        for (int p = 0; p < instancia.technical_place; p++)
                        {
                            exp.AddTerm(2, w[n, p, j]);
                            exp.AddTerm(-1, w1[n, p, j]);
                            exp.AddTerm(-1, w2[n, p, j]);
                        }
                        modelo.AddConstr(exp == 2 * y[n, j], "R29_" + n + "_" + j);
                    }
                }

                //variáveis a serem fixadas
                if (iteracao != 0)
                {
                    for (int n = 0; n < instancia.crew; n++)
                    {
                        //fixar variável y
                        for (int j = 0; j < iteracao - 1; j++)
                        {
                            y[n, j].Set(GRB.DoubleAttr.LB, matriz_RaF_y[n, j]);
                            y[n, j].Set(GRB.DoubleAttr.UB, matriz_RaF_y[n, j]);

                            //fixar variável z
                            for (int i = 0; i < instancia.task; i++)
                            {
                                z[n, i, j].Set(GRB.DoubleAttr.LB, matriz_RaF_z[n, i, j]);
                                z[n, i, j].Set(GRB.DoubleAttr.UB, matriz_RaF_z[n, i, j]);
                            }
                        }
                    }
                }

                //varivais binárias
                //variável z
                for (int n = 0; n < instancia.crew; n++)
                {
                    for (int i = 0; i < instancia.task; i++)
                    {
                        z[n, i, iteracao].Set(GRB.CharAttr.VType, GRB.BINARY);
                    }
                }
                //variável y
                for (int n = 0; n < instancia.crew; n++)
                {
                    y[n, iteracao].Set(GRB.CharAttr.VType, GRB.BINARY);
                }
                //variável x4
                for (int i = 0; i < instancia.task; i++)
                {
                    x4[i].Set(GRB.CharAttr.VType, GRB.BINARY);
                }
                //variável x5
                for (int n = 0; n < instancia.crew; n++)
                {
                    for (int i = 0; i < instancia.task; i++)
                    {
                        for (int j = 0; j < iteracao; j++)
                        {
                            x5[n, i, j].Set(GRB.CharAttr.VType, GRB.BINARY);
                        }
                    }
                }
                //variável x6
                for (int i = 0; i < instancia.task; i++)
                {
                    for (int j = 0; j < iteracao; j++)
                    {
                        x6[i, j].Set(GRB.CharAttr.VType, GRB.BINARY);
                    }
                }
                //variável z1
                for (int n = 0; n < instancia.crew; n++)
                {
                    for (int i = 0; i < instancia.task; i++)
                    {
                        z1[n, i].Set(GRB.CharAttr.VType, GRB.BINARY);
                    }
                }
                //variável w
                for (int n = 0; n < instancia.crew; n++)
                {
                    for (int p = 0; p < instancia.technical_place; p++)
                    {
                        for (int j = 0; j < iteracao; j++)
                        {
                            w[n, p, j].Set(GRB.CharAttr.VType, GRB.BINARY);
                        }
                    }
                }
                //variável v
                for (int n = 0; n < instancia.crew; n++)
                {
                    for (int p = 0; p < instancia.technical_place; p++)
                    {
                        for (int q = 0; q < instancia.technical_place; q++)
                        {
                            for (int j = 0; j < iteracao; j++)
                            {
                                v[n, p, q, j].Set(GRB.CharAttr.VType, GRB.BINARY);
                            }
                        }
                    }
                }
                //variável w1
                for (int n = 0; n < instancia.crew; n++)
                {
                    for (int p = 0; p < instancia.technical_place; p++)
                    {
                        for (int j = 0; j < iteracao; j++)
                        {
                            w1[n, p, j].Set(GRB.CharAttr.VType, GRB.BINARY);
                        }
                    }
                }
                //variável w2
                for (int n = 0; n < instancia.crew; n++)
                {
                    for (int p = 0; p < instancia.technical_place; p++)
                    {
                        for (int j = 0; j < iteracao; j++)
                        {
                            w2[n, p, j].Set(GRB.CharAttr.VType, GRB.BINARY);
                        }
                    }
                }

                //otimizar modelo
                modelo.Set(GRB.DoubleParam.TimeLimit, tempo_iteracao);
                modelo.Update();
                modelo.Optimize();
                tempo_total -= modelo.Get(GRB.DoubleAttr.Runtime);

                //atualizar
                int solverStatus = modelo.Get(GRB.IntAttr.Status);

                if (modelo.SolCount == 0 || solverStatus == 3)
                {
                    status_RF = 999999;
                    return;
                }
                else
                {
                    //salvar a salocao
                    for (int n = 0; n < instancia.crew; n++)
                    {
                        for (int i = 0; i < instancia.task; i++)
                        {
                            //variável z
                            matriz_RaF_z[n, i, iteracao] = z[n, i, iteracao].X;
                        }
                        //variável y
                        matriz_RaF_y[n, iteracao] = y[n, iteracao].X;
                    }
                    // se estiver na última iteracao salvar nas matizes o valor das variáveis
                    if (iteracao == instancia.date)
                    {
                        //variável x
                        for (int n = 0; n < instancia.crew; n++)
                        {
                            for (int i = 0; i < instancia.task; i++)
                            {
                                for (int j = 0; j < instancia.date; j++)
                                {
                                    matriz_RaF_x[n, i, j] = x[n, i, j].X;
                                }
                            }
                        }
                        //variável x3
                        for (int i = 0; i < instancia.task; i++)
                        {
                            for (int j = 0; j < instancia.date; j++)
                            {
                                matriz_RaF_x3[i, j] = x3[i, j].X;
                            }
                        }
                        //vairável x2
                        for (int i = 0; i < instancia.task; i++)
                        {
                            for (int j = 0; j < instancia.date; j++)
                            {
                                matriz_RaF_x2[i, j] = x2[i, j].X;
                            }
                        }
                        //variável x4
                        for (int i = 0; i < instancia.task; i++)
                        {
                            matriz_RaF_x4[i] = x4[i].X;
                        }
                        //variável x5
                        for (int n = 0; n < instancia.crew; n++)
                        {
                            for (int i = 0; i < instancia.task; i++)
                            {
                                for (int j = 0; j < instancia.date; j++)
                                {
                                    matriz_RaF_x5[n, i, j] = x5[n, i, j].X;
                                }
                            }
                        }
                        //variável x6
                        for (int i = 0; i < instancia.task; i++)
                        {
                            for (int j = 0; j < instancia.date; j++)
                            {
                                matriz_RaF_x6[i, j] = x6[i, j].X;
                            }
                        }
                        //variável z1
                        for (int n = 0; n < instancia.crew; n++)
                        {
                            for (int i = 0; i < instancia.task; i++)
                            {
                                matriz_RaF_z1[n, i] = z1[n, i].X;
                            }
                        }
                        //variável w
                        for (int n = 0; n < instancia.crew; n++)
                        {
                            for (int p = 0; p < instancia.technical_place; p++)
                            {
                                for (int j = 0; j < instancia.date; j++)
                                {
                                    matriz_RaF_w[n, p, j] = w[n, p, j].X;
                                }
                            }
                        }
                        //variável v
                        for (int n = 0; n < instancia.crew; n++)
                        {
                            for (int p = 0; p < instancia.technical_place; p++)
                            {
                                for (int q = 0; q < instancia.technical_place; q++)
                                {
                                    for (int j = 0; j < instancia.date; j++)
                                    {
                                        matriz_RaF_v[n, p, q, j] = v[n, p, q, j].X;
                                    }
                                }
                            }
                        }
                        //variável w1
                        for (int n = 0; n < instancia.crew; n++)
                        {
                            for (int p = 0; p < instancia.technical_place; p++)
                            {
                                for (int j = 0; j < instancia.date; j++)
                                {
                                    matriz_RaF_w1[n, p, j] = w1[n, p, j].X;
                                }
                            }
                        }
                        //variável w2
                        for (int n = 0; n < instancia.crew; n++)
                        {
                            for (int p = 0; p < instancia.technical_place; p++)
                            {
                                for (int j = 0; j < instancia.date; j++)
                                {
                                    matriz_RaF_w2[n, p, j] = w2[n, p, j].X;
                                }
                            }
                        }
                    }
                }
                if (iteracao == instancia.date)
                {
                    double funcaoObjetivo;
                    funcaoObjetivo = modelo.Get(GRB.DoubleAttr.ObjVal);
                    Console.WriteLine("Solução atual:" + funcaoObjetivo.ToString());
                    lista_RF.Add(funcaoObjetivo);
                    soma_RF += funcaoObjetivo;
                }
            }

            //Relaz and Fix

            //Stopwatch para contar o tempo
            Stopwatch relogio = new Stopwatch();

            tempo_total = 3600;
            relogio.Start();
            for (int j = 0; j < instancia.date; j++)
            {
                status_RF      = 0;
                tempo_iteracao = tempo_total / (instancia.date - j + 1);
                modelo_RelaxAndFixData(j);
                if (status_RF != 0)
                {
                    lista_RF.Add(99999999);
                    soma_RF += 99999999;
                }
            }
            relogio.Stop();
            Console.WriteLine("tempo total de:" + (relogio.ElapsedMilliseconds / 1000).ToString() + "segundos");
            Console.ReadKey();
        }
Exemple #6
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();
        }
Exemple #7
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 };

          // Amount each worker is paid to work one shift
          double[] pay = new double[] { 10, 12, 10, 8, 8, 9, 11 };

          // 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.Set(GRB.StringAttr.ModelName, "assignment");

          // Assignment variables: x[w][s] == 1 if worker w is assigned
          // to shift s. Since an assignment model always produces integer
          // solutions, we use continuous variables and solve as an LP.
          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], pay[w], GRB.CONTINUOUS,
                           Workers[w] + "." + Shifts[s]);
        }
          }

          // The objective is to minimize the total pay costs
          model.Set(GRB.IntAttr.ModelSense, 1);

          // Update model to integrate new variables
          model.Update();

          // Constraint: assign exactly shiftRequirements[s] workers
          // to each shift s
          LinkedList<GRBConstr> reqCts = new LinkedList<GRBConstr>();
          for (int s = 0; s < nShifts; ++s) {
        GRBLinExpr lhs = 0.0;
        for (int w = 0; w < nWorkers; ++w)
          lhs += x[w,s];
        GRBConstr newCt =
            model.AddConstr(lhs == shiftRequirements[s], Shifts[s]);
        reqCts.AddFirst(newCt);
          }

          // Optimize
          model.Optimize();
          int status = model.Get(GRB.IntAttr.Status);
          if (status == GRB.Status.UNBOUNDED) {
        Console.WriteLine("The model cannot be solved "
            + "because it is unbounded");
        return;
          }
          if (status == GRB.Status.OPTIMAL) {
        Console.WriteLine("The optimal objective is " +
            model.Get(GRB.DoubleAttr.ObjVal));
        return;
          }
          if ((status != GRB.Status.INF_OR_UNBD) &&
          (status != GRB.Status.INFEASIBLE)) {
        Console.WriteLine("Optimization was stopped with status " + status);
        return;
          }

          // Add slack variables to make the model feasible
          Console.WriteLine("The model is infeasible; adding slack variables");

          // Set original objective coefficients to zero
          model.SetObjective(new GRBLinExpr());

          // Add a new slack variable to each shift constraint so that the shifts
          // can be satisfied
          LinkedList<GRBVar> slacks = new LinkedList<GRBVar>();
          foreach (GRBConstr c in reqCts) {
        GRBColumn col = new GRBColumn();
        col.AddTerm(1.0, c);
        GRBVar newvar =
            model.AddVar(0, GRB.INFINITY, 1.0, GRB.CONTINUOUS, col,
                         c.Get(GRB.StringAttr.ConstrName) + "Slack");
        slacks.AddFirst(newvar);
          }

          // Solve the model with slacks
          model.Optimize();
          status = model.Get(GRB.IntAttr.Status);
          if ((status == GRB.Status.INF_OR_UNBD) ||
          (status == GRB.Status.INFEASIBLE) ||
          (status == GRB.Status.UNBOUNDED)) {
        Console.WriteLine("The model with slacks cannot be solved "
            + "because it is infeasible or unbounded");
        return;
          }
          if (status != GRB.Status.OPTIMAL) {
        Console.WriteLine("Optimization was stopped with status " + status);
        return;
          }

          Console.WriteLine("\nSlack values:");
          foreach (GRBVar sv in slacks) {
        if (sv.Get(GRB.DoubleAttr.X) > 1e-6) {
          Console.WriteLine(sv.Get(GRB.StringAttr.VarName) + " = " +
              sv.Get(GRB.DoubleAttr.X));
        }
          }

          // Dispose of model and env
          model.Dispose();
          env.Dispose();

        } catch (GRBException e) {
          Console.WriteLine("Error code: " + e.ErrorCode + ". " +
          e.Message);
        }
    }
Exemple #8
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");

          // Integrate new variables

          model.Update();

          // Set objective

          GRBQuadExpr obj = x*x + x*y + y*y + y*z + z*z;
          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.Get(GRB.StringAttr.VarName)
                         + " " + x.Get(GRB.DoubleAttr.X));
          Console.WriteLine(y.Get(GRB.StringAttr.VarName)
                         + " " + y.Get(GRB.DoubleAttr.X));
          Console.WriteLine(z.Get(GRB.StringAttr.VarName)
                         + " " + z.Get(GRB.DoubleAttr.X));

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

          // Change variable types to integer

          x.Set(GRB.CharAttr.VType, GRB.INTEGER);
          y.Set(GRB.CharAttr.VType, GRB.INTEGER);
          z.Set(GRB.CharAttr.VType, GRB.INTEGER);

          // Optimize model

          model.Optimize();

          Console.WriteLine(x.Get(GRB.StringAttr.VarName)
                         + " " + x.Get(GRB.DoubleAttr.X));
          Console.WriteLine(y.Get(GRB.StringAttr.VarName)
                         + " " + y.Get(GRB.DoubleAttr.X));
          Console.WriteLine(z.Get(GRB.StringAttr.VarName)
                         + " " + z.Get(GRB.DoubleAttr.X));

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

          // Dispose of model and env

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

        } catch (GRBException e) {
          Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message);
        }
    }
        public override Schedule Generate(Scenario scenario, FilledBaseline baseline = null)
        {
            var opportunities    = scenario.Projects.Where(p => p is Opportunity).ToArray();
            var batches          = scenario.Projects.SelectMany(p => p.Batches).ToArray();
            var batchesBothLines = batches.Where(b => b.Compatibility == Batch.LineCompatibility.Both).ToArray();
            var batchesLine1     = batches.Where(b => b.Compatibility == Batch.LineCompatibility.Line1).ToArray();
            var batchesLine2     = batches.Where(b => b.Compatibility == Batch.LineCompatibility.Line2).ToArray();

            int       bBc          = batchesBothLines.Count();
            var       earliestDate = scenario.Projects.Min(p => p.DeliveryDate);
            var       lastDate     = scenario.Projects.Max(p => p.DeliveryDate.AddDays(7 * p.Batches.Count())).AddDays(7 * 3); // add an additional buffer of 3 weeks.
            double    maxDays      = (lastDate - earliestDate).Days;
            var       maxWeek      = maxDays / 7 + 2;
            const int weeksBuffer  = 3;

            const double numericScale = 100d;

            const double delayPenaltyMultiplier    = 0.01;            // 1% of revenue per week
            const double interestPenaltyMultiplier = (0.045 / 52.14); // 4.5%  / 52.14 * (revenue – margin)


            var env = new GRBEnv();

            env.Set(GRB.IntParam.UpdateMode, 1);
            env.Set(GRB.IntParam.LogToConsole, 1);
            //env.Set(GRB.IntParam.ScaleFlag, 2);
            //env.Set(GRB.IntParam.Presolve, 0);
            //env.Set(GRB.DoubleParam.TimeLimit, _config.TimeLimit.Value);
            //env.Set(GRB.DoubleParam.MIPGap, 0.02);

            var m = new GRBModel(env);

            // decide: which batch is when, on which line
            // [batch, time]
            var varBatchTimeLine1 = m.AddVars(bBc + batchesLine1.Count(), bBc + batchesLine1.Count(), 0, 1, GRB.BINARY, "varBatchTimeLine1");
            var varBatchTimeLine2 = m.AddVars(bBc + batchesLine2.Count(), bBc + batchesLine2.Count(), 0, 1, GRB.BINARY, "varBatchTimeLine2");
            // what are the time differences between times
            var varBatchTimeDiffsLine1 = m.AddVars(bBc + batchesLine1.Count() - 1, 0, maxDays, GRB.CONTINUOUS, "varBatchTimeDiffsLine1");
            var varBatchTimeDiffsLine2 = m.AddVars(bBc + batchesLine2.Count() - 1, 0, maxDays, GRB.CONTINUOUS, "varBatchTimeDiffsLine2");
            var varLineDecision        = m.AddVars(bBc, 0, 1, GRB.BINARY, "varLineDecision"); // 0 = Line1, 1 = Line2


            // make stupid solution:
            // assign fixed projects, set the rest as unused
            m.Update();
            for (int l = 0; l < 2; l++)
            {
                var line  = l == 0 ? varBatchTimeLine1 : varBatchTimeLine2;
                var diffs = l == 0 ? varBatchTimeDiffsLine1 : varBatchTimeDiffsLine2;
                for (int i = 0; i < diffs.GetLength(0); i++)
                {
                    diffs[i].Set(GRB.DoubleAttr.Start, 0);
                }
                //m.AddConstr(diffs[i] == 0, "initial solution diffs");

                int lineT = 0;
                for (int bi = bBc; bi < line.GetLength(0); bi++)
                {
                    var  batch          = (l == 0 ? batchesLine1 : batchesLine2)[bi - bBc];
                    bool isFixedProject = scenario.Projects.First(p => p.Batches.Contains(batch)) is FixedProject;
                    if (isFixedProject)
                    {
                        line[bi, lineT].Set(GRB.DoubleAttr.Start, 1);
                        //m.AddConstr(line[bi, lineT] == 1, "assign batches of project in succession");
                        for (int j = 0; j < line.GetLength(1); j++)
                        {
                            if (j != lineT)
                            {
                                line[bi, j].Set(GRB.DoubleAttr.Start, 0);
                            }
                        }
                        //m.AddConstr(line[bi, j] == 0, "initial solution");
                        lineT++;
                    }
                    else
                    {
                        for (int j = 0; j < line.GetLength(1); j++)
                        {
                            line[bi, j].Set(GRB.DoubleAttr.Start, 0);
                        }
                        //m.AddConstr(line[bi, j] == 0, "initial solution");
                    }
                }

                // make zeros also for both line batches
                for (int i = 0; i < bBc; i++)
                {
                    for (int j = 0; j < line.GetLength(1); j++)
                    {
                        line[i, j].Set(GRB.DoubleAttr.Start, 0);
                    }
                }
                //m.AddConstr(line[i, j] == 0, "initial solution");
            }


            // line constraints:

            // assign batch only once (constraint for single lines then both lines)
            // if it's a fixed project though, then it must be allocated
            for (int l = 0; l < 2; l++)
            {
                var line = l == 0 ? varBatchTimeLine1 : varBatchTimeLine2;
                for (int bi = bBc; bi < line.GetLength(0); bi++)
                {
                    var batchTotal = new GRBLinExpr();
                    for (int t = 0; t < line.GetLength(1); t++)
                    {
                        batchTotal += line[bi, t];
                    }
                    var  batch          = (l == 0 ? batchesLine1 : batchesLine2)[bi - bBc];
                    bool isFixedProject = scenario.Projects.First(p => p.Batches.Contains(batch)) is FixedProject;
                    if (!isFixedProject)
                    {
                        m.AddConstr(batchTotal <= 1, "assign batch only once");
                    }
                    else
                    {
                        m.AddConstr(batchTotal == 1, "assign batch exactly once");
                    }
                }
            }
            for (int bi = 0; bi < bBc; bi++)
            {
                var batchTotal = new GRBLinExpr();
                for (int t = 0; t < varBatchTimeLine1.GetLength(1); t++)
                {
                    batchTotal += varBatchTimeLine1[bi, t];
                }
                for (int t = 0; t < varBatchTimeLine2.GetLength(1); t++)
                {
                    batchTotal += varBatchTimeLine2[bi, t];
                }

                var  batch          = batchesBothLines[bi];
                bool isFixedProject = scenario.Projects.First(p => p.Batches.Contains(batch)) is FixedProject;
                if (!isFixedProject)
                {
                    m.AddConstr(batchTotal <= 1, "assign batch only once");
                }
                else
                {
                    m.AddConstr(batchTotal == 1, "assign batch exactly once");
                }
            }

            // a time slot can only be used once on each line
            for (int l = 0; l < 2; l++)
            {
                var line = l == 0 ? varBatchTimeLine1 : varBatchTimeLine2;
                for (int t = 0; t < line.GetLength(1); t++)
                {
                    var timeTotal = new GRBLinExpr();
                    for (int bi = 0; bi < line.GetLength(0); bi++)
                    {
                        timeTotal += line[bi, t];
                    }
                    m.AddConstr(timeTotal <= 1, "assign time slot only once on line " + (l + 1).ToString());
                }
            }


            // for all batches which aren't assigned to a line yet, limit the allocation of yet unassigned batches of a project to one line
            // TODO: If project has e.g. line1 and both lines, limit both lines to line 1?
            for (int pi = 0; pi < scenario.Projects.Count(); pi++)
            {
                var p = scenario.Projects[pi];

                if (!p.Batches.Any(b => b.Compatibility == Batch.LineCompatibility.Both))
                {
                    continue;
                }

                int lineRestriction = -1;
                if (p.Batches.Any(b => b.Compatibility != Batch.LineCompatibility.Both))
                {
                    lineRestriction = p.Batches.First(b => b.Compatibility != Batch.LineCompatibility.Both).Compatibility == Batch.LineCompatibility.Line1 ? 0 : 1;
                }

                int i_prev = -1;
                for (int j = 0; j < p.Batches.Count(); j++)
                {
                    if (p.Batches[j].Compatibility != Batch.LineCompatibility.Both)
                    {
                        continue;
                    }

                    var i = batchesBothLines.IndexOf(p.Batches[j]);
                    if (lineRestriction == -1)
                    {
                        if (i_prev != -1)
                        {
                            m.AddConstr(varLineDecision[i] == varLineDecision[i_prev], "lineDecisionRestrictionAllSame");
                        }
                    }
                    else
                    {
                        // if there are other batches on this project which are already on a specific line, limit to the same line
                        m.AddConstr(varLineDecision[i] == lineRestriction, "lineDecisionRestrictionSpecific");
                    }
                    i_prev = i;
                }
            }


            // for each project, either all or no batches must be assigned
            var totalBatchesOfProject = new Dictionary <Project, List <GRBLinExpr> >();

            foreach (var p in scenario.Projects)
            {
                var allBatches = new List <GRBLinExpr>();

                // gather the total of all batches
                GRBLinExpr previousBatchTotal = null;
                for (int bi = 0; bi < p.Batches.Count(); bi++)
                {
                    var b          = p.Batches[bi];
                    var batchTotal = new GRBLinExpr();
                    if (b.Compatibility == Batch.LineCompatibility.Line1)
                    {
                        var bIndex = bBc + batchesLine1.IndexOf(b);
                        for (int ti = 0; ti < varBatchTimeLine1.GetLength(1); ti++)
                        {
                            batchTotal += varBatchTimeLine1[bIndex, ti];
                        }
                    }
                    else if (b.Compatibility == Batch.LineCompatibility.Line2)
                    {
                        var bIndex = bBc + batchesLine2.IndexOf(b);
                        for (int ti = 0; ti < varBatchTimeLine2.GetLength(1); ti++)
                        {
                            batchTotal += varBatchTimeLine2[bIndex, ti];
                        }
                    }
                    else
                    {
                        var bIndex = batchesBothLines.IndexOf(b);
                        for (int t = 0; t < varBatchTimeLine1.GetLength(1); t++)
                        {
                            batchTotal += varBatchTimeLine1[bIndex, t];
                        }
                        for (int t = 0; t < varBatchTimeLine2.GetLength(1); t++)
                        {
                            batchTotal += varBatchTimeLine2[bIndex, t];
                        }
                    }

                    // the sum of this batch over all times (0 or 1) has to be the same as the sum of the previous one
                    if (bi > 0)
                    {
                        //m.AddConstr(previousBatchTotal == batchTotal, "allBatchesAllocatedOrNot");
                    }

                    previousBatchTotal = batchTotal;
                    allBatches.Add(batchTotal);
                }
                totalBatchesOfProject.Add(p, allBatches);
            }

            // Tbd: Only half of the batch slots of line 1 may be occupied. Sometimes existst as internal projects.
            // fill gap between 50% and internal projects, monthly resolution

            // gather the time of time slots
            GRBLinExpr[] startTimesLine1    = new GRBLinExpr[varBatchTimeLine1.GetLength(1)];
            GRBLinExpr[] startTimesLine2    = new GRBLinExpr[varBatchTimeLine2.GetLength(1)];
            var          varStartTimesLine1 = m.AddVars(startTimesLine1.Count(), 0, maxDays, GRB.CONTINUOUS, "varStartTimesLine1");
            var          varStartTimesLine2 = m.AddVars(startTimesLine2.Count(), 0, maxDays, GRB.CONTINUOUS, "varStartTimesLine2");

            for (int l = 0; l < 2; l++)
            {
                var batchLine      = l == 0 ? varBatchTimeLine1 : varBatchTimeLine2;
                var startTimes     = l == 0 ? startTimesLine1 : startTimesLine2;
                var batchesLine    = l == 0 ? batchesLine1 : batchesLine2;
                var batchTimeDiffs = l == 0 ? varBatchTimeDiffsLine1 : varBatchTimeDiffsLine2;

                for (int t = 0; t < batchLine.GetLength(1); t++)
                {
                    startTimes[t] = new GRBLinExpr();
                    // sum up all durations and buffer times before this time instance
                    for (int previous_t = 0; previous_t < t; previous_t++)
                    {
                        var duration_prev_t = new GRBLinExpr();
                        for (int bi = 0; bi < batchLine.GetLength(0); bi++)
                        {
                            var batch    = bi < bBc ? batchesBothLines[bi] : batchesLine[bi];
                            var duration = batch.UsedWorkHours / 24d;
                            duration_prev_t += batchLine[bi, previous_t] * duration;
                        }
                        duration_prev_t += batchTimeDiffs[previous_t];

                        startTimes[t] += duration_prev_t;
                    }
                }

                var varStartTime = l == 0 ? varStartTimesLine1 : varStartTimesLine2;
                for (int i = 0; i < varStartTime.Count(); i++)
                {
                    m.AddConstr(varStartTime[i] == startTimes[i], "varStartTimeAssignment");
                }
            }


            // gather the start time of the batches
            var varStartTimesBatches1 = m.AddVars(varBatchTimeLine1.GetLength(0), 0, maxDays, GRB.CONTINUOUS, "varBatchStartTimesLine1");
            var varStartTimesBatches2 = m.AddVars(varBatchTimeLine2.GetLength(0), 0, maxDays, GRB.CONTINUOUS, "varBatchStartTimesLine2");

            for (int l = 0; l < 2; l++)
            {
                var batchLine       = l == 0 ? varBatchTimeLine1 : varBatchTimeLine2;
                var batchStartTimes = l == 0 ? varStartTimesBatches1 : varStartTimesBatches2;
                var batchesLine     = l == 0 ? batchesLine1 : batchesLine2;
                var varStartTimes   = l == 0 ? varStartTimesLine1 : varStartTimesLine2;

                for (int bi = 0; bi < batchLine.GetLength(0); bi++)
                {
                    // make the batch take the value of its time slot
                    for (int ti = 0; ti < batchLine.GetLength(1); ti++)
                    {
                        m.AddConstr(batchStartTimes[bi] <= varStartTimes[ti] + maxDays * (1 - batchLine[bi, ti]), "batchTimeAssignment");
                        m.AddConstr(batchStartTimes[bi] >= varStartTimes[ti] - maxDays * (1 - batchLine[bi, ti]), "batchTimeAssignment");
                    }
                }
            }


            // scheduling formulation
            for (int l = 0; l < 2; l++)
            {
                var varBatchStartTimes = l == 0 ? varStartTimesBatches1 : varStartTimesBatches2;
                var line = batchesBothLines.ToList();
                line.AddRange(l == 0 ? batchesLine1 : batchesLine2);

                for (int bi1 = 0; bi1 < line.Count() - 1; bi1++)
                {
                    var batch1         = line[bi1];
                    var o1_exists      = opportunities.FirstOrDefault(o => o.Batches.Contains(batch1));
                    var oi1            = o1_exists != null ? (1 - totalBatchesOfProject[o1_exists][0]) : new GRBLinExpr();
                    var s1             = varBatchStartTimes[bi1];
                    var bothLineSlack1 = (bi1 < bBc) ? (l == 0 ? varLineDecision[bi1] - 0 : 1 - varLineDecision[bi1]) : new GRBLinExpr();
                    for (int bi2 = bi1 + 1; bi2 < line.Count(); bi2++)
                    {
                        var batch2         = line[bi2];
                        var o2_exists      = opportunities.FirstOrDefault(o => o.Batches.Contains(batch2));
                        var oi2            = o2_exists != null ? (1 - totalBatchesOfProject[o1_exists][0]) : new GRBLinExpr();
                        var s2             = varBatchStartTimes[bi2];
                        var bothLineSlack2 = (bi2 < bBc) ? (l == 0 ? varLineDecision[bi2] - l : l - varLineDecision[bi2]) : new GRBLinExpr();

                        // S1 - E2 >= 0 OR S2 - E1 >= 0
                        // IF both batches are used
                        var decisionVar                   = m.AddVar(0, 1, GRB.BINARY, "schedulingORvar");
                        var opportunityNotUsedSlack       = oi1 + oi2;
                        var varBothLinesLineDecisionSlack = bothLineSlack1 + bothLineSlack2; // LineDecisionSlack for both lines batches, i.e. if a bothline batch is used, don't restrict unused line.
                        m.AddConstr(s1 - (s2 + batch2.UsedWorkHours / 24d) >= -maxDays * (decisionVar + opportunityNotUsedSlack + varBothLinesLineDecisionSlack), "batchesScheduling");
                        m.AddConstr(s2 - (s1 + batch1.UsedWorkHours / 24d) >= -maxDays * (1 - decisionVar + opportunityNotUsedSlack + varBothLinesLineDecisionSlack), "batchesScheduling");
                    }
                }
            }


            // Maximize the margin (including delay and interest penalties) and the workload
            // Only the delivery of the first batch is really important. The rest is less important.

            var margin     = new GRBLinExpr();
            var delays     = new List <GRBLinExpr>();
            var interests  = new List <GRBLinExpr>();
            var weekValues = new List <GRBLinExpr>();
            var weekDiffs  = new List <GRBLinExpr>();

            foreach (var p in scenario.Projects)
            {
                // if the project is used add the margin
                if (p is Opportunity)
                {
                    margin += totalBatchesOfProject[p][0] * p.Margin * (1d / numericScale);
                }
                else
                {
                    margin += p.Margin / numericScale;
                }

                // deduct the delay penalty for each batch.
                var startDayOfProject = (p.DeliveryDate - earliestDate).TotalDays;
                var varMaxedValue     = m.AddVars(p.Batches.Count(), 0, maxWeek, GRB.CONTINUOUS, "penaltyIndicator" + p.Description);
                //var varDecisionVar = m.AddVars(p.Batches.Count(), 0, 1, GRB.BINARY, "penaltyIndicator" + p.Description);

                //m.Update();
                GRBLinExpr previousWeekValue = new GRBLinExpr();
                for (int pbi = 0; pbi < p.Batches.Count(); pbi++)
                {
                    var b = p.Batches[pbi];
                    // compare the minimal batch time (3 + 1 weeks) to the actual delivery time

                    GRBLinExpr weekValue;
                    if (batchesLine1.Contains(b))
                    {
                        var bi = batchesLine1.IndexOf(b) + bBc;
                        weekValue = varStartTimesBatches1[bi] / 7d;
                    }
                    else if (batchesLine2.Contains(b))
                    {
                        var bi = batchesLine2.IndexOf(b) + bBc;
                        weekValue = varStartTimesBatches2[bi] / 7d;
                    }
                    else
                    {
                        var bi = batchesBothLines.IndexOf(b);
                        // create a new var
                        var bothLineWeekVar = m.AddVar(0, maxWeek, GRB.CONTINUOUS, "weekValueBothLines");
                        //m.Update();
                        m.AddConstr(bothLineWeekVar >= varStartTimesBatches1[bi] / 7d - (varLineDecision[bi]) * maxWeek, "weekValueBothLinesDefinitionByConstraints");
                        m.AddConstr(bothLineWeekVar <= varStartTimesBatches1[bi] / 7d + (varLineDecision[bi]) * maxWeek, "weekValueBothLinesDefinitionByConstraints");
                        m.AddConstr(bothLineWeekVar >= varStartTimesBatches2[bi] / 7d - (1 - varLineDecision[bi]) * maxWeek, "weekValueBothLinesDefinitionByConstraints");
                        m.AddConstr(bothLineWeekVar <= varStartTimesBatches2[bi] / 7d + (1 - varLineDecision[bi]) * maxWeek, "weekValueBothLinesDefinitionByConstraints");
                        weekValue = bothLineWeekVar;
                    }


                    if (true || pbi < p.Batches.Count() - 1)
                    {
                        // for positive difference add delay penalty, for negative difference add interest penalty
                        // x = opportunity used ? x : 0
                        // var = max(0, x)
                        // margin += var * delay
                        // margin += (x - var) * interest
                        var        plannedWeek = startDayOfProject / 7d + pbi * (weeksBuffer + 1);
                        GRBLinExpr weekDiff;
                        if (p is Opportunity)
                        {
                            var weekDiffIfUsed = m.AddVar(-maxWeek, maxWeek, GRB.CONTINUOUS, "weekDiffIfUsed");
                            //m.Update();
                            var wD = weekValue - plannedWeek;
                            m.AddConstr(weekDiffIfUsed >= wD - (1 - totalBatchesOfProject[p][0]) * maxWeek, "weekDiffConstraintDefinition1");
                            m.AddConstr(weekDiffIfUsed <= wD + (1 - totalBatchesOfProject[p][0]) * maxWeek, "weekDiffConstraintDefinition2");
                            m.AddConstr(weekDiffIfUsed <= (totalBatchesOfProject[p][0]) * maxWeek, "weekDiffConstraintDefinition3");
                            m.AddConstr(weekDiffIfUsed >= -(totalBatchesOfProject[p][0]) * maxWeek, "weekDiffConstraintDefinition4");
                            weekDiff = weekDiffIfUsed;
                        }
                        else
                        {
                            weekDiff = weekValue - plannedWeek;
                        }

                        m.AddConstr(varMaxedValue[pbi] >= weekDiff, "maxedWeekDiffValueConstraintDefinition");
                        //m.AddConstr(varMaxedValue[pbi] >= 0, "maxedWeekDiffValueConstraintDefinition");
                        //m.AddConstr(varMaxedValue[pbi] <= weekDiff + maxWeek * (varDecisionVar[pbi]), "maxedWeekDiffValueConstraintDefinition");
                        //m.AddConstr(varMaxedValue[pbi] <= 0 + maxWeek * (1 - varDecisionVar[pbi]), "maxedWeekDiffValueConstraintDefinition");


                        double firstBatchImportance = pbi == 0 ? 1 : 0.2; // mainly the first batch is important, the rest is meh
                        weekValues.Add(weekValue);
                        weekDiffs.Add(weekDiff);
                        double revenueBase = p.Revenue == 0 ? 1E+8 : p.Revenue; // if it's an internal project it must not be shifted, therefore we make the penalty high
                        revenueBase /= numericScale;
                        delays.Add(varMaxedValue[pbi] * delayPenaltyMultiplier * revenueBase * firstBatchImportance);
                        interests.Add(-(weekDiff - varMaxedValue[pbi]) * interestPenaltyMultiplier * revenueBase * firstBatchImportance);
                        margin -= delays.Last() + interests.Last();
                    }

                    // constraint: batches of a project have to be in succession, i.e. batch2 can't come after batch3 chronologically
                    if (pbi > 0)
                    {
                        m.AddConstr(weekValue - previousWeekValue >= 0, "batchesOfProjectHaveToBeInSuccession");
                    }
                    previousWeekValue = weekValue;
                }
            }



            //m.SetObjective(margin, GRB.MAXIMIZE);

            m.Update();
            m.Write("ilproman3.mps");
            m.Write("ilproman3.mst");

            //m.Tune();
            //m.GetTuneResult(0);
            m.Optimize();

            //env.Set(GRB.IntParam.IISMethod, 0); // makes IIS computation fast but potentially inaccurate
            m.ComputeIIS();
            m.Write("ilp.ilp");


            // TODO: Max 5 weeks delay per project


            // build the solution from the optimization
            var    sol                = new Schedule();
            int    batchCount         = 0;
            double cumulatedDelays    = 0;
            double cumulatedInterests = 0;

            foreach (var p in scenario.Projects)
            {
                List <Schedule.BatchAllocation> allocatedBatches = new List <Schedule.BatchAllocation>();
                var data = new List <double[]>();
                for (int bi = 0; bi < p.Batches.Count(); bi++)
                {
                    var b        = p.Batches[bi];
                    var delay    = delays[batchCount].Value;
                    var interest = interests[batchCount].Value;
                    cumulatedDelays    += delay;
                    cumulatedInterests += interest;
                    var weekValue = weekValues[batchCount].Value;
                    var weekDiff  = weekDiffs[batchCount].Value;
                    // figure out on which week and which line the batch is allocated
                    double dayLine1 = 0;
                    double dayLine2 = 0;
                    if (b.Compatibility == Batch.LineCompatibility.Line1)
                    {
                        dayLine1 = varStartTimesBatches1[bBc + batchesLine1.IndexOf(b)].Get(GRB.DoubleAttr.X);
                    }
                    else if (b.Compatibility == Batch.LineCompatibility.Line2)
                    {
                        dayLine2 = varStartTimesBatches2[bBc + batchesLine2.IndexOf(b)].Get(GRB.DoubleAttr.X);
                    }
                    else
                    {
                        var bbi          = batchesBothLines.IndexOf(b);
                        var lineDecision = varLineDecision[bbi].Get(GRB.DoubleAttr.X);
                        dayLine1 = varStartTimesBatches1[bbi].Get(GRB.DoubleAttr.X) * (1 - lineDecision);
                        dayLine2 = varStartTimesBatches2[bbi].Get(GRB.DoubleAttr.X) * lineDecision;
                    }

                    data.Add(new double[] { delay, interest, weekValue, weekDiff, dayLine1 + dayLine2 });

                    if (dayLine1 > 0 && dayLine2 > 0)
                    {
                        throw new InvalidOperationException();
                    }

                    var alloc = Schedule.LineAllocation.None;
                    if (p is FixedProject || (p is Opportunity && totalBatchesOfProject[p][0].Value > 0.5))
                    {
                        if (b.Compatibility == Batch.LineCompatibility.Both)
                        {
                            alloc = varLineDecision[batchesBothLines.IndexOf(b)].Get(GRB.DoubleAttr.X) > 0.5 ? Schedule.LineAllocation.Line2 : Schedule.LineAllocation.Line1;
                        }
                        else
                        {
                            alloc = b.Compatibility == Batch.LineCompatibility.Line1 ? Schedule.LineAllocation.Line1 : Schedule.LineAllocation.Line2;
                        }
                    }
                    //if (dayLine1 > 0) alloc = Solution.LineAllocation.Line1;
                    //if (dayLine2 > 0) alloc = Solution.LineAllocation.Line2;

                    allocatedBatches.Add(new Schedule.BatchAllocation(b, alloc, earliestDate.AddDays(dayLine1 + dayLine2)));
                    batchCount++;
                }
                sol.Add(new Schedule.ProjectAllocation(p, allocatedBatches));
            }

            /*var maxMustWinDate = mustWinOpportunitites.Max(p => p.DeliveryDate.AddDays(7 * p.Batches.Count())).AddDays(7 * 3);
             * var minMustWinDate = mustWinOpportunitites.Min(p2 => p2.DeliveryDate);
             * var sevenmonthsrange = sol.Where(p => p.Project.DeliveryDate >= minMustWinDate && p.Project.DeliveryDate <= maxMustWinDate).ToArray();
             * var ops = sevenmonthsrange.Where(p => mustWinOpportunitites.Contains(p.Project) || p.Project is FixedProject);
             * var s = ops.Sum(p => p.Project.Revenue);*/

            return(sol);
        }
        public Instance Match(Instance instance, string path, bool print)
        {
            try
            {
                LP = "";
                if (!System.IO.Directory.Exists(path) && print)
                    System.IO.Directory.CreateDirectory(path);

                GRBEnv env = new GRBEnv("mip1.log");
                GRBModel model = new GRBModel(env);

                List<LPEdge> LPEdges = new List<LPEdge>();


                if (print)
                {
                    instance.Draw().Save(path + "/0Start.bmp");
                }

                int EdgeCounter = 0;
                foreach (Instance.Applicant a in instance.Applicants)
                {
                    EdgeCounter += a.Priorities.Count;
                    foreach (Instance.Priority Prio in a.Priorities)
                    {
                        {
                            LPEdges.Add(new LPEdge(a, instance.Posts[Prio.Target], Prio.Rank));
                            if (Prio.Rank == 0)
                                instance.Posts[Prio.Target].IsF = 1;
                        }
                    }

                }
                // Create variables

                GRBVar[] Edges = new GRBVar[EdgeCounter];

                for (int i = 0; i < Edges.Length; i++)
                {
                    Edges[i] = model.AddVar(0.0, 1.0, 0.0, GRB.BINARY, "ve" + i.ToString());
                }

                // Integrate new variables

                model.Update();

                if (print)
                    LP += "Applicant Matching Conditions:" + Environment.NewLine;

                foreach (Instance.Applicant a in instance.Applicants)
                {
                    GRBLinExpr Temp = new GRBLinExpr();
                    for (int i = 0; i < LPEdges.Count; i++)
                    {
                        if (LPEdges[i].Applicant == a)
                        {
                            Temp += Edges[i];
                            if (print)
                                LP += "(a" + LPEdges[i].Applicant.ID + ", p" + LPEdges[i].Post.ID + ") + ";
                        }
                    }
                    model.AddConstr(Temp == 1.0, "a" + a.ID.ToString());
                    if (print)
                        LP += " = 1;" + Environment.NewLine;
                }

                if (print)
                    LP += Environment.NewLine + "Post Matching Conditions:" + Environment.NewLine;
                
                foreach (Instance.Post p in instance.Posts)
                {
                    GRBLinExpr Temp = new GRBLinExpr();
                    for (int i = 0; i < LPEdges.Count; i++)
                    {
                        if (LPEdges[i].Post == p)
                        {
                            Temp += Edges[i];
                            if (print)
                                LP += "(a" + LPEdges[i].Applicant.ID + ", p" + LPEdges[i].Post.ID + ") + ";
                        }
                    }
                    model.AddConstr(Temp <= 1.0, "p" + p.ID.ToString());
                    if (print)
                        LP += " <= 1;" + Environment.NewLine;
                }

                if (print)
                    LP += Environment.NewLine + "First Choice Conditions:" + Environment.NewLine;

                for (int i = 0; i < LPEdges.Count; i++)
                {
                    LPEdge le1 = LPEdges[i];

                    if (le1.Post.IsF == 1 && le1.Rank != 0)
                    {
                        model.AddConstr(Edges[i] <= 0, "s" + i.ToString());
                        if (print)
                            LP += "(a" + LPEdges[i].Applicant.ID + ", p" + LPEdges[i].Post.ID + ") <= 0;" + Environment.NewLine;

                        for (int j = 0; j < LPEdges[i].Applicant.Priorities.Count; j++)
                        {
                            if (LPEdges[i].Applicant.Priorities[j].Target == LPEdges[i].Post.ID && LPEdges[i].Rank == LPEdges[i].Applicant.Priorities[j].Rank)
                            {
                                LPEdges[i].Applicant.Priorities.RemoveAt(j);
                            }
                        }
                    }
                }

                if (print)
                    LP += Environment.NewLine + "Second Choice Conditions:" + Environment.NewLine;

                for (int i = 0; i < LPEdges.Count; i++)
                {
                    LPEdge le1 = LPEdges[i];

                    foreach (LPEdge le2 in LPEdges)
                    {
                        if (le2 != le1 && le2.Post.IsF == 0 && le1.Applicant == le2.Applicant && le2.Rank != 0 && le2.Rank < le1.Rank)
                        {
                            model.AddConstr(Edges[i] <= 0, "s" + i.ToString());
                            if (print)
                                LP += "(a" + LPEdges[i].Applicant.ID + ", p" + LPEdges[i].Post.ID + ") <= 0;" + Environment.NewLine;
                            for (int j = 0; j < LPEdges[i].Applicant.Priorities.Count; j++)
                            {
                                if (LPEdges[i].Applicant.Priorities[j].Target == LPEdges[i].Post.ID && LPEdges[i].Rank == LPEdges[i].Applicant.Priorities[j].Rank)
                                {
                                    LPEdges[i].Applicant.Priorities.RemoveAt(j);
                                }
                            }
                            break;
                        }
                    }
                }

                if (print)
                    LP += Environment.NewLine + "First Post Conditions:" + Environment.NewLine;

                foreach (Instance.Post p in instance.Posts)
                {
                    if (p.IsF == 1)
                    {
                        GRBLinExpr Temp = new GRBLinExpr();
                        for (int i = 0; i < LPEdges.Count; i++)
                        {
                            if (LPEdges[i].Post == p)
                            {
                                Temp += Edges[i];
                                if (print)
                                    LP += "(a" + LPEdges[i].Applicant.ID + ", p" + LPEdges[i].Post.ID + ") + ";
                            }
                        }
                        model.AddConstr(Temp >= 1.0, "f" + p.ID.ToString());
                        if (print)
                            LP += ">= 1;" + Environment.NewLine;
                    }
                }


                // Optimize model

                model.Optimize();

                if (print)
                {
                    instance.Draw().Save(path + "/1Reduced.bmp");
                }

                for (int i = 0; i < Edges.Length; i++)
                {
                    if (Edges[i].Get(GRB.DoubleAttr.X) == 1)
                    {
                        instance.AddMatch(LPEdges[i].Post.ID, LPEdges[i].Applicant.ID);
                    }
                }

                if (print)
                {
                    instance.Draw().Save(path + "/2Matched.bmp");
                }

                // Dispose of model and env

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

                return instance;

            }
            catch (GRBException e)
            {
                Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message);
                return null;
            }
        }
        static void Main(string[] args)
        {
            double[] Demand   = new double[] { 15, 18, 14, 20 };
            double[] Capacity = new double[] { 20, 22, 17, 19, 18 };
            double[,] ShipCosts =
                new double[, ] {
                { 4000, 2500, 1200, 2200 },
                { 2000, 2600, 1800, 2600 },
                { 3000, 3400, 2600, 3100 },
                { 2500, 3000, 4100, 3700 },
                { 4500, 4000, 3000, 3200 }
            };
            int nWarehouses = Capacity.Length;
            int nCustomers  = Demand.Length;

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

            GRBVar[,] Ship = new GRBVar[nWarehouses, nCustomers];
            for (int i = 0; i < nWarehouses; ++i)
            {
                for (int j = 0; j < nCustomers; ++j)
                {
                    Ship[i, j] = m.AddVar(0, GRB.INFINITY, 0, GRB.CONTINUOUS, "ship." + i + "." + j);
                }
            }

            GRBVar[] Shortage = new GRBVar[nCustomers];
            for (int j = 0; j < nCustomers; ++j)
            {
                Shortage[j] = m.AddVar(0, GRB.INFINITY, 0, GRB.CONTINUOUS, "shortage." + j);
            }

            GRBVar TotalShortage     = m.AddVar(0, GRB.INFINITY, 0, GRB.CONTINUOUS, "TotalShortage");
            GRBVar TotalShippingCost = m.AddVar(0, GRB.INFINITY, 1, GRB.CONTINUOUS, "TotalShippingCost");

            m.Update();

            GRBConstr[] DemandCon = new GRBConstr[nCustomers];
            for (int j = 0; j < nCustomers; ++j)
            {
                GRBLinExpr lhs = 0.0;
                for (int i = 0; i < nWarehouses; ++i)
                {
                    lhs += Ship[i, j];
                }
                DemandCon[j] = m.AddConstr(lhs == Demand[j] - Shortage[j], "demand." + j);
            }

            GRBConstr[] CapacityCon = new GRBConstr[nWarehouses];
            for (int i = 0; i < nWarehouses; ++i)
            {
                GRBLinExpr lhs = 0.0;
                for (int j = 0; j < nCustomers; ++j)
                {
                    lhs += Ship[i, j];
                }
                CapacityCon[i] = m.AddConstr(lhs <= Capacity[i], "capacity." + i);
            }

            GRBLinExpr expr = 0.0;

            for (int j = 0; j < nCustomers; ++j)
            {
                expr += Shortage[j];
            }
            GRBConstr TotalShortageCon = m.AddConstr(expr == TotalShortage, "total_shortage");

            expr = 0.0;
            for (int i = 0; i < nWarehouses; ++i)
            {
                for (int j = 0; j < nCustomers; ++j)
                {
                    expr += ShipCosts[i, j] * Ship[i, j];
                }
            }
            GRBConstr TotalShippingCon = m.AddConstr(expr == TotalShippingCost, "total_shipping");

            while (true)
            {
                m.Optimize();
                double OptShortage = TotalShortage.Get(GRB.DoubleAttr.X);
                double OptShipping = TotalShippingCost.Get(GRB.DoubleAttr.X);
                Console.WriteLine("TotalShortage = {0}", OptShortage);
                Console.WriteLine("TotalShippingCost= {0}", OptShipping);
                if (OptShortage < EPS)
                {
                    break;
                }
                double ObjectiveBound = TotalShortage.Get(GRB.DoubleAttr.SAObjUp);
                TotalShortage.Set(GRB.DoubleAttr.Obj, ((1 + EPS) * ObjectiveBound));
            }
        }
Exemple #12
0
        public List <int[]> SolveVRP(int timeLimitMilliseconds)
        {
            using (var env = new GRBEnv($"{DateTime.Now:yy-MM-dd-HH-mm-ss}_vrp_gurobi.log"))
                using (var vrpModel = new GRBModel(env))
                {
                    #region initialize Variables
                    var numberOfRoutes = input.Santas.Length * input.Days.Length;
                    var v = new GRBVar[numberOfRoutes][]; // [santa] visits [visit]
                    var w = new GRBVar[numberOfRoutes][]; // [santa] uses [way]


                    for (int s = 0; s < numberOfRoutes; s++)
                    {
                        v[s] = new GRBVar[visitDurations.Length];
                        for (int i = 0; i < v[s].Length; i++)
                        {
                            v[s][i] = vrpModel.AddVar(0, 1, 0.0, GRB.BINARY, $"v[{s}][{i}]");
                        }

                        w[s] = vrpModel.AddVars(distances.GetLength(0) * distances.GetLength(1), GRB.BINARY);
                    }
                    #endregion initialize Variables

                    #region add constraints
                    SelfieConstraint(vrpModel, numberOfRoutes, w);
                    VisitVisitedOnce(vrpModel, numberOfRoutes, v);
                    IncomingOutgoingWaysConstraints(vrpModel, numberOfRoutes, w, v);
                    IncomingOutgoingSanta(vrpModel, numberOfRoutes, v, w);
                    IncomingOutgoingSantaHome(vrpModel, numberOfRoutes, w, v);
                    NumberOfWaysMatchForSanta(vrpModel, numberOfRoutes, v, w);
                    BreakHandling(vrpModel, numberOfRoutes, v);
                    #endregion add constraints

                    var totalWayTime = new GRBLinExpr(0);
                    var longestRoute = vrpModel.AddVar(0, input.Days.Max(d => d.to - d.from), 0, GRB.CONTINUOUS,
                                                       "longestRoute");
                    for (int s = 0; s < numberOfRoutes; s++)
                    {
                        var routeTime = new GRBLinExpr(0);
                        for (int i = 0; i < visitDurations.Length; i++)
                        {
                            routeTime += v[s][i] * visitDurations[i];
                            for (int j = 0; j < visitDurations.Length; j++)
                            {
                                routeTime += AccessW(w[s], i, j) * distances[i, j];
                            }
                        }

                        totalWayTime += routeTime;
                        vrpModel.AddConstr(longestRoute >= routeTime, $"longesRouteConstr{s}");
                    }

                    vrpModel.SetObjective(
                        +(40d / 3600d) * totalWayTime
                        + (30d / 3600d) * longestRoute
                        , GRB.MINIMIZE);

                    vrpModel.Parameters.LazyConstraints = 1;
                    vrpModel.SetCallback(new VRPCallbackSolverCallback(w, AccessW, ConvertBack));
                    vrpModel.Parameters.TimeLimit = timeLimitMilliseconds / 1000;
                    InitializeModel(w, v, numberOfRoutes, input.Visits, input.Santas.Length);
                    vrpModel.Optimize();
                    if (vrpModel.SolCount == 0)
                    {
                        return(null);
                    }

                    var routes = new List <int[]>();
                    for (int s = 0; s < numberOfRoutes; s++)
                    {
                        var route     = new List <int>();
                        var currVisit = 0;
                        do
                        {
                            route.Add(currVisit);
                            for (int i = 0; i < visitDurations.Length; i++)
                            {
                                if (AccessW(w[s], currVisit, i).X > 0.5)
                                {
                                    currVisit = i;
                                    break;
                                }
                            }
                        } while (currVisit != 0);
                        routes.Add(route.ToArray());
                    }

                    vrpModel.Reset();
                    return(routes);
                }
        }
Exemple #13
0
        public static Graph RunSolver(Graph graph)
        {
            GRBEnv env = new GRBEnv();
            env.Set(GRB.IntParam.OutputFlag, 0);
            env.Set(GRB.IntParam.LogToConsole, 0);
            env.Set(GRB.IntParam.Presolve, 2);
            env.Set(GRB.DoubleParam.Heuristics, 0.0);
            GRBModel model = new GRBModel(env);
            GRBVar[] variables = new GRBVar[graph.NumberOfEdges];
            model.SetCallback(new LPSolverCallback());
            Dictionary<Edge, GRBVar> edgeVars = new Dictionary<Edge, GRBVar>();

            // Add variables to the LP model
            for (int i = 0; i < graph.NumberOfEdges; i++)
            {
                variables[i] = model.AddVar(0.0, 1.0, 0.0, GRB.BINARY, "x_" + i);
                edgeVars.Add(graph.Edges[i], variables[i]);
            }
            model.Update();

            // Add constraints to the LP model
            Console.Write("\rRunning LP. Creating constraints...\r");
            //var nonTerminals = graph.Vertices.Except(graph.Terminals).ToList();
            ulong conNr = 0;
            //var terminalCombinations = new List<List<Vertex>>();

            // Assume, without loss of generality, that Terminals[0] is the root, and thus is always included
            int rootNr = 1;
            foreach (var rootTerminal in graph.Terminals)
            //var rootTerminal = graph.Terminals[0];
            {
                Console.Write("\rRunning LP. Creating constraints... {0}/{1}\r", rootNr, graph.Terminals.Count);
                foreach (var combination in GetBFS(graph, rootTerminal))
                {
                    var nodes = combination.ToList(); //new HashSet<Vertex>(combination);
                    if (nodes.Count == graph.NumberOfVertices || graph.Terminals.All(nodes.Contains))
                        continue;
                    //Debug.WriteLine("Combination: {0}", string.Join(" ", nodes));
                    //for (int i = 1; i <= nodes.Count; i++)
                    {
                        var edges = nodes//.Take(i)
                                         .SelectMany(graph.GetEdgesForVertex)
                                         .Distinct()
                                         .Where(x => x.WhereOne(y => !nodes.Contains(y)));
                        GRBLinExpr expression = 0;
                        foreach (var edge in edges)
                            expression.AddTerm(1, edgeVars[edge]);
                        model.AddConstr(expression >= 1.0, "subset_" + conNr);
                        conNr++;

                        if (conNr % 100000 == 0)
                        {
                            //model = model.Presolve(); //Pre-solve the model every 1000 constraints.
                            int constrBefore = model.GetConstrs().Length, varsBefore = model.GetVars().Length;
                            Debug.WriteLine("Presolve called.");
                            var presolved = model.Presolve();
                            Debug.WriteLine("Model has {0} constraints, {1} variables. Presolve has {2} constraints, {3} variables",
                                constrBefore, varsBefore, presolved.GetConstrs().Length, presolved.GetVars().Length);
                        }
                    }
                }

                //Debug.WriteLine("   ");
                //Debug.WriteLine("   ");
                rootNr++;
            }

            //terminalCombinations.Add(new List<Vertex>(new[] { graph.Terminals[0] }));
            //for (int j = 1; j < graph.Terminals.Count - 1; j++)
            //    terminalCombinations.AddRange(new Combinations<Vertex>(graph.Terminals.Skip(1), j).Select(combination => combination.Union(new[] { graph.Terminals[0] }).ToList()));

            //long nonTerminalSetsDone = 0;
            //long nonTerminalSets = 0;
            //for (int i = 0; i <= nonTerminals.Count; i++)
            //    nonTerminalSets += Combinations<Vertex>.NumberOfCombinations(nonTerminals.Count, i);

            //for (int i = 0; i <= nonTerminals.Count; i++)
            //{
            //    foreach (var nonTerminalSet in new Combinations<Vertex>(nonTerminals, i))
            //    {
            //        foreach (var nodes in (from a in terminalCombinations
            //                               select new HashSet<Vertex>(a.Union(nonTerminalSet))))
            //        {
            //            var edges = nodes.SelectMany(graph.GetEdgesForVertex)
            //                             .Distinct()
            //                             .Where(x => x.WhereOne(y => !nodes.Contains(y)));
            //            GRBLinExpr expression = 0;
            //            foreach (var edge in edges)
            //                expression.AddTerm(1, edgeVars[edge]);
            //            model.AddConstr(expression >= 1.0, "subset_" + conNr);
            //            conNr++;
            //        }
            //        nonTerminalSetsDone++;
            //        if (nonTerminalSetsDone % 100 == 0)
            //            Console.Write("\rRunning LP. Creating constraints... {0}/{1} ({2:0.000}%)\r", nonTerminalSetsDone, nonTerminalSets, nonTerminalSetsDone * 100.0 / nonTerminalSets);
            //    }
            //}

            // Solve the LP model
            Console.Write("\rRunning LP. Creating objective & updating...                                   \r");
            GRBLinExpr objective = new GRBLinExpr();
            for (int i = 0; i < graph.NumberOfEdges; i++)
                objective.AddTerm(graph.Edges[i].Cost, variables[i]);
            model.SetObjective(objective, GRB.MINIMIZE);
            Console.Write("\rRunning LP. Tuning...                                   \r");
            model.Tune();
            Debug.WriteLine("Presolve called.");
            model.Presolve();
            Console.Write("\rRunning LP. Solving...                               \r");
            Debug.WriteLine("Optimize called.");
            model.Optimize();

            Graph solution = graph.Clone();
            HashSet<Edge> includedEdges = new HashSet<Edge>();
            for (int i = 0; i < solution.NumberOfEdges; i++)
            {
                var value = variables[i].Get(GRB.DoubleAttr.X);
                if (value == 1)
                    includedEdges.Add(solution.Edges[i]);
            }

            foreach (var edge in solution.Edges.ToList())
                if (!includedEdges.Contains(edge))
                    solution.RemoveEdge(edge);

            Console.Write("\r                                                  \r");

            return solution;
        }
Exemple #14
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 };

          // Amount each worker is paid to work one shift
          double[] pay = new double[] { 10, 12, 10, 8, 8, 9, 11 };

          // 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.Set(GRB.StringAttr.ModelName, "assignment");

          // Assignment variables: x[w][s] == 1 if worker w is assigned
          // to shift s. Since an assignment model always produces integer
          // solutions, we use continuous variables and solve as an LP.
          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], pay[w], GRB.CONTINUOUS,
                           Workers[w] + "." + Shifts[s]);
        }
          }

          // The objective is to minimize the total pay costs
          model.Set(GRB.IntAttr.ModelSense, 1);

          // Update model to integrate new variables
          model.Update();

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

          // Optimize
          model.Optimize();
          int status = model.Get(GRB.IntAttr.Status);
          if (status == GRB.Status.UNBOUNDED) {
        Console.WriteLine("The model cannot be solved "
            + "because it is unbounded");
        return;
          }
          if (status == GRB.Status.OPTIMAL) {
        Console.WriteLine("The optimal objective is " +
            model.Get(GRB.DoubleAttr.ObjVal));
        return;
          }
          if ((status != GRB.Status.INF_OR_UNBD) &&
          (status != GRB.Status.INFEASIBLE)) {
        Console.WriteLine("Optimization was stopped with status " + status);
        return;
          }

          // Do IIS
          Console.WriteLine("The model is infeasible; computing IIS");
          LinkedList<string> removed = new LinkedList<string>();

          // Loop until we reduce to a model that can be solved
          while (true) {
        model.ComputeIIS();
        Console.WriteLine("\nThe following constraint cannot be satisfied:");
        foreach (GRBConstr c in model.GetConstrs()) {
          if (c.Get(GRB.IntAttr.IISConstr) == 1) {
            Console.WriteLine(c.Get(GRB.StringAttr.ConstrName));
            // Remove a single constraint from the model
            removed.AddFirst(c.Get(GRB.StringAttr.ConstrName));
            model.Remove(c);
            break;
          }
        }

        Console.WriteLine();
        model.Optimize();
        status = model.Get(GRB.IntAttr.Status);

        if (status == GRB.Status.UNBOUNDED) {
          Console.WriteLine("The model cannot be solved "
              + "because it is unbounded");
          return;
        }
        if (status == GRB.Status.OPTIMAL) {
          break;
        }
        if ((status != GRB.Status.INF_OR_UNBD) &&
            (status != GRB.Status.INFEASIBLE)) {
          Console.WriteLine("Optimization was stopped with status " +
              status);
          return;
        }
          }

          Console.WriteLine("\nThe following constraints were removed "
          + "to get a feasible LP:");
          foreach (string s in removed) {
        Console.Write(s + " ");
          }
          Console.WriteLine();

          // Dispose of model and env
          model.Dispose();
          env.Dispose();

        } catch (GRBException e) {
          Console.WriteLine("Error code: " + e.ErrorCode + ". " +
          e.Message);
        }
    }
Exemple #15
0
 public void RangeSetup(GRBModel model, double lb, INumExpr expr, double ub, string name)
 {
     this.model = model;
     this.LB = lb;
     this.UB = ub;
     this._name = name;
     if (expr == null)
     {
         _expr = new INumExpr();
     }
     else
     {
         _expr = expr;
     }
     this.constr = null;
     if (lb > -System.Double.MaxValue && ub < System.Double.MaxValue)
     {
         // "lb < expr < ub"    -->    " expr - newvar = lb, 0 < newvar < ub - lb"
         GRBVar var = model.AddVar(0, ub - lb, 0, GRB.CONTINUOUS, null);
         GRBLinExpr modExpr = Expr.expr - var;
         this.constr = model.AddConstr(modExpr, GRB.EQUAL, lb, name);
     }
     else if (lb > -System.Double.MaxValue)
     {
         this.constr = model.AddConstr(Expr.expr, GRB.GREATER_EQUAL, lb, name);
     }
     else
     {
         this.constr = model.AddConstr(Expr.expr, GRB.LESS_EQUAL, ub, name);
     }
 }
Exemple #16
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 };

            // Amount each worker is paid to work one shift
            double[] pay = new double[] { 10, 12, 10, 8, 8, 9, 11 };

            // 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. Since an assignment model always produces integer
            // solutions, we use continuous variables and solve as an LP.
            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], pay[w], GRB.CONTINUOUS,
                                     Workers[w] + "." + Shifts[s]);
                }
            }

            // The objective is to minimize the total pay costs
            model.ModelSense = GRB.MINIMIZE;

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

            // Optimize
            model.Optimize();
            int status = model.Status;
            if (status == GRB.Status.UNBOUNDED)
            {
                Console.WriteLine("The model cannot be solved "
                                  + "because it is unbounded");
                return;
            }
            if (status == GRB.Status.OPTIMAL)
            {
                Console.WriteLine("The optimal objective is " + model.ObjVal);
                return;
            }
            if ((status != GRB.Status.INF_OR_UNBD) &&
                (status != GRB.Status.INFEASIBLE))
            {
                Console.WriteLine("Optimization was stopped with status " + status);
                return;
            }

            // Relax the constraints to make the model feasible
            Console.WriteLine("The model is infeasible; relaxing the constraints");
            int orignumvars = model.NumVars;
            model.FeasRelax(0, false, false, true);
            model.Optimize();
            status = model.Status;
            if ((status == GRB.Status.INF_OR_UNBD) ||
                (status == GRB.Status.INFEASIBLE) ||
                (status == GRB.Status.UNBOUNDED))
            {
                Console.WriteLine("The relaxed model cannot be solved "
                                  + "because it is infeasible or unbounded");
                return;
            }
            if (status != GRB.Status.OPTIMAL)
            {
                Console.WriteLine("Optimization was stopped with status " + status);
                return;
            }

            Console.WriteLine("\nSlack values:");
            GRBVar[] vars = model.GetVars();
            for (int i = orignumvars; i < model.NumVars; ++i)
            {
                GRBVar sv = vars[i];
                if (sv.X > 1e-6)
                {
                    Console.WriteLine(sv.VarName + " = " + sv.X);
                }
            }

            // Dispose of model and environment
            model.Dispose();
            env.Dispose();
        } catch (GRBException e) {
            Console.WriteLine("Error code: " + e.ErrorCode + ". " +
                              e.Message);
        }
    }
Exemple #17
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 };

            // Amount each worker is paid to work one shift
            double[] pay = new double[] { 10, 12, 10, 8, 8, 9, 11 };

            // 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.Set(GRB.StringAttr.ModelName, "assignment");

            // Assignment variables: x[w][s] == 1 if worker w is assigned
            // to shift s. Since an assignment model always produces integer
            // solutions, we use continuous variables and solve as an LP.
            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], pay[w], GRB.CONTINUOUS,
                                     Workers[w] + "." + Shifts[s]);
                }
            }

            // The objective is to minimize the total pay costs
            model.Set(GRB.IntAttr.ModelSense, 1);

            // Update model to integrate new variables
            model.Update();

            // Constraint: assign exactly shiftRequirements[s] workers
            // to each shift s
            LinkedList <GRBConstr> reqCts = new LinkedList <GRBConstr>();
            for (int s = 0; s < nShifts; ++s)
            {
                GRBLinExpr lhs = 0.0;
                for (int w = 0; w < nWorkers; ++w)
                {
                    lhs.AddTerm(1.0, x[w, s]);
                }
                GRBConstr newCt =
                    model.AddConstr(lhs == shiftRequirements[s], Shifts[s]);
                reqCts.AddFirst(newCt);
            }

            // Optimize
            model.Optimize();
            int status = model.Get(GRB.IntAttr.Status);
            if (status == GRB.Status.UNBOUNDED)
            {
                Console.WriteLine("The model cannot be solved "
                                  + "because it is unbounded");
                return;
            }
            if (status == GRB.Status.OPTIMAL)
            {
                Console.WriteLine("The optimal objective is " +
                                  model.Get(GRB.DoubleAttr.ObjVal));
                return;
            }
            if ((status != GRB.Status.INF_OR_UNBD) &&
                (status != GRB.Status.INFEASIBLE))
            {
                Console.WriteLine("Optimization was stopped with status " + status);
                return;
            }

            // Add slack variables to make the model feasible
            Console.WriteLine("The model is infeasible; adding slack variables");

            // Set original objective coefficients to zero
            model.SetObjective(new GRBLinExpr());

            // Add a new slack variable to each shift constraint so that the shifts
            // can be satisfied
            LinkedList <GRBVar> slacks = new LinkedList <GRBVar>();
            foreach (GRBConstr c in reqCts)
            {
                GRBColumn col = new GRBColumn();
                col.AddTerm(1.0, c);
                GRBVar newvar =
                    model.AddVar(0, GRB.INFINITY, 1.0, GRB.CONTINUOUS, col,
                                 c.Get(GRB.StringAttr.ConstrName) + "Slack");
                slacks.AddFirst(newvar);
            }

            // Solve the model with slacks
            model.Optimize();
            status = model.Get(GRB.IntAttr.Status);
            if ((status == GRB.Status.INF_OR_UNBD) ||
                (status == GRB.Status.INFEASIBLE) ||
                (status == GRB.Status.UNBOUNDED))
            {
                Console.WriteLine("The model with slacks cannot be solved "
                                  + "because it is infeasible or unbounded");
                return;
            }
            if (status != GRB.Status.OPTIMAL)
            {
                Console.WriteLine("Optimization was stopped with status " + status);
                return;
            }

            Console.WriteLine("\nSlack values:");
            foreach (GRBVar sv in slacks)
            {
                if (sv.Get(GRB.DoubleAttr.X) > 1e-6)
                {
                    Console.WriteLine(sv.Get(GRB.StringAttr.VarName) + " = " +
                                      sv.Get(GRB.DoubleAttr.X));
                }
            }

            // Dispose of model and env
            model.Dispose();
            env.Dispose();
        } catch (GRBException e) {
            Console.WriteLine("Error code: " + e.ErrorCode + ". " +
                              e.Message);
        }
    }
Exemple #18
0
        public static double MIP_arc_based(int SAA_m, int SAA_type, int sample_size)
        {
            int trial_limit = sample_size;

            System.Console.WriteLine("Constructing the MIP with Gurobi...");
            double solution = -1;

            try
            {
                GRBEnv   env   = new GRBEnv("mip1.log");
                GRBModel model = new GRBModel(env);
                //model.Parameters.Presolve = 1;

                GRBVar[] y_j = new GRBVar[E];
                GRBVar[,] x_ir = new GRBVar[N, sample_size];

                System.Console.WriteLine("Creating y_i (edges)");
                for (int i = 0; i < E; i++)
                {
                    y_j[i] = model.AddVar(0.0, 1.0, 0, GRB.BINARY, "y_" + node_index[unique_arcs[i].Key.Head] + "_" + node_index[unique_arcs[i].Key.Tail]);
                }

                System.Console.WriteLine("Creating x_ir");
                for (int i = 0; i < N; i++)
                {
                    for (int r = 0; r < sample_size; r++)
                    {
                        x_ir[i, r] = model.AddVar(0.0, 1.0, 1.0, GRB.CONTINUOUS, "x_" + i + "_" + r);
                    }
                }

                model.ModelSense = GRB.MINIMIZE;

                //----------------------------------------------------------
                //--------------- create the constraints
                int        counter = 0;
                GRBLinExpr temp_exp2;
                temp_exp2 = 0.0;
                System.Console.WriteLine("Starting the constraints... Total : " + (trial_limit * N + 1) + " constraints");
                // exactly k initial active users
                for (int i = 0; i < E; i++)
                {
                    temp_exp2.AddTerm(1.0, y_j[i]);
                }

                model.AddConstr(temp_exp2 == K, "constraint_y");
                temp_exp2 = 0.0;
                //--- influence constraints x_i_r <= Sum_j (y_j)          j in all accessing nodes to i          (total of N.R constraints)
                //string[] neigh_arr;


                GRBLinExpr temp_exp;

                int j = 0;

                temp_exp = 0.0;
                int      counter2 = 0;
                ReadData temp_arc = new ReadData();

                for (int r = 0; r < trial_limit; r++)
                {
                    for (int i = 0; i < N; i++)
                    {
                        //if (SAA_tree_list[r][i].Count > 0)
                        //if (x_exist[r, i] == true)
                        {
                            //x_ir[i, r] = model.AddVar(0.0, 1.0, 1.0, GRB.CONTINUOUS, "x_" + i + "_" + r);
                            temp_exp.AddTerm(1.0, x_ir[i, r]);

                            //if (SAA_tree_list[r][i].Count <= N)
                            {
                                foreach (UInt16 node in SAA_pred_list[r][i])   //my predecessors can activate me
                                {
                                    var x = unique_arcs.FindIndex(a => a.Key.Head == node_set[(int)node] && a.Key.Tail == node_set[i]);
                                    //int arcID=unique_arcs.IndexOf()
                                    temp_exp2.AddTerm(-1, x_ir[(int)node, r]);
                                    temp_exp2.AddTerm(1, y_j[x]);
                                    model.AddConstr(temp_exp + temp_exp2 >= 0, "constraint_2" + (counter + 1));
                                    temp_exp2 = 0.0;
                                    counter++;
                                }
                            }
                        }       //end of if for null neighbourhood
                        temp_exp = 0.0;
                    }           //end of for loop for nodes
                }               //end of for loop for sample size R

                for (int r = 0; r < trial_limit; r++)
                {
                    for (int i = 0; i < I; i++)
                    {
                        temp_exp.AddTerm(1.0, x_ir[(int)initial_infected[i], r]);
                        model.AddConstr(temp_exp >= 1, "constraint_3" + (counter + 1));
                        temp_exp = 0.0;
                    }
                }
                //no need for this in edge blocking
                //for (int i = 0; i < I; i++)
                //{
                //    temp_exp.AddTerm(1.0, y_j[(int)initial_infected[i]]);
                //    model.AddConstr(temp_exp == 0, "constraint_3" + (counter + 1));
                //    temp_exp = 0.0;
                //}

                model.Write("model.lp");
                //model.Write("modelGRB2" + SAA_m + ".mps");
                //model.Write("modelGRB2" + SAA_m + ".lp");
                GRBModel p = model.Presolve();
                p.Write("presolve.lp");

                model.Optimize();

                if (model.Status == GRB.Status.OPTIMAL)
                {
                    Console.WriteLine("Obj: " + model.Get(GRB.DoubleAttr.ObjVal));
                    solution = model.Get(GRB.DoubleAttr.ObjVal);


                    List <UInt16> SAA_sample_result = new List <UInt16>(K);
                    int           isfractional      = 0;
                    result_set = new List <ushort>();
                    for (int jj = 0; jj < y_j.Count(); ++jj)
                    {
                        if (y_j[jj].X > 0.001)
                        {
                            //result_set.Add(node_set[jj]);
                            result_set.Add(node_set[jj]);
                            SAA_sample_result.Add((UInt16)jj);
                            System.Console.WriteLine(y_j[jj].VarName + "=" + y_j[jj].X);
                            if (y_j[jj].X < 0.9)
                            {
                                System.Console.WriteLine("Fractional value found");
                                System.Console.ReadKey();
                                isfractional = 1;
                            }
                        }
                    }
                    if (isfractional == 1)
                    {
                        System.Console.WriteLine("To conitnue click...");
                        System.Console.ReadKey();
                    }

                    SAA_list.Add(SAA_sample_result);
                }
                else
                {
                    Console.WriteLine("No solution");
                    solution = 0;
                }

                // Dispose of model and env

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


            return(solution);
        }
Exemple #19
0
 private static GRBVar CreateLargeVasesVariable(double glazeSupply, GRBModel model)
 {
     return(model.AddVar(0.0, glazeSupply, 0.0, GRB.INTEGER, "xL"));
 }
Exemple #20
0
        public void CriarResolverModeloExato()
        {
            Ambiente          = new GRBEnv();
            Modelo            = new GRBModel(Ambiente);
            Modelo.ModelSense = GRB.MINIMIZE;
            GRBVar[] Y = new GRBVar[NumeroItens];
            GRBVar[,] X = new GRBVar[NumeroItens, NumeroItens];
            //Função objetivo (1) e Conjuntos de Restrições (5) e (6)
            for (int j = 0; j < NumeroItens; j++)
            {
                Y[j] = Modelo.AddVar(0, 1, 0, GRB.BINARY, "y_" + j.ToString());
            }
            for (int i = 0; i < NumeroItens; i++)
            {
                for (int j = 0; j < NumeroItens; j++)
                {
                    X[i, j] = Modelo.AddVar(0, 1, Itens[i].Demanda * MatrizDistancias[i, j], GRB.BINARY, "x_" + i.ToString() + "_" + j.ToString());
                }
            }

            //Restrição (2)
            GRBLinExpr expr = new GRBLinExpr();

            //expr=
            //j=0: expr=1 Y[0]
            //j=1: expr=1 Y[0] + 1 Y[1]
            //...
            //j=19: expr=1 Y[0] + 1 Y[1] + ... + 1 Y[18] + 1 Y[19]
            for (int j = 0; j < NumeroItens; j++)
            {
                expr.AddTerm(1, Y[j]);
            }
            Modelo.AddConstr(expr == NumeroMedianas, "R2");

            //Conjunto de Restrições (3)
            expr.Clear();
            //expr=
            for (int i = 0; i < NumeroItens; i++)
            {
                expr.Clear();
                for (int j = 0; j < NumeroItens; j++)
                {
                    expr.AddTerm(1, X[i, j]);
                }
                Modelo.AddConstr(expr == 1, "R3" + "_" + i.ToString());
            }

            //Conjunto de Restrições (4)
            for (int j = 0; j < NumeroItens; j++)
            {
                expr.Clear();
                for (int i = 0; i < NumeroItens; i++)
                {
                    expr.AddTerm(Itens[i].Demanda, X[i, j]);
                }
                Modelo.AddConstr(expr <= Itens[j].Capacidade * Y[j], "R4_" + j.ToString());
            }

            //conjunto de restrições (GGG)
            //for (int i = 0; i < NumeroItens; i++)
            //{
            //    for (int j = 0; j < NumeroItens; j++)
            //    {
            //        Modelo.AddConstr(MatrizDistancias[i, j] * X[i, j] <= 300, "RGGG_" + i.ToString() + "_" + j.ToString());
            //    }
            //}

            //Escrever Modelo .lp
            Modelo.Write(@"C:\Teste\ModeloPmedianas.lp");

            //Otimizar
            Modelo.Optimize();
            DistanciaTotal = Modelo.ObjVal;
            //"Ler" resultado
            int NumeroMedianasJaDefinidas            = 0;
            Dictionary <int, int> DicionarioMedianas = new Dictionary <int, int>();

            for (int j = 0; j < NumeroItens; j++)
            {
                if (Y[j].X > 0.9)
                {
                    Medianas[NumeroMedianasJaDefinidas].ItemMediana           = j;
                    Medianas[NumeroMedianasJaDefinidas].ItensAlocados         = new List <int>();
                    Medianas[NumeroMedianasJaDefinidas].DistanciaItensMediana = 0;
                    DicionarioMedianas.Add(j, NumeroMedianasJaDefinidas);
                    NumeroMedianasJaDefinidas++;
                }
            }
            for (int i = 0; i < NumeroItens; i++)
            {
                for (int j = 0; j < NumeroItens; j++)
                {
                    if (X[i, j].X > 0.9)
                    {
                        Itens[i].MedianaAlocada = DicionarioMedianas[j];
                        Medianas[DicionarioMedianas[j]].ItensAlocados.Add(i);
                        Medianas[DicionarioMedianas[j]].DistanciaItensMediana += MatrizDistancias[i, j];
                    }
                }
            }
        }
        public double Calculate(IList <Constraint> synthesizedConstraints, IList <Constraint> referenceConstraints)
        {
            // Assume benchmark restrictions indexes are bound to rows
            var matrix = new double[referenceConstraints.Count, synthesizedConstraints.Count];

            for (var i = 0; i < matrix.GetLength(0); i++)
            {
                for (var j = 0; j < matrix.GetLength(1); j++)
                {
                    matrix[i, j] = AngleBetweenVectors(referenceConstraints[i].GetAllCoefficients(), synthesizedConstraints[j].GetAllCoefficients());
                }
            }

            // Assignment problem
            var env   = new GRBEnv("angle.log");
            var model = new GRBModel(env)
            {
                ModelSense = GRB.MINIMIZE,
                ModelName  = "Mean Angle Assignment Problem"
            };

            // Binary variable for each matrix cell
            var grbVars = new GRBVar[matrix.GetLength(0), matrix.GetLength(1)];

            for (var i = 0; i < matrix.GetLength(0); i++)
            {
                for (var j = 0; j < matrix.GetLength(1); j++)
                {
                    grbVars[i, j] = model.AddVar(0.0, 1.0, 0.0, GRB.BINARY, $"b{i}.{j}");
                }
            }

            var contraintCounter = 0;
            var objectiveExpr    = new GRBLinExpr();

            // First add contraints for each row
            for (var i = 0; i < matrix.GetLength(0); i++)
            {
                var rowExpr = new GRBLinExpr();
                for (var j = 0; j < matrix.GetLength(1); j++)
                {
                    rowExpr.AddTerm(1.0, grbVars[i, j]);
                    // Creating objective equation ONLY ONCE !
                    objectiveExpr.AddTerm(matrix[i, j], grbVars[i, j]);
                }
                model.AddConstr(rowExpr, GRB.GREATER_EQUAL, 1, $"c{contraintCounter++}");
            }

            // Transpose matrix so we can perform the same operation
            matrix = matrix.Transpose();

            // Add contstaints for originally columns
            for (var i = 0; i < matrix.GetLength(0); i++)
            {
                var rowExpr = new GRBLinExpr();
                for (var j = 0; j < matrix.GetLength(1); j++)
                {
                    // Inverted indexes i and j
                    rowExpr.AddTerm(1.0, grbVars[j, i]);
                }
                model.AddConstr(rowExpr, GRB.GREATER_EQUAL, 1, $"c{contraintCounter++}");
            }

            model.SetObjective(objectiveExpr);

            model.Optimize();

            // Back to orignal shape
            matrix = matrix.Transpose();

            // Gets indicators for each bianry variable for solution
            var binarySolutions = new double[matrix.GetLength(0), matrix.GetLength(1)];

            for (var i = 0; i < matrix.GetLength(0); i++)
            {
                for (var j = 0; j < matrix.GetLength(1); j++)
                {
                    binarySolutions[i, j] = grbVars[i, j].X;
                }
            }

            // Multiplies binary indicators with coeficients
            var sum = Matrix.ElementwiseMultiply(matrix, binarySolutions).Sum();

            model.Write("angle_out.lp");

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

            // Return mean angle
            return(sum / (matrix.GetLength(0) > matrix.GetLength(1)
                ? matrix.GetLength(0)
                : matrix.GetLength(1)));
        }
Exemple #22
0
    static void Main()
    {
        try {

          // Nutrition guidelines, based on
          // USDA Dietary Guidelines for Americans, 2005
          // http://www.health.gov/DietaryGuidelines/dga2005/
          string[] Categories =
          new string[] { "calories", "protein", "fat", "sodium" };
          int nCategories = Categories.Length;
          double[] minNutrition = new double[] { 1800, 91, 0, 0 };
          double[] maxNutrition = new double[] { 2200, GRB.INFINITY, 65, 1779 };

          // Set of foods
          string[] Foods =
          new string[] { "hamburger", "chicken", "hot dog", "fries",
              "macaroni", "pizza", "salad", "milk", "ice cream" };
          int nFoods = Foods.Length;
          double[] cost =
          new double[] { 2.49, 2.89, 1.50, 1.89, 2.09, 1.99, 2.49, 0.89,
              1.59 };

          // Nutrition values for the foods
          double[,] nutritionValues = new double[,] {
          { 410, 24, 26, 730 },   // hamburger
          { 420, 32, 10, 1190 },  // chicken
          { 560, 20, 32, 1800 },  // hot dog
          { 380, 4, 19, 270 },    // fries
          { 320, 12, 10, 930 },   // macaroni
          { 320, 15, 12, 820 },   // pizza
          { 320, 31, 12, 1230 },  // salad
          { 100, 8, 2.5, 125 },   // milk
          { 330, 8, 10, 180 }     // ice cream
          };

          // Model
          GRBEnv env = new GRBEnv();
          GRBModel model = new GRBModel(env);
          model.Set(GRB.StringAttr.ModelName, "diet");

          // Create decision variables for the nutrition information,
          // which we limit via bounds
          GRBVar[] nutrition = new GRBVar[nCategories];
          for (int i = 0; i < nCategories; ++i) {
        nutrition[i] =
            model.AddVar(minNutrition[i], maxNutrition[i], 0, GRB.CONTINUOUS,
                         Categories[i]);
          }

          // Create decision variables for the foods to buy
          GRBVar[] buy = new GRBVar[nFoods];
          for (int j = 0; j < nFoods; ++j) {
        buy[j] =
            model.AddVar(0, GRB.INFINITY, cost[j], GRB.CONTINUOUS, Foods[j]);
          }

          // The objective is to minimize the costs
          model.Set(GRB.IntAttr.ModelSense, 1);

          // Update model to integrate new variables
          model.Update();

          // Nutrition constraints
          for (int i = 0; i < nCategories; ++i) {
        GRBLinExpr ntot = 0.0;
        for (int j = 0; j < nFoods; ++j)
          ntot += nutritionValues[j,i] * buy[j];
        model.AddConstr(ntot == nutrition[i], Categories[i]);
          }

          // Solve
          model.Optimize();
          PrintSolution(model, buy, nutrition);

          Console.WriteLine("\nAdding constraint: at most 6 servings of dairy");
          model.AddConstr(buy[7] + buy[8] <= 6.0, "limit_dairy");

          // Solve
          model.Optimize();
          PrintSolution(model, buy, nutrition);

          // Dispose of model and env
          model.Dispose();
          env.Dispose();

        } catch (GRBException e) {
          Console.WriteLine("Error code: " + e.ErrorCode + ". " +
          e.Message);
        }
    }
Exemple #23
0
        private GRBLinExpr AttachedToSpecialQuestion(int y, int x, int type, Crossword crossword, GRBModel m, int sizeX, int sizeY, int maxWordLength, GRBVar[,] fields, GRBLinExpr[,] specialQuestionUsed, GRBVar[,,] specialQuestionType)
        {
            // 0 = Down, then right
            // 1 = Left, then down
            // 2 = Right, then down
            // 3 = Up, then right
            if (type == 0 && y - 1 < 0)
            {
                return(null);
            }
            if (type == 1 && x + 1 >= sizeX)
            {
                return(null);
            }
            if (type == 2 && x - 1 < 0)
            {
                return(null);
            }
            if (type == 3 && y + 1 >= sizeY)
            {
                return(null);
            }

            // Is this field attached to a special question?
            var attachedToSpecialQuestion = new GRBLinExpr();

            for (int len = 0; len < maxWordLength; len++)
            {
                var qpos = new { y = y + (type == 0 ? -1 : 1), x = x - len };
                if (type == 1 || type == 2)
                {
                    qpos = new { y = y - len, x = x + (type == 1 ? 1 : -1) }
                }
                ;

                if ((type == 0 || type == 3) && (x - len < 0 || crossword.HasBlock(y, x - len, y, x) || crossword.HasBlock(qpos.y, qpos.x)))
                {
                    continue;
                }
                if ((type == 1 || type == 2) && (y - len < 0 || crossword.HasBlock(y - len, x, y, x) || crossword.HasBlock(qpos.y, qpos.x)))
                {
                    continue;
                }

                if ((object)specialQuestionUsed[qpos.y, qpos.x] == null)
                {
                    continue;
                }

                var atsp = m.AddVar(0, 1, 0, GRB.BINARY, "attachedToSpecialQuestion" + type + "len" + len + "_" + y + "_" + x);
                var questionsInbetween = (type == 0 || type == 3) ? fields.SumRange(y, x - len, y, x) : fields.SumRange(y - len, x, y, x);
                m.AddConstr(atsp >= fields[qpos.y, qpos.x] + specialQuestionType[qpos.y, qpos.x, type] - 1 - questionsInbetween, "attachedToSpecialQuestion_len" + len + "_" + y + "_" + x);
                if (type == 0 || type == 3)
                {
                    for (int xi = x - len; xi <= x; xi++)
                    {
                        m.AddConstr(atsp <= 1 - fields[y, xi], "notAttachedToSpecialQuestion1_len" + len + "_" + y + "_" + x);
                    }
                }
                else
                {
                    for (int yi = y - len; yi <= y; yi++)
                    {
                        m.AddConstr(atsp <= 1 - fields[yi, x], "notAttachedToSpecialQuestion1_len" + len + "_" + y + "_" + x);
                    }
                }
                m.AddConstr(atsp <= fields[qpos.y, qpos.x], "notAttachedToSpecialQuestion2_len" + len + "_" + y + "_" + x);
                m.AddConstr(atsp <= specialQuestionType[qpos.y, qpos.x, type], "notAttachedToSpecialQuestion3_len" + len + "_" + y + "_" + x);
                attachedToSpecialQuestion += atsp;
            }
            return(attachedToSpecialQuestion);
        }
    }
Exemple #24
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", "Tobi" };

            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 },
                { 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1 },
                { 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }
            };

            // Create environment
            GRBEnv env = new GRBEnv();

            // Create initial model
            GRBModel model = new GRBModel(env);
            model.ModelName = "workforce5_cs";

            // Initialize assignment decision 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,
                                     string.Format("{0}.{1}", 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,
                                 string.Format("{0}Slack", Shifts[s]));
            }

            // 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,
                                            string.Format("{0}TotShifts", Workers[w]));
            }

            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, GRB.EQUAL, shiftRequirements[s], Shifts[s]);
            }

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

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

            // Constraint: set minShift/maxShift variable to less <=/>= to the
            // number of shifts among all workers
            GRBVar minShift = model.AddVar(0, GRB.INFINITY, 0, GRB.CONTINUOUS,
                                           "minShift");
            GRBVar maxShift = model.AddVar(0, GRB.INFINITY, 0, GRB.CONTINUOUS,
                                           "maxShift");
            model.AddGenConstrMin(minShift, totShifts, GRB.INFINITY, "minShift");
            model.AddGenConstrMax(maxShift, totShifts, -GRB.INFINITY, "maxShift");

            // Set global sense for ALL objectives
            model.ModelSense = GRB.MINIMIZE;

            // Set primary objective
            model.SetObjectiveN(totSlack, 0, 2, 1.0, 2.0, 0.1, "TotalSlack");

            // Set secondary objective
            model.SetObjectiveN(maxShift - minShift, 1, 1, 1.0, 0, 0, "Fairness");

            // Save problem
            model.Write("workforce5_cs.lp");

            // Optimize
            int status = solveAndPrint(model, totSlack, nWorkers, Workers, totShifts);

            if (status != GRB.Status.OPTIMAL)
            {
                return;
            }

            // Dispose of model and environment
            model.Dispose();
            env.Dispose();
        } catch (GRBException e) {
            Console.WriteLine("Error code: {0}. {1}", e.ErrorCode, e.Message);
        }
    }
 public GRBVar AddToModel(GRBModel model)
 {
     return(model.AddVar(lowerBound, upperBound, ObjectiveCoefficient, variableType, name));
 }
        /// <summary>
        /// Creates and saves model to a path set in <see cref="GlobalVariables.GurobiModelPath"/>
        /// </summary>
        public void Create()
        {
            using (var sr = new StreamReader(_path))
            {
                while (!sr.EndOfStream)
                {
                    Rules.Add(new Rule(sr.ReadLine()));
                }
            }

            // Item1 contains a list of unique Constraints and Item2 is a number of bool variables
            var tuple = Rules.ReturnUniqueSplitsWithBooleans();

            UniqueConstraints = tuple.Item1;

            var inputs = new string[GlobalVariables.Dimensions];

            for (var i = 0; i < GlobalVariables.Dimensions; i++)
            {
                inputs[i] = "x" + i;
            }

            // Create Gurobi Environment and model
            var env = new GRBEnv();

            Model = new GRBModel(env)
            {
                ModelName = "OneClassClassifier"
            };

            // Add continous variables
            var continousVariables = new GRBVar[inputs.Length];

            for (var i = 0; i < continousVariables.Length; i++)
            {
                continousVariables[i] = Model.AddVar(-Gurobi.GRB.INFINITY, Gurobi.GRB.INFINITY, 0, Gurobi.GRB.CONTINUOUS,
                                                     inputs[i]);
            }

            // Add binary variables
            var binaryVariables = new GRBVar[tuple.Item2];

            for (var i = 0; i < binaryVariables.Length; i++)
            {
                binaryVariables[i] = Model.AddVar(0.0, 1.0, 0.0, Gurobi.GRB.BINARY, $"b{i}");
            }

            var constraintCounter = 0;
            var termsCounter      = 0; // Because there is always 1 dimension variable

            // Add constraints
            foreach (var constraint in UniqueConstraints)
            {
                termsCounter += 1;

                var valueEquals = constraint.Value;

                var expr = new GRBLinExpr();
                expr.AddTerm(1.0, continousVariables[constraint.Axis]);

                foreach (var split in constraint.Splits)
                {
                    double m;
                    if (constraint.Sign == split.OriginalSign)
                    {
                        m = split.OriginalSign == Gurobi.GRB.LESS_EQUAL ? GlobalVariables.M :
                            -GlobalVariables.M;
                    }
                    else
                    {
                        m = split.OriginalSign == Gurobi.GRB.LESS_EQUAL ? -GlobalVariables.M :
                            GlobalVariables.M;
                    }

                    if (split.OneMinus)
                    {
                        valueEquals  += m;
                        termsCounter += 2;
                    }
                    else
                    {
                        m = -m;
                        termsCounter++;
                    }

                    expr.AddTerm(m, binaryVariables[split.SplitNumber]);
                }

                Model.AddConstr(expr, constraint.Sign, valueEquals, $"c{constraintCounter++}");
            }

            Constraints = constraintCounter;
            Terms       = termsCounter;

            Model.Write(GlobalVariables.GurobiModelPath);
        }
Exemple #27
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";
        }
Exemple #28
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 };

            // Amount each worker is paid to work one shift
            double[] pay = new double[] { 10, 12, 10, 8, 8, 9, 11 };

            // 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. Since an assignment model always produces integer
            // solutions, we use continuous variables and solve as an LP.
            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], pay[w], GRB.CONTINUOUS,
                                     Workers[w] + "." + Shifts[s]);
                }
            }

            // The objective is to minimize the total pay costs
            model.ModelSense = GRB.MINIMIZE;

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

            // Optimize
            model.Optimize();
            int status = model.Status;
            if (status == GRB.Status.UNBOUNDED)
            {
                Console.WriteLine("The model cannot be solved "
                                  + "because it is unbounded");
                return;
            }
            if (status == GRB.Status.OPTIMAL)
            {
                Console.WriteLine("The optimal objective is " + model.ObjVal);
                return;
            }
            if ((status != GRB.Status.INF_OR_UNBD) &&
                (status != GRB.Status.INFEASIBLE))
            {
                Console.WriteLine("Optimization was stopped with status " + status);
                return;
            }

            // Do IIS
            Console.WriteLine("The model is infeasible; computing IIS");
            LinkedList <string> removed = new LinkedList <string>();

            // Loop until we reduce to a model that can be solved
            while (true)
            {
                model.ComputeIIS();
                Console.WriteLine("\nThe following constraint cannot be satisfied:");
                foreach (GRBConstr c in model.GetConstrs())
                {
                    if (c.IISConstr == 1)
                    {
                        Console.WriteLine(c.ConstrName);
                        // Remove a single constraint from the model
                        removed.AddFirst(c.ConstrName);
                        model.Remove(c);
                        break;
                    }
                }

                Console.WriteLine();
                model.Optimize();
                status = model.Status;

                if (status == GRB.Status.UNBOUNDED)
                {
                    Console.WriteLine("The model cannot be solved "
                                      + "because it is unbounded");
                    return;
                }
                if (status == GRB.Status.OPTIMAL)
                {
                    break;
                }
                if ((status != GRB.Status.INF_OR_UNBD) &&
                    (status != GRB.Status.INFEASIBLE))
                {
                    Console.WriteLine("Optimization was stopped with status " +
                                      status);
                    return;
                }
            }

            Console.WriteLine("\nThe following constraints were removed "
                              + "to get a feasible LP:");
            foreach (string s in removed)
            {
                Console.Write(s + " ");
            }
            Console.WriteLine();

            // Dispose of model and env
            model.Dispose();
            env.Dispose();
        } catch (GRBException e) {
            Console.WriteLine("Error code: " + e.ErrorCode + ". " +
                              e.Message);
        }
    }
    static void Main()
    {
        try {
            // Nutrition guidelines, based on
            // USDA Dietary Guidelines for Americans, 2005
            // http://www.health.gov/DietaryGuidelines/dga2005/
            string[] Categories =
                new string[] { "calories", "protein", "fat", "sodium" };
            int      nCategories  = Categories.Length;
            double[] minNutrition = new double[] { 1800, 91, 0, 0 };
            double[] maxNutrition = new double[] { 2200, GRB.INFINITY, 65, 1779 };

            // Set of foods
            string[] Foods =
                new string[] { "hamburger", "chicken", "hot dog", "fries",
                               "macaroni", "pizza", "salad", "milk", "ice cream" };
            int      nFoods = Foods.Length;
            double[] cost   =
                new double[] { 2.49, 2.89, 1.50, 1.89, 2.09, 1.99, 2.49, 0.89,
                               1.59 };

            // Nutrition values for the foods
            double[,] nutritionValues = new double[, ] {
                { 410, 24, 26, 730 },  // hamburger
                { 420, 32, 10, 1190 }, // chicken
                { 560, 20, 32, 1800 }, // hot dog
                { 380, 4, 19, 270 },   // fries
                { 320, 12, 10, 930 },  // macaroni
                { 320, 15, 12, 820 },  // pizza
                { 320, 31, 12, 1230 }, // salad
                { 100, 8, 2.5, 125 },  // milk
                { 330, 8, 10, 180 } // ice cream
            };

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

            model.ModelName = "diet";

            // Create decision variables for the nutrition information,
            // which we limit via bounds
            GRBVar[] nutrition = new GRBVar[nCategories];
            for (int i = 0; i < nCategories; ++i)
            {
                nutrition[i] =
                    model.AddVar(minNutrition[i], maxNutrition[i], 0, GRB.CONTINUOUS,
                                 Categories[i]);
            }

            // Create decision variables for the foods to buy
            GRBVar[] buy = new GRBVar[nFoods];
            for (int j = 0; j < nFoods; ++j)
            {
                buy[j] =
                    model.AddVar(0, GRB.INFINITY, cost[j], GRB.CONTINUOUS, Foods[j]);
            }

            // The objective is to minimize the costs
            model.ModelSense = GRB.MINIMIZE;

            // Nutrition constraints
            for (int i = 0; i < nCategories; ++i)
            {
                GRBLinExpr ntot = 0.0;
                for (int j = 0; j < nFoods; ++j)
                {
                    ntot.AddTerm(nutritionValues[j, i], buy[j]);
                }
                model.AddConstr(ntot == nutrition[i], Categories[i]);
            }

            // Solve
            model.Optimize();
            PrintSolution(model, buy, nutrition);

            Console.WriteLine("\nAdding constraint: at most 6 servings of dairy");
            model.AddConstr(buy[7] + buy[8] <= 6.0, "limit_dairy");

            // Solve
            model.Optimize();
            PrintSolution(model, buy, nutrition);

            // Dispose of model and env
            model.Dispose();
            env.Dispose();
        } catch (GRBException e) {
            Console.WriteLine("Error code: " + e.ErrorCode + ". " +
                              e.Message);
        }
    }
Exemple #30
0
    static void Main()
    {
        try {
            // Warehouse demand in thousands of units
            double[] Demand = new double[] { 15, 18, 14, 20 };

            // Plant capacity in thousands of units
            double[] Capacity = new double[] { 20, 22, 17, 19, 18 };

            // Fixed costs for each plant
            double[] FixedCosts =
                new double[] { 12000, 15000, 17000, 13000, 16000 };

            // Transportation costs per thousand units
            double[,] TransCosts =
                new double[, ] {
                { 4000, 2000, 3000, 2500, 4500 },
                { 2500, 2600, 3400, 3000, 4000 },
                { 1200, 1800, 2600, 4100, 3000 },
                { 2200, 2600, 3100, 3700, 3200 }
            };

            // Number of plants and warehouses
            int nPlants     = Capacity.Length;
            int nWarehouses = Demand.Length;

            double maxFixed = -GRB.INFINITY;
            double minFixed = GRB.INFINITY;
            for (int p = 0; p < nPlants; ++p)
            {
                if (FixedCosts[p] > maxFixed)
                {
                    maxFixed = FixedCosts[p];
                }

                if (FixedCosts[p] < minFixed)
                {
                    minFixed = FixedCosts[p];
                }
            }

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

            model.ModelName = "multiscenario";

            // Plant open decision variables: open[p] == 1 if plant p is open.
            GRBVar[] open = new GRBVar[nPlants];
            for (int p = 0; p < nPlants; ++p)
            {
                open[p] = model.AddVar(0, 1, FixedCosts[p], GRB.BINARY, "Open" + p);
            }

            // Transportation decision variables: how much to transport from
            // a plant p to a warehouse w
            GRBVar[,] transport = new GRBVar[nWarehouses, nPlants];
            for (int w = 0; w < nWarehouses; ++w)
            {
                for (int p = 0; p < nPlants; ++p)
                {
                    transport[w, p] = model.AddVar(0, GRB.INFINITY, TransCosts[w, p],
                                                   GRB.CONTINUOUS, "Trans" + p + "." + w);
                }
            }

            // The objective is to minimize the total fixed and variable costs
            model.ModelSense = GRB.MINIMIZE;

            // Production constraints
            // Note that the right-hand limit sets the production to zero if
            // the plant is closed
            for (int p = 0; p < nPlants; ++p)
            {
                GRBLinExpr ptot = 0.0;
                for (int w = 0; w < nWarehouses; ++w)
                {
                    ptot.AddTerm(1.0, transport[w, p]);
                }
                model.AddConstr(ptot <= Capacity[p] * open[p], "Capacity" + p);
            }

            // Demand constraints
            GRBConstr[] demandConstr = new GRBConstr[nWarehouses];
            for (int w = 0; w < nWarehouses; ++w)
            {
                GRBLinExpr dtot = 0.0;
                for (int p = 0; p < nPlants; ++p)
                {
                    dtot.AddTerm(1.0, transport[w, p]);
                }
                demandConstr[w] = model.AddConstr(dtot == Demand[w], "Demand" + w);
            }

            // We constructed the base model, now we add 7 scenarios
            //
            // Scenario 0: Represents the base model, hence, no manipulations.
            // Scenario 1: Manipulate the warehouses demands slightly (constraint right
            //             hand sides).
            // Scenario 2: Double the warehouses demands (constraint right hand sides).
            // Scenario 3: Manipulate the plant fixed costs (objective coefficients).
            // Scenario 4: Manipulate the warehouses demands and fixed costs.
            // Scenario 5: Force the plant with the largest fixed cost to stay open
            //             (variable bounds).
            // Scenario 6: Force the plant with the smallest fixed cost to be closed
            //             (variable bounds).

            model.NumScenarios = 7;

            // Scenario 0: Base model, hence, nothing to do except giving the
            //             scenario a name
            model.Parameters.ScenarioNumber = 0;
            model.ScenNName = "Base model";

            // Scenario 1: Increase the warehouse demands by 10%
            model.Parameters.ScenarioNumber = 1;
            model.ScenNName = "Increased warehouse demands";

            for (int w = 0; w < nWarehouses; w++)
            {
                demandConstr[w].ScenNRHS = Demand[w] * 1.1;
            }

            // Scenario 2: Double the warehouse demands
            model.Parameters.ScenarioNumber = 2;
            model.ScenNName = "Double the warehouse demands";

            for (int w = 0; w < nWarehouses; w++)
            {
                demandConstr[w].ScenNRHS = Demand[w] * 2.0;
            }

            // Scenario 3: Decrease the plant fixed costs by 5%
            model.Parameters.ScenarioNumber = 3;
            model.ScenNName = "Decreased plant fixed costs";

            for (int p = 0; p < nPlants; p++)
            {
                open[p].ScenNObj = FixedCosts[p] * 0.95;
            }

            // Scenario 4: Combine scenario 1 and scenario 3 */
            model.Parameters.ScenarioNumber = 4;
            model.ScenNName = "Increased warehouse demands and decreased plant fixed costs";

            for (int w = 0; w < nWarehouses; w++)
            {
                demandConstr[w].ScenNRHS = Demand[w] * 1.1;
            }
            for (int p = 0; p < nPlants; p++)
            {
                open[p].ScenNObj = FixedCosts[p] * 0.95;
            }

            // Scenario 5: Force the plant with the largest fixed cost to stay
            //             open
            model.Parameters.ScenarioNumber = 5;
            model.ScenNName = "Force plant with largest fixed cost to stay open";

            for (int p = 0; p < nPlants; p++)
            {
                if (FixedCosts[p] == maxFixed)
                {
                    open[p].ScenNLB = 1.0;
                    break;
                }
            }

            // Scenario 6: Force the plant with the smallest fixed cost to be
            //             closed
            model.Parameters.ScenarioNumber = 6;
            model.ScenNName = "Force plant with smallest fixed cost to be closed";

            for (int p = 0; p < nPlants; p++)
            {
                if (FixedCosts[p] == minFixed)
                {
                    open[p].ScenNUB = 0.0;
                    break;
                }
            }

            // Guess at the starting point: close the plant with the highest
            // fixed costs; open all others

            // First, open all plants
            for (int p = 0; p < nPlants; ++p)
            {
                open[p].Start = 1.0;
            }

            // Now close the plant with the highest fixed cost
            Console.WriteLine("Initial guess:");
            for (int p = 0; p < nPlants; ++p)
            {
                if (FixedCosts[p] == maxFixed)
                {
                    open[p].Start = 0.0;
                    Console.WriteLine("Closing plant " + p + "\n");
                    break;
                }
            }

            // Use barrier to solve root relaxation
            model.Parameters.Method = GRB.METHOD_BARRIER;

            // Solve multi-scenario model
            model.Optimize();

            int nScenarios = model.NumScenarios;

            for (int s = 0; s < nScenarios; s++)
            {
                int modelSense = GRB.MINIMIZE;

                // Set the scenario number to query the information for this scenario
                model.Parameters.ScenarioNumber = s;

                // collect result for the scenario
                double scenNObjBound = model.ScenNObjBound;
                double scenNObjVal   = model.ScenNObjVal;

                Console.WriteLine("\n\n------ Scenario " + s
                                  + " (" + model.ScenNName + ")");

                // Check if we found a feasible solution for this scenario
                if (scenNObjVal >= modelSense * GRB.INFINITY)
                {
                    if (scenNObjBound >= modelSense * GRB.INFINITY)
                    {
                        // Scenario was proven to be infeasible
                        Console.WriteLine("\nINFEASIBLE");
                    }
                    else
                    {
                        // We did not find any feasible solution - should not happen in
                        // this case, because we did not set any limit (like a time
                        // limit) on the optimization process
                        Console.WriteLine("\nNO SOLUTION");
                    }
                }
                else
                {
                    Console.WriteLine("\nTOTAL COSTS: " + scenNObjVal);
                    Console.WriteLine("SOLUTION:");
                    for (int p = 0; p < nPlants; p++)
                    {
                        double scenNX = open[p].ScenNX;

                        if (scenNX > 0.5)
                        {
                            Console.WriteLine("Plant " + p + " open");
                            for (int w = 0; w < nWarehouses; w++)
                            {
                                scenNX = transport[w, p].ScenNX;

                                if (scenNX > 0.0001)
                                {
                                    Console.WriteLine("  Transport " + scenNX
                                                      + " units to warehouse " + w);
                                }
                            }
                        }
                        else
                        {
                            Console.WriteLine("Plant " + p + " closed!");
                        }
                    }
                }
            }

            // Print a summary table: for each scenario we add a single summary
            // line
            Console.WriteLine("\n\nSummary: Closed plants depending on scenario\n");
            Console.WriteLine("{0,8} | {1,17} {2,13}", "", "Plant", "|");

            Console.Write("{0,8} |", "Scenario");
            for (int p = 0; p < nPlants; p++)
            {
                Console.Write("{0,6}", p);
            }
            Console.WriteLine(" | {0,6}  Name", "Costs");

            for (int s = 0; s < nScenarios; s++)
            {
                int modelSense = GRB.MINIMIZE;

                // Set the scenario number to query the information for this scenario
                model.Parameters.ScenarioNumber = s;

                // Collect result for the scenario
                double scenNObjBound = model.ScenNObjBound;
                double scenNObjVal   = model.ScenNObjVal;

                Console.Write("{0,-8} |", s);

                // Check if we found a feasible solution for this scenario
                if (scenNObjVal >= modelSense * GRB.INFINITY)
                {
                    if (scenNObjBound >= modelSense * GRB.INFINITY)
                    {
                        // Scenario was proven to be infeasible
                        Console.WriteLine(" {0,-30}| {1,6}  " + model.ScenNName,
                                          "infeasible", "-");
                    }
                    else
                    {
                        // We did not find any feasible solution - should not happen in
                        // this case, because we did not set any limit (like a time
                        // limit) on the optimization process
                        Console.WriteLine(" {0,-30}| {1,6}  " + model.ScenNName,
                                          "no solution found", "-");
                    }
                }
                else
                {
                    for (int p = 0; p < nPlants; p++)
                    {
                        double scenNX = open[p].ScenNX;
                        if (scenNX > 0.5)
                        {
                            Console.Write("{0,6}", " ");
                        }
                        else
                        {
                            Console.Write("{0,6}", "x");
                        }
                    }

                    Console.WriteLine(" | {0,6}  " + model.ScenNName, scenNObjVal);
                }
            }

            // Dispose of model and env
            model.Dispose();
            env.Dispose();
        } catch (GRBException e) {
            Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message);
        }
    }
Exemple #31
0
        /// <summary>
        /// Method called when a process token executes the step.
        /// </summary>
        public ExitType Execute(IStepExecutionContext context)
        {
            IState _timenow = _propTimenow.GetState(context);
            double timenow  = Convert.ToDouble(_timenow.StateValue);

            SerializarElement sr = new SerializarElement();

            if (File.Exists(sr.SerializationFile))
            {
                Vect v = sr.deserializa();
                vectores = sr.deserializa();

                vectores.MipYc = v.MipYc;
                vectores.MipYv = v.MipYv;
                vectores.MipTc = v.MipTc;
                vectores.MipTv = v.MipTv;

                //Dinamico
                vectores.Din1   = v.Din1;
                vectores.DesCam = v.DesCam;
                vectores.Fila   = v.Fila;

                //LP
                vectores.TCV           = v.TCV;
                vectores.TCC           = v.TCC;
                vectores.TCj           = v.TCj;
                vectores.TDi           = v.TDi;
                vectores.Destij        = v.Destij;
                vectores.Dj            = v.Dj;
                vectores.Uj            = v.Uj;
                vectores.Ui            = v.Ui;
                vectores.RLi           = v.RLi;
                vectores.RUi           = v.RUi;
                vectores.PlYc          = v.PlYc;
                vectores.PlYv          = v.PlYv;
                vectores.PlTc          = v.PlTc;
                vectores.PlTv          = v.PlTv;
                vectores.PlTcmalo      = v.PlTcmalo;
                vectores.Mine          = v.Mine;
                vectores.Mineralocado  = v.Mineralocado;
                vectores.Lastrealocado = v.Lastrealocado;
            }

            int    i = 30;
            int    j = 20;
            double TA;

            TA = 0.0158333333; //tiempo de aculatado
            double expr;

            expr = 0; //variable auxiliar

            GRBEnv env = new GRBEnv();

            GRBModel disp = new GRBModel(env);

            GRBLinExpr L = 320; //Numero auxiliar de velocidad de descarga
            GRBLinExpr M = 110; //Numero max camiones

            double[,] Tcvij = new double[30, 20];
            double[,] Tccij = new double[30, 20];

            for (int a = 0; a < i; a = a + 1) // saca tiempo de viaje total
            {
                for (int b = 0; b < j; b = b + 1)
                {
                    Tcvij[a, b] = vectores.TCV[a, b] + vectores.TDi[a];

                    if (vectores.Destij[a, b] != 0)
                    {
                        Tccij[a, b] = vectores.TCC[a, b] + vectores.TCj[b] + TA;
                    }
                    else
                    {
                        Tccij[a, b] = 9999;
                    }
                }
            }



            for (int b = 0; b < j; b = b + 1)
            {
                expr = 0;

                for (int a = 0; a < i; a = a + 1)
                {
                    expr = expr + vectores.Destij[a, b];
                }
                if (expr == 0)
                {
                    vectores.Uj[b] = 0;
                }
            }


            GRBVar[,] Ycij = new GRBVar[30, 20]; //Camiones cargados de i a j
            GRBVar[,] Yvij = new GRBVar[30, 20]; //Camiones vacios de i a j
            GRBVar[,] Tcij = new GRBVar[30, 20]; //Throughtput cargado de i a j
            GRBVar[,] Tvij = new GRBVar[30, 20]; //Throughtput vacio de i a j

            for (int a = 0; a < i; a = a + 1)
            {
                for (int b = 0; b < j; b = b + 1)
                {
                    Ycij[a, b] = disp.AddVar(0.0, 1000, 0.0, GRB.CONTINUOUS, "Yc" + a + "_" + b);
                    Yvij[a, b] = disp.AddVar(0.0, 1000, 0.0, GRB.CONTINUOUS, "Yv" + a + "_" + b);
                    Tcij[a, b] = disp.AddVar(0.0, 100000, 0.0, GRB.CONTINUOUS, "Tc" + a + "_" + b); //tonelaje cargado pasando hacia j en toneladas
                    Tvij[a, b] = disp.AddVar(0.0, 100000, 0.0, GRB.CONTINUOUS, "Tv" + a + "_" + b); //tonelaje vacio pasando hacia j en toneladas
                }
            }

            for (int a = 0; a < i; a = a + 1)
            {
                for (int b = 0; b < j; b = b + 1)
                {
                    disp.AddConstr(Tcij[a, b] == ((Ycij[a, b] / Tccij[a, b]) * L), "tonelaje_minimo" + a);
                    disp.AddConstr(Tvij[a, b] == ((Yvij[a, b] / Tcvij[a, b]) * L), "tonelaje_maximo" + b);
                }
            }

            for (int b = 0; b < j; b = b + 1)
            {
                GRBLinExpr P = 0;

                for (int a = 0; a < i; a = a + 1)
                {
                    P = P + Tcij[a, b];
                }
                disp.AddConstr((vectores.Dj[b] * vectores.Uj[b]), GRB.LESS_EQUAL, P, "tonelaje_minimo_de_palas" + b);
            }



            for (int a = 0; a < i; a = a + 1)
            {
                GRBLinExpr P = 0;

                for (int b = 0; b < j; b = b + 1)
                {
                    P = P + Tcij[a, b];
                }
                disp.AddConstr(P, GRB.LESS_EQUAL, vectores.RUi[a] * vectores.Ui[a], "tonelaje_minimo_a_basureros" + a);
            }

            //Restriccion del chancador independiente

            for (int a = 1; a < i; a = a + 1)
            {
                GRBLinExpr P = 0;

                for (int b = 0; b < j; b = b + 1)
                {
                    P = P + Tcij[a, b];
                }
                disp.AddConstr(vectores.RLi[a] * vectores.Ui[a], GRB.LESS_EQUAL, P, "tonelajecargado2" + a);
            }

            for (int a = 0; a < i; a = a + 1)
            {
                GRBLinExpr P = 0;

                for (int b = 0; b < j; b = b + 1)
                {
                    P = P + Tcij[a, b];
                }
                disp.AddConstr(vectores.Ui[a] * (vectores.RLi[a] - (vectores.PlTcmalo[0, 3] * (1 - vectores.Uj[3]) + vectores.PlTcmalo[0, 4] * (1 - vectores.Uj[4]) + vectores.PlTcmalo[0, 5] * (1 - vectores.Uj[5]) + vectores.PlTcmalo[0, 16] * (1 - vectores.Uj[16]) + vectores.PlTcmalo[0, 17] * (1 - vectores.Uj[17]))), GRB.LESS_EQUAL, P, "tonelajecargado2" + a);
            }



            GRBLinExpr Qonda = 0;

            for (int a = 0; a < i; a = a + 1)
            {
                for (int b = 0; b < j; b = b + 1)
                {
                    Qonda = (Qonda + Ycij[a, b] + Yvij[a, b]);
                }
            }

            disp.AddConstr(Qonda, GRB.LESS_EQUAL, M, "maximocamiones");



            for (int b = 0; b < j; b = b + 1)
            {
                GRBLinExpr P1 = 0;
                GRBLinExpr P2 = 0;

                for (int a = 0; a < i; a = a + 1)
                {
                    P1 = P1 + Tcij[a, b];
                    P2 = P2 + Tvij[a, b];
                }
                disp.AddConstr(P1, GRB.EQUAL, P2, "conservaciondeflujo" + i);
            }


            for (int a = 0; a < i; a = a + 1)
            {
                GRBLinExpr P1 = 0;
                GRBLinExpr P2 = 0;

                for (int b = 0; b < j; b = b + 1)
                {
                    P1 = P1 + Tcij[a, b];
                    P2 = P2 + Tvij[a, b];
                }

                disp.AddConstr(P1, GRB.EQUAL, P2, "conservaciondeflujo2" + i);
            }


            GRBLinExpr Pobj = 0;

            for (int a = 0; a < i; a = a + 1)
            {
                for (int b = 0; b < j; b = b + 1)
                {
                    Pobj = Pobj + Ycij[a, b] + Yvij[a, b];
                }
            }

            disp.Update();

            disp.SetObjective(Pobj, GRB.MINIMIZE);

            disp.Optimize();


            double sumayc = 0;
            double sumayv = 0;
            double sumatc = 0;
            double sumatv = 0;

            for (int a = 0; a < i; a = a + 1)
            {
                double sumajyc = 0;
                double sumajyv = 0;
                double sumajtc = 0;
                double sumajtv = 0;

                for (int b = 0; b < j; b = b + 1)
                {
                    vectores.PlYc[a, b] = Convert.ToDouble(Ycij[a, b].X);
                    vectores.PlYv[a, b] = Convert.ToDouble(Yvij[a, b].X);
                    vectores.PlTc[a, b] = Convert.ToDouble(Tcij[a, b].X);
                    vectores.PlTv[a, b] = Convert.ToDouble(Tvij[a, b].X);
                    sumayc  = sumayc + vectores.PlYc[a, b];             //suma todos los flujos llenos
                    sumayv  = sumayv + vectores.PlYv[a, b];             //suma todos los flujos vacios
                    sumatc  = sumatc + vectores.PlTc[a, b];             //suma todos los camiones llenos
                    sumatv  = sumatv + vectores.PlTv[a, b];             //suma todos los camiones vacios
                    sumajyc = sumajyc + Convert.ToDouble(Ycij[a, b].X); //suma todo el flujo cargado al botadero "a"
                    sumajyv = sumajyv + Convert.ToDouble(Yvij[a, b].X); //suma todo el flujo vacio al botadero "a"
                    sumajtc = sumajtc + Convert.ToDouble(Tcij[a, b].X); //suma todos los camiones cargados yendo a botadero "a"
                    sumajtv = sumajtv + Convert.ToDouble(Tvij[a, b].X); //suma todos los camiones vacios yendo a botadero "a"
                }

                vectores.PlYc[a, 20] = sumajyc; // deja total
                vectores.PlYv[a, 20] = sumajyv; //
                vectores.PlTc[a, 20] = sumajtc; //
                vectores.PlTv[a, 20] = sumajtv; //
            }

            for (int b = 0; b < j; b = b + 1)
            {
                double sumaiyc = 0;
                double sumaiyv = 0;
                double sumaitc = 0;
                double sumaitv = 0;

                for (int a = 0; a < i; a = a + 1)
                {
                    sumaiyc = sumaiyc + Convert.ToDouble(Ycij[a, b].X);
                    sumaiyv = sumaiyv + Convert.ToDouble(Yvij[a, b].X);
                    sumaitc = sumaitc + Convert.ToDouble(Tcij[a, b].X);
                    sumaitv = sumaitv + Convert.ToDouble(Tvij[a, b].X);
                }

                vectores.PlYc[30, b] = sumaiyc;
                vectores.PlYv[30, b] = sumaiyv;
                vectores.PlTc[30, b] = sumaitc;
                vectores.PlTv[30, b] = sumaitv;
            }

            vectores.PlYc[30, 20] = sumayc;
            vectores.PlYv[30, 20] = sumayv;
            vectores.PlTc[30, 20] = sumatc;
            vectores.PlTv[30, 20] = sumatv;

            _timenow.StateValue = vectores.PlTc[0, 20];
            sr.serializa(vectores);
            sr.closeStream();

            disp.Dispose();
            env.Dispose();



            return(ExitType.FirstExit);
        }
    static void Main(string[] args)
    {
        int n = 9;
        int s = 3;

        if (args.Length < 1)
        {
            Console.Out.WriteLine("Usage: sudoku_cs filename");
            return;
        }

        try {
            GRBEnv   env   = new GRBEnv();
            GRBModel model = new GRBModel(env);

            // Create 3-D array of model variables

            GRBVar[,,] vars = new GRBVar[n, n, n];

            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    for (int v = 0; v < n; v++)
                    {
                        string st = "G_" + i.ToString() + "_" + j.ToString()
                                    + "_" + v.ToString();
                        vars[i, j, v] = model.AddVar(0.0, 1.0, 0.0, GRB.BINARY, st);
                    }
                }
            }

            // Add constraints

            GRBLinExpr expr;

            // Each cell must take one value

            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    expr = 0.0;
                    for (int v = 0; v < n; v++)
                    {
                        expr.AddTerm(1.0, vars[i, j, v]);
                    }
                    string st = "V_" + i.ToString() + "_" + j.ToString();
                    model.AddConstr(expr == 1.0, st);
                }
            }

            // Each value appears once per row

            for (int i = 0; i < n; i++)
            {
                for (int v = 0; v < n; v++)
                {
                    expr = 0.0;
                    for (int j = 0; j < n; j++)
                    {
                        expr.AddTerm(1.0, vars[i, j, v]);
                    }
                    string st = "R_" + i.ToString() + "_" + v.ToString();
                    model.AddConstr(expr == 1.0, st);
                }
            }

            // Each value appears once per column

            for (int j = 0; j < n; j++)
            {
                for (int v = 0; v < n; v++)
                {
                    expr = 0.0;
                    for (int i = 0; i < n; i++)
                    {
                        expr.AddTerm(1.0, vars[i, j, v]);
                    }
                    string st = "C_" + j.ToString() + "_" + v.ToString();
                    model.AddConstr(expr == 1.0, st);
                }
            }

            // Each value appears once per sub-grid

            for (int v = 0; v < n; v++)
            {
                for (int i0 = 0; i0 < s; i0++)
                {
                    for (int j0 = 0; j0 < s; j0++)
                    {
                        expr = 0.0;
                        for (int i1 = 0; i1 < s; i1++)
                        {
                            for (int j1 = 0; j1 < s; j1++)
                            {
                                expr.AddTerm(1.0, vars[i0 * s + i1, j0 * s + j1, v]);
                            }
                        }
                        string st = "Sub_" + v.ToString() + "_" + i0.ToString()
                                    + "_" + j0.ToString();
                        model.AddConstr(expr == 1.0, st);
                    }
                }
            }

            // Fix variables associated with pre-specified cells

            StreamReader sr = File.OpenText(args[0]);

            for (int i = 0; i < n; i++)
            {
                string input = sr.ReadLine();
                for (int j = 0; j < n; j++)
                {
                    int val = (int)input[j] - 48 - 1; // 0-based

                    if (val >= 0)
                    {
                        vars[i, j, val].LB = 1.0;
                    }
                }
            }

            // Optimize model

            model.Optimize();

            // Write model to file
            model.Write("sudoku.lp");

            double[,,] x = model.Get(GRB.DoubleAttr.X, vars);

            Console.WriteLine();
            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    for (int v = 0; v < n; v++)
                    {
                        if (x[i, j, v] > 0.5)
                        {
                            Console.Write(v + 1);
                        }
                    }
                }
                Console.WriteLine();
            }

            // Dispose of model and env
            model.Dispose();
            env.Dispose();
        } catch (GRBException e) {
            Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message);
        }
    }
Exemple #33
0
    static void Main()
    {
        try {
            // Warehouse demand in thousands of units
            double[] Demand = new double[] { 15, 18, 14, 20 };

            // Plant capacity in thousands of units
            double[] Capacity = new double[] { 20, 22, 17, 19, 18 };

            // Fixed costs for each plant
            double[] FixedCosts =
                new double[] { 12000, 15000, 17000, 13000, 16000 };

            // Transportation costs per thousand units
            double[,] TransCosts =
                new double[, ] {
                { 4000, 2000, 3000, 2500, 4500 },
                { 2500, 2600, 3400, 3000, 4000 },
                { 1200, 1800, 2600, 4100, 3000 },
                { 2200, 2600, 3100, 3700, 3200 }
            };

            // Number of plants and warehouses
            int nPlants     = Capacity.Length;
            int nWarehouses = Demand.Length;

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

            model.ModelName = "facility";

            // Plant open decision variables: open[p] == 1 if plant p is open.
            GRBVar[] open = new GRBVar[nPlants];
            for (int p = 0; p < nPlants; ++p)
            {
                open[p] = model.AddVar(0, 1, FixedCosts[p], GRB.BINARY, "Open" + p);
            }

            // Transportation decision variables: how much to transport from
            // a plant p to a warehouse w
            GRBVar[,] transport = new GRBVar[nWarehouses, nPlants];
            for (int w = 0; w < nWarehouses; ++w)
            {
                for (int p = 0; p < nPlants; ++p)
                {
                    transport[w, p] =
                        model.AddVar(0, GRB.INFINITY, TransCosts[w, p], GRB.CONTINUOUS,
                                     "Trans" + p + "." + w);
                }
            }

            // The objective is to minimize the total fixed and variable costs
            model.ModelSense = GRB.MINIMIZE;

            // Production constraints
            // Note that the right-hand limit sets the production to zero if
            // the plant is closed
            for (int p = 0; p < nPlants; ++p)
            {
                GRBLinExpr ptot = 0.0;
                for (int w = 0; w < nWarehouses; ++w)
                {
                    ptot.AddTerm(1.0, transport[w, p]);
                }
                model.AddConstr(ptot <= Capacity[p] * open[p], "Capacity" + p);
            }

            // Demand constraints
            for (int w = 0; w < nWarehouses; ++w)
            {
                GRBLinExpr dtot = 0.0;
                for (int p = 0; p < nPlants; ++p)
                {
                    dtot.AddTerm(1.0, transport[w, p]);
                }
                model.AddConstr(dtot == Demand[w], "Demand" + w);
            }

            // Guess at the starting point: close the plant with the highest
            // fixed costs; open all others

            // First, open all plants
            for (int p = 0; p < nPlants; ++p)
            {
                open[p].Start = 1.0;
            }

            // Now close the plant with the highest fixed cost
            Console.WriteLine("Initial guess:");
            double maxFixed = -GRB.INFINITY;
            for (int p = 0; p < nPlants; ++p)
            {
                if (FixedCosts[p] > maxFixed)
                {
                    maxFixed = FixedCosts[p];
                }
            }
            for (int p = 0; p < nPlants; ++p)
            {
                if (FixedCosts[p] == maxFixed)
                {
                    open[p].Start = 0.0;
                    Console.WriteLine("Closing plant " + p + "\n");
                    break;
                }
            }

            // Use barrier to solve root relaxation
            model.Parameters.Method = GRB.METHOD_BARRIER;

            // Solve
            model.Optimize();

            // Print solution
            Console.WriteLine("\nTOTAL COSTS: " + model.ObjVal);
            Console.WriteLine("SOLUTION:");
            for (int p = 0; p < nPlants; ++p)
            {
                if (open[p].X > 0.99)
                {
                    Console.WriteLine("Plant " + p + " open:");
                    for (int w = 0; w < nWarehouses; ++w)
                    {
                        if (transport[w, p].X > 0.0001)
                        {
                            Console.WriteLine("  Transport " +
                                              transport[w, p].X + " units to warehouse " + w);
                        }
                    }
                }
                else
                {
                    Console.WriteLine("Plant " + p + " closed!");
                }
            }

            // Dispose of model and env
            model.Dispose();
            env.Dispose();
        } catch (GRBException e) {
            Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message);
        }
    }
        void BuildGRBModel()
        {
            _env = new GRBEnv("SolutionLog.log");
            _env.Set(GRB.DoubleParam.MIPGap, 0.0);
            _env.Set(GRB.DoubleParam.TimeLimit, 500);
            _env.Set(GRB.DoubleParam.Heuristics, 0.5);
            _grbModel = new GRBModel(_env);

            //决策变量
            foreach (Node n in Data.NodeSet)
            {
                n.Result_GenerateFlow = _grbModel.AddVar(0.0, Data.M, 0.0, GRB.CONTINUOUS, "g_" + n.ID);
                n.Result_IsServerLoacationSelected = _grbModel.AddVar(0.0, 1.0, 0.0, GRB.BINARY, "x_" + n.ID);
            }
            foreach (Arc a in Data.ArcSet)
            {
                a.Result_FlowF = _grbModel.AddVar(0.0, Data.M, 0.0, GRB.CONTINUOUS, "fF_" + a.FromNode.ID + "_" + a.ToNode.ID);
                a.Result_FlowR = _grbModel.AddVar(0.0, Data.M, 0.0, GRB.CONTINUOUS, "fR_" + a.FromNode.ID + "_" + a.ToNode.ID);
            }
            _grbModel.Update();

            //目标函数
            GRBLinExpr expr1 = 0;

            foreach (Node n in Data.NodeSet)
            {
                expr1 += n.Result_IsServerLoacationSelected * Data.ServerInstalationFee;
            }
            GRBLinExpr expr2 = 0;

            foreach (Arc a in Data.ArcSet)
            {
                expr2 += (a.Result_FlowF + a.Result_FlowR) * Data.FlowFeePerUnit;
            }

            _grbModel.SetObjective(expr1 + expr2, GRB.MINIMIZE);


            //约束条件
            foreach (Node n in Data.NodeSet)
            {
                _grbModel.AddConstr(n.Result_GenerateFlow <= n.Result_IsServerLoacationSelected * Data.M, "ct1_" + n.ID);
            }
            foreach (Node n in Data.NodeSet)
            {
                GRBLinExpr sum1 = 0;
                GRBLinExpr sum2 = 0;
                GRBLinExpr sum3 = 0;
                GRBLinExpr sum4 = 0;
                foreach (Arc a in n.ArcSet)
                {
                    if (a.ToNode == n)//进
                    {
                        sum1 += a.Result_FlowF;
                        sum3 += a.Result_FlowR;
                    }
                    else//出
                    {
                        sum2 += a.Result_FlowR;
                        sum4 += a.Result_FlowF;
                    }
                }
                _grbModel.AddConstr(n.Result_GenerateFlow + sum1 + sum2 == n.Demand + sum3 + sum4, "ct2_" + n.ID);
            }
            foreach (Arc a in Data.ArcSet)
            {
                _grbModel.AddConstr(a.Result_FlowF + a.Result_FlowR <= a.Capacity, "ct3_" + a.FromNode.ID + "_" + a.ToNode.ID);
            }
        }
Exemple #35
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);
        }
    }
        public void OptimalPlacement(ref List <Station> stationList, ref List <OHCAEvent> eventList)
        {
            int[,] a = new int[J, I];
            for (int j = 0; j < J; j++)
            {
                for (int i = 0; i < I; i++)
                {
                    a[j, i] = (Utils.GetDistance(stationList[i].lat, stationList[i].lon, eventList[j].lat, eventList[j].lon) < Utils.GOLDEN_TIME - 1.0 / 6.0) ? 1 : 0;
                }
            }

            try
            {
                GRBEnv   env   = new GRBEnv("Boutilier.log");
                GRBModel model = new GRBModel(env);

                GRBVar[] y = new GRBVar[I];
                for (int i = 0; i < I; i++)
                {
                    y[i] = model.AddVar(0.0, 1.0, 0.0, GRB.BINARY, "y_" + i);
                }

                GRBVar[, ] z = new GRBVar[J, I];
                for (int j = 0; j < J; j++)
                {
                    for (int i = 0; i < I; i++)
                    {
                        z[j, i] = model.AddVar(0.0, 1.0, 0.0, GRB.BINARY, "z_" + i + "," + j);
                    }
                }

                GRBLinExpr obj_expr = 0.0;
                for (int i = 0; i < I; i++)
                {
                    obj_expr.AddTerm(1.0, y[i]);
                }

                model.SetObjective(obj_expr, GRB.MINIMIZE);
                GRBLinExpr bigExpr = 0.0;
                for (int j = 0; j < J; j++)
                {
                    GRBLinExpr expr = 0.0;
                    for (int i = 0; i < I; i++)
                    {
                        expr.AddTerm(1, z[j, i]);
                    }
                    bigExpr.Add(expr);
                    model.AddConstr(expr, GRB.LESS_EQUAL, 1.0, "c0_" + j);
                }
                model.AddConstr(bigExpr, GRB.GREATER_EQUAL, f / 100.0 * J, "c1");

                for (int j = 0; j < J; j++)
                {
                    for (int i = 0; i < I; i++)
                    {
                        model.AddConstr(z[j, i], GRB.LESS_EQUAL, a[j, i] * y[i], "c2_" + i + "," + j);
                    }
                }

                model.Write("model_b.lp");

                model.Optimize();

                int optimstatus = model.Status;

                if (optimstatus == GRB.Status.INF_OR_UNBD)
                {
                    model.Parameters.Presolve = 0;
                    model.Optimize();
                    optimstatus = model.Status;
                }

                if (optimstatus == GRB.Status.OPTIMAL)
                {
                }

                else if (optimstatus == GRB.Status.INFEASIBLE)
                {
                    Console.WriteLine("Model is unbounded");
                }
                else
                {
                    Console.WriteLine("Optimization was stopped with status = " + optimstatus);
                }

                List <Station> tempList = new List <Station>();
                CloneList(stationList, tempList);
                stationList.Clear();
                for (int i = 0; i < I; i++)
                {
                    if (y[i].Get(GRB.DoubleAttr.X) > 0)
                    {
                        stationList.Add(tempList[i]);
                    }
                }

                I = stationList.Count;

                coverList = new List <List <int> >();
                for (int i = 0; i < I; i++)
                {
                    coverList.Add(new List <int>());
                }

                for (int j = 0; j < J; j++)
                {
                    for (int i = 0; i < I; i++)
                    {
                        if (z[j, i].Get(GRB.DoubleAttr.X) > 0)
                        {
                            coverList[i].Add(j);
                        }
                    }
                }

                model.Dispose();
                env.Dispose();
            }
            catch (GRBException e)
            {
                Console.WriteLine("Error code : " + e.ErrorCode + ", " + e.Message);
            }
        }
Exemple #37
0
        private void RunOptimization()
        {
            GRBEnv   env   = new GRBEnv();
            GRBModel model = new GRBModel(env);

            List <List <GRBVar> > varsFromElements = new List <List <GRBVar> >();

            //Variables: LoD for each element with their respective utility value
            for (var i = 0; i < _model.Elements.Count; i++)
            {
                var element  = _model.Elements[i];
                var allLoads = CalcUtil.GetAllCognitiveLoadsForElement(element);

                List <GRBVar> varsCurrentElement = new List <GRBVar>();

                var lowerBound = 0.0;
                var upperBound = 0.0;

                for (var j = 0; j < allLoads.Count; j++)
                {
                    //Fix element and current LoD if flag is set, i.e. lower and upper bound are 1.0
                    if (element.FixateElement)
                    {
                        //lowerBound = (j + 1) == element.CurrentLevelOfDetail ? 1.0 : 0.0;

                        if (element.ElementIsInView)
                        {
                            lowerBound = (j + 1) == element.CurrentLevelOfDetail ? 1.0 : 0.0;
                        }
                        else
                        {
                            lowerBound = (j + 1) == element.MaxViewLevelOfDetail ? 1.0 : 0.0;
                        }
                    }

                    //Omit element if omit-flag is set, ie lower and upper bound are 0.0
                    //also: minimum LoD is 1 for any element that is optimized
                    upperBound = !element.OmitElement && j > 0 ? 1.0 : 0.0;

                    if (lowerBound < 1.0 && upperBound > 0.0)
                    {
                        //element is in sight, therefore should be spatially anchored, not in view
                        //if (element.ElementIsInView && (j + 1) <= 2)
                        //{
                        //    upperBound = 0.0;
                        //}
                        //else
                        if (!element.ElementIsInView && ((j + 1) > element.MaxViewLevelOfDetail || (j + 1) < element.MinViewLevelOfDetail))
                        {
                            upperBound = 0.0;
                        }
                    }

                    //Disable changing the LoD by more than 1, ie set upper bound to 0.0 (except if element is fixated)
                    //var absLoDDifference = Math.Abs(element.CurrentLevelOfDetail - 1 - j);
                    //if (lowerBound < 1.0 && absLoDDifference > 1 && (j + 1) > 1)
                    //    upperBound = 0.0;

                    GRBVar eLod = model.AddVar(lowerBound, upperBound, CalcUtil.GetObjectiveForElement(element, j + 1, _model), GRB.BINARY, "e_" + i + "_lod_" + j);
                    varsCurrentElement.Add(eLod);
                }

                varsFromElements.Add(varsCurrentElement);
            }

            //Constraint: overall cognitive load must be below user's cognitive capacity
            GRBLinExpr lhs = 0.0;

            for (var i = 0; i < _model.Elements.Count; i++)
            {
                var element  = _model.Elements[i];
                var allLoads = CalcUtil.GetAllCognitiveLoadsForElement(element);

                for (var j = 0; j < allLoads.Count; j++)
                {
                    var load = allLoads[j] + CalcUtil.GetTimeDependentCognitiveLoadOnsetPenalty(element, _model);
                    lhs.AddTerm(load, varsFromElements[i][j]);
                }
            }
            model.AddConstr(lhs, GRB.LESS_EQUAL, _model.UserModel.CognitiveCapacity, "c_cog");

            //Constraint: constraints to number of available slots
            lhs = 0.0;
            for (var i = 0; i < _model.Elements.Count; i++)
            {
                for (var j = 0; j < _model.Elements[i].MaxLevelOfDetail; j++)
                {
                    lhs.AddTerm(1.0, varsFromElements[i][j]);
                }
            }

            model.AddConstr(lhs, GRB.GREATER_EQUAL, _model.NumMinPlacementSlots, "c_slots_min");
            model.AddConstr(lhs, GRB.LESS_EQUAL, _model.NumMaxPlacementSlots, "c_slots_max");

            //Constraint: only 1 LoD per Element
            for (var i = 0; i < _model.Elements.Count; i++)
            {
                lhs = 0.0;

                for (var j = 0; j < _model.Elements[i].MaxLevelOfDetail; j++)
                {
                    lhs.AddTerm(1.0, varsFromElements[i][j]);
                }

                model.AddConstr(lhs, GRB.LESS_EQUAL, 1.0, "c" + i + "_lod");
            }

            model.ModelSense = GRB.MAXIMIZE;

            model.Optimize();

            var status = model.Status;

            _model.IsFeasible = !(status == GRB.Status.INF_OR_UNBD || status == GRB.Status.INFEASIBLE || status == GRB.Status.UNBOUNDED);

            if (_model.IsFeasible)
            {
                //UpdateModels(model, varsFromElements);
                StoreAllSolutions(model);

                Console.WriteLine(@"The model solved with cogLoad " + _model.UserModel.CognitiveCapacity + " / objective " + _model.Solutions[0].Objective);
            }
            else
            {
                Console.WriteLine(@"The model cannot be solved because it is infeasible or unbounded");
            }

            model.Dispose();
            env.Dispose();
        }
 public static GRBVar AddVar(this GRBModel _m, double lb, double ub, char type, string _prefix = null)
 {
     return(_m.AddVar(lb, ub, 0, type, _prefix));
 }
        public HttpResponseMessage Optimize(string RunName)
        {
            using (var dbConn = new ApplicationDbContext())
            {
                //Variables for students, semesters, courses, and course/semester offerings
                students = dbConn.StudentPreferences.Where(m => m.IsActive == true).Include(m => m.Courses).Include(m => m.Student.CompletedCourses).OrderByDescending(m => m.Student.CompletedCourses.Count()).ToArray();
                crssems = dbConn.CourseSemesters.Where(m => m.IsActive == true).Include(m => m.Course).Include(m => m.Semester).ToArray();
                courses = crssems.Select(m => m.Course).Distinct().ToArray();
                sems = crssems.Select(m => m.Semester).Distinct().OrderBy(m => m.Type).OrderBy(m => m.Year).ToArray();

                var completed = dbConn.CompletedCourses.ToList();
                try
                {
                    GRBEnv env = new GRBEnv("mip1.log");
                    GRBModel model = new GRBModel(env);
                    model.Set(GRB.StringAttr.ModelName, "Course Optimizer");
                    GRBVar[,] slacks = new GRBVar[courses.Length, sems.Length];

                    //Assignment of student, course, and semester.  Student must have a desire to take the coure, has not taken the course, and the course is offered to be included
                    GRBVar[,,] CourseAllocation = new GRBVar[students.Length, courses.Length, sems.Length];
                    for (int i = 0; i < students.Length; i++)
                    {
                        for (int j = 0; j < courses.Length; j++)
                        {
                            for (int k = 0; k < sems.Length; k++)
                            {
                                if (students[i].Courses.Contains(courses[j]) && !completed.Any(m => m.GaTechId == students[i].GaTechId && courses[j].ID == m.Course_ID) && crssems.Contains(crssems.SingleOrDefault(m => m.Course == courses[j] && m.Semester == sems[k])))
                                    CourseAllocation[i, j, k] = model.AddVar(0, 1, 1, GRB.BINARY, "students." + (i + 1).ToString() + "_Course." + (j + 1).ToString() + "_Semester." + (k + 1).ToString());
                                else
                                    CourseAllocation[i, j, k] = model.AddVar(0, 0, 1, GRB.BINARY, "students." + (i + 1).ToString() + "_Course." + (j + 1).ToString() + "_Semester." + (k + 1).ToString());
                            }
                        }
                    }
                    model.Set(GRB.IntAttr.ModelSense, 1);
                    model.Update();

                    //MUST TAKE DESIRED COURSE ONLY ONCE
                    //Constrains the students to only take courses they desire once and for when the course is offered and does not allow a repeat of a course in another semester
                    for (int i = 0; i < students.Length; i++)
                    {
                        for (int j = 0; j < courses.Length; j++)
                        {
                            if (students[i].Courses.Contains(courses[j]) && !completed.Any(m => m.GaTechId == students[i].GaTechId && courses[j].ID == m.Course_ID))
                            {
                                GRBLinExpr constStudentDesiredCourses = 0.0;
                                for (int k = 0; k < sems.Length; k++)
                                {
                                    if (crssems.Any(m => m.Course.ID == courses[j].ID && m.Semester.Type == sems[k].Type && m.Semester.Year == sems[k].Year))
                                        constStudentDesiredCourses.AddTerm(1.0, CourseAllocation[i, j, k]);
                                }
                                String sStudentDesiredCourses = "DesiredCourse." + j + 1 + "_Student." + i + 1;
                                model.AddConstr(constStudentDesiredCourses == 1, sStudentDesiredCourses);
                            }
                        }

                        //MAX COURSES PER SEMESTER
                        //Constrains the students to only have a maximum number of 2 courses per semester.
                        for (int k = 0; k < sems.Length; k++)
                        {
                            GRBLinExpr constMaxPerSem = 0.0;
                            for (int j = 0; j < courses.Length; j++)
                            {
                                if (!completed.Any(m => m.GaTechId == students[i].GaTechId && courses[j].ID == m.Course_ID) && (crssems.Any(m => m.Course.ID == courses[j].ID && m.Semester.Type == sems[k].Type && m.Semester.Year == sems[k].Year)))
                                    constMaxPerSem.AddTerm(1, CourseAllocation[i, j, k]);
                            }
                            String sCourseSem = "maxCourseStudent." + i + 1 + "_Semester." + k + 1;
                            model.AddConstr(constMaxPerSem <= MAX_COURSES_PER_SEMESTER, sCourseSem);
                        }

                        //PREREQUISITES
                        //Constrains the students to take prerequisite courses prior to taking a course that needs the prerequisite
                        for (int j = 0; j < courses.Length; j++)
                        {
                            if (courses[j].Prerequisites.Any() && students[i].Courses.Contains(courses[j]) && !completed.Any(m => m.GaTechId == students[i].GaTechId && courses[j].ID == m.Course_ID))
                            {

                                foreach (var prereq in courses[j].Prerequisites)
                                {
                                    int prereqIndex = Array.IndexOf(courses, prereq);
                                    GRBLinExpr coursePrereqConst1 = 0.0;
                                    GRBLinExpr coursePrereqConst2 = 0.0;
                                    if (!completed.Any(m => m.GaTechId == students[i].GaTechId && m.Course.ID == prereq.ID))
                                    {

                                        for (int k = 0; k < sems.Length; k++)
                                        {

                                            if (prereqIndex >= 0)
                                            {
                                                coursePrereqConst1.AddTerm(k + 1, CourseAllocation[i, prereqIndex, k]);
                                                coursePrereqConst2.AddTerm(k, CourseAllocation[i, j, k]);
                                            }
                                        }
                                    }
                                    model.AddConstr(coursePrereqConst1, GRB.LESS_EQUAL, coursePrereqConst2, "PREREQ_Student" + i + "_Course+" + j + "_Prereq" + prereqIndex);

                                }

                            }
                        }
                    }

                    //SENIORITY
                    //Students are already ordered from dB query by seniority in descending order and puts a preference to senior students over the next student that desires that
                    //same course with less seniority.
                    for (int j = 0; j < courses.Length; j++)
                    {
                        for (int i = 0; i < students.Length - 1; i++)
                        {
                            if (students[i].Courses.Contains(courses[j]) && !completed.Any(m => m.GaTechId == students[i].GaTechId && courses[j].ID == m.Course_ID))
                            {
                                int SemsRemain = (students[i].Courses.Count - students[i].Student.CompletedCourses.Count) / 2 + (students[i].Courses.Count - students[i].Student.CompletedCourses.Count) % 2;
                                for (int n = i + 1; n < students.Length; n++)
                                {
                                    if (students[n].Courses.Contains(courses[j]) && !completed.Any(m => m.GaTechId == students[n].GaTechId && courses[j].ID == m.Course_ID))
                                    {
                                        GRBLinExpr​ seniority = 0.0;
                                        for (int k = 0; k < sems.Length; k++)
                                        {
                                            if (crssems.Any(m => m.Course.ID == courses[j].ID && m.Semester.Type == sems[k].Type && m.Semester.Year == sems[k].Year))
                                            {
                                                if (k <= SemsRemain)
                                                {
                                                    seniority​.AddTerm(1.0, CourseAllocation[i, j, k]);
                                                    seniority​.AddTerm(-1.0, CourseAllocation​[n, j, k]);
                                                }
                                                else
                                                {
                                                    seniority​.AddTerm(-1.0, CourseAllocation[i, j, k]);
                                                    seniority​.AddTerm(1.0, CourseAllocation​[n, j, k]);
                                                }
                                            }
                                        }
                                        model.AddConstr(seniority, GRB.GREATER_EQUAL, 0, "Seniority for Student." + students[i] + "_Course." + courses[j]);
                                        break;
                                    }
                                }
                            }
                        }
                    }

                    //Add the slack variable for all semester & course offerings then constrain the maximum number of students
                    //to take a couse in a semester.
                    for (int k = 0; k < sems.Length; k++)
                    {
                        for (int j = 0; j < courses.Length; j++)
                        {
                            if (crssems.Any(m => m.Course.ID == courses[j].ID && m.Semester.Type == sems[k].Type && m.Semester.Year == sems[k].Year))
                            {
                                slacks[j, k] = model.AddVar(0, GRB.INFINITY, 0, GRB.INTEGER, sems[k].Type.ToString() + "." + sems[k].Year.ToString() + "." + courses[j].Name + ".Slacks");
                                GRBLinExpr constMaxStudCrsSem = 0.0;
                                for (int i = 0; i < students.Length; i++)
                                {
                                    if (!completed.Any(m => m.GaTechId == students[i].GaTechId && courses[j].ID == m.Course_ID))
                                        constMaxStudCrsSem.AddTerm(1.0, CourseAllocation[i, j, k]);
                                }
                                model.Update();
                                constMaxStudCrsSem.AddTerm(-1.0, slacks[j, k]);
                                model.AddConstr(constMaxStudCrsSem <= crssems.Single(m => m.Course.ID == courses[j].ID && m.Semester.Type == sems[k].Type && m.Semester.Year == sems[k].Year).StudentLimit, sems[k].Type.ToString() + "." + sems[k].Year.ToString() + "." + courses[j].Name);
                            }
                        }
                    }

                    //Add total slack to the optimization model for all courses in the semesters they are offered.
                    GRBVar totSlack = model.AddVar(0, GRB.INFINITY, 0, GRB.INTEGER, "totSlack");
                    GRBLinExpr lhs = new GRBLinExpr();
                    lhs.AddTerm(-1.0, totSlack);
                    for (int j = 0; j < courses.Length; j++)
                    {
                        for (int k = 0; k < sems.Length; k++)
                        {
                            if (crssems.Any(m => m.Course.ID == courses[j].ID && m.Semester.Type == sems[k].Type && m.Semester.Year == sems[k].Year))
                                lhs.AddTerm(1.0, slacks[j, k]);
                        }
                    }
                    model.Update();
                    model.AddConstr(lhs, GRB.EQUAL, 0, "totSlack");

                    // Objective: minimize the total slack
                    GRBLinExpr obj = new GRBLinExpr();
                    obj.AddTerm(1.0, totSlack);
                    model.SetObjective(obj);

                    //Optimize the model to minimize the total slack and maximize students to course offerings based on input variables and constraints.
                    model.Optimize();

                    //Write Results optimization results to database
                    writeResults(CourseAllocation, students, courses, sems, crssems, dbConn, Convert.ToInt32(model.Get(GRB.DoubleAttr.ObjVal)), RunName);

                    //Clean-Up
                    model.Dispose();
                    env.Dispose();
            }
                catch (Exception e)
            {
                return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, "An Error occured while running the optimization.");
            }
            }
            return Request.CreateResponse(HttpStatusCode.OK);
        }
Exemple #40
0
    public static void Main(String[] args)
    {
        if (args.Length < 1) {
          Console.WriteLine("Usage: tsp_cs nnodes");
          return;
        }

        int n = Convert.ToInt32(args[0]);

        try {
          GRBEnv   env   = new GRBEnv();
          GRBModel model = new GRBModel(env);

          // Must disable dual reductions when using lazy constraints

          model.GetEnv().Set(GRB.IntParam.DualReductions, 0);

          double[] x = new double[n];
          double[] y = new double[n];

          Random r = new Random();
          for (int i = 0; i < n; i++) {
        x[i] = r.NextDouble();
        y[i] = r.NextDouble();
          }

          // Create variables

          GRBVar[,] vars = new GRBVar[n, n];

          for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++)
          vars[i, j] = model.AddVar(0.0, 1.0, distance(x, y, i, j),
                                    GRB.BINARY, "x"+i+"_"+j);

          // Integrate variables

          model.Update();

          // Degree-2 constraints

          for (int i = 0; i < n; i++) {
        GRBLinExpr expr = 0;
        for (int j = 0; j < n; j++)
          expr += vars[i, j];
        model.AddConstr(expr == 2.0, "deg2_"+i);
          }

          // Forbid edge from node back to itself

          for (int i = 0; i < n; i++)
        vars[i, i].Set(GRB.DoubleAttr.UB, 0.0);

          // Symmetric TSP

          for (int i = 0; i < n; i++)
        for (int j = 0; j < i; j++)
          model.AddConstr(vars[i, j]== vars[j, i], "");

          model.SetCallback(new tsp_cs(vars));
          model.Optimize();

          if (model.Get(GRB.IntAttr.SolCount) > 0) {
        int[] tour = findsubtour(model.Get(GRB.DoubleAttr.X, vars));

        Console.Write("Tour: ");
        for (int i = 0; i < tour.Length; i++)
          Console.Write(tour[i] + " ");
        Console.WriteLine();
          }

          // Dispose of model and environment
          model.Dispose();
          env.Dispose();

        } catch (GRBException e) {
          Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message);
          Console.WriteLine(e.StackTrace);
        }
    }
Exemple #41
0
    static void Main(string[] args)
    {
        int n = 9;
        int s = 3;

        if (args.Length < 1) {
          Console.Out.WriteLine("Usage: sudoku_cs filename");
          return;
        }

        try {
          GRBEnv env = new GRBEnv();
          GRBModel model = new GRBModel(env);

          // Create 3-D array of model variables

          GRBVar[,,] vars = new GRBVar[n,n,n];

          for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
          for (int v = 0; v < n; v++) {
            string st = "G_" + i.ToString() + "_" + j.ToString()
                             + "_" + v.ToString();
            vars[i,j,v] = model.AddVar(0.0, 1.0, 0.0, GRB.BINARY, st);
          }
        }
          }

          // Integrate variables into model

          model.Update();

          // Add constraints

          GRBLinExpr expr;

          // Each cell must take one value

          for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
          expr = 0.0;
          for (int v = 0; v < n; v++)
            expr += vars[i,j,v];
          string st = "V_" + i.ToString() + "_" + j.ToString();
          model.AddConstr(expr == 1.0, st);
        }
          }

          // Each value appears once per row

          for (int i = 0; i < n; i++) {
        for (int v = 0; v < n; v++) {
          expr = 0.0;
          for (int j = 0; j < n; j++)
            expr += vars[i,j,v];
          string st = "R_" + i.ToString() + "_" + v.ToString();
          model.AddConstr(expr == 1.0, st);
        }
          }

          // Each value appears once per column

          for (int j = 0; j < n; j++) {
        for (int v = 0; v < n; v++) {
          expr = 0.0;
          for (int i = 0; i < n; i++)
            expr += vars[i,j,v];
          string st = "C_" + j.ToString() + "_" + v.ToString();
          model.AddConstr(expr == 1.0, st);
        }
          }

          // Each value appears once per sub-grid

          for (int v = 0; v < n; v++) {
        for (int i0 = 0; i0 < s; i0++) {
          for (int j0 = 0; j0 < s; j0++) {
            expr = 0.0;
            for (int i1 = 0; i1 < s; i1++) {
              for (int j1 = 0; j1 < s; j1++) {
                expr += vars[i0*s+i1,j0*s+j1,v];
              }
            }
            string st = "Sub_" + v.ToString() + "_" + i0.ToString()
                               + "_" + j0.ToString();
            model.AddConstr(expr == 1.0, st);
          }
        }
          }

          // Update model

          model.Update();

          // Fix variables associated with pre-specified cells

          StreamReader sr = File.OpenText(args[0]);

          for (int i = 0; i < n; i++) {
        string input = sr.ReadLine();
        for (int j = 0; j < n; j++) {
          int val = (int) input[j] - 48 - 1; // 0-based

          if (val >= 0)
            vars[i,j,val].Set(GRB.DoubleAttr.LB, 1.0);
        }
          }

          // Optimize model

          model.Optimize();

          // Write model to file
          model.Write("sudoku.lp");

          double[,,] x = model.Get(GRB.DoubleAttr.X, vars);

          Console.WriteLine();
          for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
          for (int v = 0; v < n; v++) {
            if (x[i,j,v] > 0.5) {
              Console.Write(v+1);
            }
          }
        }
        Console.WriteLine();
          }

          // Dispose of model and env
          model.Dispose();
          env.Dispose();

        } catch (GRBException e) {
          Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message);
        }
    }
Exemple #42
0
        public GurobiSolver4(Crossword crossword)
        {
            var wordLengthHistogram = new Dictionary <int, double>()
            {
                { 2, 0 },
                { 3, 18 },
                { 4, 24 },
                { 5, 20 },
                { 6, 18 },
                { 7, 12 },
                { 8, 4 },
                { 9, 1 },
                { 10, 1 },
                { 11, 1 },
                { 12, 1 },
                { 13, 0 },
                { 14, 0 },
                { 15, 0 },
            };

            const int maxWordLength = 15;
            const int minWordLength = 2;

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


            var requiredAmountOfLetters = wordLengthHistogram.Sum(wl => wl.Key * wl.Value) / 1.8d;
            int totalFields             = sizeX * sizeY;

            for (int y = 0; y < sizeY; y++)
            {
                for (int x = 0; x < sizeX; x++)
                {
                    totalFields -= crossword.Grid[y, x] is Blocked ? 1 : 0;
                }
            }

            int amountQuestions = (int)Math.Round(0.22 * totalFields);

            var wordLengthRatio = requiredAmountOfLetters / (totalFields - amountQuestions);

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

            m.GetEnv().Method = 0;

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

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

            // 0 = Down, then right
            // 1 = Left, then down
            // 2 = Right, then down
            // 3 = Up, then right
            // Mostly null, except for places down and right of a blocked field or y==0 or x==0
            GRBVar[,,] specialQuestionType = new GRBVar[sizeY, sizeX, 4];

            var specialQuestionUsed = new GRBLinExpr[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" + y + "_" + x);
                        questionType[y, x] = m.AddVar(0, 1, 0, GRB.BINARY, "QType" + y + "_" + x);

                        // Is null except for places down and right of a blocked field or y==0 or x==0
                        if (y == 0 || x == 0 || crossword.Grid[y - 1, x] is Blocked || crossword.Grid[y, x - 1] is Blocked)
                        {
                            for (int t = 0; t < 4; t++)
                            {
                                specialQuestionType[y, x, t] = m.AddVar(0, 1, 0, GRB.BINARY, "SpecialQType" + t + "_" + y + "_" + x);
                            }
                            specialQuestionUsed[y, x] = specialQuestionType[y, x, 0] + specialQuestionType[y, x, 1] + specialQuestionType[y, x, 2] + specialQuestionType[y, x, 3];
                            // Max 1 special type, can also be no special question
                            m.AddConstr(specialQuestionUsed[y, x] <= 1, "MaxOneSpecialQuestion" + y + "_" + x);
                        }
                    }
                }
            }

            // TEST
            //m.AddConstr(specialQuestionType[0, 0, 0] == 1);



            GRBLinExpr allFieldsSum = new GRBLinExpr();

            for (int y = 0; y < sizeY; y++)
            {
                for (int x = 0; x < sizeX; x++)
                {
                    if (crossword.Grid[y, x] is Blocked)
                    {
                        continue;
                    }


                    allFieldsSum += fields[y, x];

                    bool noQuestionToTheRightAllowed  = false;
                    bool noQuestionTowardsDownAllowed = false;
                    if (x + minWordLength < sizeX && !crossword.HasBlock(y, x, y, x + minWordLength))
                    {
                        // for right: if [0,0] is question, [0,1..3] must not be question
                        var totalQuestionsHorizontal = fields.SumRange(y, x + 1, y, x + minWordLength);
                        var isQuestionAndPointsRight = fields[y, x] + (1 - questionType[y, x]) - 1;
                        if ((object)specialQuestionUsed[y, x] != null)
                        {
                            isQuestionAndPointsRight += (1 - specialQuestionUsed[y, x]) - 1;
                        }
                        for (int len = 1; len <= minWordLength; len++)
                        {
                            m.AddConstr(isQuestionAndPointsRight <= 1 - fields[y, x + len], "MinWordLength3" + y + "_" + x + "_right" + len);
                        }
                    }
                    else
                    {
                        noQuestionToTheRightAllowed = true;
                    }

                    // for down:
                    if (y + minWordLength < sizeY && !crossword.HasBlock(y, x, y + minWordLength, x))
                    {
                        var totalQuestionsVertical  = fields.SumRange(y + 1, x, y + minWordLength, x);
                        var isQuestionAndPointsDown = fields[y, x] + questionType[y, x] - 1;
                        if ((object)specialQuestionUsed[y, x] != null)
                        {
                            isQuestionAndPointsDown += (1 - specialQuestionUsed[y, x]) - 1;
                        }
                        for (int len = 1; len <= minWordLength; len++)
                        {
                            m.AddConstr(isQuestionAndPointsDown <= 1 - fields[y + len, x], "MinWordLength3" + y + "_" + x + "_down" + len);
                        }
                    }
                    else
                    {
                        noQuestionTowardsDownAllowed = true;
                    }


                    bool atLeastOneSpecialAllowed = false;
                    if ((object)specialQuestionUsed[y, x] != null)
                    {
                        // down, then right
                        if (y + 1 < sizeY && x + minWordLength - 1 < sizeX && !crossword.HasBlock(y + 1, x, y + 1, x + minWordLength - 1))
                        {
                            for (int len = 1; len <= minWordLength; len++)
                            {
                                m.AddConstr(fields[y, x] + specialQuestionType[y, x, 0] - 1 <= 1 - fields[y + 1, x + len - 1], "MinWordLength3" + y + "_" + x + "_downRight" + len);
                            }
                            if (x > 0)
                            {
                                m.AddConstr(fields[y, x] + specialQuestionType[y, x, 0] - 1 <= fields[y + 1, x - 1], "QuestionBeforeSQ" + y + "_" + x + "_downRight");
                            }
                            atLeastOneSpecialAllowed = true;
                        }
                        else
                        {
                            m.AddConstr(specialQuestionType[y, x, 0] == 0, "NoSpecialQuestionAllowed" + y + "_" + x + "_downRight");
                        }
                        // left, then down
                        if (y + minWordLength - 1 < sizeY && x - 1 >= 0 && !crossword.HasBlock(y, x - 1, y + minWordLength - 1, x - 1))
                        {
                            for (int len = 1; len <= minWordLength; len++)
                            {
                                m.AddConstr(fields[y, x] + specialQuestionType[y, x, 1] - 1 <= 1 - fields[y + len - 1, x - 1], "MinWordLength3" + y + "_" + x + "_leftDown" + len);
                            }
                            if (y > 0)
                            {
                                m.AddConstr(fields[y, x] + specialQuestionType[y, x, 1] - 1 <= fields[y - 1, x - 1], "QuestionBeforeSQ" + y + "_" + x + "_leftDown");
                            }
                            atLeastOneSpecialAllowed = true;
                        }
                        else
                        {
                            m.AddConstr(specialQuestionType[y, x, 1] == 0, "NoSpecialQuestionAllowed" + y + "_" + x + "_leftDown");
                        }
                        // right, then down
                        if (y + minWordLength - 1 < sizeY && x + 1 < sizeX && !crossword.HasBlock(y, x + 1, y + minWordLength - 1, x + 1))
                        {
                            for (int len = 1; len <= minWordLength; len++)
                            {
                                m.AddConstr(fields[y, x] + specialQuestionType[y, x, 2] - 1 <= 1 - fields[y + len - 1, x + 1], "MinWordLength3" + y + "_" + x + "_rightDown" + len);
                            }
                            if (y > 0)
                            {
                                m.AddConstr(fields[y, x] + specialQuestionType[y, x, 2] - 1 <= fields[y - 1, x + 1], "QuestionBeforeSQ" + y + "_" + x + "_rightDown");
                            }
                            atLeastOneSpecialAllowed = true;
                        }
                        else
                        {
                            m.AddConstr(specialQuestionType[y, x, 2] == 0, "NoSpecialQuestionAllowed" + y + "_" + x + "_rightDown");
                        }
                        // up, then right
                        if (y - 1 >= 0 && x + minWordLength - 1 < sizeX && !crossword.HasBlock(y - 1, x, y - 1, x + minWordLength - 1))
                        {
                            for (int len = 1; len <= minWordLength; len++)
                            {
                                m.AddConstr(fields[y, x] + specialQuestionType[y, x, 3] - 1 <= 1 - fields[y - 1, x + len - 1], "MinWordLength3" + y + "_" + x + "_upRight" + len);
                            }
                            if (x > 0)
                            {
                                m.AddConstr(fields[y, x] + specialQuestionType[y, x, 3] - 1 <= fields[y - 1, x - 1], "QuestionBeforeSQ" + y + "_" + x + "_upRight");
                            }
                            atLeastOneSpecialAllowed = true;
                        }
                        else
                        {
                            m.AddConstr(specialQuestionType[y, x, 3] == 0, "NoSpecialQuestionAllowed" + y + "_" + x + "_upRight");
                        }

                        if (!atLeastOneSpecialAllowed)
                        {
                            m.AddConstr(specialQuestionUsed[y, x] == 0, "NoSpecialQuestionAllowedAtALl" + y + "_" + x);
                        }
                    }

                    if (noQuestionToTheRightAllowed && noQuestionTowardsDownAllowed)
                    {
                        if (!atLeastOneSpecialAllowed)
                        {
                            m.AddConstr(fields[y, x] == 0, "NoQuestionAllowed" + y + "_" + x);
                        }
                        else
                        {
                            m.AddConstr(specialQuestionUsed[y, x] == 1, "OnlySpecialQuestionAllowed" + y + "_" + x);
                        }
                    }
                    else
                    {
                        if (noQuestionToTheRightAllowed)
                        {
                            m.AddConstr(questionType[y, x] == 1, "QuestionCantPointRight" + y + "_" + x);
                        }
                        if (noQuestionTowardsDownAllowed)
                        {
                            m.AddConstr(questionType[y, x] == 0, "QuestionCantPointDown" + y + "_" + x);
                        }
                    }

                    // max word length constraints
                    // for right: if [0,0] is question, [0,1..maxLength+1] must have at least another question field
                    if (x + maxWordLength + 1 < sizeX && !crossword.HasBlock(y, x, y, x + maxWordLength + 1))
                    {
                        var allHorizontalFields = new GRBLinExpr();
                        for (int xi = 1; xi <= maxWordLength + 1; xi++)
                        {
                            allHorizontalFields += fields[y, x + xi];
                        }
                        if ((object)specialQuestionUsed[y, x] != null)
                        {
                            m.AddConstr(fields[y, x] + (1 - questionType[y, x]) + (1 - specialQuestionUsed[y, x]) - 2 <= allHorizontalFields, "MaxLengthHorizontal" + y + "_" + x);
                        }
                        else
                        {
                            m.AddConstr(fields[y, x] + (1 - questionType[y, x]) - 1 <= allHorizontalFields, "MaxLengthHorizontal" + y + "_" + x);
                        }
                    }
                    // for down:
                    if (y + maxWordLength + 1 < sizeY && !crossword.HasBlock(y, x, y + maxWordLength + 1, x))
                    {
                        var fieldsSum = fields.SumRange(y + 1, x, y + maxWordLength + 1, x);
                        if ((object)specialQuestionUsed[y, x] != null)
                        {
                            m.AddConstr(fields[y, x] + questionType[y, x] + (1 - specialQuestionUsed[y, x]) - 2 <= fieldsSum, "MaxLengthVertical" + y + "_" + x);
                        }
                        else
                        {
                            m.AddConstr(fields[y, x] + questionType[y, x] - 1 <= fieldsSum, "MaxLengthVertical" + y + "_" + x);
                        }
                    }
                    if ((object)specialQuestionUsed[y, x] != null)
                    {
                        // down, then right
                        if (y + 1 < sizeY && x + maxWordLength < sizeX && !crossword.HasBlock(y + 1, x, y + 1, x + maxWordLength))
                        {
                            var fieldsSum = fields.SumRange(y + 1, x, y + 1, x + maxWordLength);
                            m.AddConstr(fields[y, x] + specialQuestionType[y, x, 0] - 1 <= fieldsSum, "MaxLengthSpecialQuestion0_" + y + "_" + x);
                            // if there is a normal field to the left of the word, it has to be a question
                            if (x - 1 >= 0 && !crossword.HasBlock(y + 1, x - 1))
                            {
                                m.AddConstr(fields[y, x] + specialQuestionType[y, x, 0] - 1 <= fields[y + 1, x - 1], "QuestionRequiredBeforeSpecialQuestion0Word_" + y + "_" + x);
                            }
                        }
                        // left, then down
                        if (y + maxWordLength < sizeY && x - 1 >= 0 && !crossword.HasBlock(y, x - 1, y + maxWordLength, x - 1))
                        {
                            var fieldsSum = fields.SumRange(y, x - 1, y + maxWordLength, x - 1);
                            m.AddConstr(fields[y, x] + specialQuestionType[y, x, 1] - 1 <= fieldsSum, "MaxLengthSpecialQuestion1_" + y + "_" + x);
                            if (y - 1 >= 0 && !crossword.HasBlock(y - 1, x - 1))
                            {
                                m.AddConstr(fields[y, x] + specialQuestionType[y, x, 0] - 1 <= fields[y - 1, x - 1], "QuestionRequiredBeforeSpecialQuestion1Word_" + y + "_" + x);
                            }
                        }
                        // right, then down
                        if (y + maxWordLength < sizeY && x + 1 < sizeX && !crossword.HasBlock(y, x + 1, y + maxWordLength, x + 1))
                        {
                            var fieldsSum = fields.SumRange(y, x + 1, y + maxWordLength, x + 1);
                            m.AddConstr(fields[y, x] + specialQuestionType[y, x, 2] - 1 <= fieldsSum, "MaxLengthSpecialQuestion2_" + y + "_" + x);
                            if (y - 1 >= 0 && !crossword.HasBlock(y - 1, x + 1))
                            {
                                m.AddConstr(fields[y, x] + specialQuestionType[y, x, 0] - 1 <= fields[y - 1, x + 1], "QuestionRequiredBeforeSpecialQuestion2Word_" + y + "_" + x);
                            }
                        }
                        // up, then right
                        if (y - 1 >= 0 && x + maxWordLength < sizeX && !crossword.HasBlock(y - 1, x, y - 1, x + maxWordLength))
                        {
                            var fieldsSum = fields.SumRange(y - 1, x, y - 1, x + maxWordLength);
                            m.AddConstr(fields[y, x] + specialQuestionType[y, x, 3] - 1 <= fieldsSum, "MaxLengthSpecialQuestion3_" + y + "_" + x);
                            if (x - 1 >= 0 && !crossword.HasBlock(y - 1, x - 1))
                            {
                                m.AddConstr(fields[y, x] + specialQuestionType[y, x, 0] - 1 <= fields[y - 1, x - 1], "QuestionRequiredBeforeSpecialQuestion3Word_" + y + "_" + x);
                            }
                        }
                    }
                }
            }

            // Does a field belong to zero, one or two questions?
            var partOfAWord = new GRBLinExpr[sizeY, sizeX, 6];

            for (int y = 0; y < sizeY; y++)
            {
                for (int x = 0; x < sizeX; x++)
                {
                    // this constraint doesn't work for [0,0]
                    if (crossword.HasBlock(y, x))
                    {
                        continue;
                    }

                    // Is this field attached to a question on the left, pointing right?
                    var attachedToHorizontalQuestion = m.AddVar(0, 1, 0, GRB.BINARY, "attachedToHorizontalQuestion" + y + "_" + x);
                    for (int len = 1; len <= maxWordLength; len++)
                    {
                        if (x - len < 0 || crossword.HasBlock(y, x - len, y, x))
                        {
                            continue;
                        }
                        var isQuestionAndPointsRight = fields[y, x - len] + (1 - questionType[y, x - len]);
                        if ((object)specialQuestionUsed[y, x - len] != null)
                        {
                            isQuestionAndPointsRight += (1 - specialQuestionUsed[y, x - len]) - 1;
                        }
                        var questionsInbetween = fields.SumRange(y, x - len + 1, y, x);
                        m.AddConstr(attachedToHorizontalQuestion >= isQuestionAndPointsRight - 1 - questionsInbetween, "attachedToHorizontalQuestionConstraint0_" + y + "_" + x);

                        // 0 IF first question is not pointing right OR there is no question to the left
                        // firstQuestion ==> total fields < 2
                        if ((object)specialQuestionUsed[y, x - len] != null)
                        {
                            m.AddConstr(attachedToHorizontalQuestion <= questionsInbetween + (1 - fields[y, x - len]) + 1 - (questionType[y, x - len] + specialQuestionUsed[y, x - len]) * 0.5, "attachedToHorizontalQuestionConstraint1_" + y + "_" + x); // the first question but DOESNT look right
                        }
                        else
                        {
                            m.AddConstr(attachedToHorizontalQuestion <= questionsInbetween + (1 - fields[y, x - len]) + 1 - questionType[y, x - len], "attachedToHorizontalQuestionConstraint2_" + y + "_" + x); // the first question but DOESNT look right
                        }
                    }
                    var questionsToTheLeft = new GRBLinExpr();
                    int qlCount            = 0;
                    for (int len = 0; len <= maxWordLength; len++)
                    {
                        if (x - len < 0 || crossword.HasBlock(y, x - len, y, x))
                        {
                            continue;
                        }
                        questionsToTheLeft += fields[y, x - len];
                        qlCount++;
                    }
                    if (qlCount > 0)
                    {
                        m.AddConstr(attachedToHorizontalQuestion <= questionsToTheLeft, "attachedToHorizontalQuestionConstraint4_" + y + "_" + x);
                    }

                    // Is this field attached to a question pointing towards down?
                    var attachedToVerticalQuestion = m.AddVar(0, 1, 0, GRB.BINARY, "attachedToVerticalQuestion" + y + "_" + x);
                    for (int len = 1; len <= maxWordLength; len++)
                    {
                        if (y - len < 0 || crossword.HasBlock(y - len, x, y, x))
                        {
                            continue;
                        }
                        var isQuestionAndPointsDown = fields[y - len, x] + questionType[y - len, x];
                        if ((object)specialQuestionUsed[y - len, x] != null)
                        {
                            isQuestionAndPointsDown += (1 - specialQuestionUsed[y - len, x]) - 1;
                        }
                        var questionsInbetween = fields.SumRange(y - len + 1, x, y, x);
                        m.AddConstr(attachedToVerticalQuestion >= isQuestionAndPointsDown - 1 - questionsInbetween, "attachedToVerticalQuestionConstraint0_" + y + "_" + x);
                        if ((object)specialQuestionUsed[y - len, x] != null)
                        {
                            m.AddConstr(attachedToVerticalQuestion <= questionsInbetween + (1 - fields[y - len, x]) + 1 - (1 - questionType[y - len, x] + specialQuestionUsed[y - len, x]) * 0.5, "attachedToVerticalQuestionConstraint1_" + y + "_" + x); // the first question but DOESNT look down OR IS specialquestion
                        }
                        else
                        {
                            m.AddConstr(attachedToVerticalQuestion <= questionsInbetween + (1 - fields[y - len, x]) + 1 - (1 - questionType[y - len, x]), "attachedToVerticalQuestionConstraint2_" + y + "_" + x); // the first question but DOESNT look down OR IS specialquestion
                        }
                    }
                    var questionsTowardsDown = new GRBLinExpr();
                    int qdCount = 0;
                    for (int len = 0; len <= maxWordLength; len++)
                    {
                        if (y - len < 0 || crossword.HasBlock(y - len, x, y, x))
                        {
                            continue;
                        }
                        questionsTowardsDown += fields[y - len, x];
                        qdCount++;
                    }
                    if (qdCount > 0)
                    {
                        m.AddConstr(attachedToVerticalQuestion <= questionsTowardsDown, "attachedToVerticalQuestionConstraint3_" + y + "_" + x);
                    }


                    var attachedToSpecialQuestions = new GRBLinExpr[4];
                    var spAll = new GRBLinExpr();
                    for (int type = 0; type < 4; type++)
                    {
                        attachedToSpecialQuestions[type] = AttachedToSpecialQuestion(y, x, type, crossword, m, sizeX, sizeY, maxWordLength, fields, specialQuestionUsed, specialQuestionType);
                        if ((object)attachedToSpecialQuestions[type] != null)
                        {
                            spAll += attachedToSpecialQuestions[type];
                        }
                    }

                    // if attached to horizontal question, can't be attached to horizontal sq (0, 3)
                    if ((object)attachedToSpecialQuestions[0] != null)
                    {
                        m.AddConstr((1 - attachedToHorizontalQuestion) >= attachedToSpecialQuestions[0], "noHorizontalOverlap1_" + y + "_" + x);
                    }
                    if ((object)attachedToSpecialQuestions[3] != null)
                    {
                        m.AddConstr((1 - attachedToHorizontalQuestion) >= attachedToSpecialQuestions[3], "noHorizontalOverlap2_" + y + "_" + x);
                    }
                    // give preference to one horizontal kind of sq
                    if ((object)attachedToSpecialQuestions[0] != null && (object)attachedToSpecialQuestions[3] != null)
                    {
                        m.AddConstr((1 - attachedToSpecialQuestions[0]) >= attachedToSpecialQuestions[3], "noHorizontalOverlap3_" + y + "_" + x);
                    }

                    // if attached to vertical question, can't be attached to vertical sq (1, 2)
                    if ((object)attachedToSpecialQuestions[1] != null)
                    {
                        m.AddConstr((1 - attachedToVerticalQuestion) >= attachedToSpecialQuestions[1], "noVerticalOverlap1_" + y + "_" + x);
                    }
                    if ((object)attachedToSpecialQuestions[2] != null)
                    {
                        m.AddConstr((1 - attachedToVerticalQuestion) >= attachedToSpecialQuestions[2], "noVerticalOverlap2_" + y + "_" + x);
                    }
                    // give preference to one horizontal kind of sq
                    if ((object)attachedToSpecialQuestions[1] != null && (object)attachedToSpecialQuestions[2] != null)
                    {
                        m.AddConstr((1 - attachedToSpecialQuestions[1]) >= attachedToSpecialQuestions[2], "noVerticalOverlap3_" + y + "_" + x);
                    }

                    var c = m.AddConstr(attachedToHorizontalQuestion + attachedToVerticalQuestion + spAll >= 1 - fields[y, x], "AttachedToQuestionConstraint_" + y + "_" + x);
                    //c.Lazy = 1;
                    partOfAWord[y, x, 0] = attachedToHorizontalQuestion;
                    partOfAWord[y, x, 1] = attachedToVerticalQuestion;
                    partOfAWord[y, x, 2] = attachedToSpecialQuestions[0];
                    partOfAWord[y, x, 3] = attachedToSpecialQuestions[1];
                    partOfAWord[y, x, 4] = attachedToSpecialQuestions[2];
                    partOfAWord[y, x, 5] = attachedToSpecialQuestions[3];
                }
            }

            // right now, [0,0] can only be a question
            //if (!crossword.HasBlock(0, 0)) m.AddConstr(fields[0, 0] == 1);
            // and similarly the bottom 3x3 can only be letters
            for (int y = sizeY - minWordLength; y < sizeY; y++)
            {
                for (int x = sizeX - minWordLength; x < sizeX; x++)
                {
                    if (!crossword.HasBlock(y, x))
                    {
                        m.AddConstr(fields[y, x] == 0, "BottomOnlyLetters_" + y + "_" + x);
                    }
                }
            }

            // Objective:
            // questions should be around ~22% (allFieldsSum ~= amountQuestions)

            /*int tolerance = (int)(amountQuestions * 0.1);
             * m.AddConstr(allFieldsSum >= amountQuestions - tolerance, "amountOfQuestionsTolerance_1");
             * m.AddConstr(allFieldsSum <= amountQuestions + tolerance, "amountOfQuestionsTolerance_2");*/
            m.AddConstr(allFieldsSum == amountQuestions);

            // uncrossed
            var partOfWordTotals = new GRBLinExpr[sizeY, sizeX];

            for (int y = 0; y < sizeY; y++)
            {
                for (int x = 0; x < sizeX; x++)
                {
                    if (!crossword.HasBlock(y, x)) //(x >= 1 || y >= 1) &&
                    {
                        var partOfWordTotal = new GRBLinExpr();
                        for (int t = 0; t < 6; t++)
                        {
                            if ((object)partOfAWord[y, x, t] != null)
                            {
                                partOfWordTotal += partOfAWord[y, x, t];
                            }
                        }
                        partOfWordTotals[y, x] = partOfWordTotal;
                    }
                }
            }

            for (int y = 0; y < sizeY - 1; y++)
            {
                for (int x = 0; x < sizeX - 1; x++)
                {
                    if (!crossword.HasBlock(y, x)) //(x >= 1 || y >= 1) &&
                    {
                        if (!crossword.HasBlock(y + 1, x))
                        {
                            m.AddConstr(partOfWordTotals[y, x] + partOfWordTotals[y + 1, x] >= (1 - fields[y, x] - fields[y + 1, x]) * 3, "noUncrossedFields" + y + "_" + x);
                        }
                        if (!crossword.HasBlock(y, x + 1))
                        {
                            m.AddConstr(partOfWordTotals[y, x] + partOfWordTotals[y, x + 1] >= (1 - fields[y, x] - fields[y, x + 1]) * 3, "noUncrossedFields" + y + "_" + x);
                        }
                    }
                }
            }

            // penalty for nearby uncrossed letters (dead fields)

            /*var deadFieldPenalty = new GRBLinExpr();
             * for (int y = 0; y < sizeY; y++)
             * {
             *  for (int x = 0; x < sizeX; x++)
             *  {
             *      var hby = y - 1 >= 0 && !crossword.HasBlock(y - 1, x);
             *      var hbx = x - 1 >= 0 && !crossword.HasBlock(y, x - 1);
             *      if (!crossword.HasBlock(y, x) && (hby || hbx))
             *      {
             *          var isDeadArea = m.AddVar(0, 1, 0, GRB.BINARY, "isDeadArea" + y + "_" + x);
             *          if (hby) m.AddConstr(isDeadArea >= uncrossedLetters[y, x] + uncrossedLetters[y - 1, x] - 1, "deadAreaConstr1" + y + "_" + x);
             *          if (hbx) m.AddConstr(isDeadArea >= uncrossedLetters[y, x] + uncrossedLetters[y, x - 1] - 1, "deadAreaConstr2" + y + "_" + x);
             *          m.AddConstr(isDeadArea <= uncrossedLetters[y, x]);
             *          if (hby && hbx)
             *              m.AddConstr(isDeadArea <= uncrossedLetters[y - 1, x] + uncrossedLetters[y, x - 1], "deadAreaConstr3" + y + "_" + x);
             *          else if (hby)
             *              m.AddConstr(isDeadArea <= uncrossedLetters[y - 1, x], "deadAreaConstr4" + y + "_" + x);
             *          else if (hbx)
             *              m.AddConstr(isDeadArea <= uncrossedLetters[y, x - 1], "deadAreaConstr5" + y + "_" + x);
             *          deadFieldPenalty += isDeadArea;
             *      }
             *  }
             * }*/



            // ideal histogram comparison
            //var wordHistogramDifferences = new GRBLinExpr();
            var wlTotals = new Dictionary <int, GRBLinExpr>();

            foreach (var wl in wordLengthHistogram.Keys)
            {
                var total = new GRBLinExpr();
                for (int y = 0; y + wl - 1 < sizeY; y++)
                {
                    for (int x = 0; x < sizeX; x++)
                    {
                        if (crossword.HasBlock(y, x, y + wl - 1, x))
                        {
                            continue;
                        }
                        // true if field-1 is question or start AND field + wl (after word) is question or end
                        var hasLength = m.AddVar(0, 1, 0, GRB.BINARY, "hasLenVert" + wl + "__" + y + "_" + x);
                        var sum       = fields.SumRange(y, x, y + wl - 1, x);
                        // no questions inbetween
                        for (int i = 0; i < wl; i++)
                        {
                            m.AddConstr(hasLength <= 1 - fields[y + i, x]);
                        }
                        // question at end
                        if (y + wl < sizeY && !crossword.HasBlock(y + wl, x))
                        {
                            sum += (1 - fields[y + wl, x]);
                            m.AddConstr(hasLength <= fields[y + wl, x]);
                        }
                        // question at start
                        if (y - 1 >= 0 && !crossword.HasBlock(y - 1, x))
                        {
                            sum += (1 - fields[y - 1, x]);
                            m.AddConstr(hasLength <= fields[y - 1, x]);
                        }

                        // counts if a letter is attached to a horizontal question
                        var qsum = new GRBLinExpr();
                        if ((object)partOfAWord[y, x, 1] != null)
                        {
                            qsum += partOfAWord[y, x, 1];
                        }
                        if ((object)partOfAWord[y, x, 3] != null)
                        {
                            qsum += partOfAWord[y, x, 3];
                        }
                        if ((object)partOfAWord[y, x, 4] != null)
                        {
                            qsum += partOfAWord[y, x, 4];
                        }
                        sum += 1 - qsum;
                        m.AddConstr(hasLength <= qsum);

                        m.AddConstr(hasLength >= 1 - sum);
                        total += hasLength;
                    }
                }
                for (int y = 0; y < sizeY; y++)
                {
                    for (int x = 0; x + wl - 1 < sizeX; x++)
                    {
                        if (crossword.HasBlock(y, x, y, x + wl - 1))
                        {
                            continue;
                        }
                        var hasLength = m.AddVar(0, 1, 0, GRB.BINARY, "hasLenHoriz" + wl + "__" + y + "_" + x);
                        var sum       = fields.SumRange(y, x, y, x + wl - 1);
                        // no questions inbetween
                        for (int i = 0; i < wl; i++)
                        {
                            m.AddConstr(hasLength <= 1 - fields[y, x + i]);
                        }
                        // question at end
                        if (x + wl < sizeX && !crossword.HasBlock(y, x + wl))
                        {
                            sum += (1 - fields[y, x + wl]);
                            m.AddConstr(hasLength <= fields[y, x + wl]);
                        }
                        // question at start
                        if (x - 1 >= 0 && !crossword.HasBlock(y, x - 1))
                        {
                            sum += (1 - fields[y, x - 1]);
                            m.AddConstr(hasLength <= fields[y, x - 1]);
                        }

                        // counts if a letter is attached to a horizontal question
                        var qsum = new GRBLinExpr();
                        if ((object)partOfAWord[y, x, 0] != null)
                        {
                            qsum += partOfAWord[y, x, 0];
                        }
                        if ((object)partOfAWord[y, x, 2] != null)
                        {
                            qsum += partOfAWord[y, x, 2];
                        }
                        if ((object)partOfAWord[y, x, 5] != null)
                        {
                            qsum += partOfAWord[y, x, 5];
                        }
                        sum += 1 - qsum;
                        m.AddConstr(hasLength <= qsum);

                        m.AddConstr(hasLength >= 1 - sum);
                        total += hasLength;
                    }
                }
                if (wl <= 9)
                {
                    wlTotals.Add(wl, total);
                }
                else
                {
                    wlTotals[9] += total;
                }
            }
            var wlPenalty  = new GRBLinExpr();
            var wordCounts = m.AddVars(8, 0, amountQuestions * 2, GRB.INTEGER, "amount");

            foreach (var wl in wlTotals.Keys)
            {
                var input = wordCounts[wl - 2];
                m.AddConstr(input == wlTotals[wl]);
                var absRes = m.AddVar(0, 100, 0, GRB.CONTINUOUS, "absRes");
                Console.WriteLine(wl == 9 ? 4 : wordLengthHistogram[wl]);
                var percentageDiff = input * (100d / amountQuestions) - (wl == 9 ? 4 : wordLengthHistogram[wl]);
                m.AddConstr(percentageDiff <= absRes, "absPos");
                m.AddConstr(-percentageDiff <= absRes, "absNeg");
                wlPenalty += absRes;
            }
            wlPenalty *= (1d / 8);

            // question field clusters
            // in a field of 2x2, minimize the nr of fields where there are 2-4 questions resp. maximize 0-1 questions
            //var clusterPenalty = new GRBLinExpr();
            int area = 3;

            for (int y = 0; y < sizeY - (area - 1); y++)
            {
                for (int x = 0; x < sizeX - (area - 1); x++)
                {
                    var clusterTotal = new GRBLinExpr();
                    int ct           = 0;
                    for (int i = 0; i < area; i++)
                    {
                        for (int j = 0; j < area; j++)
                        {
                            if (crossword.HasBlock(y + i, x + j) || (i == 1 && j == 1))
                            {
                                continue;
                            }
                            clusterTotal += fields[y + i, x + j];
                            ct++;
                        }
                    }
                    if (ct >= 2 && !crossword.HasBlock(y + 1, x + 1))
                    {
                        //var varClusterTotalPenalty = m.AddVar(0, 1, 0, GRB.BINARY, "varClusterTotalPenalty" + y + "_" + x);
                        // 0-1 = good, 2-4 = bad
                        m.AddConstr(clusterTotal - 1 <= (1 - fields[y + 1, x + 1]) * 8, "cluster" + y + "_" + x);

                        /*m.AddConstr(varClusterTotalPenalty <= clusterTotal * 0.5, "clusterPenaltyConstr1_" + y + "_" + x);
                         * m.AddConstr(varClusterTotalPenalty >= (clusterTotal - 1) * (1d / 3), "clusterPenaltyConstr2_" + y + "_" + x);
                         * clusterPenalty += varClusterTotalPenalty;*/
                    }
                }
            }

            //m.AddConstr(deadFieldPenalty <= 30);

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

            m.SetCallback(new GRBMipSolCallback(crossword, fields, questionType, specialQuestionType, true, wordCounts));

            // Insert previous solution

            /*var cwdCheck = new Crossword(@"C:\Users\Roman Bolzern\Documents\GitHub\Crossword\docs\15x15_1_noDoubles.cwg");
             * cwdCheck.Draw();
             * for (int y = 0; y < cwdCheck.Grid.GetLength(0); y++)
             * {
             *  for (int x = 0; x < cwdCheck.Grid.GetLength(1); x++)
             *  {
             *      if (cwdCheck.Grid[y, x] is Question)
             *      {
             *          m.AddConstr(fields[y, x] == 1);
             *          var q = (Question)cwdCheck.Grid[y, x];
             *          if (q.Arrow == Question.ArrowType.Right)
             *          {
             *              m.AddConstr(questionType[y, x] == 0);
             *              if ((object)specialQuestionType[y, x, 0] != null)
             *                  m.AddConstr(specialQuestionType[y, x, 0] + specialQuestionType[y, x, 1] + specialQuestionType[y, x, 2] + specialQuestionType[y, x, 3] == 0);
             *          }
             *          else if (q.Arrow == Question.ArrowType.Down)
             *          {
             *              m.AddConstr(questionType[y, x] == 1);
             *              if ((object)specialQuestionType[y, x, 0] != null)
             *                  m.AddConstr(specialQuestionType[y, x, 0] + specialQuestionType[y, x, 1] + specialQuestionType[y, x, 2] + specialQuestionType[y, x, 3] == 0);
             *          }
             *          else if (q.Arrow == Question.ArrowType.DownRight)
             *          {
             *              m.AddConstr(specialQuestionType[y, x, 0] == 1);
             *          }
             *          else if (q.Arrow == Question.ArrowType.LeftDown)
             *          {
             *              m.AddConstr(specialQuestionType[y, x, 1] == 1);
             *          }
             *          else if (q.Arrow == Question.ArrowType.RightDown)
             *          {
             *              m.AddConstr(specialQuestionType[y, x, 2] == 1);
             *          }
             *          else if (q.Arrow == Question.ArrowType.UpRight)
             *          {
             *              m.AddConstr(specialQuestionType[y, x, 3] == 1);
             *          }
             *      }
             *      else if (cwdCheck.Grid[y, x] is Letter)
             *      {
             *          m.AddConstr(fields[y, x] == 0);
             *      }
             *  }
             * }*/


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

            m.Dispose();
            env.Dispose();
        }
 public GRBVar AddToModel(GRBModel model)
 {
     return model.AddVar(lowerBound, upperBound, ObjectiveCoefficient, variableType, name);
 }
Exemple #44
0
    static void Main()
    {
        try {

          // Warehouse demand in thousands of units
          double[] Demand = new double[] { 15, 18, 14, 20 };

          // Plant capacity in thousands of units
          double[] Capacity = new double[] { 20, 22, 17, 19, 18 };

          // Fixed costs for each plant
          double[] FixedCosts =
          new double[] { 12000, 15000, 17000, 13000, 16000 };

          // Transportation costs per thousand units
          double[,] TransCosts =
          new double[,] { { 4000, 2000, 3000, 2500, 4500 },
              { 2500, 2600, 3400, 3000, 4000 },
              { 1200, 1800, 2600, 4100, 3000 },
              { 2200, 2600, 3100, 3700, 3200 } };

          // Number of plants and warehouses
          int nPlants = Capacity.Length;
          int nWarehouses = Demand.Length;

          // Model
          GRBEnv env = new GRBEnv();
          GRBModel model = new GRBModel(env);
          model.Set(GRB.StringAttr.ModelName, "facility");

          // Plant open decision variables: open[p] == 1 if plant p is open.
          GRBVar[] open = new GRBVar[nPlants];
          for (int p = 0; p < nPlants; ++p) {
        open[p] = model.AddVar(0, 1, FixedCosts[p], GRB.BINARY, "Open" + p);
          }

          // Transportation decision variables: how much to transport from
          // a plant p to a warehouse w
          GRBVar[,] transport = new GRBVar[nWarehouses,nPlants];
          for (int w = 0; w < nWarehouses; ++w) {
        for (int p = 0; p < nPlants; ++p) {
          transport[w,p] =
              model.AddVar(0, GRB.INFINITY, TransCosts[w,p], GRB.CONTINUOUS,
                           "Trans" + p + "." + w);
        }
          }

          // The objective is to minimize the total fixed and variable costs
          model.Set(GRB.IntAttr.ModelSense, 1);

          // Update model to integrate new variables
          model.Update();

          // Production constraints
          // Note that the right-hand limit sets the production to zero if
          // the plant is closed
          for (int p = 0; p < nPlants; ++p) {
        GRBLinExpr ptot = 0.0;
        for (int w = 0; w < nWarehouses; ++w)
          ptot += transport[w,p];
        model.AddConstr(ptot <= Capacity[p] * open[p], "Capacity" + p);
          }

          // Demand constraints
          for (int w = 0; w < nWarehouses; ++w) {
        GRBLinExpr dtot = 0.0;
        for (int p = 0; p < nPlants; ++p)
          dtot += transport[w,p];
        model.AddConstr(dtot == Demand[w], "Demand" + w);
          }

          // Guess at the starting point: close the plant with the highest
          // fixed costs; open all others

          // First, open all plants
          for (int p = 0; p < nPlants; ++p) {
        open[p].Set(GRB.DoubleAttr.Start, 1.0);
          }

          // Now close the plant with the highest fixed cost
          Console.WriteLine("Initial guess:");
          double maxFixed = -GRB.INFINITY;
          for (int p = 0; p < nPlants; ++p) {
        if (FixedCosts[p] > maxFixed) {
          maxFixed = FixedCosts[p];
        }
          }
          for (int p = 0; p < nPlants; ++p) {
        if (FixedCosts[p] == maxFixed) {
          open[p].Set(GRB.DoubleAttr.Start, 0.0);
          Console.WriteLine("Closing plant " + p + "\n");
          break;
        }
          }

          // Use barrier to solve root relaxation
          model.GetEnv().Set(GRB.IntParam.Method, GRB.METHOD_BARRIER);

          // Solve
          model.Optimize();

          // Print solution
          Console.WriteLine("\nTOTAL COSTS: " + model.Get(GRB.DoubleAttr.ObjVal));
          Console.WriteLine("SOLUTION:");
          for (int p = 0; p < nPlants; ++p) {
        if (open[p].Get(GRB.DoubleAttr.X) == 1.0) {
          Console.WriteLine("Plant " + p + " open:");
          for (int w = 0; w < nWarehouses; ++w) {
            if (transport[w,p].Get(GRB.DoubleAttr.X) > 0.0001) {
              Console.WriteLine("  Transport " +
                  transport[w,p].Get(GRB.DoubleAttr.X) +
                  " units to warehouse " + w);
            }
          }
        } else {
          Console.WriteLine("Plant " + p + " closed!");
        }
          }

          // Dispose of model and env
          model.Dispose();
          env.Dispose();

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