예제 #1
0
        static void SolveDual3(GRBEnv env, HashSet <string> nodes_set, List <Arc> arcs)
        {
            GRBModel dual = new GRBModel(env);
            Dictionary <string, GRBConstr> flow_balance  = new Dictionary <string, GRBConstr>();
            Dictionary <Arc, GRBVar>       arc_traversed = new Dictionary <Arc, GRBVar>();

            GRBConstr[] constrs = dual.AddConstrs(nodes_set.Count);
            dual.Update();

            int i = 0;

            foreach (string s in nodes_set)
            {
                GRBConstr con = constrs[i];
                con.Set(GRB.StringAttr.ConstrName, "flow_balance." + s);
                con.Set(GRB.CharAttr.Sense, GRB.EQUAL);
                flow_balance[s] = con;
                ++i;
            }
            flow_balance[ORIGIN].Set(GRB.DoubleAttr.RHS, -1);
            flow_balance[DESTINATION].Set(GRB.DoubleAttr.RHS, 1);

            foreach (Arc a in arcs)
            {
                GRBColumn col = new GRBColumn();
                col.AddTerm(1, flow_balance[a.dest]);
                col.AddTerm(-1, flow_balance[a.source]);
                arc_traversed[a] = dual.AddVar(0, 1, a.length, GRB.CONTINUOUS, col, "arc_traversed." + a.source + "." + a.dest);
            }
            dual.Optimize();
            dual.Write("dual3.lp");
            dual.Write("dual3.sol");
            dual.Dispose();
        }
예제 #2
0
        /// <summary>
        /// Exports the model to the specified path as an MPS-file.
        /// </summary>
        /// <param name="path">The path to the file (has to end with .mps).</param>
        public void ExportMPS(string path)
        {
            path = path.EndsWith(".mps") ? path : path + ".mps";
            switch (Type)
            {
            case SolverType.CPLEX: CplexModel.ExportModel(path); break;

            case SolverType.Gurobi: GurobiModel.Update(); GurobiModel.Write(path); break;

            default: throw new ArgumentException("Unknown solver type: " + Type);
            }
        }
예제 #3
0
        public bool TrySolve(out double prepS, out double execS)
        {
            _model.SetObjective(_value);
            _model.Parameters.DualReductions = 0;
            _model.Update();
            _model.Write("debug.lp");

            _model.Optimize();

            if (_model.Status != GRB.Status.OPTIMAL)
            {
                Logger.Warn($"Didn't find solution to time conditions. Gurobi status: {_model.Status}");
                prepS = -1;
                execS = -1;
                return(false);
            }

            try
            {
                prepS = _prepS.X;
                execS = _execS.X;
            } catch
            {
                Logger.Warn($"Exception. Gurobi status: {_model.Status}");
                prepS = -1;
                execS = -1;
                return(false);
            }

            return(true);
        }
예제 #4
0
        static void Main(string[] args)
        {
            GRBEnv   env = new GRBEnv();
            GRBModel m   = new GRBModel(env);
            GRBVar   x1  = m.AddVar(0, GRB.INFINITY, 20, GRB.CONTINUOUS, "food.1");
            GRBVar   x2  = m.AddVar(0, GRB.INFINITY, 10, GRB.CONTINUOUS, "food.2");
            GRBVar   x3  = m.AddVar(0, GRB.INFINITY, 31, GRB.CONTINUOUS, "food.3");
            GRBVar   x4  = m.AddVar(0, GRB.INFINITY, 11, GRB.CONTINUOUS, "food.4");
            GRBVar   x5  = m.AddVar(0, GRB.INFINITY, 12, GRB.CONTINUOUS, "food.5");

            m.Update();
            GRBConstr con1 = m.AddConstr(2 * x1 + 3 * x3 + 1 * x4 + 2 * x5 >= 21, "nutrient.iron");
            GRBConstr con2 = m.AddConstr(1 * x2 + 2 * x3 + 2 * x4 + 1 * x5 >= 12, "nutrient.calcium");

            m.Optimize();
            m.Write("diet.lp");
            foreach (GRBVar var in m.GetVars())
            {
                Console.WriteLine("{0} = {1}, reduced cost = {2}", var.Get(GRB.StringAttr.VarName), var.Get(GRB.DoubleAttr.X), var.Get(GRB.DoubleAttr.RC));
            }
            foreach (GRBConstr constr in m.GetConstrs())
            {
                Console.WriteLine("{0}, slack = {1}, pi = {2}", constr.Get(GRB.StringAttr.ConstrName), constr.Get(GRB.DoubleAttr.Slack), constr.Get(GRB.DoubleAttr.Pi));
            }
            m.Dispose();
            env.Dispose();
        }
예제 #5
0
            /// <summary>
            /// 求解主问题
            /// </summary>
            /// <returns></returns>
            public bool Solve()
            {
                _env              = new GRBEnv();
                _env.OutputFlag   = 0;
                _env.LogToConsole = 0;

                _model = new GRBModel(_env);

                BuildVar();
                BuildConst();

                _model.Write("Benders_Master.lp");
                _model.Optimize();
                if (_model.Status == GRB.Status.OPTIMAL)
                {
                    Frmk.SlaveObj = new SlaveObjCoef();
                    foreach (Node n in Frmk.Data.NodeSet)
                    {
                        double x = _model.GetVarByName("x_" + n.ID).X;
                        Frmk.SlaveObj.x.Add(n, Convert.ToInt32(x));
                    }
                    Output();
                    return(true);
                }
                else
                {
                    throw new ApplicationException("没可行解!");
                    return(false);
                }
            }
