Example #1
0
    static void Main()
    {
        try {
            GRBEnv env = new GRBEnv();

            GRBModel model = new GRBModel(env);

            // Create variables

            double[] ub    = { 1, 1, 2 };
            double[] obj   = { -2, -1, -1 };
            string[] names = { "x0", "x1", "x2" };

            GRBVar[] x = model.AddVars(null, ub, obj, null, names);

            // Integrate new variables

            model.Update();

            // Add first SOS1: x0=0 or x1=0

            GRBVar[] sosv1  = { x[0], x[1] };
            double[] soswt1 = { 1, 2 };

            model.AddSOS(sosv1, soswt1, GRB.SOS_TYPE1);

            // Add second SOS1: x0=0 or x2=0

            GRBVar[] sosv2  = { x[0], x[2] };
            double[] soswt2 = { 1, 2 };

            model.AddSOS(sosv2, soswt2, GRB.SOS_TYPE1);

            // Optimize model

            model.Optimize();

            for (int i = 0; i < 3; i++)
            {
                Console.WriteLine(x[i].Get(GRB.StringAttr.VarName) + " "
                                  + x[i].Get(GRB.DoubleAttr.X));
            }

            // Dispose of model and env
            model.Dispose();
            env.Dispose();
        } catch (GRBException e) {
            Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message);
        }
    }
Example #2
0
    static void Main()
    {
        try {
          GRBEnv env = new GRBEnv();

          GRBModel model = new GRBModel(env);

          // Create variables

          double[] ub    = {1, 1, 2};
          double[] obj   = {-2, -1, -1};
          string[] names = {"x0", "x1", "x2"};

          GRBVar[] x = model.AddVars(null, ub, obj, null, names);

          // Integrate new variables

          model.Update();

          // Add first SOS1: x0=0 or x1=0

          GRBVar[] sosv1  = {x[0], x[1]};
          double[] soswt1 = {1, 2};

          model.AddSOS(sosv1, soswt1, GRB.SOS_TYPE1);

          // Add second SOS1: x0=0 or x2=0

          GRBVar[] sosv2  = {x[0], x[2]};
          double[] soswt2 = {1, 2};

          model.AddSOS(sosv2, soswt2, GRB.SOS_TYPE1);

          // Optimize model

          model.Optimize();

          for (int i = 0; i < 3; i++)
        Console.WriteLine(x[i].Get(GRB.StringAttr.VarName) + " "
                           + x[i].Get(GRB.DoubleAttr.X));

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

        } catch (GRBException e) {
          Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message);
        }
    }
Example #3
0
        protected GRBVar[] CreatePermutationVariable()
        {
            var ub   = new double[_k];
            var obj  = new double[_k];
            var type = new char[_k];

            for (var i = 0; i < _k; i++)
            {
                ub[i]   = _k - 1;
                obj[i]  = 0;
                type[i] = GRB.INTEGER;
            }

            return(_model.AddVars(null, ub, obj, type, null, 0, _k));
        }
Example #4
0
        public static GRBVar[,] AddVars(this GRBModel _m, int _width, int _height, double lb, double ub, char type)
        {
            var vars = _m.AddVars(Enumerable.Repeat(lb, _width * _height).ToArray(), Enumerable.Repeat(ub, _width * _height).ToArray(), null, Enumerable.Repeat(type, _width * _height).ToArray(), null);

            var i   = 0;
            var res = new GRBVar[_width, _height];

            for (var y = 0; y < _height; y++)
            {
                for (var x = 0; x < _width; x++)
                {
                    res[x, y] = vars[i++];
                }
            }
            return(res);
        }
        public static GRBVar[,] AddVars(this GRBModel _m, int _width, int _height, double lb, double ub, char type, string _prefix = null)
        {
            var vars = _m.AddVars(Enumerable.Repeat(lb, _width * _height).ToArray(), Enumerable.Repeat(ub, _width * _height).ToArray(), null, Enumerable.Repeat(type, _width * _height).ToArray(),
                                  _prefix == null ? null : Enumerable.Range(0, _width * _height).Select(j => $"{_prefix}[{j % _width},{j/_width}]").ToArray()
                                  );

            var i   = 0;
            var res = new GRBVar[_width, _height];

            for (var y = 0; y < _height; y++)
            {
                for (var x = 0; x < _width; x++)
                {
                    res[x, y] = vars[i++];
                }
            }

            return(res);
        }
        public static GRBVar[,,,] AddVars(this GRBModel _m, int _width, int _height, int _depth, int _d4, double lb, double ub, char type, string _prefix = null)
        {
            var vars = _m.AddVars(Enumerable.Repeat(lb, _width * _height * _depth * _d4).ToArray(), Enumerable.Repeat(ub, _width * _height * _depth * _d4).ToArray(), null, Enumerable.Repeat(type, _width * _height * _depth * _d4).ToArray(),
                                  _prefix == null ? null : Enumerable.Range(0, _width * _height * _depth * _d4).Select(j => $"{_prefix}[{j % _width},{(j/_width) % _height},{(j/_width/_height) % _depth},{j/_width/_height/_depth}]").ToArray()
                                  );

            var i   = 0;
            var res = new GRBVar[_width, _height, _depth, _d4];

            for (var a = 0; a < _d4; a++)
            {
                for (var z = 0; z < _depth; z++)
                {
                    for (var y = 0; y < _height; y++)
                    {
                        for (var x = 0; x < _width; x++)
                        {
                            res[x, y, z, a] = vars[i++];
                        }
                    }
                }
            }
            return(res);
        }
Example #7
0
    protected static bool dense_optimize(GRBEnv    env,
                   int       rows,
                   int       cols,
                   double[]  c,      // linear portion of objective function
                   double[,] Q,      // quadratic portion of objective function
                   double[,] A,      // constraint matrix
                   char[]    sense,  // constraint senses
                   double[]  rhs,    // RHS vector
                   double[]  lb,     // variable lower bounds
                   double[]  ub,     // variable upper bounds
                   char[]    vtype,  // variable types (continuous, binary, etc.)
                   double[]  solution)
    {
        bool success = false;

        try {
          GRBModel model = new GRBModel(env);

          // Add variables to the model

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

          // Populate A matrix

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

          // Populate objective

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

          // Solve model

          model.Optimize();

          // Extract solution

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

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

          model.Dispose();

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

        return success;
    }
Example #8
0
        static void Main(string[] args)
        {
            int        round;
            List <int> deglist = new List <int>();
            //StreamWriter MaxDegT = new StreamWriter("MaxdegreeTerms.txt");
            int startround = 960;

            //the target round runs from 960 to 1152.
            for (round = startround; round < 1153; round++)
            {
                GRBEnv env = new GRBEnv("Trvium.log");

                GRBModel model = new GRBModel(env);
                Console.Write("****************** The " + round.ToString() + "-th round ******************\n");
                //设置gurobi不输出中间结果
                model.Parameters.LogToConsole = 0;
                int[] pos = new int[] { 65, 92, 161, 176, 242, 287 };//6个输出位置 65,92, 161, 176, 242, 287
                //int[] pos = new int[3] {  };//6个输出位置
                GRBVar[] IV  = model.AddVars(80, GRB.BINARY);
                GRBVar[] Key = model.AddVars(80, GRB.BINARY);
                for (int i = 0; i < 80; i++)
                {
                    IV[i].VarName  = "IV" + i.ToString();  //IV变量,命名为IV0-IV79
                    Key[i].VarName = "Key" + i.ToString(); //IV变量,命名为Key0-Key79
                }
                GRBVar[] s = model.AddVars(288, GRB.BINARY);
                for (int i = 0; i < 288; i++)
                {
                    s[i].VarName = "var" + i.ToString(); //288个寄存器,命名为var0-var288
                }
                char[] FlagS = new char[288];            //288个寄存器的Flag

                GRBVar[] NewVars = model.AddVars(30 * round, GRB.BINARY);
                for (int i = 0; i < NewVars.Length; i++)
                {
                    NewVars[i].VarName = "y" + i.ToString(); //每过一次更新许需要加30个变量,总共为30*round,命名为y0-y300*round
                }
                char[] FlagNewVars = new char[30 * round];   //新加变量的Flag

                List <uint> cube = new List <uint>()
                {
                    0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48, 51, 54, 57, 60, 63, 66, 69, 72, 75, 78
                };
                List <uint> ivbits_set_to_1 = new List <uint>()
                {
                };
                List <uint> ivbits_set_to_0 = new List <uint>()
                {
                };
                for (uint i = 0; i < 80; i = i + 1)
                {
                    ivbits_set_to_0.Add(i);
                }
                for (int i = 0; i < cube.Count; i++)
                {
                    ivbits_set_to_0.Remove(cube[i]);
                }
                for (int i = 0; i < cube.Count; i++)
                {
                    Console.Write(cube[i] + " ");
                }
                Console.WriteLine();

                List <UInt32> Noncube = new List <uint>()
                {
                    0x0, 0x0, 0x0
                };                                                        //Noncube stores the value of the non-cube variables

                //for each iv bit which is set to 1, set the corresponding bit of Noncube to 1.
                for (int i = 0; i < ivbits_set_to_1.Count; i++)
                {
                    Noncube[(int)ivbits_set_to_1[i] >> 5] |= (uint)(0x01 << ((int)(ivbits_set_to_1[i] & 0x1f)));
                }

                GRBLinExpr ChooseIV = new GRBLinExpr();//
                for (int i = 0; i < cube.Count; i++)
                {
                    ChooseIV.AddTerm(1.0, IV[cube[i]]);
                }

                //the bits set to constants
                List <int> chokey = new List <int>()
                {
                    1, 2, 4, 5, 7, 8, 10, 11, 13, 14, 16, 17, 19, 20, 22, 23, 25, 26, 28, 29, 31, 32, 34, 35, 37, 38, 40, 41, 43, 44, 46, 47, 49, 50, 52, 53, 55, 56, 58, 59, 61, 62, 64, 65, 66, 67, 68, 70, 71, 73, 74, 76, 77, 79
                };

                //pick up the key variables which are not fixed.
                //i.e. keydeg= k_i1+k_i2+...+k_in, where k_i1,k_i2,...,k_im are the key bits which are not fixed
                GRBLinExpr keydeg = new GRBLinExpr();
                for (int i = 0; i < 80; i++)
                {
                    if (!chokey.Contains(i))
                    {
                        keydeg.AddTerm(1.0, Key[i]);
                    }
                }

                //set maximizing the linear expression keydeg as the objective function of our model
                //Hence, we could obtain the upper bound of the degree of the superpoly of the chosen cube.
                model.SetObjective(keydeg, GRB.MAXIMIZE);

                //in this function, we set the conditions which are imposed to the key bits and iv bits
                //before running, it needs to set some parameters, such as the key bits set to 0/1 and so on, in this function,
                initial(model, s, FlagS, cube, Noncube, IV, Key);

                int VarNumber = 0;

                //describe the propagation of the division property with flag through Trivium
                for (int i = 1; i <= round; i++)
                {
                    Triviumcore(model, s, FlagS, NewVars, FlagNewVars, ref VarNumber);
                }

                for (int i = 0; i < 288; i++)
                {
                    if (!pos.Contains(i))
                    {
                        model.AddConstr(s[i] == 0, "a" + i.ToString());
                    }
                }
                GRBLinExpr expr = new GRBLinExpr();
                for (int i = 0; i < pos.Count(); i++)
                {
                    expr.AddTerm(1.0, s[pos[i]]);
                }
                model.AddConstr(expr == 1, "t1");

                //solve the MILP model.
                model.Optimize();
                int currentdeg = 0;

                //outout the solution
                int NO = 0;
                // is the model is feasible the upper bound of the degree of the superpoly is large than 0.
                // In this case, we output a possible term of degree d, where d is the upper bound of the degree of the superpoly.
                if (model.SolCount > 0)
                {
                    StreamWriter MaxDegT = new StreamWriter("MaxdegreeTerms.txt", true);
                    currentdeg = (int)model.ObjVal;
                    NO++;
                    Console.WriteLine("****************No." + round + "********************\n");
                    //MaxDegT.WriteLine("****************No." + NO + "********************\n");
                    MaxDegT.WriteLine("*****************round" + round + "**********************\n");
                    MaxDegT.Write("Upper bound of degree of superpoly: ");
                    Console.WriteLine(model.ObjVal);
                    MaxDegT.WriteLine(model.ObjVal);
                    GRBLinExpr ChoIV = new GRBLinExpr();//选择能到达最大次数的IV;
                    // for (int i = 0; i < cube.Count; i++)
                    int sumy = 0;
                    for (int i = 0; i < 80; i++)
                    {
                        Console.Write(Key[i].X + ",");
                    }
                    Console.WriteLine();

                    MaxDegT.Write("One possible terms of degree " + model.ObjVal + " is : ");
                    for (int i = 0; i < 80; i++)
                    {
                        if (Key[i].X > 0.781)
                        {
                            sumy++;
                            MaxDegT.Write(i + ",");
                            Console.Write(i + ",");
                        }
                    }
                    MaxDegT.Write("\n\n***********************************************\n");
                    Console.Write("\n***********************************************\n");
                    for (int i = 0; i < cube.Count(); i++)
                    {
                        // Console.Write(IV[i].X + ",");
                        if (s[cube[i]].X > 0.781)
                        {
                            sumy++;
                            MaxDegT.Write(i + ",");
                            Console.Write(i + ",");
                        }
                    }

                    Console.WriteLine();
                    MaxDegT.WriteLine();
                    MaxDegT.Close();
                }

                if (model.SolCount > 0)
                {
                    deglist.Add((int)model.ObjVal);
                }
                else//if the model is imfeasible, then the degree of the superpoly is upper bounded by 0.
                {
                    deglist.Add(0);
                    StreamWriter MaxDegT = new StreamWriter("MaxdegreeTerms.txt", true);
                    MaxDegT.WriteLine("*****************round" + round + "**********************\n");
                    MaxDegT.WriteLine("Upper bound of degree of superpoly: 0");
                    MaxDegT.Write("\n***********************************************\n");
                    MaxDegT.WriteLine();
                    MaxDegT.Close();
                }
                model.Dispose();
                env.Dispose();
            }
            //MaxDegT.Close();
            for (int i = startround; i < round; i++)
            {
                Console.Write(i.ToString() + "  " + deglist[i - startround].ToString() + "\n");
            }

            Console.ReadLine();
        }
    public static void Main()
    {
        try {
            int      n = 5;
            int      m = 5;
            double[] c = new double[] { 0.5, 0.8, 0.5, 0.1, -1 };
            double[,] A = new double[, ] {
                { 0, 0, 0, 1, -1 },
                { 0, 0, 1, 1, -1 },
                { 1, 1, 0, 0, -1 },
                { 1, 0, 1, 0, -1 },
                { 1, 0, 0, 1, -1 }
            };
            double[] xpts = new double[] { -1, 0, 0, 0, 1 };
            double[] ypts = new double[] { 2, 1, 0, 1, 2 };

            // Env and model
            GRBEnv   env   = new GRBEnv();
            GRBModel model = new GRBModel(env);
            model.ModelName = "gc_pwl_cs";

            // Add variables, set bounds and obj coefficients
            GRBVar[] x = model.AddVars(n, GRB.CONTINUOUS);
            for (int i = 0; i < n; i++)
            {
                x[i].LB  = -GRB.INFINITY;
                x[i].Obj = c[i];
            }

            GRBVar[] y = model.AddVars(n, GRB.CONTINUOUS);

            // Set objective to maximize
            model.ModelSense = GRB.MAXIMIZE;

            // Add linear constraints
            for (int i = 0; i < m; i++)
            {
                GRBLinExpr le = 0.0;
                for (int j = 0; j < n; j++)
                {
                    le.AddTerm(A[i, j], x[j]);
                }
                model.AddConstr(le, GRB.LESS_EQUAL, 0, "cx" + i);
            }

            GRBLinExpr le1 = 0.0;
            for (int j = 0; j < n; j++)
            {
                le1.AddTerm(1.0, y[j]);
            }
            model.AddConstr(le1, GRB.LESS_EQUAL, 3, "cy");

            // Add piecewise constraints
            for (int j = 0; j < n; j++)
            {
                model.AddGenConstrPWL(x[j], y[j], xpts, ypts, "pwl" + j);
            }

            // Optimize model
            model.Optimize();

            for (int j = 0; j < n; j++)
            {
                Console.WriteLine("x[" + j + "] = " + x[j].X);
            }
            Console.WriteLine("Obj: " + model.ObjVal);

            // Dispose of model and environment
            model.Dispose();
            env.Dispose();
        } catch (GRBException e) {
            Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message);
        }
    }