예제 #6
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);
        }
    }
        private void btnModelo2_Click(object sender, EventArgs e)
        {
            GRBEnv   Ambinte   = new GRBEnv();
            GRBModel Modelo    = new GRBModel(Ambinte);
            Random   Aleatorio = new Random(4);
            int      m         = 1600;

            GRBVar[,] X = new GRBVar[m, m];
            for (int i = 0; i < m; i++)
            {
                for (int j = 0; j < m; j++)
                {
                    X[i, j] = Modelo.AddVar(0, 1, Aleatorio.Next(1, 20), GRB.BINARY, "x_" + i.ToString() + "_" + j.ToString());
                }
            }
            Modelo.ModelSense = GRB.MAXIMIZE;
            GRBLinExpr Expressao = new GRBLinExpr();

            for (int i = 0; i < m; i++)
            {
                Expressao.Clear();
                for (int j = 0; j < m; j++)
                {
                    Expressao.AddTerm(1, X[i, j]);
                }
                Modelo.AddConstr(Expressao == 1, "Vendedor_" + i);
            }

            for (int j = 0; j < m; j++)
            {
                Expressao.Clear();
                for (int i = 0; i < m; i++)
                {
                    Expressao.AddTerm(1, X[i, j]);
                }
                Modelo.AddConstr(Expressao == 1, "Regiao_" + j);
            }
            Stopwatch Cronometro = new Stopwatch();

            Cronometro.Start();
            Modelo.Optimize();
            Cronometro.Stop();
            MessageBox.Show("O valor do lucro é: " + Modelo.ObjVal.ToString());
            MessageBox.Show("O tempo para resolver foi de: " + Cronometro.ElapsedMilliseconds.ToString() + " ms");
            MessageBox.Show("Se quiser saber a alocação que gera esse lucro é só me pagar");
            //for (int j = 0; j < m; j++)
            //{
            //    for (int i = 0; i < m; i++)
            //    {
            //        if(X[i,j].X>0)
            //        {
            //            MessageBox.Show("O vendedor " + i + " é alocado para a região " + j);
            //        }
            //    }
            //}
            Modelo.Write("C:\\Teste\\Modelo2.lp");
        }
예제 #8
0
파일: feasopt_cs.cs 프로젝트: revisalo/cr2
    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);
        }
    }
예제 #9
0
    static void Main(string[] args)
    {
        if (args.Length < 1)
        {
            Console.Out.WriteLine("Usage: lp_cs filename");
            return;
        }

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

            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)
            {
                double objval = model.ObjVal;
                Console.WriteLine("Optimal objective: " + objval);
            }
            else if (optimstatus == GRB.Status.INFEASIBLE)
            {
                Console.WriteLine("Model is infeasible");

                // compute and write out IIS

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

            // Dispose of model and env
            model.Dispose();
            env.Dispose();
        } catch (GRBException e) {
            Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message);
        }
    }
예제 #10
0
        public void Solve()
        {
            GenerateModel();

            model.Optimize();

            if (model.Status == GRB.Status.OPTIMAL)
            {
                model.Write("solution.sol");
                InterpretSolution();
            }
        }
예제 #11
0
        private void GenerateModel()
        {
            environment = new GRBEnv("gurobi.log");
            model       = new GRBModel(environment);

            GenerateVariables();
            model.Update();

            GenerateObj();
            GenerateConst();

            model.Write("model.lp");
        }
예제 #12
0
        private void OptimizeFASub()
        {
            _env_FlowAssignmentSub      = new GRBEnv("FASub.log");
            _grbModel_FlowAssignmentSub = new GRBModel(_env_FlowAssignmentSub);


            BuildVar_FA();
            BuildObj_FA();
            BuildConst_FA();

            _grbModel_FlowAssignmentSub.Write("FASub.lp");

            _grbModel_FlowAssignmentSub.Optimize();
            OutputValue();
        }
예제 #13
0
        bool Solve()
        {
            _grbModel.Write("OrgModel.lp");
            _grbModel.Optimize();

            int status   = _grbModel.Get(GRB.IntAttr.Status);
            int solution = _grbModel.Get(GRB.IntAttr.SolCount);

            if (status == GRB.Status.OPTIMAL || (status == GRB.Status.TIME_LIMIT && solution > 0))
            {
                return(true);
            }
            else
            {
                return(false);
            }
        }
        private void btnOi_Click(object sender, EventArgs e)
        {
            GRBEnv   Ambiente = new GRBEnv();
            GRBModel Modelo   = new GRBModel(Ambiente);
            GRBVar   x        = Modelo.AddVar(0, 1, 0, GRB.BINARY, "x");
            GRBVar   y        = Modelo.AddVar(0, 1, 0, GRB.BINARY, "y");
            GRBVar   z        = Modelo.AddVar(0, 1, 0, GRB.BINARY, "z");

            Modelo.SetObjective(x + y + 2 * z, GRB.MAXIMIZE);
            Modelo.AddConstr(x + 2 * y + 3 * z <= 4.0, "c0");
            Modelo.AddConstr(x + y >= 1.0, "c1");
            Modelo.Write("C:\\Teste\\ModeloAula.lp");
            Modelo.Optimize();
            MessageBox.Show("O valor da variável x é: " + x.X.ToString());
            MessageBox.Show("O valor da variável y é: " + y.X.ToString());
            MessageBox.Show("O valor da variável z é: " + z.X.ToString());
        }
예제 #15
0
        private void OptimizeSchemeSub()
        {
            _env_SchemeGenerateSub      = new GRBEnv("SchemeSub.log");
            _grbModel_SchemeGenerateSub = new GRBModel(_env_SchemeGenerateSub);

            BuildVar_SG();
            BuildObj_SG();
            BuildConst_SG();

            _grbModel_SchemeGenerateSub.Write("SchemeSub.lp");

            _grbModel_SchemeGenerateSub.Optimize();

            OutputSolution_SchemeSub();

            //_grbModel_SchemeGenerateSub.Dispose();
            //_env_SchemeGenerateSub.Dispose();
        }
예제 #16
0
    static void Main(string[] args)
    {
        if (args.Length < 1)
        {
            Console.Out.WriteLine("Usage: tune_cs filename");
            return;
        }

        try {
            GRBEnv env = new GRBEnv();

            // Read model from file
            GRBModel model = new GRBModel(env, args[0]);

            // Set the TuneResults parameter to 1
            model.GetEnv().Set(GRB.IntParam.TuneResults, 1);

            // Tune the model
            model.Tune();

            // Get the number of tuning results
            int resultcount = model.Get(GRB.IntAttr.TuneResultCount);

            if (resultcount > 0)
            {
                // Load the tuned parameters into the model's environment
                model.GetTuneResult(0);

                // Write the tuned parameters to a file
                model.Write("tune.prm");

                // Solve the model using the tuned parameters
                model.Optimize();
            }

            // Dispose of model and environment
            model.Dispose();
            env.Dispose();
        } catch (GRBException e) {
            Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message);
        }
    }
예제 #17
0
        static void SolvePrimal(GRBEnv env, HashSet <string> nodes_set, List <Arc> arcs)
        {
            GRBModel m = new GRBModel(env);

            Dictionary <string, GRBVar> distances = new Dictionary <string, GRBVar>(); // pi

            foreach (string node in nodes_set)
            {
                distances[node] = m.AddVar(0, GRB.INFINITY, 0, GRB.CONTINUOUS, "distance." + node);
            }
            m.Update();
            distances[ORIGIN].Set(GRB.DoubleAttr.Obj, -1);
            distances[DESTINATION].Set(GRB.DoubleAttr.Obj, 1);
            m.Set(GRB.IntAttr.ModelSense, -1);

            Dictionary <Arc, GRBConstr> constrs = new Dictionary <Arc, GRBConstr>();

            foreach (Arc a in arcs)
            {
                constrs[a] = m.AddConstr(distances[a.dest] <= distances[a.source] + a.length, "distance_con." + a.source + "." + a.dest);
            }

            m.Update();
            m.Write("shortest_path.lp");
            m.Optimize();

            foreach (var pair in distances)
            {
                Console.WriteLine("distance to {0} is {1}", pair.Key, pair.Value.Get(GRB.DoubleAttr.X));
            }

            foreach (var pair in constrs)
            {
                GRBConstr con = pair.Value;
                if (con.Get(GRB.DoubleAttr.Pi) > 0.5)
                {
                    Console.WriteLine("Arc {0}, {1} is in shortest path", pair.Key.source, pair.Key.dest);
                }
            }
            Console.WriteLine("Length of shortest path is {0}", m.Get(GRB.DoubleAttr.ObjVal));
            m.Dispose();
        }
예제 #18
0
        public void Optimize()
        {
            Data.LoadData();

            GenerateInitialFeasibleSolution();

            while (true)
            {
                _envMaster      = new GRBEnv("CG_Model.log");
                _grbModelMaster = new GRBModel(_envMaster);


                BuildVar();
                GenerateConst();

                _grbModelMaster.Write("CG_Model.lp");
                _grbModelMaster.Optimize();

                GetDual();

                OutputSolution();

                OptimizeSchemeSub();
                OptimizeFASub();

                bool IsActive = AddColumn();

                _grbModelMaster.Dispose();
                _envMaster.Dispose();
                _grbModel_SchemeGenerateSub.Dispose();
                _env_SchemeGenerateSub.Dispose();
                _grbModel_FlowAssignmentSub.Dispose();
                _env_FlowAssignmentSub.Dispose();

                if (!IsActive)
                {
                    break;
                }
            }
        }