Example #10
0
 public static GRBVar[] AddVars(this GRBModel _m, int _count, double lb, double ub, char type)
 {
     return(_m.AddVars(Enumerable.Repeat(lb, _count).ToArray(), Enumerable.Repeat(ub, _count).ToArray(), null, Enumerable.Repeat(type, _count).ToArray(), null));
 }
        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);
        }
Example #12
0
        static void Main(string[] args)
        {
            //for (int i = 0; i < 26; i++)
            //    Console.Write(3*i + ",");
            //Console.ReadKey();
            GRBEnv env = new GRBEnv("Kreyium.log");

            int round = 892;

            GRBModel model = new GRBModel(env);

            int[] pos = new int[7] {
                65, 92, 161, 176, 242, 287, 415
            };                                                       //7个输出位置
            GRBVar[] s = model.AddVars(544, GRB.BINARY);
            for (int i = 0; i < 544; i++)
            {
                s[i].VarName = "var" + i.ToString(); //288个寄存器,命名为var0-var288
            }
            char[]   FlagS   = new char[544];        //288个寄存器的Flag
            GRBVar[] NewVars = model.AddVars(34 * round, GRB.BINARY);
            for (int i = 0; i < NewVars.Length; i++)
            {
                NewVars[i].VarName = "y" + i.ToString(); //每过一次更新许需要加30个变量,总共为30*round,命名为y0-y300*round
            }
            char[]   FlagNewVars = new char[34 * round]; //新加变量的Flag
            GRBVar[] IV          = model.AddVars(128, GRB.BINARY);
            for (int i = 0; i < 128; i++)
            {
                IV[i].VarName = "IV" + i.ToString();//128个IV变量
            }
            GRBVar[] Key = model.AddVars(128, GRB.BINARY);
            for (int i = 0; i < 128; i++)
            {
                Key[i].VarName = "Key" + i.ToString();//128个Key变量
            }
            // List<uint> cube = new List<uint>() { 1, 3, 5, 7, 9, 11, 13, 16, 18, 20, 22, 24, 26, 28, 31, 33, 35, 37, 39, 41, 43, 46,
            //                                      48, 50, 52, 54, 61, 63, 65, 67, 69, 71, 73, 76, 78, 80, 82, 84, 86, 88, 90, 92, 95,
            //                                      97, 99, 101, 103, 106, 108, 110, 112, 114, 116, 118, 120, 125, 127};//cube变量
            //dcc19
            // List<uint> cube = new List<uint>() { 0,2,4,6,8,10,12,15,17,19,21,24,26,28,30,32,34,36,39,41,43,45,47,49,52,54,56,58,
            //                                      60,62,67,69,71,73,75,80,82,84,86,89,91,93,95,97,99,102,104,106,108,110,112,114,
            //                                      117,119,121,123};//cube变量
            //List<uint> cube = new List<uint>() {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 37, 39, 41, 43, 45, 46, 47, 48, 49, 50, 51, 52, 54, 56, 59, 61, 63, 65, 67, 69, 71, 74, 76, 78, 80, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127};
            //dis880 try 892
            //List<uint> cube =new List<uint>(){0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,29,31,33,35,37,39,41,44,46,48,50,52,54,56,59,61,63,65,67,69,72,74,76,78,80,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127};
            List <uint> cube = new List <uint>()
            {
                0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 37, 39, 41, 43, 44, 45, 46, 47, 48, 49, 50, 52, 54, 57, 59, 61, 63, 65, 67, 69, 72, 74, 76, 78, 80, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127
            };
            List <int> keyset = new List <int>()
            {
            };

            for (int i = 0; i < 128; i++)
            {
                keyset.Add(i);
            }
            for (int i = 0; i < cube.Count(); i++)
            {
                Console.Write(cube[i] + " ");
            }
            Console.WriteLine();
            List <UInt32> Noncube = new List <uint>()
            {
                0x0, 0x0, 0x0, 0x0
            };
            GRBLinExpr ChooseKey = new GRBLinExpr();//超多项式中可能含有的密钥变量集合
            int        VarNumber = 0;

            initial(model, s, FlagS, cube, Noncube, keyset, ChooseKey, IV, Key);//初始化设置
            for (int i = 1; i <= round; i++)
            {
                Triviumcore(model, s, FlagS, NewVars, FlagNewVars, ref VarNumber);
            }

            for (int i = 0; i < 544; i++)
            {
                if (!pos.Contains(i))
                {
                    model.AddConstr(s[i] == 0, "a" + i.ToString());
                }
            }
            GRBLinExpr expr = new GRBLinExpr();

            for (int i = 0; i < 7; i++)
            {
                expr.AddTerm(1.0, s[pos[i]]);
            }
            model.AddConstr(expr == 1, "t1");
            model.Optimize();

            if (model.SolCount > 0)
            {
                Console.WriteLine(model.ObjVal);
            }
            else
            {
                Console.WriteLine("************************************");
                Console.WriteLine("Model is infeasible!!!");
                Console.WriteLine("************************************");
            }
            model.Dispose();
            env.Dispose();
            Console.ReadKey();
        }
    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);
        }
    }
Example #14
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);
        }
    }