예제 #19
0
        public MasterModelOutputs buildModel(
            InputData inputData,
            int nCUT,
            MasterModelParameters masterModelParameters,
            string outputFolder
            )
        {
            try
            {
                // Create an empty environment, set options and start
                GRBEnv env = new GRBEnv(true);
                env.Set("LogFile", "LogFileGurobiModel.log");
                env.Start();

                int            T      = 4;
                List <T_param> Tlist2 = inputData.TList.FindAll(tl => tl.T >= 2);
                List <T_param> Tlist3 = inputData.TList.FindAll(tl => tl.T >= 3);

                // Create empty Gurobi model
                GRBModel gModel = new GRBModel(env);

                // Create an empty linear expression object.
                //Parameters and variables will be added and then used to add model components
                //(Objective Function and Constraints).
                GRBLinExpr expr1 = 0.0;
                GRBLinExpr expr2 = 0.0;

                // Crear la variables
                GRBVar[] Make1 = gModel.AddVars(inputData.ProdList.Count, GRB.CONTINUOUS);
                GRBVar[] Inv1  = gModel.AddVars(inputData.ProdList.Count, GRB.CONTINUOUS);
                GRBVar[] Sell1 = gModel.AddVars(inputData.ProdList.Count, GRB.CONTINUOUS);

                //MAKE1 VARNAME
                inputData.ProdList.ForEach(pl => {
                    int ixP            = inputData.ProdList.IndexOf(pl);
                    Make1[ixP].VarName = "MAKE1_Prod: " + pl.PROD;
                });

                //INV1 VARNAME
                inputData.ProdList.ForEach(pl => {
                    int ixP           = inputData.ProdList.IndexOf(pl);
                    Inv1[ixP].VarName = "INV1_Prod: " + pl.PROD;
                });

                //MAKE1 VARNAME
                inputData.ProdList.ForEach(pl => {
                    int ixP            = inputData.ProdList.IndexOf(pl);
                    Sell1[ixP].VarName = "SELL1_Prod: " + pl.PROD;
                });

                //MAKE1 => 0 (constrain)
                //GRB.CONTINUOUS
                for (int a = 0; a < Make1.Length; a++)
                {
                    expr1.Clear();
                    expr1.AddTerm(1, Make1[a]);
                    gModel.AddConstr(expr1, GRB.GREATER_EQUAL, 0, ">=0");
                }

                //INV1 => 0 (constrain)
                for (int a = 0; a < Inv1.Length; a++)
                {
                    expr1.Clear();
                    expr1.AddTerm(1, Inv1[a]);
                    gModel.AddConstr(expr1, GRB.GREATER_EQUAL, 0, ">=0");
                }

                //SELL1 => 0 (constrain)
                for (int a = 0; a < Sell1.Length; a++)
                {
                    expr1.Clear();
                    expr1.AddTerm(1, Sell1[a]);
                    gModel.AddConstr(expr1, GRB.GREATER_EQUAL, 0, ">=0");
                }

                //SELL1 <= market[p,1]
                expr1.Clear();
                inputData.ProdList.ForEach(pl => {
                    double market = inputData
                                    .MarketList
                                    .Find(ml =>
                                          ml.PROD.Equals(pl.PROD) &&
                                          ml.T.Equals(1)).MARKET;

                    int ixP = inputData.ProdList.IndexOf(pl);

                    expr1.Clear();
                    expr1.AddTerm(1, Sell1[ixP]);
                    gModel.AddConstr(expr1, GRB.LESS_EQUAL, market, "<=Market");
                });

                GRBVar Min_Stage2_Profit = gModel.AddVar(double.MinValue, double.MaxValue, masterModelParameters.Min_Stage2_Profit, GRB.CONTINUOUS, "Min_Stage2_Profit");

                //Funcion objetivo
                //maximize Expected_Profit:
                //sum { s in SCEN}
                //prob[s] *
                //sum { p in PROD} (revenue[p, 1, s] * Sell1[p] -
                //prodcost[p] * Make1[p] - invcost[p] * Inv1[p]) +
                //Min_Stage2_Profit;
                expr1.Clear();
                inputData.ScenList.ForEach(sl =>
                {
                    double prob = inputData.ProbList.Find(x => x.SCEN.Equals(sl.SCEN)).PROB;

                    inputData.ProdList.ForEach(pl => {
                        double revenue = inputData
                                         .RevenueList
                                         .Find(rl =>
                                               rl.PROD.Equals(pl.PROD) &&
                                               rl.T.Equals(1) &&
                                               rl.SCEN.Equals(sl.SCEN))
                                         .REVENUE;

                        int ixP        = inputData.ProdList.IndexOf(pl);
                        double invcost = inputData.InvCostList.Find(inv => inv.PROD.Equals(pl.PROD)).INVCOST;

                        double prodcost = inputData.ProdCostList.Find(inv => inv.PROD.Equals(pl.PROD)).PRODCOST;

                        expr1.AddTerm(prob * revenue, Sell1[ixP]);
                        expr1.AddTerm(-prob * prodcost, Make1[ixP]);
                        expr1.AddTerm(-prob * invcost, Inv1[ixP]);
                        expr1.AddTerm(1, Min_Stage2_Profit);
                    });
                });

                //Insertar funcion objetivo
                gModel.SetObjective(expr1, GRB.MAXIMIZE);

                //subj to Cut_Defn {k in 1..nCUT}:  KE ESTA PASANDO
                // Min_Stage2_Profit <=
                //    sum { t in 2..T, s in SCEN}
                //    time_price[t, s, k] * avail[t] +
                //    sum { p in PROD, s in SCEN}
                //    bal2_price[p, s, k] * (-Inv1[p]) +
                //    sum { p in PROD, t in 2..T, s in SCEN}
                //    sell_lim_price[p, t, s, k] * market[p, t];
                expr1.Clear();
                double sumPriceAvail  = 0;
                double sumPriceMarket = 0;
                expr1.AddTerm(1, Min_Stage2_Profit);
                for (int k = 1; k <= nCUT; k++)
                {
                    //    sum { t in 2..T, s in SCEN}
                    //    time_price[t, s, k] * avail[t] +
                    Tlist2.ForEach(tl =>
                    {
                        inputData.ScenList.ForEach(sl =>
                        {
                            double timePrice = masterModelParameters.timePriceList.Find(x => x.T.Equals(tl.T) &&
                                                                                        x.SCEN.Equals(sl.SCEN) &&
                                                                                        x.nCUT.Equals(k)).TIMEPRICE;

                            double avail = inputData.AvailList.Find(al => al.T.Equals(tl.T)).AVAIL;

                            sumPriceAvail += timePrice * avail;
                        });
                    });

                    //    sum { p in PROD, t in 2..T, s in SCEN}
                    //    sell_lim_price[p, t, s, k] * market[p, t];
                    inputData.ProdList.ForEach(pl => {
                        Tlist2.ForEach(tl => {
                            inputData.ScenList.ForEach(sl =>
                            {
                                double sellLimPrice = masterModelParameters.sellLimPriceList.Find(slpl => slpl.PROD.Equals(pl.PROD) &&
                                                                                                  slpl.T.Equals(tl.T) &&
                                                                                                  slpl.SCEN.Equals(sl.SCEN) &&
                                                                                                  slpl.nCUT.Equals(k)).SELLLIMPRICE;

                                double market = inputData.MarketList.Find(ml => ml.PROD.Equals(pl.PROD) &&
                                                                          ml.T.Equals(tl.T)).MARKET;

                                sumPriceMarket += sellLimPrice * market;
                            });
                        });
                    });

                    //  sum { p in PROD, s in SCEN}
                    //  bal2_price[p, s, k] * (-Inv1[p]) +
                    inputData.ProdList.ForEach(pl =>
                    {
                        inputData.ScenList.ForEach(sl =>
                        {
                            double bal2Price = masterModelParameters.balance2PriceList.Find(bp => bp.PROD.Equals(pl.PROD) &&
                                                                                            bp.SCEN.Equals(sl.SCEN) && bp.nCUT.Equals(k)).BALANCE2PRICE;

                            int ixP = inputData.ProdList.IndexOf(pl);
                            expr1.AddTerm(bal2Price, Inv1[ixP]);
                        });
                    });
                }
                gModel.AddConstr(expr1, GRB.LESS_EQUAL, sumPriceAvail + sumPriceMarket, "Cut_Defn");

                //subject to Time1:
                //sum { p in PROD} (1 / rate[p]) * Make1[p] <= avail[1];
                expr1.Clear();
                inputData.ProdList.ForEach(pl =>
                {
                    double rate      = 1 / inputData.RateList.Find(rl => rl.PROD.Equals(pl.PROD)).RATE;
                    double avail     = inputData.AvailList.Find(al => al.T.Equals(1)).AVAIL;
                    double rateAvail = avail / rate;
                    int ixP          = inputData.ProdList.IndexOf(pl);

                    gModel.AddConstr(Make1[ixP], GRB.GREATER_EQUAL, rateAvail, "TIME1");
                });


                //subject to Balance1 { p in PROD}:
                //Make1[p] + inv0[p] = Sell1[p] + Inv1[p];
                expr1.Clear();
                inputData.ProdList.ForEach(pl => {
                    expr1.Clear();

                    int ixP = inputData.ProdList.IndexOf(pl);
                    expr1.AddTerm(1, Sell1[ixP]);
                    expr1.AddTerm(1, Inv1[ixP]);
                    expr1.AddTerm(-1, Make1[ixP]);

                    double inv0 = inputData.Inv0List.Find(il => il.PROD.Equals(pl.PROD)).INV0;

                    gModel.AddConstr(inv0, GRB.EQUAL, expr1, "Balance1");
                });

                //carpeta donde se expande el modelo master
                gModel.Write(outputFolder + "Master_Model.lp");

                // RESOLVER EL MODELO
                try
                {
                    Console.WriteLine("Solving the master model with gurobi..");
                    gModel.Optimize();

                    if (gModel.Status == 2)
                    {
                        for (int m = 0; m < Make1.Length; m++)
                        {
                            Console.WriteLine("Make1 Var: " + Make1[m].VarName + " = " + Make1[m].X);
                        }

                        for (int m = 0; m < Inv1.Length; m++)
                        {
                            Console.WriteLine("Inv1 Var: " + Inv1[m].VarName + " = " + Inv1[m].X);
                        }

                        for (int m = 0; m < Sell1.Length; m++)
                        {
                            Console.WriteLine("Sell Var: " + Sell1[m].VarName + " = " + Sell1[m].X);
                        }
                    }

                    gModel.Dispose();
                    env.Dispose();

                    return(new MasterModelOutputs()
                    {
                        make1 = Make1,
                        sell1 = Sell1,
                        inv1 = Inv1,
                        expectedProfit = gModel.ObjVal,
                        gModel = gModel
                    });
                }
                catch { Console.WriteLine("ERROR SOLVING THE MODEL"); }

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

            return(new MasterModelOutputs());
        }
    static void Main()
    {
        try{
            // Sample data
            int      groundSetSize = 10;
            double[] objCoef = new double[] { 32, 32, 15, 15, 6, 6, 1, 1, 1, 1 };
            double[] knapsackCoef = new double[] { 16, 16, 8, 8, 4, 4, 2, 2, 1, 1 };
            double   Budget = 33;
            int      e, status, nSolutions;

            // Create environment
            GRBEnv env = new GRBEnv("poolsearch_cs.log");

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

            // Initialize decision variables for ground set:
            // x[e] == 1 if element e is chosen
            GRBVar[] Elem = model.AddVars(groundSetSize, GRB.BINARY);
            model.Set(GRB.DoubleAttr.Obj, Elem, objCoef, 0, groundSetSize);

            for (e = 0; e < groundSetSize; e++)
            {
                Elem[e].VarName = string.Format("El{0}", e);
            }

            // Constraint: limit total number of elements to be picked to be at most
            // Budget
            GRBLinExpr lhs = new GRBLinExpr();
            for (e = 0; e < groundSetSize; e++)
            {
                lhs.AddTerm(knapsackCoef[e], Elem[e]);
            }
            model.AddConstr(lhs, GRB.LESS_EQUAL, Budget, "Budget");

            // set global sense for ALL objectives
            model.ModelSense = GRB.MAXIMIZE;

            // Limit how many solutions to collect
            model.Parameters.PoolSolutions = 1024;

            // Limit the search space by setting a gap for the worst possible solution that will be accepted
            model.Parameters.PoolGap = 0.10;

            // do a systematic search for the k-best solutions
            model.Parameters.PoolSearchMode = 2;

            // save problem
            model.Write("poolsearch_cs.lp");

            // Optimize
            model.Optimize();

            // Status checking
            status = model.Status;

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

            // Print best selected set
            Console.WriteLine("Selected elements in best solution:");
            Console.Write("\t");
            for (e = 0; e < groundSetSize; e++)
            {
                if (Elem[e].X < .9)
                {
                    continue;
                }
                Console.Write("El{0} ", e);
            }
            Console.WriteLine();

            // Print number of solutions stored
            nSolutions = model.SolCount;
            Console.WriteLine("Number of solutions found: {0}", nSolutions);

            // Print objective values of solutions
            for (e = 0; e < nSolutions; e++)
            {
                model.Parameters.SolutionNumber = e;
                Console.Write("{0} ", model.PoolObjVal);
                if (e % 15 == 14)
                {
                    Console.WriteLine();
                }
            }
            Console.WriteLine();

            // Print fourth best set if available
            if (nSolutions >= 4)
            {
                model.Parameters.SolutionNumber = 3;

                Console.WriteLine("Selected elements in fourth best solution:");
                Console.Write("\t");
                for (e = 0; e < groundSetSize; e++)
                {
                    if (Elem[e].Xn < .9)
                    {
                        continue;
                    }
                    Console.Write("El{0} ", e);
                }
                Console.WriteLine();
            }

            model.Dispose();
            env.Dispose();
        } catch (GRBException e) {
            Console.WriteLine("Error code: {0}. {1}", e.ErrorCode, e.Message);
        }
    }
    static void Main()
    {
        try {
            // Example data:
            //   e.g. {0, n+1, 2} means clause (x0 or ~x1 or x2)
            int[,] Clauses = new int[, ]
            {
                { 0, n + 1, 2 }, { 1, n + 2, 3 },
                { 2, n + 3, 0 }, { 3, n + 0, 1 },
                { n + 0, n + 1, 2 }, { n + 1, n + 2, 3 },
                { n + 2, n + 3, 0 }, { n + 3, n + 0, 1 }
            };

            int i, status;

            // Create environment
            GRBEnv env = new GRBEnv("genconstr_cs.log");

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

            // Initialize decision variables and objective

            GRBVar[] Lit    = new GRBVar[NLITERALS];
            GRBVar[] NotLit = new GRBVar[NLITERALS];
            for (i = 0; i < NLITERALS; i++)
            {
                Lit[i]    = model.AddVar(0.0, 1.0, 0.0, GRB.BINARY, string.Format("X{0}", i));
                NotLit[i] = model.AddVar(0.0, 1.0, 0.0, GRB.BINARY, string.Format("notX{0}", i));
            }

            GRBVar[] Cla = new GRBVar[NCLAUSES];
            for (i = 0; i < NCLAUSES; i++)
            {
                Cla[i] = model.AddVar(0.0, 1.0, 0.0, GRB.BINARY, string.Format("Clause{0}", i));
            }

            GRBVar[] Obj = new GRBVar[NOBJ];
            for (i = 0; i < NOBJ; i++)
            {
                Obj[i] = model.AddVar(0.0, 1.0, 1.0, GRB.BINARY, string.Format("Obj{0}", i));
            }

            // Link Xi and notXi
            GRBLinExpr lhs;
            for (i = 0; i < NLITERALS; i++)
            {
                lhs = new GRBLinExpr();
                lhs.AddTerm(1.0, Lit[i]);
                lhs.AddTerm(1.0, NotLit[i]);
                model.AddConstr(lhs, GRB.EQUAL, 1.0, string.Format("CNSTR_X{0}", i));
            }

            // Link clauses and literals
            for (i = 0; i < NCLAUSES; i++)
            {
                GRBVar[] clause = new GRBVar[3];
                for (int j = 0; j < 3; j++)
                {
                    if (Clauses[i, j] >= n)
                    {
                        clause[j] = NotLit[Clauses[i, j] - n];
                    }
                    else
                    {
                        clause[j] = Lit[Clauses[i, j]];
                    }
                }
                model.AddGenConstrOr(Cla[i], clause, string.Format("CNSTR_Clause{0}", i));
            }

            // Link objs with clauses
            model.AddGenConstrMin(Obj[0], Cla, GRB.INFINITY, "CNSTR_Obj0");
            lhs = new GRBLinExpr();
            for (i = 0; i < NCLAUSES; i++)
            {
                lhs.AddTerm(1.0, Cla[i]);
            }
            model.AddGenConstrIndicator(Obj[1], 1, lhs, GRB.GREATER_EQUAL, 4.0, "CNSTR_Obj1");

            // Set global objective sense
            model.ModelSense = GRB.MAXIMIZE;

            // Save problem
            model.Write("genconstr_cs.mps");
            model.Write("genconstr_cs.lp");

            // Optimize
            model.Optimize();

            // Status checking
            status = model.Status;

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

            // Print result
            double objval = model.ObjVal;

            if (objval > 1.9)
            {
                Console.WriteLine("Logical expression is satisfiable");
            }
            else if (objval > 0.9)
            {
                Console.WriteLine("At least four clauses can be satisfied");
            }
            else
            {
                Console.WriteLine("Not even three clauses can be satisfied");
            }

            // Dispose of model and environment
            model.Dispose();
            env.Dispose();
        } catch (GRBException e) {
            Console.WriteLine("Error code: {0}. {1}", e.ErrorCode, e.Message);
        }
    }
예제 #22
0
        public override void PrintLp(object solver)
        {
            GRBModel grbSolver = solver as GRBModel;

            grbSolver.Write(output_file_name);
        }
    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);
        }
    }
예제 #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);
        }
    }
예제 #25
0
        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);
            }
        }
예제 #26
0
        public double OptimalCoverage(int p, ref List <Station> stationList)
        {
            double res = -1;

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

                GRBVar[] X = new GRBVar[m];         // number of drones launched from site j
                for (int j = 0; j < m; j++)
                {
                    X[j] = model.AddVar(0.0, Double.PositiveInfinity, 0.0, GRB.INTEGER, "X_" + j);
                }

                GRBVar[] Z = new GRBVar[n];         // amount of total overall coverage received by demand unit i
                for (int i = 0; i < n; i++)
                {
                    Z[i] = model.AddVar(0.0, Double.PositiveInfinity, 0.0, GRB.CONTINUOUS, "Z_" + i);
                }

                GRBVar[] Y = new GRBVar[n];         // amount of backup coverage received by demand unit i
                for (int i = 0; i < n; i++)
                {
                    Y[i] = model.AddVar(0.0, Double.PositiveInfinity, 0.0, GRB.CONTINUOUS, "Y_" + i);
                }

                GRBVar[] W = new GRBVar[n];         // amount of primary coverage received by demand unit i
                for (int i = 0; i < n; i++)
                {
                    W[i] = model.AddVar(0.0, Double.PositiveInfinity, 0.0, GRB.CONTINUOUS, "W_" + i);
                }

                GRBLinExpr obj_expr = 0.0;
                for (int i = 0; i < n; i++)
                {
                    obj_expr.AddTerm(w, Y[i]);
                }
                for (int i = 0; i < n; i++)
                {
                    obj_expr.AddTerm(1 - w, W[i]);
                }

                model.SetObjective(obj_expr, GRB.MAXIMIZE);

                for (int i = 0; i < n; i++)         // sum_{j} {b_i,j * X_j} >= Z_i for i = 0, ..., n - 1
                {
                    GRBLinExpr expr = 0.0;
                    foreach (int j in N[i])
                    {
                        expr.AddTerm(b[i, j], X[j]);
                    }
                    expr.AddTerm(-1.0, Z[i]);
                    model.AddConstr(expr, GRB.GREATER_EQUAL, 0.0, "c0_" + i);
                }

                for (int i = 0; i < n; i++)         // Y_i <= Z_i - d_i
                {
                    GRBLinExpr expr = 0.0;
                    expr.AddTerm(-1.0, Z[i]);
                    expr.AddTerm(1.0, Y[i]);
                    model.AddConstr(expr, GRB.LESS_EQUAL, -demandList[i], "c1_" + i);
                }

                for (int i = 0; i < n; i++)         // W_i <= Z_i
                {
                    GRBLinExpr expr = 0.0;
                    expr.AddTerm(-1.0, Z[i]);
                    expr.AddTerm(1.0, W[i]);
                    model.AddConstr(expr, GRB.LESS_EQUAL, 0, "c2_" + i);
                }

                for (int i = 0; i < n; i++)         // W_i <= d_i
                {
                    GRBLinExpr expr = 0.0;
                    expr.AddTerm(1.0, W[i]);
                    model.AddConstr(expr, GRB.LESS_EQUAL, demandList[i], "c3_" + i);
                }

                for (int i = 0; i < n; i++)         // Z_i <= h * d_i
                {
                    GRBLinExpr expr = 0.0;
                    expr.AddTerm(1.0, Z[i]);
                    model.AddConstr(expr, GRB.LESS_EQUAL, h * demandList[i], "c4_" + i);
                }

                GRBLinExpr p_expr = 0.0;
                for (int j = 0; j < m; j++)         // sum_{j} {X_j} <= p
                {
                    p_expr.AddTerm(1.0, X[j]);
                }
                model.AddConstr(p_expr, GRB.LESS_EQUAL, p, "c_p");
                model.Write("model.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)
                {
                    double objval = model.ObjVal;

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

                int sum = 0;
                for (int l = 0; l < m; l++)
                {
                    int numDrone = (int)X[l].Get(GRB.DoubleAttr.X);
                    sum += numDrone;
                    for (int k = 0; k < numDrone; k++)
                    {
                        stationList[l].droneList.Add(new Drone(stationList[l].stationID));
                    }

                    if (/*DEBUG && */ numDrone > 0)
                    {
                        Console.WriteLine(numDrone + " drones at station " + l + ", which is at (" + stationList[l].lat + ", " + stationList[l].lon + ")");
                    }
                }
                for (int l = stationList.Count - 1; l >= 0; l--)
                {
                    if (stationList[l].droneList.Count == 0)
                    {
                        stationList.RemoveAt(l);
                    }
                }
                Console.WriteLine("sum = " + sum);

                model.Dispose();
                env.Dispose();
            }
            catch (GRBException e)

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

            return(res);
        }
예제 #27
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();
        }