Example #15
0
        public override Schedule Generate(Scenario scenario, FilledBaseline fillerBaseline = null)
        {
            var projects = fillerBaseline == null ? scenario.Projects : fillerBaseline.Projects;
            // TODO: With fillerBaseline use ALL OF the projects

            var opportunities    = projects.Where(p => p is Opportunity).ToArray();
            var batches          = 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 = projects.Min(p => p.DeliveryDate);
            var       lastDate     = 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 + 1;
            const int weeksBuffer  = 3;


            var delayPenaltyMultiplier    = 0.01;            // 1% of revenue per week
            var 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.Threads, 1);
            //env.Set(GRB.IntParam.NumericFocus, 3);
            //env.Set(GRB.DoubleParam.TimeLimit, 30);
            env.Set(GRB.DoubleParam.MIPGap, 0.06);


            //env.Set(GRB.IntParam.Presolve,2);
            //env.Set(GRB.IntParam.ScaleFlag, 2);
            //env.Set(GRB.IntParam.Method, 2);



            var m = new GRBModel(env);

            // decide: which batch is when, on which line
            var varBatchTimeLine1    = m.AddVars(bBc + batchesLine1.Count(), 0, maxDays, GRB.CONTINUOUS, "varBatchTimeLine1");
            var varBatchTimeLine2    = m.AddVars(bBc + batchesLine2.Count(), 0, maxDays, GRB.CONTINUOUS, "varBatchTimeLine2");
            var varOpportunityIsUsed = m.AddVars(opportunities.Count(), 0, 1, GRB.BINARY, "varOpportunityIsUsed");
            var varLineDecision      = m.AddVars(bBc, 0, 1, GRB.BINARY, "varLineDecision"); // 0 = Line1, 1 = Line2

            //m.Update();

            //TODO: Start heuristic
            //m.Update();
            //varMaxedValue[0].Set(GRB.DoubleAttr.Start, 5);

            // baseline constraint:
            // we want some opportunities to be used for sure

            /*if (baseline  != null)
             * {
             *  var mustWinOpportunitites = new List<Opportunity>();
             *  for (int oi = 0; oi < opportunities.Count(); oi++)
             *  {
             *      if (baseline.Projects.Contains(opportunities[oi]))
             *      {
             *          mustWinOpportunitites.Add((Opportunity)opportunities[oi]);
             *          m.AddConstr(varOpportunityIsUsed[opportunities.IndexOf(opportunities[oi])] == 1);
             *      }
             *  }
             *
             * }*/


            // line constraints:
            // if it's a fixed project though, then it must be allocated
            // 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 < projects.Count(); pi++)
            {
                var p = 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]);
                        }
                    }
                    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);
                    }
                    i_prev = i;
                }
            }

            // scheduling formulation
            for (int l = 0; l < 2; l++)
            {
                var lineVars = l == 0 ? varBatchTimeLine1 : varBatchTimeLine2;
                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 - varOpportunityIsUsed[opportunities.IndexOf(o1_exists)]) : new GRBLinExpr();
                    var s1        = lineVars[bi1];
                    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 - varOpportunityIsUsed[opportunities.IndexOf(o2_exists)]) : new GRBLinExpr();
                        var s2        = lineVars[bi2];

                        // 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;
                        m.AddConstr(s1 - (s2 + batch2.UsedWorkHours / 24d) >= -maxDays * (decisionVar + opportunityNotUsedSlack)); //TODO: varLineDecisionSlack for both lines batches
                        m.AddConstr(s2 - (s1 + batch1.UsedWorkHours / 24d) >= -maxDays * (1 - decisionVar + opportunityNotUsedSlack));
                    }
                }
            }

            // 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



            // 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 projects)
            {
                // if the project is used add the margin
                if (p is Opportunity)
                {
                    margin += varOpportunityIsUsed[opportunities.IndexOf(p)] * p.Margin;
                }
                else
                {
                    margin += p.Margin;
                }

                // 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 = varBatchTimeLine1[bi] / 7d;
                    }
                    else if (batchesLine2.Contains(b))
                    {
                        var bi = batchesLine2.IndexOf(b) + bBc;
                        weekValue = varBatchTimeLine2[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 >= varBatchTimeLine1[bi] / 7d - (varLineDecision[bi]) * maxWeek);
                        m.AddConstr(bothLineWeekVar <= varBatchTimeLine1[bi] / 7d + (varLineDecision[bi]) * maxWeek);
                        m.AddConstr(bothLineWeekVar >= varBatchTimeLine2[bi] / 7d - (1 - varLineDecision[bi]) * maxWeek);
                        m.AddConstr(bothLineWeekVar <= varBatchTimeLine2[bi] / 7d + (1 - varLineDecision[bi]) * maxWeek);
                        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(0, maxWeek, GRB.CONTINUOUS, "weekValueBothLines");
                            //m.Update();
                            var wD = weekValue - plannedWeek;
                            m.AddConstr(weekDiffIfUsed >= wD - (1 - varOpportunityIsUsed[opportunities.IndexOf(p)]) * maxWeek);
                            m.AddConstr(weekDiffIfUsed <= wD + (1 - varOpportunityIsUsed[opportunities.IndexOf(p)]) * maxWeek);
                            m.AddConstr(weekDiffIfUsed <= (varOpportunityIsUsed[opportunities.IndexOf(p)]) * maxWeek);
                            m.AddConstr(weekDiffIfUsed >= -(varOpportunityIsUsed[opportunities.IndexOf(p)]) * maxWeek);
                            weekDiff = weekDiffIfUsed;
                        }
                        else
                        {
                            weekDiff = weekValue - plannedWeek;
                        }

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


                        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 ? 999999999 : p.Revenue;
                        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);
                    }
                    previousWeekValue = weekValue;
                }
            }



            m.SetObjective(margin, GRB.MAXIMIZE);

            //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 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 = varBatchTimeLine1[bBc + batchesLine1.IndexOf(b)].Get(GRB.DoubleAttr.X);
                    }
                    else if (b.Compatibility == Batch.LineCompatibility.Line2)
                    {
                        dayLine2 = varBatchTimeLine2[bBc + batchesLine2.IndexOf(b)].Get(GRB.DoubleAttr.X);
                    }
                    else
                    {
                        var bbi          = batchesBothLines.IndexOf(b);
                        var lineDecision = varLineDecision[bbi].Get(GRB.DoubleAttr.X);
                        dayLine1 = varBatchTimeLine1[bbi].Get(GRB.DoubleAttr.X) * (1 - lineDecision);
                        dayLine2 = varBatchTimeLine2[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 && varOpportunityIsUsed[opportunities.IndexOf(p)].Get(GRB.DoubleAttr.X) > 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));
            }

            return(sol);
        }
        public OptimizationResult Solve(long timelimitMiliseconds, EventHandler <ProgressReport> progress,
                                        EventHandler <string> consoleProgress)
        {
            var sw     = Stopwatch.StartNew();
            var output = new OptimizationResult
            {
                OptimizationInput = input
            };

            var timeWindowIsRelevant = !input.Visits.All(visit =>
            {
                if (visit.Desired.Length > 0)
                {
                    return(false);
                }

                return(!visit.Unavailable.Any(unavailable =>
                {
                    var(unavailableFrom, unavailableTo) = unavailable;
                    foreach (var(dayFrom, dayTo) in input.Days)
                    {
                        if (IntersectionLength(unavailableFrom, unavailableTo, dayFrom, dayTo) > 0)
                        {
                            return true;
                        }
                    }
                    return false;
                }));
            });

            // first solve vrp, take result as initial solution.
            if (!timeWindowIsRelevant)
            {
                vrpTimeLimitFactor = 1;
            }

            var vrpSolution = input.Visits.Length > 75 ? FakeVRPSolution(input.Santas.Length * input.Days.Length) : new VRPCallbackSolver(input).SolveVRP((int)(timelimitMiliseconds * vrpTimeLimitFactor));

            consoleProgress?.Invoke(this, $"vrp needed {sw.ElapsedMilliseconds}ms, remaining {timelimitMiliseconds - sw.ElapsedMilliseconds}");

            if (!timeWindowIsRelevant)
            {
                BuildResultFromVRP(output, vrpSolution);
                output.TimeElapsed = sw.ElapsedMilliseconds / 1000;
                return(output);
            }

            timelimitMiliseconds -= sw.ElapsedMilliseconds;
            using (var env = new GRBEnv($"{DateTime.Now:yy-MM-dd-HH-mm-ss}_gurobi.log"))
                using (var model = new GRBModel(env))
                {
                    #region initialize Variables
                    var numberOfRoutes = input.Santas.Length * input.Days.Length;
                    var v = new GRBVar[numberOfRoutes][]; // [santa] visits [visit]
                    var w = new GRBVar[numberOfRoutes][]; // [santa] uses [way]
                    var c = new GRBVar[numberOfRoutes][]; // [santa] visits visit at the end of [way]

                    var desiredDuration     = new GRBVar[numberOfRoutes][][];
                    var unavailableDuration = new GRBVar[numberOfRoutes][][];

                    var maxRoutes = new GRBVar[numberOfRoutes];
                    var minRoutes = new GRBVar[numberOfRoutes];

                    for (int s = 0; s < numberOfRoutes; s++)
                    {
                        v[s] = new GRBVar[visitDurations.Length];
                        c[s] = new GRBVar[visitDurations.Length];
                        desiredDuration[s]     = new GRBVar[visitDurations.Length][];
                        unavailableDuration[s] = new GRBVar[visitDurations.Length][];
                        var(dayStart, dayEnd)  = input.Days[s / input.Santas.Length];
                        var dayDuration = dayEnd - dayStart;
                        for (int i = 0; i < v[s].Length; i++)
                        {
                            v[s][i] = model.AddVar(0, 1, 0.0, GRB.BINARY, GurobiVarName($"v[{s}][{i}]"));
                            c[s][i] = model.AddVar(0, dayDuration, 0, GRB.CONTINUOUS, GurobiVarName($"c[{s}][{i}]"));

                            if (i > 0)
                            {
                                var visit = input.Visits[i - 1];
                                desiredDuration[s][i]     = new GRBVar[visit.Desired.Length];
                                unavailableDuration[s][i] = new GRBVar[visit.Unavailable.Length];

                                for (int d = 0; d < visit.Desired.Length; d++)
                                {
                                    var ub = Math.Max(0, Math.Min(visit.Duration, visit.Desired[d].to - visit.Desired[d].from));
                                    desiredDuration[s][i][d] = model.AddVar(0, ub, 0, GRB.CONTINUOUS, GurobiVarName($"desiredDuration[{s}][{i}][{d}]"));
                                }

                                for (int u = 0; u < visit.Unavailable.Length; u++)
                                {
                                    var ub = Math.Max(0, Math.Min(visit.Duration, visit.Unavailable[u].to - visit.Unavailable[u].from));
                                    unavailableDuration[s][i][u] = model.AddVar(0, ub, 0, GRB.CONTINUOUS, GurobiVarName($"unavailableDuration[{s}][{i}][{u}]"));
                                }
                            }
                        }

                        w[s]         = model.AddVars(distances.GetLength(0) * distances.GetLength(1), GRB.BINARY);
                        maxRoutes[s] = model.AddVar(0, dayEnd - dayStart, 0, GRB.CONTINUOUS, GurobiVarName($"santa{s} maxRoute"));
                        minRoutes[s] = model.AddVar(0, dayEnd - dayStart, 0, GRB.CONTINUOUS, GurobiVarName($"santa{s} minRoute"));
                    }

                    #endregion initialize Variables


                    #region add constraints
                    SelfieConstraint(model, numberOfRoutes, w);

                    // visit visited once
                    VisitVisitedOnce(model, numberOfRoutes, v);
                    // breaks
                    BreakHandling(model, numberOfRoutes, v);

                    // number of ways = number of visits + home
                    NumberOfWaysMatchForSanta(model, numberOfRoutes, v, w);

                    // incoming & outgoing constraint
                    IncomingOutgoingGlobal(model, numberOfRoutes, w);
                    IncomingOutgoingSanta(model, numberOfRoutes, v, w);

                    IncomingOutgoingSantaHome(model, numberOfRoutes, w, v);

                    IncreasingC(model, numberOfRoutes, w, c, v);

                    DesiredOverlap(model, numberOfRoutes, v, w, c, desiredDuration);

                    UnavailableOverlap(model, numberOfRoutes, v, w, c, unavailableDuration, true);

                    FillMaxRoute(model, maxRoutes, c, v);
                    FillMinRoutes(model, minRoutes, c, v);
                    MinRouteSmallerThanMaxRoute(model, minRoutes, maxRoutes);

                    // Symmetry breaking constraint if no breaks
                    if (!input.Visits.Any(visit => visit.IsBreak))
                    {
                        for (int d = 0; d < input.Days.Length; d++)
                        {
                            var dayOffset = d * input.Santas.Length;
                            for (int s = 1; s < input.Santas.Length; s++)
                            {
                                model.AddConstr(maxRoutes[dayOffset + s] - minRoutes[dayOffset + s] <= maxRoutes[dayOffset + s - 1] - minRoutes[dayOffset + s - 1], null);
                            }
                        }
                    }

                    #endregion add constraints

                    // TARGET FUNCTION
                    var totalWayTime = new GRBLinExpr(0);
                    var longestRoute = model.AddVar(0, input.Days.Max(d => d.to - d.from), 0, GRB.CONTINUOUS, "longestRoute");
                    for (int s = 0; s < numberOfRoutes; s++)
                    {
                        totalWayTime += (maxRoutes[s] - minRoutes[s]);
                        model.AddConstr(longestRoute >= maxRoutes[s] - minRoutes[s], $"longesRouteConstr{s}");
                    }

                    var desiredSum     = new GRBLinExpr(0);
                    var unavailableSum = new GRBLinExpr(0);
                    for (int s = 0; s < numberOfRoutes; s++)
                    {
                        for (int i = 1; i < visitDurations.Length; i++)
                        {
                            var visit = input.Visits[i - 1];
                            for (int d = 0; d < visit.Desired.Length; d++)
                            {
                                if (!(desiredDuration[s][i][d] is null))
                                {
                                    desiredSum += desiredDuration[s][i][d];
                                }
                            }

                            for (int u = 0; u < visit.Unavailable.Length; u++)
                            {
                                if (!(unavailableDuration[s][i][u] is null))
                                {
                                    unavailableSum += unavailableDuration[s][i][u];
                                }
                            }
                        }
                    }

                    LowerBoundTotalWaytime(model, totalWayTime);

                    model.SetObjective(
                        +(12d) * unavailableSum
                        + (4d) * totalWayTime
                        - (2d) * desiredSum
                        + (3d) * longestRoute
                        , GRB.MINIMIZE);
                    model.Parameters.TimeLimit = Math.Max(0, timelimitMiliseconds / 1000);
                    InitializeWithVRPSolution(vrpSolution, numberOfRoutes, model, v, w, c);

#if DEBUG
                    model.Write($"{name}_{visitDurations.Length}.mst");
                    model.Write($"{name}_{visitDurations.Length}.mps");
                    model.Write($"{name}_{visitDurations.Length}.lp");
#endif

                    model.Optimize();
                    output.TimeElapsed = sw.ElapsedMilliseconds / 1000;
                    try
                    {
                        if (model.SolCount == 0 && vrpSolution != null)
                        {
                            consoleProgress?.Invoke(this, "No solution found -> try with vrpsolution");
                            BuildResultFromVRP(output, vrpSolution);
                            return(output);
                        }
                        BuildResult(output, numberOfRoutes, w, c);
                        consoleProgress?.Invoke(this, $"longestRoute: {longestRoute.X}");
                        consoleProgress?.Invoke(this, $"totalWayTime: {totalWayTime.Value}");
                        consoleProgress?.Invoke(this, $"DesiredDuration: {desiredSum.Value}");
                        consoleProgress?.Invoke(this, $"UnavailableDuration: {unavailableSum.Value}");
                        for (int s = 0; s < numberOfRoutes; s++)
                        {
                            consoleProgress?.Invoke(this, $"maxRoutes[{s}]: {maxRoutes[s].X}, {minRoutes[s].X} , ->{maxRoutes[s].X - minRoutes[s].X}");
                            for (int visitIndex = 0; visitIndex < visitDurations.Length; visitIndex++)
                            {
                                consoleProgress?.Invoke(this, $"c[{s}][{visitIndex}] ({v[s][visitIndex].X}): {c[s][visitIndex].X}");
                            }
                        }
                    }
                    catch (Exception e)
                    {
                        consoleProgress?.Invoke(this, $"ERROR: {e.Message}");
                        output.Routes = new Route[0];
                    }
                }

            return(output);
        }