예제 #28
0
        public GurobiSolver2(Crossword crossword)
        {
            var wordLengthHistogram = new Dictionary <int, double>()
            {
                { 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);


            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);

            // 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)
            int tolerance = (int)(amountQuestions * 0.2);

            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 GRBLinExpr();
            foreach (var wl in wordLengthHistogram.Keys)
            {
                /*var varDiffInput = m.AddVar(-sizeX * sizeY / 3, sizeX * sizeY / 3, 0, GRB.INTEGER, "varDiffInput" + wl);
                 * m.AddConstr(varDiffInput == (wordLengthHistogram[wl] - lengths[wl]));
                 * var varDiffRes = m.AddVar(0, sizeX * sizeY / 3, 0, GRB.INTEGER, "varDiff" + wl);
                 * m.AddGenConstrAbs(varDiffRes, varDiffInput, "diffGenConstr" + wl);
                 * wordHistogramDifferences += varDiffRes;*/

                int histogramTolerance = Math.Max(1, (int)(wordLengthHistogram[wl] * 0.2 * wordLengthRatio));
                //m.AddConstr(wordLengthHistogram[wl] - lengths[wl] >= -histogramTolerance);
                //m.AddConstr(wordLengthHistogram[wl] - lengths[wl] <= histogramTolerance);
            }

            // 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 = 2;
             * for (int y = 0; y < sizeY - (area - 1); y++)
             * {
             *  for (int x = 0; x < sizeX - (area - 1); x++)
             *  {
             *      var clusterTotal = new GRBLinExpr();
             *      for (int i = 0; i < area; i++)
             *      {
             *          for (int j = 0; j < area; j++)
             *          {
             *              clusterTotal += fields[y + i, x + j];
             *          }
             *      }
             *      var varClusterTotalPenalty = m.AddVar(0, 1, 0, GRB.BINARY, "varClusterTotalPenalty" + y + "_" + x);
             *      // 0-1 = good, 2-4 = bad
             *      m.AddConstr(varClusterTotalPenalty <= clusterTotal * 0.5);
             *      m.AddConstr(varClusterTotalPenalty >= (clusterTotal - 1) * (1d / 3));
             *      clusterPenalty += varClusterTotalPenalty;
             *  }
             * }*/

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

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

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

            m.Dispose();
            env.Dispose();
        }
예제 #29
0
        public Dictionary <string, string> Solve(bool tune, bool debug, string tuneOutputFile = null, string paramFile = null)
        {
            var times = new Dictionary <string, string>();

            var totalTime = Utils.TimeAction(() =>
            {
                try
                {
                    // Create an empty environment, set options and start
                    GRBEnv env = new GRBEnv(true);

                    // Use gurobi's parameter reader to load the best file
                    if (paramFile != null)
                    {
                        env.ReadParams(paramFile);
                    }

                    if (!debug)
                    {
                        env.Set(GRB.IntParam.OutputFlag, 0);
                    }

                    env.Start();

                    // Create empty model
                    GRBModel model = new GRBModel(env);

                    (var grbSeated, var addDecisionVariableTime) = Utils.TimeFunction(() => AddSeatedBinaryVariables(model), "Add Decision Variables");

                    var addConstraintsTime = Utils.TimeAction(() => AddContraints(model, grbSeated), "Add Constraints");

                    var addObjectiveTime = Utils.TimeAction(() => AddObjective(model, grbSeated), "Add Objective");

                    var optimizeTime = Utils.TimeAction(() => model.Optimize(), "Optimizing");

                    if (tune)
                    {
                        model.Tune();

                        model.GetTuneResult(0);
                        model.Write(tuneOutputFile);
                    }

                    SeatGroups(grbSeated);

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

                    times.Add("Add Decision Variables", addDecisionVariableTime);
                    times.Add("Add Constraints", addConstraintsTime);
                    times.Add("Add Objective", addObjectiveTime);
                    times.Add("Optimizing", optimizeTime);
                }
                catch (GRBException e)
                {
                    Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message);
                    throw e;
                }
            }, "Total");

            times.Add("Total", totalTime);

            return(times);
        }