Example #17
0
        public List <int[]> SolveVRP(int timeLimitMilliseconds)
        {
            using (var env = new GRBEnv($"{DateTime.Now:yy-MM-dd-HH-mm-ss}_vrp_gurobi.log"))
                using (var vrpModel = new GRBModel(env))
                {
                    #region initialize Variables
                    var numberOfRoutes = input.Santas.Length * input.Days.Length;
                    var v = new GRBVar[numberOfRoutes][]; // [santa] visits [visit]
                    var w = new GRBVar[numberOfRoutes][]; // [santa] uses [way]


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

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

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

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

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

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

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

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

                    vrpModel.Reset();
                    return(routes);
                }
        }
Example #18
0
        public SubModelOutputs Build_Model(
            InputData inputData,
            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[] Make = gModel.AddVars(inputData.ProdList.Count * Tlist2.Count * inputData.ScenList.Count, GRB.CONTINUOUS);
                GRBVar[] Inv  = gModel.AddVars(inputData.ProdList.Count * Tlist2.Count * inputData.ScenList.Count, GRB.CONTINUOUS);
                GRBVar[] Sell = gModel.AddVars(inputData.ProdList.Count * Tlist2.Count * inputData.ScenList.Count, GRB.CONTINUOUS);

                //MAKE VARNAME
                inputData.ProdList.ForEach(pl => {
                    Tlist2.ForEach(tl => {
                        inputData.ScenList.ForEach(sl =>
                        {
                            int ixP          = inputData.ProdList.IndexOf(pl);
                            int ixT          = Tlist2.IndexOf(tl);
                            int ixS          = inputData.ScenList.IndexOf(sl);
                            int ix           = ixVar.getIx3(ixP, ixT, ixS, inputData.ProdList.Count, Tlist2.Count, inputData.ScenList.Count);
                            Make[ix].VarName = "MAKE_PROD: " + pl.PROD + " T: " + tl.T + " SCEN: " + sl.SCEN;
                        });
                    });
                });

                //INV VARNAME
                inputData.ProdList.ForEach(pl => {
                    Tlist2.ForEach(tl => {
                        inputData.ScenList.ForEach(sl =>
                        {
                            int ixP         = inputData.ProdList.IndexOf(pl);
                            int ixT         = Tlist2.IndexOf(tl);
                            int ixS         = inputData.ScenList.IndexOf(sl);
                            int ix          = ixVar.getIx3(ixP, ixT, ixS, inputData.ProdList.Count, Tlist2.Count, inputData.ScenList.Count);
                            Inv[ix].VarName = "INV_PROD: " + pl.PROD + " T: " + tl.T + " SCEN: " + sl.SCEN;
                        });
                    });
                });

                //SELL VARNAME
                inputData.ProdList.ForEach(pl => {
                    Tlist2.ForEach(tl => {
                        inputData.ScenList.ForEach(sl =>
                        {
                            int ixP          = inputData.ProdList.IndexOf(pl);
                            int ixT          = Tlist2.IndexOf(tl);
                            int ixS          = inputData.ScenList.IndexOf(sl);
                            int ix           = ixVar.getIx3(ixP, ixT, ixS, inputData.ProdList.Count, Tlist2.Count, inputData.ScenList.Count);
                            Sell[ix].VarName = "SELL_PROD: " + pl.PROD + " T: " + tl.T + " SCEN: " + sl.SCEN;
                        });
                    });
                });

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

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

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

                //SELL <= market[p,t]
                expr1.Clear();
                inputData.ProdList.ForEach(pl => {
                    Tlist2.ForEach(tl => {
                        inputData.ScenList.ForEach(sl => {
                            double market = inputData
                                            .MarketList
                                            .Find(ml =>
                                                  ml.PROD.Equals(pl.PROD) &&
                                                  ml.T.Equals(tl.T)).MARKET;

                            int ixP = inputData.ProdList.IndexOf(pl);
                            int ixT = Tlist2.IndexOf(tl);
                            int ixS = inputData.ScenList.IndexOf(sl);

                            int index = ixVar.getIx3(ixP, ixT, ixS, inputData.ProdList.Count, Tlist2.Count, inputData.ScenList.Count);
                            expr1.Clear();
                            expr1.AddTerm(1, Sell[index]);
                            gModel.AddConstr(expr1, GRB.LESS_EQUAL, market, "<=Market");
                        });
                    });
                });

                //Construir funcion objetivo
                //maximize Stage2_Profit:
                //   sum {s in SCEN} prob[s] *
                //      sum {p in PROD, t in 2..T} (revenue[p,t,s]*Sell[p,t,s] -
                //         prodcost[p]*Make[p,t,s] - invcost[p]*Inv[p,t,s]);
                expr1.Clear();
                inputData.ScenList.ForEach(s =>
                {
                    double prob = inputData.ProbList.Find(x => x.SCEN.Equals(s.SCEN)).PROB;

                    inputData.ProdList.ForEach(p =>
                    {
                        Tlist2.ForEach(tl =>
                        {
                            //SELL
                            double revenue = inputData
                                             .RevenueList
                                             .Find(r =>
                                                   r.PROD.Equals(p.PROD) &&
                                                   r.T.Equals(tl.T) &&
                                                   r.SCEN.Equals(s.SCEN)
                                                   ).REVENUE;

                            double prodCost = inputData
                                              .ProdCostList
                                              .Find(pc =>
                                                    pc.PROD.Equals(p.PROD)
                                                    ).PRODCOST;

                            double invCost = inputData
                                             .InvCostList
                                             .Find(ic =>
                                                   ic.PROD.Equals(p.PROD)
                                                   ).INVCOST;

                            int ixP = inputData.ProdList.IndexOf(p);
                            int ixT = Tlist2.IndexOf(tl);
                            int ixS = inputData.ScenList.IndexOf(s);

                            int indexVar = ixVar.getIx3(ixP, ixT, ixS, inputData.ProdList.Count, Tlist2.Count, inputData.ScenList.Count);

                            expr1.AddTerm(prob * revenue, Sell[indexVar]);
                            expr1.AddTerm(-1 * prob * prodCost, Make[indexVar]);
                            expr1.AddTerm(-1 * prob * invCost, Inv[indexVar]);
                        });
                    });
                });

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

                //Insertar Restricciones

                //subject to Time {t in 2..T, s in SCEN}:
                //sum {p in PROD} (1/rate[p]) * Make[p,t,s] <= avail[t];
                expr1.Clear();
                Tlist2.ForEach(tl => {
                    inputData.ScenList.ForEach(sl =>
                    {
                        inputData.ProdList.ForEach(pl =>
                        {
                            double rate = 1 / inputData.RateList.Find(rl => rl.PROD.Equals(pl.PROD)).RATE;

                            int ixP = inputData.ProdList.IndexOf(pl);
                            int ixT = Tlist2.IndexOf(tl);
                            int ixS = inputData.ScenList.IndexOf(sl);

                            int ixMake = ixVar.getIx3(ixP, ixT, ixS, inputData.ProdList.Count, Tlist2.Count, inputData.ScenList.Count);

                            expr1.AddTerm(rate, Make[ixMake]);
                        });

                        double avail = inputData.AvailList.Find(al => al.T.Equals(tl.T)).AVAIL;
                        gModel.AddConstr(expr1, GRB.LESS_EQUAL, avail, "TIME_" + tl.T + "_" + sl.SCEN);
                    });
                });

                //subject to Balance2 { p in PROD, s in SCEN}:
                //Make[p, 2, s] + inv1[p] = Sell[p, 2, s] + Inv[p, 2, s];
                //2 => index T => 0
                expr1.Clear();
                inputData.ProdList.ForEach(pl =>
                {
                    inputData.ScenList.ForEach(sl =>
                    {
                        int ixP = inputData.ProdList.IndexOf(pl);
                        int ixT = 0;
                        int ixS = inputData.ScenList.IndexOf(sl);
                        int ix  = ixVar.getIx3(ixP, ixT, ixS, inputData.ProdList.Count, Tlist2.Count, inputData.ScenList.Count);

                        double inv1 = subModelParams.inv1.Find(il => il.PROD.Equals(pl.PROD)).INV0;

                        expr1.Clear();
                        expr2.Clear();

                        //como sumar un param ????
                        expr1.AddTerm(1, Make[ix]);
                        //expr1.AddTerm(inv1, null); ???? como??? // Se despeja vars & params
                        expr1.AddTerm(-1, Sell[ix]);
                        expr1.AddTerm(-1, Inv[ix]);

                        gModel.AddConstr(expr1, GRB.EQUAL, inv1, "BALANCE2_" + pl.PROD + "_" + sl.SCEN);
                    });
                });

                //subject to Balance { p in PROD, t in 3..T, s in SCEN}:
                //Make[p, t, s] + Inv[p, t - 1, s] = Sell[p, t, s] + Inv[p, t, s];

                inputData.ProdList.ForEach(pl =>
                {
                    Tlist3.ForEach(tl =>
                    {
                        inputData.ScenList.ForEach(sl =>
                        {
                            int ixP = inputData.ProdList.IndexOf(pl);
                            int ixT = Tlist2.IndexOf(tl);
                            int ixS = inputData.ScenList.IndexOf(sl);
                            int ix  = ixVar.getIx3(ixP, ixT, ixS, inputData.ProdList.Count, Tlist2.Count, inputData.ScenList.Count);
                            int ix2 = ixVar.getIx3(ixP, ixT - 1, ixS, inputData.ProdList.Count, Tlist2.Count, inputData.ScenList.Count);

                            expr1.Clear();
                            expr2.Clear();

                            expr1.AddTerm(1, Make[ix]);
                            expr1.AddTerm(1, Inv[ix2]);

                            expr2.AddTerm(1, Sell[ix]);
                            expr2.AddTerm(1, Inv[ix]);

                            gModel.AddConstr(expr1, GRB.EQUAL, expr2, "SUBJECT TO BALANCE");
                        });
                    });
                });

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

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

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

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

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

                    SubModelOutputs smo = new SubModelOutputs()
                    {
                        make         = Make,
                        sell         = Sell,
                        inv          = Inv,
                        stage2Profit = gModel.ObjVal,
                        gModel       = gModel
                    };

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

                    return(smo);
                }
                catch { Console.WriteLine("ERROR SOLVING THE MODEL"); }

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

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


            return(new SubModelOutputs());
        }
        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());
        }
 public static GRBVar[] AddVars(this GRBModel _m, int _count, double lb, double ub, char type, string _prefix = null)
 {
     return(_m.AddVars(Enumerable.Repeat(lb, _count).ToArray(), Enumerable.Repeat(ub, _count).ToArray(), null, Enumerable.Repeat(type, _count).ToArray(),
                       _prefix == null ? null : Enumerable.Range(0, _count).Select(i => $"{_prefix}[{i}]").ToArray()
                       ));
 }