예제 #30
0
    static void Main()
    {
        try {
            // Sample data
            int groundSetSize = 20;
            int nSubsets      = 4;
            int Budget        = 12;
            double[,] Set = new double[, ]
            {
                { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                { 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1 },
                { 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0 },
                { 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0 }
            };
            int[]    SetObjPriority = new int[] { 3, 2, 2, 1 };
            double[] SetObjWeight = new double[] { 1.0, 0.25, 1.25, 1.0 };
            int      e, i, status, nSolutions;

            // Create environment
            GRBEnv env = new GRBEnv("multiobj_cs.log");

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

            // Initialize decision variables for ground set:
            // x[e] == 1 if element e is chosen for the covering.
            GRBVar[] Elem = model.AddVars(groundSetSize, GRB.BINARY);
            for (e = 0; e < groundSetSize; e++)
            {
                string vname = string.Format("El{0}", e);
                Elem[e].VarName = vname;
            }

            // Constraint: limit total number of elements to be picked to be at most
            // Budget
            GRBLinExpr lhs = new GRBLinExpr();
            for (e = 0; e < groundSetSize; e++)
            {
                lhs.AddTerm(1.0, Elem[e]);
            }
            model.AddConstr(lhs, GRB.LESS_EQUAL, Budget, "Budget");

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

            // Limit how many solutions to collect
            model.Parameters.PoolSolutions = 100;

            // Set and configure i-th objective
            for (i = 0; i < nSubsets; i++)
            {
                string     vname = string.Format("Set{0}", i);
                GRBLinExpr objn  = new GRBLinExpr();
                for (e = 0; e < groundSetSize; e++)
                {
                    objn.AddTerm(Set[i, e], Elem[e]);
                }

                model.SetObjectiveN(objn, i, SetObjPriority[i], SetObjWeight[i],
                                    1.0 + i, 0.01, vname);
            }

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

            // Optimize
            model.Optimize();

            // Status checking
            status = model.Status;

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

            // Print best selected set
            Console.WriteLine("Selected elements in best solution:");
            Console.Write("\t");
            for (e = 0; e < groundSetSize; e++)
            {
                if (Elem[e].X < .9)
                {
                    continue;
                }
                Console.Write("El{0} ", e);
            }
            Console.WriteLine();

            // Print number of solutions stored
            nSolutions = model.SolCount;
            Console.WriteLine("Number of solutions found: {0}", nSolutions);

            // Print objective values of solutions
            if (nSolutions > 10)
            {
                nSolutions = 10;
            }
            Console.WriteLine("Objective values for first {0} solutions:", nSolutions);
            for (i = 0; i < nSubsets; i++)
            {
                model.Parameters.ObjNumber = i;

                Console.Write("\tSet" + i);
                for (e = 0; e < nSolutions; e++)
                {
                    model.Parameters.SolutionNumber = e;
                    Console.Write("{0,8}", model.ObjNVal);
                }
                Console.WriteLine();
            }
            model.Dispose();
            env.Dispose();
        } catch (GRBException e) {
            Console.WriteLine("Error code = {0}", e);
            Console.WriteLine(e.Message);
        }
    }
예제 #31
0
파일: sudoku_cs.cs 프로젝트: revisalo/cr2
    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);
        }
    }
        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);
        }