Example #21
0
 private void CreateBatchSizeVariables()
 {
     variables.batch_size = model.AddVars(num_periods, GRB.INTEGER);
 }
Example #22
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();
        }
Example #23
0
        public override Schedule Generate(Scenario scenario, FilledBaseline baseline = null)
        {
            var batches          = scenario.Projects.SelectMany(p => p.Batches).OrderBy(b => b.Compatibility).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.
            int       maxWeek      = (lastDate - earliestDate).Days / 7;                                                       // 0 to 200
            const int weeksBuffer  = 3;

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


            var env = new GRBEnv();

            env.Set(GRB.IntParam.LogToConsole, 1);
            //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
            // TODO: Batch can be over two weeks
            var varBatchWeekLine1 = m.AddVars(batchesBothLines.Count() + batchesLine1.Count(), maxWeek, 0, 1, GRB.BINARY, "batchWeekLine1");
            var varBatchWeekLine2 = m.AddVars(batchesBothLines.Count() + batchesLine2.Count(), maxWeek, 0, 1, GRB.BINARY, "batchWeekLine2");

            m.Update();

            // 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 ? varBatchWeekLine1 : varBatchWeekLine2;
                for (int bi = bBc; bi < line.GetLength(0); bi++)
                {
                    var batchTotal = new GRBLinExpr();
                    for (int w = 0; w < maxWeek; w++)
                    {
                        batchTotal += line[bi, w];
                    }
                    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 w = 0; w < maxWeek; w++)
                {
                    batchTotal += varBatchWeekLine1[bi, w];
                    batchTotal += varBatchWeekLine2[bi, w];
                }
                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");
                }
            }


            // 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?
            var varLineDecision = m.AddVars(scenario.Projects.Count(), 0, 1, GRB.BINARY, "varLineDecision");

            m.Update();
            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;
                }

                var sumBatchLine1 = new GRBLinExpr();
                var sumBatchLine2 = new GRBLinExpr();
                int i             = batches.IndexOf(p.Batches.First());
                for (int j = 0; j < p.Batches.Count(); j++)
                {
                    if (p.Batches[j].Compatibility != Batch.LineCompatibility.Both)
                    {
                        continue;
                    }

                    for (int w = 0; w < maxWeek; w++)
                    {
                        sumBatchLine1 += varBatchWeekLine1[i + j, w];
                        sumBatchLine2 += varBatchWeekLine2[i + j, w];
                    }
                }
                m.AddConstr(sumBatchLine1 <= (1 - varLineDecision[pi]) * GRB.INFINITY);
                m.AddConstr(sumBatchLine2 <= varLineDecision[pi] * GRB.INFINITY);
            }

            // on each line the total of a week must not exceed 24*7
            for (int l = 0; l < 2; l++)
            {
                var lineVars = l == 0 ? varBatchWeekLine1 : varBatchWeekLine2;
                var line     = l == 0 ? batchesLine1 : batchesLine2;
                int bBC      = batchesBothLines.Count();

                for (int w = 0; w < maxWeek; w++)
                {
                    var weekTotal = new GRBLinExpr();
                    for (int b = 0; b < lineVars.GetLength(0); b++)
                    {
                        var batch = b < bBC ? batchesBothLines[b] : line[b - bBC];

                        weekTotal += lineVars[b, w] * batch.UsedWorkHours;

                        /*var test = new GRBLinExpr();
                         * test += (lineVars[b] == w) * 0.1;
                         * (l[b] - w) * batch.UsedWorkHours*/
                    }
                    m.AddConstr(weekTotal <= 24 * 7);
                }
            }

            // 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 w = 0; w < maxWeek; w++)
                        {
                            batchTotal += varBatchWeekLine1[bIndex, w];
                        }
                    }
                    else if (b.Compatibility == Batch.LineCompatibility.Line2)
                    {
                        var bIndex = bBc + batchesLine2.IndexOf(b);
                        for (int w = 0; w < maxWeek; w++)
                        {
                            batchTotal += varBatchWeekLine2[bIndex, w];
                        }
                    }
                    else
                    {
                        var bIndex = batchesBothLines.IndexOf(b);
                        for (int w = 0; w < maxWeek; w++)
                        {
                            batchTotal += varBatchWeekLine1[bIndex, w];
                            batchTotal += varBatchWeekLine2[bIndex, w];
                        }
                    }

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

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

            // DEPRECATED: penalty/interest term adds this constraint with slack
            // in-between batches of the same project, 3 weeks distance should exist, otherwise there will be a penalty

            /*foreach (var p in scenario.Projects)
             * {
             *  var bCompatibility = p.Batches.First().Compatibility;
             *
             *  // for all batches of this project make sure that the previous one is at least (3 + 1) weeks away
             *  // in other words: the total of batches within (3 + 1) weeks must be 4 at least.
             *  for (int w = 0; w < maxWeek - weeksBuffer; w++)
             *  {
             *      var batchTotalOver4Weeks = new GRBLinExpr();
             *      // sum all batches over a 4 week period
             *      for (int i = 0; i <= weeksBuffer; i++)
             *      {
             *          foreach (var b in p.Batches)
             *          {
             *              if (bCompatibility == Batch.LineCompatibility.Line1)
             *              {
             *                  batchTotalOver4Weeks += varBatchWeekLine1[bBc + batchesLine1.IndexOf(b), w + i];
             *              }
             *              else if (bCompatibility == Batch.LineCompatibility.Line2)
             *              {
             *                  batchTotalOver4Weeks += varBatchWeekLine2[bBc + batchesLine2.IndexOf(b), w + i];
             *              }
             *              else
             *              {
             *                  var bIndex = batchesBothLines.IndexOf(b);
             *                  batchTotalOver4Weeks += varBatchWeekLine1[bIndex, w + i];
             *                  batchTotalOver4Weeks += varBatchWeekLine2[bIndex, w + i];
             *              }
             *          }
             *      }
             *      m.AddConstr(batchTotalOver4Weeks <= 1);
             *  }
             * }*/

            // 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



            // Maximize the margin (including delay and interest penalties) and the workload
            // TODO: Only first one important? no delay otherwise?
            var margin = new GRBLinExpr();

            foreach (var p in scenario.Projects)
            {
                // if the project is used add the margin
                margin += totalBatchesOfProject[p].First() * p.Margin;

                // deduct the delay penalty for each batch.
                int startWeekOfProject = (p.DeliveryDate - earliestDate).Days / 7;
                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 bi = 0; bi < p.Batches.Count(); bi++)
                {
                    var b = p.Batches[bi];
                    // compare the minimal batch time (3 + 1 weeks) to the actual delivery time
                    var weekValue = new GRBLinExpr();
                    if (b.Compatibility == Batch.LineCompatibility.Line1)
                    {
                        var bIndex = bBc + batchesLine1.IndexOf(b);
                        for (int w = 0; w < maxWeek; w++)
                        {
                            weekValue += varBatchWeekLine1[bIndex, w] * w;
                        }
                    }
                    else if (b.Compatibility == Batch.LineCompatibility.Line2)
                    {
                        var bIndex = bBc + batchesLine2.IndexOf(b);
                        for (int w = 0; w < maxWeek; w++)
                        {
                            weekValue += varBatchWeekLine2[bIndex, w] * w;
                        }
                    }
                    else
                    {
                        var bIndex = batchesBothLines.IndexOf(b);
                        for (int w = 0; w < maxWeek; w++)
                        {
                            weekValue += varBatchWeekLine1[bIndex, w] * w;
                            weekValue += varBatchWeekLine2[bIndex, w] * w;
                        }
                    }

                    if (bi < p.Batches.Count() - 1)
                    {
                        // for positive difference add delay penalty, for negative difference add interest penalty
                        // var = max(0, x)
                        // var * delay
                        // (x - var) * interest
                        var plannedWeek = startWeekOfProject + bi * (weeksBuffer + 1);
                        var weekDiff    = weekValue - plannedWeek * totalBatchesOfProject[p].First(); // here we multiply the planned week with the (0/1)-allocation-indicator to avoid penalties when the project is not assigned (and therefore weekValue = 0)
                        m.AddConstr(varMaxedValue[bi] >= weekDiff);
                        m.AddConstr(varMaxedValue[bi] >= 0);
                        m.AddConstr(varMaxedValue[bi] <= weekDiff + maxWeek * (varDecisionVar[bi]));
                        m.AddConstr(varMaxedValue[bi] <= 0 + maxWeek * (1 - varDecisionVar[bi]));

                        double firstBatchImportance = bi == 0 ? 1 : 0.2; // mainly the first batch is important, the rest is meh

                        margin += varMaxedValue[bi] * delayPenaltyMultiplier * firstBatchImportance;
                        margin += (weekDiff - varMaxedValue[bi]) * interestPenaltyMultiplier * firstBatchImportance;
                    }

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



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

            m.Optimize();

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


            // build the solution from the optimization
            var sol = new Schedule();

            foreach (var p in scenario.Projects)
            {
                List <Schedule.BatchAllocation> allocatedBatches = new List <Schedule.BatchAllocation>();
                for (int bi = 0; bi < p.Batches.Count(); bi++)
                {
                    var b = p.Batches[bi];
                    // figure out on which week and which line the batch is allocated
                    int weekLine1 = 0;
                    int weekLine2 = 0;
                    if (b.Compatibility == Batch.LineCompatibility.Line1)
                    {
                        for (int w = 1; w <= maxWeek; w++)
                        {
                            weekLine1 += (int)varBatchWeekLine1[bBc + batchesLine1.IndexOf(b), w - 1].Get(GRB.DoubleAttr.X) * w;
                        }
                    }
                    else if (b.Compatibility == Batch.LineCompatibility.Line2)
                    {
                        for (int w = 1; w <= maxWeek; w++)
                        {
                            weekLine2 += (int)varBatchWeekLine2[bBc + batchesLine2.IndexOf(b), w - 1].Get(GRB.DoubleAttr.X) * w;
                        }
                    }
                    else
                    {
                        for (int w = 1; w <= maxWeek; w++)
                        {
                            weekLine1 += (int)varBatchWeekLine1[batchesBothLines.IndexOf(b), w - 1].Get(GRB.DoubleAttr.X) * w;
                            weekLine2 += (int)varBatchWeekLine2[batchesBothLines.IndexOf(b), w - 1].Get(GRB.DoubleAttr.X) * w;
                        }
                    }

                    if (weekLine1 > 0 && weekLine2 > 0)
                    {
                        throw new InvalidOperationException();
                    }

                    var alloc = Schedule.LineAllocation.None;
                    if (weekLine1 > 0)
                    {
                        alloc = Schedule.LineAllocation.Line1;
                    }
                    if (weekLine2 > 0)
                    {
                        alloc = Schedule.LineAllocation.Line2;
                    }

                    allocatedBatches.Add(new Schedule.BatchAllocation(b, alloc, earliestDate.AddDays(weekLine1 + weekLine2 - 1)));
                }
                sol.Add(new Schedule.ProjectAllocation(p, allocatedBatches));
            }

            return(sol);
        }
    dense_optimize(GRBEnv env,
                   int rows,
                   int cols,
                   double[]  c,      // linear portion of objective function
                   double[,] Q,      // quadratic portion of objective function
                   double[,] A,      // constraint matrix
                   char[]    sense,  // constraint senses
                   double[]  rhs,    // RHS vector
                   double[]  lb,     // variable lower bounds
                   double[]  ub,     // variable upper bounds
                   char[]    vtype,  // variable types (continuous, binary, etc.)
                   double[]  solution)
    {
        bool success = false;

        try {
            GRBModel model = new GRBModel(env);

            // Add variables to the model

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

            // Populate A matrix

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

            // Populate objective

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

            // Solve model

            model.Optimize();

            // Extract solution

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

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

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

        return(success);
    }
        static void Main(string[] args)
        {
            GRBEnv   env   = new GRBEnv("TJLinearCharacter.log");
            GRBModel model = new GRBModel(env);

            //declare the iv variables and key variables
            GRBVar[] keyvar = model.AddVars(80, GRB.BINARY);    //declare the assignment variables of key variables
            GRBVar[] ivvar  = model.AddVars(80, GRB.BINARY);    //declare the assignment variables of iv variables
            GRBVar[] kvf    = model.AddVars(80, GRB.BINARY);    //declare the flag variables of key variables
            GRBVar[] vvf    = model.AddVars(80, GRB.BINARY);    //declare the flag variables of iv variables

            GRBVar[] Uvar = model.AddVars(8000, GRB.BINARY);    //interval assignment variables used to long XOR expression into short ones y=k1+k2+k3+k4--> u1=k1+k2, u2=k3+k4, y=u1+u2
            GRBVar[] Vvar = model.AddVars(8000, GRB.INTEGER);   //interval variables
            GRBVar[] Wvar = model.AddVars(8000, GRB.BINARY);    //interval variables

            GRBVar[] UFvar = model.AddVars(8000, GRB.BINARY);   //UFvar[i] is the flag variables corresponding to Uvar[i]
            GRBVar[] NUvar = model.AddVars(8000, GRB.BINARY);   //NUvar[i]= 1-Uvar[i]
            GRBVar[] NUFvar = model.AddVars(8000, GRB.BINARY);  //NUFvar[i]= 1-UFvar[i]
            GRBVar[] Consvar = model.AddVars(8000, GRB.BINARY); //constant variables
            GRBVar[] bvar = model.AddVars(8000, GRB.BINARY);    //b variables
            int      i, j, k;
            int      loc0 = 0, loc1 = 0, loc2 = 0, loc3 = 0, loc4 = 0, locb = 0;
            int      locf = 0;
            int      con  = 0;

            // name all the variables used in this MILP model
            for (i = 0; i < keyvar.Length; i++)
            {
                keyvar[i].VarName = "k" + i.ToString();
                ivvar[i].VarName  = "v" + i.ToString();
                kvf[i].VarName    = "kf" + i.ToString();
                vvf[i].VarName    = "vf" + i.ToString();
            }
            for (i = 0; i < Uvar.Length; i++)
            {
                Uvar[i].VarName    = "U" + i.ToString();
                Wvar[i].VarName    = "W" + i.ToString();
                UFvar[i].VarName   = "UF" + i.ToString();
                Vvar[i].VarName    = "V" + i.ToString();
                NUvar[i].VarName   = "NU" + i.ToString();
                NUFvar[i].VarName  = "NUF" + i.ToString();
                bvar[i].VarName    = "b" + i.ToString();
                Consvar[i].VarName = "cons" + i.ToString();
            }

            UInt32[, ,] ConS = new UInt32[1000, 200, 6];//used to store the conditions derived to control the propagation of difference
            int[] conlen   = new int[1000];
            int[] consflag = new int[1000];
            int[] rec_loc1 = new int[1000];
            int[] rec_locf = new int[1000];

            //the number of the conditions
            int consnum = 652;

            int[] loc        = new int[2];
            int[] locw       = new int[1];
            int[] condiassig = new int[consnum];
            int[] condiflag  = new int[consnum];

            GRBLinExpr Tar     = new GRBLinExpr();//declare the target linear expression, which is used as the objective function
            List <int> indlist = new List <int>()
            {
            };
            List <GRBVar> Varlist = new List <GRBVar>()
            {
            };
            List <GRBVar> VarlistCopy = new List <GRBVar>()
            {
            };
            List <GRBVar> VarFlaglist = new List <GRBVar>()
            {
            };
            //List<GRBVar> VarFlaglistCopy = new List<GRBVar>() { };
            StreamWriter sw = new StreamWriter("FinalCons.txt");
            //the index of cube variables
            List <int> cube = new List <int>()
            {
                0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48, 51, 54, 57, 60, 63, 66, 69, 72, 75, 78
            };

            //set the state of cube variables to \delta
            for (i = 0; i < cube.Count; i++)
            {
                model.AddConstr(vvf[cube[i]] == 1, "iniiv" + (cube[i]).ToString());
            }

            //set the contraints between an assigment variable and the corresponding flag variable
            for (i = 0; i < 80; i++)
            {
                model.AddConstr(keyvar[i] <= 1 - kvf[i], "keyflagrel");
                model.AddConstr(ivvar[i] <= 1 - vvf[i], "ivflagrel");
            }
            model.Update();

            //read the derived constraints from the file
            ReadCondition(ConS, conlen, consflag);
            Console.Write("ReadConditionDone\n");

            //model each condition
            for (i = 0; i < consnum; i++)
            {
                loc[0] = loc1;
                loc[1] = locf;
                VarFlaglist.Clear();
                Varlist.Clear();
                //linearize a condition and return a list of involved variables.

                //In this condition, for condition f, it would linearize it and would return the assignment/flag variable of each monomial in f;
                //In paticular, Uvar[0],Uvar[1],...,Uvar[m-1] are the assignment variables of the linearized monomials
                //UFvar[0],UFvar[1],...,UFvar[m-1] are the flag variables of the linearized monomials
                //For eaxmple, for a condition f=k1+k2*k3+k4, it can be linearized as f=u1+u2+u3 where u2=k2k3.
                //Then, Varlist[0],Varlist[1],Varlist[2] are assignment variables of u1,u2,u3
                //and VarFlaglist[0],VarFlaglist[1],...,VarFlaglist[2] are the flag variables of u1,u2,u3
                Varlist = LinearConstrain(model, Uvar, UFvar, ConS, conlen, i, keyvar, ivvar, loc, kvf, vvf, Wvar, locw, VarFlaglist);
                loc1    = loc[0];
                locf    = loc[1];
                //here a condition f is linearized and so it is the XOR of several variables.
                //in the following, we would determine the assigment varible and flag variable of f
                // and we denote the assigment variable and flag variable of f by f_av and f_fv respectively for short.

                //The target expression 'Tar' is determined according to the assigment variable and flag variable of each condition f
                //In particular, Tar= sum(f in Conset) f_av +(-10000)*f_fv, where Conset is the set of conditions.

                //If the size of f is 1(excluding the constant), namely f consists of only one variable, then we do not need extra operations.
                if (Varlist.Count == 1)
                {
                    //if consflag[i]=1, then it means that there is a constant 1 in f.
                    //In this case, we add (-1.0*f_av) to Tar and increase con by 1 which is added to Tar in the end.
                    if (consflag[i] == 1)
                    {
                        Tar.AddTerm(-1.0, Varlist[0]);
                        con++;
                    }
                    else
                    {
                        Tar.AddTerm(1.0, Varlist[0]);
                    }
                    //add -10000*f_fv to Tar
                    Tar.AddTerm(-10000, VarFlaglist[0]);
                    rec_loc1[i] = loc1;
                    rec_locf[i] = locf;
                }

                //If f is the XOR of two variables(assumin that f=u1+u2+c), where c is a constant in {0,1}.
                //then we shoule calclate f_av and f_fv according to (u1_av, u2_av) and (u1_fv, u2_fv).
                if (Varlist.Count == 2)
                {
                    VarlistCopy.Clear();
                    GRBVar[] VarFlaglistCopy = new GRBVar[3];
                    GRBVar[] Vartemplist     = new GRBVar[4];
                    //copy Varlist/VarFlaglist to VarlistCopy/VarFlaglistCopy
                    for (j = 0; j < Varlist.Count(); j++)
                    {
                        VarlistCopy.Add(Varlist[j]);
                        VarFlaglistCopy[j] = VarFlaglist[j];
                    }
                    VarlistCopy.Add(Uvar[loc1]);

                    //model u1_av+u2_av. Here, VarlistCopy[0]and VarlistCoyp[1] are u1_av and u2_av respectively.
                    AddCons2Vars(model, VarlistCopy);
                    //model u1_av+u2_av+c. if consflag[i]=1, then c is 1. In this case, we add an constant variable Consvar[loc0] to the model
                    //and model u1_av+u2_av+c.
                    if (consflag[i] == 1)
                    {
                        model.AddConstr(Consvar[loc0++] == 1, "Flip" + j.ToString());
                        VarlistCopy[0] = Uvar[loc1];
                        VarlistCopy[1] = Consvar[loc0 - 1];
                        VarlistCopy[2] = Uvar[loc1 + 1];
                        //Console.WriteLine("*****\n" + loc1 + "\n******\n" + loc0 + "\n*****\n");
                        loc1++;
                        AddCons2Vars(model, VarlistCopy);
                    }

                    //until now, Uvar[loc1] is corresponding to beta_d in Proposition 2 of our paper.
                    //Then, we shall show how to obtain the final assignment/flag variable of f.

                    //UF flip the variables
                    model.AddConstr(NUvar[loc3++] == 1 - VarFlaglist[0], "Flip1" + (loc3).ToString());
                    model.AddConstr(NUvar[loc3++] == 1 - VarFlaglist[1], "Flip2" + (loc3).ToString());
                    VarFlaglistCopy[0] = NUvar[loc3 - 1];
                    VarFlaglistCopy[1] = VarFlaglist[0];
                    //Vvar[loc2++]=min(1 - VarFlaglist[1], VarFlaglist[0]). Vvar[loc2] corresponds to T_j in Proposition 2.
                    model.AddGenConstrMin(Vvar[loc2++], VarFlaglistCopy, 1000, "FlagTransOxr1" + loc2.ToString());
                    VarFlaglistCopy[0] = NUvar[loc3 - 2];
                    VarFlaglistCopy[1] = VarFlaglist[1];
                    //Vvar[loc2++]=min(1 - VarFlaglist[0], VarFlaglist[1]). Vvar[loc2] corresponds to T_j in Proposition 2.
                    model.AddGenConstrMin(Vvar[loc2++], VarFlaglistCopy, 1000, "FlagTransOxr2" + loc2.ToString());
                    //UFvar[loc1]=Vvar[loc2-1]+Vvar[loc2-2], UFvar[loc1] is the flag variable of f
                    // model.AddConstr(UFvar[loc1] == Vvar[loc2 - 1] + Vvar[loc2 - 2], "FlagTransOxr3" + loc2.ToString());
                    for (j = 0; j < Varlist.Count; j++)
                    {
                        Vartemplist[j] = Vvar[loc2 - 1 - j];
                    }
                    //UFvar[locf]=max(Vvar[loc2],Vvar[loc2-1],...,). is equivalent to UFvar[locf]= Vvar[loc2]+Vvar[loc2-1]+...+
                    //since only one of Vvar[loc2],Vvar[loc2-1],..., is equal to 1.
                    //UFvar[locf] is the flag variable of f, corresponding to F_d in Proposition 2.
                    model.AddGenConstrMax(UFvar[locf], Vartemplist, 0, "FlagTransXor-2" + loc2.ToString());

                    //NUFvar[loc4] =1-UFvar[loc1] and increase loc4 by 1. NUFvar[loc4] corresponds to 1-F_d in Proposition 2.
                    model.AddConstr(NUFvar[loc4++] == 1 - UFvar[locf], "Flip3" + loc4.ToString());
                    //max(u1_fv,u2_fv). bvar[locb] corresponds to b_d in Proposition 2.
                    VarFlaglistCopy[0] = VarFlaglist[0];
                    VarFlaglistCopy[1] = VarFlaglist[1];
                    model.AddGenConstrMax(bvar[locb++], VarFlaglistCopy, 0, "maxfv" + locb.ToString());

                    //NUFvar[loc4] =1-bvar[locb++] and increase loc4 by 1. NUFvar[loc4] corresponds to 1-b_d in Proposition 2.
                    model.AddConstr(NUFvar[loc4++] == 1 - bvar[locb - 1], "Flip3" + loc4.ToString());

                    VarFlaglistCopy[0] = NUFvar[loc4 - 1]; //corresponding to 1-F_d
                    VarFlaglistCopy[1] = NUFvar[loc4 - 2]; //corresponding to 1-b_d
                    VarFlaglistCopy[2] = Uvar[loc1];       //corresponding to beta_d
                    loc1++;
                    //Uvar[loc1]=min(NUFvar[loc4-1],NUFvar[loc4-2],loc1), is the  assigment variable of f.
                    model.AddGenConstrMin(Uvar[loc1], VarFlaglistCopy, 1000, "minav" + loc1.ToString());
                    //model.Update();
                    Tar.AddTerm(1.0, Uvar[loc1]);

                    Tar.AddTerm(-10000, UFvar[locf]);
                    rec_loc1[i] = loc1;
                    rec_locf[i] = locf;
                    loc1++;
                    locf++;
                }
                //in this case, assume that f=u1+u2+u3+c
                if (Varlist.Count == 3)
                {
                    VarlistCopy.Clear();
                    GRBVar[] VarFlaglistCopy  = new GRBVar[4];
                    GRBVar[] VarFlaglistCopy2 = new GRBVar[4];
                    GRBVar[] Vartemplist      = new GRBVar[4];
                    for (j = 0; j < Varlist.Count(); j++)
                    {
                        VarlistCopy.Add(Varlist[j]);
                        VarFlaglistCopy[j] = VarFlaglist[j];
                    }
                    VarlistCopy.Add(Uvar[loc1]);
                    //Uvar[loc1]=u1+u2+u3
                    AddCons3Vars(model, VarlistCopy);
                    //model.AddGenConstrMax(UFvar[loc1], VarFlaglistCopy, 0, "TransFlagXor" + loc1.ToString());

                    //if c==1, namely f has the constant term 1, U[loc1+1]=Uvar[loc]+1
                    if (consflag[i] == 1)
                    {
                        model.AddConstr(Consvar[loc0++] == 1, "Flip" + j.ToString());
                        VarlistCopy[0] = Uvar[loc1];
                        VarlistCopy[1] = Consvar[loc0 - 1];
                        VarlistCopy[2] = Uvar[loc1 + 1];
                        loc1++;
                        AddCons2Vars(model, VarlistCopy);
                    }

                    //filp every variable,
                    for (j = 0; j < Varlist.Count; j++)
                    {
                        model.AddConstr(NUvar[loc3++] == 1 - VarFlaglistCopy[j], "Flip" + j.ToString());
                    }
                    //
                    for (j = 0; j < Varlist.Count; j++)
                    {
                        for (k = 0; k < Varlist.Count; k++)
                        {
                            if (k != j)
                            {
                                Vartemplist[k] = NUvar[loc3 - 1 - (Varlist.Count - 1 - k)];
                            }
                            else
                            {
                                Vartemplist[k] = VarFlaglistCopy[k];
                            }
                        }
                        //Vvar[loc2]=min(1-VarFlaglistCopy[0],1-VarFlaglistCopy[2],...,VarFlaglistCopy[j],1-VarFlaglistCopy[j],...)
                        model.AddGenConstrMin(Vvar[loc2++], Vartemplist, 1000, "FlagTransOxr1" + loc2.ToString());
                    }

                    for (j = 0; j < Varlist.Count; j++)
                    {
                        Vartemplist[j] = Vvar[loc2 - 1 - j];
                    }
                    //Since only one of Vvar[loc2 - 1],Vvar[loc2 - 2],..., is equal to 0 and the remainings are equal to 0s,
                    //UFvar[loc1]=max(Vvar[loc2 - 1],Vvar[loc2 - 2],...,) is equivalently to UFvar[loc1]=Vvar[loc2 - 1]+Vvar[loc2 - 2]+...+
                    //UFvar[loc1]is the fianl flag variable of f
                    model.AddGenConstrMax(UFvar[locf], Vartemplist, 0, "FlagTransXor-2" + loc2.ToString());


                    //NUFvar[loc4] =1-UFvar[loc1] and increase loc4 by 1
                    model.AddConstr(NUFvar[loc4++] == 1 - UFvar[locf], "Flip3" + loc4.ToString());
                    //max(u1_fv,u2_fv,u3_fv)
                    VarFlaglistCopy[0] = VarFlaglist[0];
                    VarFlaglistCopy[1] = VarFlaglist[1];
                    VarFlaglistCopy[2] = VarFlaglist[2];
                    model.AddGenConstrMax(bvar[locb++], VarFlaglistCopy, 0, "maxfv" + locb.ToString());

                    //NUFvar[loc4] =1-bvar[locb++] and increase loc4 by 1
                    model.AddConstr(NUFvar[loc4++] == 1 - bvar[locb - 1], "Flip3" + loc4.ToString());

                    VarFlaglistCopy2[0] = NUFvar[loc4 - 1];
                    VarFlaglistCopy2[1] = NUFvar[loc4 - 2];
                    VarFlaglistCopy2[2] = Uvar[loc1];
                    loc1++;
                    //Uvar[loc1]=min(NUFvar[loc4-1],NUFvar[loc4-2],loc1), is the  assigment variable of f.
                    model.AddGenConstrMin(Uvar[loc1], VarFlaglistCopy2, 1000, "min_av" + loc1.ToString());


                    Tar.AddTerm(1.0, Uvar[loc1]);
                    Tar.AddTerm(-10000, UFvar[locf]);
                    rec_loc1[i] = loc1;
                    rec_locf[i] = locf;
                    loc1++;
                    locf++;
                }
                //assuming f=u1+u2+u3+u4+c
                if (Varlist.Count == 4)
                {
                    List <GRBVar> templist = new List <GRBVar>()
                    {
                    };
                    GRBVar[] VarFlaglistCopy  = new GRBVar[5];
                    GRBVar[] VarFlaglistCopy2 = new GRBVar[5];
                    GRBVar[] Vartemplist      = new GRBVar[5];

                    for (j = 0; j < Varlist.Count(); j++)
                    {
                        VarFlaglistCopy[j] = VarFlaglist[j];
                    }

                    templist.Add(Varlist[0]);
                    templist.Add(Varlist[1]);
                    templist.Add(Uvar[loc1]);
                    AddCons2Vars(model, templist);

                    templist.Clear();
                    loc1++;
                    templist.Add(Varlist[2]);
                    templist.Add(Varlist[3]);
                    templist.Add(Uvar[loc1]);
                    AddCons2Vars(model, templist);


                    templist.Clear();
                    loc1++;
                    templist.Add(Uvar[loc1 - 2]);
                    templist.Add(Uvar[loc1 - 1]);
                    templist.Add(Uvar[loc1]);
                    AddCons2Vars(model, templist);

                    //if c==1
                    if (consflag[i] == 1)
                    {
                        model.AddConstr(Consvar[loc0++] == 1, "Flip" + j.ToString());
                        VarlistCopy[0] = Uvar[loc1];
                        VarlistCopy[1] = Consvar[loc0 - 1];
                        VarlistCopy[2] = Uvar[loc1 + 1];
                        loc1++;
                        AddCons2Vars(model, VarlistCopy);
                    }


                    for (j = 0; j < Varlist.Count; j++)
                    {
                        model.AddConstr(NUvar[loc3++] == 1 - VarFlaglistCopy[j], "Flip" + j.ToString());
                    }

                    for (j = 0; j < Varlist.Count; j++)
                    {
                        for (k = 0; k < Varlist.Count; k++)
                        {
                            if (k != j)
                            {
                                Vartemplist[k] = NUvar[loc3 - 1 - (Varlist.Count - 1 - k)];
                            }
                            else
                            {
                                Vartemplist[k] = VarFlaglistCopy[k];
                            }
                        }
                        model.AddGenConstrMin(Vvar[loc2++], Vartemplist, 1000, "FlagTransOxr1" + loc2.ToString());
                    }

                    for (j = 0; j < Varlist.Count; j++)
                    {
                        Vartemplist[j] = Vvar[loc2 - 1 - j];
                    }
                    model.AddGenConstrMax(UFvar[locf], Vartemplist, 0, "FlagTransXor-2" + loc2.ToString());

                    //NUFvar[loc4] =1-UFvar[loc1] and increase loc4 by 1
                    model.AddConstr(NUFvar[loc4] == 1 - UFvar[locf], "Flip3" + loc4.ToString());
                    loc4++;
                    //max(u1_fv,u2_fv,u3_fv,u4_fv)
                    VarFlaglistCopy[0] = VarFlaglist[0];
                    VarFlaglistCopy[1] = VarFlaglist[1];
                    VarFlaglistCopy[2] = VarFlaglist[2];
                    VarFlaglistCopy[3] = VarFlaglist[3];
                    model.AddGenConstrMax(bvar[locb++], VarFlaglistCopy, 0, "maxfv" + locb.ToString());

                    //NUFvar[loc4] =1-bvar[locb++] and increase loc4 by 1
                    model.AddConstr(NUFvar[loc4] == 1 - bvar[locb - 1], "Flip4" + loc4.ToString());
                    loc4++;
                    //VarFlaglistCopy.Initialize();

                    VarFlaglistCopy2[0] = NUFvar[loc4 - 1];
                    VarFlaglistCopy2[1] = NUFvar[loc4 - 2];
                    VarFlaglistCopy2[2] = Uvar[loc1];
                    loc1++;

                    //Uvar[loc1]=min(NUFvar[loc4-1],NUFvar[loc4-2],loc1), is the  assigment variable of f.
                    model.AddGenConstrMin(Uvar[loc1], VarFlaglistCopy2, 1000, "min_av" + loc1.ToString());

                    //Tar=Tar+assigment variable +(-10000)*flag variable
                    Tar.AddTerm(1.0, Uvar[loc1]);
                    Tar.AddTerm(-10000, UFvar[locf]);
                    rec_loc1[i] = loc1;
                    rec_locf[i] = locf;
                    loc1++;
                    locf++;
                }
                //assuming f=u1+u2+u3+u4+u5+c
                if (Varlist.Count == 5)
                {
                    List <GRBVar> templist = new List <GRBVar>()
                    {
                    };
                    GRBVar[] VarFlaglistCopy  = new GRBVar[6];
                    GRBVar[] VarFlaglistCopy2 = new GRBVar[6];
                    GRBVar[] Vartemplist      = new GRBVar[6];

                    for (j = 0; j < Varlist.Count(); j++)
                    {
                        VarFlaglistCopy[j] = VarFlaglist[j];
                    }

                    templist.Add(Varlist[0]);
                    templist.Add(Varlist[1]);
                    templist.Add(Uvar[loc1]);
                    AddCons2Vars(model, templist);

                    templist.Clear();
                    loc1++;
                    templist.Add(Varlist[2]);
                    templist.Add(Varlist[3]);
                    templist.Add(Varlist[4]);
                    templist.Add(Uvar[loc1]);
                    AddCons3Vars(model, templist);


                    templist.Clear();
                    loc1++;
                    templist.Add(Uvar[loc1 - 2]);
                    templist.Add(Uvar[loc1 - 1]);
                    templist.Add(Uvar[loc1]);
                    AddCons2Vars(model, templist);


                    if (consflag[i] == 1)
                    {
                        model.AddConstr(Consvar[loc0++] == 1, "Flip" + j.ToString());
                        VarlistCopy[0] = Uvar[loc1];
                        VarlistCopy[1] = Consvar[loc0 - 1];
                        VarlistCopy[2] = Uvar[loc1 + 1];
                        loc1++;
                        AddCons2Vars(model, VarlistCopy);
                    }

                    for (j = 0; j < Varlist.Count; j++)
                    {
                        model.AddConstr(NUvar[loc3++] == 1 - VarFlaglistCopy[j], "Flip" + j.ToString());
                    }
                    //flip and calculate Tj
                    for (j = 0; j < Varlist.Count; j++)
                    {
                        for (k = 0; k < Varlist.Count; k++)
                        {
                            if (k != j)
                            {
                                Vartemplist[k] = NUvar[loc3 - 1 - (Varlist.Count - 1 - k)];
                            }
                            else
                            {
                                Vartemplist[k] = VarFlaglistCopy[k];
                            }
                        }
                        model.AddGenConstrMin(Vvar[loc2++], Vartemplist, 1000, "FlagTransOxr1" + loc2.ToString());
                    }
                    //
                    for (j = 0; j < Varlist.Count; j++)
                    {
                        Vartemplist[j] = Vvar[loc2 - 1 - j];
                    }
                    model.AddGenConstrMax(UFvar[locf], Vartemplist, 0, "FlagTransXor-2" + loc2.ToString());


                    //NUFvar[loc4] =1-UFvar[loc1] and increase loc4 by 1
                    model.AddConstr(NUFvar[loc4++] == 1 - UFvar[locf], "Flip3" + loc4.ToString());
                    //max(u1_fv,u2_fv,u3_fv,u4_fv,u5_fv)
                    VarFlaglistCopy[0] = VarFlaglist[0];
                    VarFlaglistCopy[1] = VarFlaglist[1];
                    VarFlaglistCopy[2] = VarFlaglist[2];
                    VarFlaglistCopy[3] = VarFlaglist[3];
                    VarFlaglistCopy[4] = VarFlaglist[4];
                    model.AddGenConstrMax(bvar[locb++], VarFlaglistCopy, 0, "maxfv" + locb.ToString());

                    //NUFvar[loc4] =1-bvar[locb++] and increase loc4 by 1
                    model.AddConstr(NUFvar[loc4++] == 1 - bvar[locb - 1], "Flip4" + loc4.ToString());

                    VarFlaglistCopy2[0] = NUFvar[loc4 - 1];
                    VarFlaglistCopy2[1] = NUFvar[loc4 - 2];
                    VarFlaglistCopy2[2] = Uvar[loc1];
                    loc1++;

                    //Uvar[loc1]=min(NUFvar[loc4-1],NUFvar[loc4-2],loc1), is the  assigment variable of f.
                    model.AddGenConstrMin(Uvar[loc1], VarFlaglistCopy2, 1000, "min_av" + loc1.ToString());
                    Tar.AddTerm(1.0, Uvar[loc1]);

                    Tar.AddTerm(-10000, UFvar[locf]);
                    rec_loc1[i] = loc1;
                    rec_locf[i] = locf;
                    loc1++;
                    locf++;
                }
                //Console.WriteLine("5: " +loc1);
                //assuming that f=u1+u2+u3+u4+u5...+um+c, where m>5.
                if (Varlist.Count > 5)
                {
                    int length;
                    length = Varlist.Count;
                    List <GRBVar> curvarlist = new List <GRBVar>()
                    {
                    };
                    GRBVar[] VarFlaglistCopy  = new GRBVar[Varlist.Count + 1];
                    GRBVar[] VarFlaglistCopy2 = new GRBVar[Varlist.Count + 1];
                    GRBVar[] Vartemplist      = new GRBVar[Varlist.Count + 1];

                    for (j = 0; j < Varlist.Count; j++)
                    {
                        curvarlist.Add(Varlist[j]);
                        VarFlaglistCopy[j] = VarFlaglist[j];
                    }

                    //model f=u1+u2+...+un. The method used here is a slight differnt from that presented in the paper.
                    //The method used here is more convenient for coding.
                    while (length > 3)
                    {
                        List <GRBVar> nextvarlist = new List <GRBVar>()
                        {
                        };
                        List <GRBVar> templist = new List <GRBVar>()
                        {
                        };
                        //
                        templist.Add(curvarlist[0]);
                        templist.Add(curvarlist[1]);
                        templist.Add(curvarlist[2]);
                        templist.Add(Uvar[loc1]);
                        AddCons3Vars(model, templist);

                        for (j = 3; j < curvarlist.Count; j++)
                        {
                            nextvarlist.Add(curvarlist[j]);
                        }
                        nextvarlist.Add(Uvar[loc1]);
                        curvarlist.Clear();
                        for (j = 0; j < nextvarlist.Count; j++)
                        {
                            curvarlist.Add(nextvarlist[j]);
                        }
                        length = curvarlist.Count;
                        loc1++;
                    }

                    if (length == 2)
                    {
                        curvarlist.Add(Uvar[loc1]);
                        AddCons2Vars(model, curvarlist);
                        //if c==1, then we need xor one more constant
                        if (consflag[i] == 1)
                        {
                            model.AddConstr(Consvar[loc0++] == 1, "Flip" + j.ToString());
                            VarlistCopy[0] = Uvar[loc1];
                            VarlistCopy[1] = Consvar[loc0 - 1];
                            VarlistCopy[2] = Uvar[loc1 + 1];
                            loc1++;
                            AddCons2Vars(model, VarlistCopy);
                        }
                    }

                    if (length == 3)
                    {
                        curvarlist.Add(Uvar[loc1]);
                        AddCons3Vars(model, curvarlist);
                        //if c==1, then we need xor one more constant
                        if (consflag[i] == 1)
                        {
                            model.AddConstr(Consvar[loc0++] == 1, "Flip" + j.ToString());
                            VarlistCopy[0] = Uvar[loc1];
                            VarlistCopy[1] = Consvar[loc0 - 1];
                            VarlistCopy[2] = Uvar[loc1 + 1];
                            loc1++;
                            AddCons2Vars(model, VarlistCopy);
                        }
                    }



                    for (j = 0; j < Varlist.Count; j++)
                    {
                        model.AddConstr(NUvar[loc3++] == 1 - VarFlaglistCopy[j], "Flip" + j.ToString());
                    }

                    for (j = 0; j < Varlist.Count; j++)
                    {
                        for (k = 0; k < Varlist.Count; k++)
                        {
                            if (k != j)
                            {
                                Vartemplist[k] = NUvar[loc3 - 1 - (Varlist.Count - 1 - k)];
                            }
                            else
                            {
                                Vartemplist[k] = VarFlaglistCopy[k];
                            }
                        }
                        model.AddGenConstrMin(Vvar[loc2++], Vartemplist, 1000, "FlagTransOxr1" + loc2.ToString());
                    }
                    for (j = 0; j < Varlist.Count; j++)
                    {
                        Vartemplist[j] = Vvar[loc2 - 1 - j];
                    }
                    model.AddGenConstrMax(UFvar[locf], Vartemplist, 0, "FlagTransXor-2" + loc2.ToString());

                    //NUFvar[loc4] =1-UFvar[loc1] and increase loc4 by 1
                    model.AddConstr(NUFvar[loc4++] == 1 - UFvar[locf], "Flip3" + loc4.ToString());
                    //bvar[locb]=max(u1_fv,u2_fv,u3_fv,u4_fv,...,un_fv) and increase locb by 1
                    for (j = 0; j < VarFlaglist.Count; j++)
                    {
                        VarFlaglistCopy[j] = VarFlaglist[j];
                    }
                    model.AddGenConstrMax(bvar[locb++], VarFlaglistCopy, 0, "maxfv" + locb.ToString());

                    //NUFvar[loc4] =1-bvar[locb++] and increase loc4 by 1
                    model.AddConstr(NUFvar[loc4++] == 1 - bvar[locb - 1], "Flip4" + loc4.ToString());

                    VarFlaglistCopy2[0] = NUFvar[loc4 - 1];
                    VarFlaglistCopy2[1] = NUFvar[loc4 - 2];
                    VarFlaglistCopy2[2] = Uvar[loc1];
                    loc1++;
                    //Uvar[loc1]=min(NUFvar[loc4-1],NUFvar[loc4-2],loc1), is the  assigment variable of f.
                    model.AddGenConstrMin(Uvar[loc1], VarFlaglistCopy2, 1000, "min_av" + loc1.ToString());

                    Tar.AddTerm(1.0, Uvar[loc1]);
                    Tar.AddTerm(-10000, UFvar[locf]);
                    rec_loc1[i] = loc1;
                    rec_locf[i] = locf;
                    loc1++;
                    locf++;
                }
            }

            //
            GRBLinExpr keyspace = new GRBLinExpr();

            for (i = 0; i < 80; i++)
            {
                keyspace.AddTerm(1.0, kvf[i]);
            }
            Tar.AddConstant((double)con);

            //Add the condition that Tar>=0. It gurantees that there is not any condition whose flag variable is equal to 1.
            model.AddConstr(Tar == 3, "finalcons");
            model.SetObjective(keyspace, GRB.MAXIMIZE);
            //Set the objective function of the model.
            //model.SetObjective(Tar, GRB.MINIMIZE);
            model.Optimize();

            //output the states of key variables and iv variables
            if (model.SolCount > 0)
            {
                sw.WriteLine("****************************Conditions on single key/iv variables***************************\n");
                Console.Write("Free Key bits:\n");
                sw.Write("Free Key bits:\n");
                for (i = 0; i < 80; i++)
                {
                    if ((keyvar[i].X == 0) && (kvf[i].X == 1))
                    {
                        Console.Write(i + ",");
                        sw.Write(i + ",");
                    }
                }
                Console.WriteLine();
                sw.WriteLine();

                Console.Write("Key bits set to 1:\n");
                sw.Write("Key bits set to 1:\n");
                for (i = 0; i < 80; i++)
                {
                    if ((keyvar[i].X == 1) && (kvf[i].X == 0))
                    {
                        Console.Write(i + ",");
                        sw.Write(i + ",");
                    }
                }
                Console.WriteLine();
                sw.WriteLine();

                Console.Write("Key bits set 0:\n");
                sw.Write("Key bits set 0:\n");
                for (i = 0; i < 80; i++)
                {
                    if ((keyvar[i].X == 0) && (kvf[i].X == 0))
                    {
                        Console.Write(i + ",");
                        sw.Write(i + ",");
                    }
                }
                Console.WriteLine();
                sw.WriteLine();

                //for (i = 0; i < loc2; i++)
                //{
                //    if (Vvar[i].X > 1)
                //    {
                //        Console.Write(Vvar[i].VarName + " " + Vvar[i].X + "\n");
                //    }

                //}

                Console.WriteLine("*******************************************************\n");
                sw.WriteLine("*******************************************************\n");

                Console.Write("Free Iv bits:\n");
                sw.Write("Free Iv bits:\n");
                for (i = 0; i < 80; i++)
                {
                    if ((ivvar[i].X == 0) && (vvf[i].X == 1))
                    {
                        Console.Write(i + ",");
                        sw.Write(i + ",");
                    }
                }
                Console.WriteLine();
                sw.WriteLine();

                Console.Write("Iv bits set to 1:\n");
                sw.Write("Iv bits set to 1:\n");
                for (i = 0; i < 80; i++)
                {
                    if ((ivvar[i].X == 1) && (vvf[i].X == 0))
                    {
                        Console.Write(i + ",");
                        sw.Write(i + ",");
                    }
                }
                Console.WriteLine();
                sw.WriteLine();

                Console.Write("Iv bits set to 0:\n");
                sw.Write("Iv bits set to 0:\n");
                for (i = 0; i < 80; i++)
                {
                    if ((ivvar[i].X == 0) && (vvf[i].X == 0))
                    {
                        Console.Write(i + ",");
                        sw.Write(i + ",");
                    }
                }
                Console.WriteLine();
                sw.WriteLine();

                double aa = Tar.Value;
                Console.WriteLine("*****************The number of 1's*****************");
                Console.WriteLine(aa);
                Console.WriteLine("***************************************************");
                sw.WriteLine("***********************The assigment/flag variable of key and iv variables***********************");
                for (i = 0; i < 80; i++)
                {
                    Console.Write(keyvar[i].VarName + "= " + keyvar[i].X + " " + kvf[i].VarName + "= " + kvf[i].X + "\n");
                    sw.Write(keyvar[i].VarName + "= " + keyvar[i].X + " " + kvf[i].VarName + "= " + kvf[i].X + "\n");
                }
                Console.WriteLine("*******************************");
                for (i = 0; i < 80; i++)
                {
                    Console.Write(ivvar[i].VarName + "= " + ivvar[i].X + " " + vvf[i].VarName + "= " + vvf[i].X + "\n");
                    sw.Write(ivvar[i].VarName + "= " + ivvar[i].X + " " + vvf[i].VarName + "= " + vvf[i].X + "\n");
                }
                Console.WriteLine();
                //
                StreamReader rw = new StreamReader("ConSet.txt");
                sw.WriteLine("***************The concrete conditions****************");
                for (j = 0; j < consnum; j++)
                {
                    string onecon = rw.ReadLine();
                    sw.WriteLine(onecon + "=" + Uvar[rec_loc1[j]].X);
                }

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

            try {
                GRBModel model = new GRBModel(env);

                // Add variables to the model

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

                // Populate A matrix

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

                // Populate objective

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

                // Solve model

                model.Optimize();

                // Extract solution

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

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

            return(success);
        }