Example #1
0
    private static void BasicLsWithFilter()
    {
        Console.WriteLine("BasicLsWithFilter");
        Solver solver = new Solver("BasicLs");

        IntVar[]        vars    = solver.MakeIntVarArray(4, 0, 4, "vars");
        IntVar          sum_var = vars.Sum().Var();
        OptimizeVar     obj     = sum_var.Minimize(1);
        DecisionBuilder db      =
            solver.MakePhase(vars, Solver.CHOOSE_FIRST_UNBOUND, Solver.ASSIGN_MAX_VALUE);
        MoveOneVar move_one_var = new MoveOneVar(vars);
        SumFilter  filter       = new SumFilter(vars);

        IntVarLocalSearchFilter[]  filters        = new IntVarLocalSearchFilter[] { filter };
        LocalSearchFilterManager   filter_manager = new LocalSearchFilterManager(filters);
        LocalSearchPhaseParameters ls_params      =
            solver.MakeLocalSearchPhaseParameters(sum_var, move_one_var, db, null, filter_manager);
        DecisionBuilder   ls        = solver.MakeLocalSearchPhase(vars, db, ls_params);
        SolutionCollector collector = solver.MakeLastSolutionCollector();

        collector.AddObjective(sum_var);
        SearchMonitor log = solver.MakeSearchLog(1000, obj);

        solver.Solve(ls, collector, obj, log);
        Console.WriteLine("Objective value = {0}", collector.ObjectiveValue(0));
    }
Example #2
0
    /**
     *
     * Solve the Least diff problem
     * For more info, see http://www.hakank.org/google_or_tools/least_diff.py
     *
     */
    private static void Solve()
    {
        Solver solver = new Solver("LeastDiff");

        //
        // Decision variables
        //
        IntVar A = solver.MakeIntVar(0, 9, "A");
        IntVar B = solver.MakeIntVar(0, 9, "B");
        IntVar C = solver.MakeIntVar(0, 9, "C");
        IntVar D = solver.MakeIntVar(0, 9, "D");
        IntVar E = solver.MakeIntVar(0, 9, "E");
        IntVar F = solver.MakeIntVar(0, 9, "F");
        IntVar G = solver.MakeIntVar(0, 9, "G");
        IntVar H = solver.MakeIntVar(0, 9, "H");
        IntVar I = solver.MakeIntVar(0, 9, "I");
        IntVar J = solver.MakeIntVar(0, 9, "J");

        IntVar[] all = new IntVar[] { A, B, C, D, E, F, G, H, I, J };
        int[]    coeffs = { 10000, 1000, 100, 10, 1 };
        IntVar   x = new IntVar[] { A, B, C, D, E }.ScalProd(coeffs).Var();
        IntVar   y = new IntVar[] { F, G, H, I, J }.ScalProd(coeffs).Var();
        IntVar   diff = (x - y).VarWithName("diff");


        //
        // Constraints
        //
        solver.Add(all.AllDifferent());
        solver.Add(A > 0);
        solver.Add(F > 0);
        solver.Add(diff > 0);


        //
        // Objective
        //
        OptimizeVar obj = diff.Minimize(1);

        //
        // Search
        //
        DecisionBuilder db = solver.MakePhase(all,
                                              Solver.CHOOSE_PATH,
                                              Solver.ASSIGN_MIN_VALUE);

        solver.NewSearch(db, obj);
        while (solver.NextSolution())
        {
            Console.WriteLine("{0} - {1} = {2}  ({3}", x.Value(), y.Value(), diff.Value(), diff.ToString());
        }

        Console.WriteLine("\nSolutions: {0}", solver.Solutions());
        Console.WriteLine("WallTime: {0}ms", solver.WallTime());
        Console.WriteLine("Failures: {0}", solver.Failures());
        Console.WriteLine("Branches: {0} ", solver.Branches());

        solver.EndSearch();
    }
        static void Main(string[] args)
        {
            Program obj = new Program();

            obj.Readfile(@"C:\binpackdata.txt");

            obj.nbCourses = obj.credits.Length;
            Solver solver = new Solver("BinPacking");

            IntVar[] x        = new IntVar[obj.nbCourses];
            IntVar[] loadVars = new IntVar[obj.nbPeriods];

            for (int i = 0; i < obj.nbCourses; i++)
            {
                x[i] = solver.MakeIntVar(0, obj.nbPeriods - 1, "x" + i);
            }

            for (int i = 0; i < obj.nbPeriods; i++)
            {
                loadVars[i] = solver.MakeIntVar(0, obj.credits.Sum(), "loadVars" + i);
            }

            //-------------------post of the constraints--------------
            obj.Pack(solver, x, obj.credits, loadVars);

            foreach (Tuple <int, int> t in obj.prereqTupleArr)
            {
                solver.Add(x[t.Item1] < x[t.Item2]);
            }

            //-------------------------Objective---------------------------
            IntVar      objectiveVar = solver.MakeMax(loadVars).Var();
            OptimizeVar objective    = solver.MakeMinimize(objectiveVar, 1);

            //------------start the search and optimization-----------
            DecisionBuilder db        = solver.MakePhase(x, Solver.CHOOSE_MIN_SIZE_LOWEST_MIN, Solver.INT_VALUE_DEFAULT);
            SearchMonitor   searchLog = solver.MakeSearchLog(100000, objectiveVar);

            solver.NewSearch(db, objective, searchLog);

            while (solver.NextSolution())
            {
                Console.WriteLine(">> Objective: " + objectiveVar.Value());
            }

            solver.EndSearch();
        }
Example #4
0
    private static void BasicLns()
    {
        Console.WriteLine("BasicLns");
        Solver solver = new Solver("BasicLns");

        IntVar[]        vars    = solver.MakeIntVarArray(4, 0, 4, "vars");
        IntVar          sum_var = vars.Sum().Var();
        OptimizeVar     obj     = sum_var.Minimize(1);
        DecisionBuilder db      = solver.MakePhase(vars,
                                                   Solver.CHOOSE_FIRST_UNBOUND,
                                                   Solver.ASSIGN_MAX_VALUE);
        OneVarLns one_var_lns = new OneVarLns(vars);
        LocalSearchPhaseParameters ls_params =
            solver.MakeLocalSearchPhaseParameters(one_var_lns, db);
        DecisionBuilder   ls        = solver.MakeLocalSearchPhase(vars, db, ls_params);
        SolutionCollector collector = solver.MakeLastSolutionCollector();

        collector.AddObjective(sum_var);
        SearchMonitor log = solver.MakeSearchLog(1000, obj);

        solver.Solve(ls, collector, obj, log);
        Console.WriteLine("Objective value = {0}", collector.ObjectiveValue(0));
    }
Example #5
0
    /**
     *
     * Lectures problem in Google CP Solver.
     *
     * Biggs: Discrete Mathematics (2nd ed), page 187.
     * """
     * Suppose we wish to schedule six one-hour lectures, v1, v2, v3, v4, v5, v6.
     * Among the the potential audience there are people who wish to hear both
     *
     * - v1 and v2
     * - v1 and v4
     * - v3 and v5
     * - v2 and v6
     * - v4 and v5
     * - v5 and v6
     * - v1 and v6
     *
     * How many hours are necessary in order that the lectures can be given
     * without clashes?
     * """
     *
     * Note: This can be seen as a coloring problem.
     *
     * Also see http://www.hakank.org/or-tools/lectures.py
     *
     */
    private static void Solve()
    {
        Solver solver = new Solver("Lectures");

        //
        // The schedule requirements:
        // lecture a cannot be held at the same time as b
        // Note: 1-based (compensated in the constraints).
        int[,] g =
        {
            { 1, 2 },
            { 1, 4 },
            { 3, 5 },
            { 2, 6 },
            { 4, 5 },
            { 5, 6 },
            { 1, 6 }
        };

        // number of nodes
        int n = 6;

        // number of edges
        int edges = g.GetLength(0);

        //
        // Decision variables
        //
        //
        // declare variables
        //
        IntVar[] v = solver.MakeIntVarArray(n, 0, n - 1, "v");

        // Maximum color (hour) to minimize.
        // Note: since C# is 0-based, the
        // number of colors is max_c+1.
        IntVar max_c = v.Max().VarWithName("max_c");


        //
        // Constraints
        //

        // Ensure that there are no clashes
        // also, adjust to 0-base.
        for (int i = 0; i < edges; i++)
        {
            solver.Add(v[g[i, 0] - 1] != v[g[i, 1] - 1]);
        }

        // Symmetry breaking:
        // - v0 has the color 0,
        // - v1 has either color 0 or 1
        solver.Add(v[0] == 0);
        solver.Add(v[1] <= 1);


        //
        // Objective
        //
        OptimizeVar obj = max_c.Minimize(1);

        //
        // Search
        //
        DecisionBuilder db = solver.MakePhase(v,
                                              Solver.CHOOSE_MIN_SIZE_LOWEST_MIN,
                                              Solver.ASSIGN_MIN_VALUE);

        solver.NewSearch(db, obj);

        while (solver.NextSolution())
        {
            Console.WriteLine("\nmax hours: {0}", max_c.Value() + 1);
            Console.WriteLine("v: " +
                              String.Join(" ", (from i in Enumerable.Range(0, n)
                                                select v[i].Value()).ToArray()));
            for (int i = 0; i < n; i++)
            {
                Console.WriteLine("Lecture {0} at {1}h", i, v[i].Value());
            }
            Console.WriteLine("\n");
        }

        Console.WriteLine("\nSolutions: " + solver.Solutions());
        Console.WriteLine("WallTime: " + solver.WallTime() + "ms ");
        Console.WriteLine("Failures: " + solver.Failures());
        Console.WriteLine("Branches: " + solver.Branches());

        solver.EndSearch();
    }
Example #6
0
        private void Model()
        {
            /* Building basic task data structures */
            for (int i = 0; i < tasks.Length; i++)
            {
                /* Create a new set of possible IntervalVars & IntVar to decide
                 * which one (and only 1) is performed */
                taskStructures[i] = new TaskAlternative(tasks[i]);

                /* Container to use when posting constraints */
                location2Task[tasks[i].LocationId][tasks[i].TaskPosition] = taskStructures[i];

                /* Get task type */
                int taskType = tasks[i].TaskType;

                /* Possible tool for this task */
                List <Tool> tools    = taskType2Tool[taskType];
                bool        optional = tools.Count > 1;

                /* List of boolean variables. If performedOnTool[t] == true then
                 * the task is performed on tool t */
                List <IntVar> performedOnTool = new List <IntVar>();
                for (int t = 0; t < tools.Count; t++)
                {
                    /* Creating an IntervalVar. If tools.Count > 1 the intervalVar
                     * is *OPTIONAL* */
                    int toolId = tools[t].Id;
                    Debug.Assert(tasks[i].Durations.ContainsKey(toolId));
                    int    duration = tasks[i].Durations[toolId];
                    string name     = "J " + tasks[i].Id + " [" + toolId + "]";

                    IntervalVar intervalVar;
                    if (taskType == factoryData.Inspection)
                    {
                        /* We set a 0 time if the task is an inspection */
                        duration    = 0;
                        intervalVar = solver.MakeFixedDurationIntervalVar(0, horizon, duration, optional, name);
                        IntVar start = intervalVar.SafeStartExpr(-1).Var();

                        intervalVar.SafeStartExpr(-1).Var().SetValues(factoryData.InspectionStarts);
                    }
                    else
                    {
                        intervalVar = solver.MakeFixedDurationIntervalVar(0, horizon, duration, optional, name);
                    }

                    taskStructures[i].Intervals.Add(intervalVar);
                    tool2Task[toolId].Add(intervalVar);
                    toolIntervalVar2TaskId[toolId].Add(i);

                    /* Collecting all the bool vars, even if they are optional */
                    performedOnTool.Add(intervalVar.PerformedExpr().Var());
                }

                /* Linking the bool var to a single integer variable: */
                /* if alternativeToolVar == t <=> performedOnTool[t] == true */
                string alternativeName    = "J " + tasks[i].Id;
                IntVar alternativeToolVar = solver.MakeIntVar(0, tools.Count - 1, alternativeName);
                taskStructures[i].ToolVar = alternativeToolVar;

                solver.Add(solver.MakeMapDomain(alternativeToolVar, performedOnTool.ToArray()));
                Debug.Assert(performedOnTool.ToArray().Length == alternativeToolVar.Max() + 1);

                selectedTool.Add(alternativeToolVar);
            }

            /* Creates precedences on a work Location in order to enforce a
             * fully ordered set within the same location
             */
            for (int d = 0; d < location2Task.Length; d++)
            {
                for (int i = 0; i < location2Task[d].Length - 1; i++)
                {
                    TaskAlternative task1 = location2Task[d][i];
                    TaskAlternative task2 = location2Task[d][i + 1];
                    /* task1 must end before task2 starts */
                    /* Adding precedence for each possible alternative pair */
                    for (int t1 = 0; t1 < task1.Intervals.Count(); t1++)
                    {
                        IntervalVar task1Alternative = task1.Intervals[t1];
                        for (int t2 = 0; t2 < task2.Intervals.Count(); t2++)
                        {
                            IntervalVar task2Alternative = task2.Intervals[t2];
                            Constraint  precedence       = solver.MakeIntervalVarRelation(
                                task2Alternative, Solver.STARTS_AFTER_END, task1Alternative);
                            solver.Add(precedence);
                        }
                    }
                }
            }

            /* Adds disjunctive constraints on unary resources, and creates
             * sequence variables. */
            for (int t = 0; t < factoryData.NbTools; t++)
            {
                string name = "Tool " + t;

                if (!factoryData.Tools[t].CanPerformTaskType(factoryData.Inspection))
                {
                    DisjunctiveConstraint ct = solver.MakeDisjunctiveConstraint(tool2Task[t].ToArray(), name);
                    solver.Add(ct);
                    allToolSequences[t] = ct.SequenceVar();
                }
                PostTransitionTimeConstraints(t, true);
            }

            /* Collecting all tasks end for makespan objective function */
            List <IntVar> intervalEnds = new List <IntVar>();

            for (int i = 0; i < tasks.Length; i++)
            {
                foreach (IntervalVar var in taskStructures[i].Intervals)
                {
                    intervalEnds.Add(var.SafeEndExpr(-1).Var());
                }
            }

            /* Objective: minimize the makespan (maximum end times of all tasks) */
            makespan  = solver.MakeMax(intervalEnds.ToArray()).Var();
            objective = solver.MakeMinimize(makespan, 1);
        }
Example #7
0
  private void Model() {
    /* Building basic task data structures */
    for (int i = 0; i < tasks.Length; i++) {

      /* Create a new set of possible IntervalVars & IntVar to decide
       * which one (and only 1) is performed */
      taskStructures[i] = new TaskAlternative(tasks[i]);

      /* Container to use when posting constraints */
      location2Task[tasks[i].LocationId][tasks[i].TaskPosition] =
          taskStructures[i];

      /* Get task type */
      int taskType = tasks[i].TaskType;

      /* Possible tool for this task */
      List<Tool> tools = taskType2Tool[taskType];
      bool optional = tools.Count > 1;

      /* List of boolean variables. If performedOnTool[t] == true then
       * the task is performed on tool t */
      List<IntVar> performedOnTool = new List<IntVar>();
      for (int t = 0; t < tools.Count; t++) {
        /* Creating an IntervalVar. If tools.Count > 1 the intervalVar
         * is *OPTIONAL* */
        int toolId = tools[t].Id;
        Debug.Assert(tasks[i].Durations.ContainsKey(toolId));
        int duration = tasks[i].Durations[toolId];
        string name = "J " + tasks[i].Id + " [" + toolId + "]";

        IntervalVar intervalVar;
        if (taskType == factoryData.Inspection) {
          /* We set a 0 time if the task is an inspection */
          duration = 0;
          intervalVar = solver.MakeFixedDurationIntervalVar(
              0, horizon, duration, optional, name);
          IntVar start = intervalVar.SafeStartExpr(-1).Var();

          intervalVar.SafeStartExpr(-1).Var().SetValues(
              factoryData.InspectionStarts);
        } else {
          intervalVar = solver.MakeFixedDurationIntervalVar(
              0, horizon, duration, optional, name);
        }

        taskStructures[i].Intervals.Add(intervalVar);
        tool2Task[toolId].Add(intervalVar);
        toolIntervalVar2TaskId[toolId].Add(i);

        /* Collecting all the bool vars, even if they are optional */
        performedOnTool.Add(intervalVar.PerformedExpr().Var());
      }

      /* Linking the bool var to a single integer variable: */
      /* if alternativeToolVar == t <=> performedOnTool[t] == true */
      string alternativeName = "J " + tasks[i].Id;
      IntVar alternativeToolVar =
          solver.MakeIntVar(0, tools.Count - 1, alternativeName);
      taskStructures[i].ToolVar = alternativeToolVar;

      solver.Add(
          solver.MakeMapDomain(alternativeToolVar, performedOnTool.ToArray()));
      Debug.Assert(
          performedOnTool.ToArray().Length == alternativeToolVar.Max()+1);

      selectedTool.Add(alternativeToolVar);
    }

    /* Creates precedences on a work Location in order to enforce a
     * fully ordered set within the same location
     */
    for (int d = 0; d < location2Task.Length; d++) {
      for (int i = 0; i < location2Task[d].Length - 1; i++) {
        TaskAlternative task1 = location2Task[d][i];
        TaskAlternative task2 = location2Task[d][i + 1];
        /* task1 must end before task2 starts */
        /* Adding precedence for each possible alternative pair */
        for (int t1 = 0; t1 < task1.Intervals.Count(); t1++) {
          IntervalVar task1Alternative = task1.Intervals[t1];
          for (int t2 = 0; t2 < task2.Intervals.Count(); t2++){
            IntervalVar task2Alternative = task2.Intervals[t2];
            Constraint precedence = solver.MakeIntervalVarRelation(
                task2Alternative, Solver.STARTS_AFTER_END, task1Alternative);
            solver.Add(precedence);
          }
        }
      }
    }

    /* Adds disjunctive constraints on unary resources, and creates
     * sequence variables. */
    for (int t = 0; t < factoryData.NbTools; t++) {
      string name = "Tool " + t;

      if (!factoryData.Tools[t].CanPerformTaskType(factoryData.Inspection)) {
        DisjunctiveConstraint ct =
            solver.MakeDisjunctiveConstraint(tool2Task[t].ToArray(), name);
        solver.Add(ct);
        allToolSequences[t] = ct.SequenceVar();
      }
      PostTransitionTimeConstraints(t, true);
    }


    /* Collecting all tasks end for makespan objective function */
    List<IntVar> intervalEnds = new List<IntVar>();
    for (int i = 0; i < tasks.Length; i++)
      foreach (IntervalVar var in taskStructures[i].Intervals)
        intervalEnds.Add(var.SafeEndExpr(-1).Var());


    /* Objective: minimize the makespan (maximum end times of all tasks) */
    makespan = solver.MakeMax(intervalEnds.ToArray()).Var();
    objective = solver.MakeMinimize(makespan, 1);
  }
Example #8
0
    /**
     *
     * Nontransitive dice.
     *
     * From
     * http://en.wikipedia.org/wiki/Nontransitive_dice
     * """
     * A set of nontransitive dice is a set of dice for which the relation
     * 'is more likely to roll a higher number' is not transitive. See also
     * intransitivity.
     *
     * This situation is similar to that in the game Rock, Paper, Scissors,
     * in which each element has an advantage over one choice and a
     * disadvantage to the other.
     * """
     *
     * Also see http://www.hakank.org/or-tools/nontransitive_dice.py
     *
     *
     */
    private static void Solve(int m = 3, int n = 6, int minimize_val = 0)
    {
        Solver solver = new Solver("Nontransitive_dice");

        Console.WriteLine("Number of dice: {0}", m);
        Console.WriteLine("Number of sides: {0}", n);
        Console.WriteLine("minimize_val: {0}\n", minimize_val);

        //
        // Decision variables
        //

        // The dice
        IntVar[,] dice = solver.MakeIntVarMatrix(m, n, 1, n * 2, "dice");
        IntVar[] dice_flat = dice.Flatten();

        // For comparison (probability)
        IntVar[,] comp = solver.MakeIntVarMatrix(m, 2, 0, n * n, "dice");
        IntVar[] comp_flat = comp.Flatten();

        // For branching
        IntVar[] all = dice_flat.Concat(comp_flat).ToArray();

        // The following variables are for summaries or objectives
        IntVar[] gap     = solver.MakeIntVarArray(m, 0, n * n, "gap");
        IntVar   gap_sum = gap.Sum().Var();

        IntVar max_val = dice_flat.Max().Var();
        IntVar max_win = comp_flat.Max().Var();

        // number of occurrences of each value of the dice
        IntVar[] counts = solver.MakeIntVarArray(n * 2 + 1, 0, n * m, "counts");

        //
        // Constraints
        //

        // Number of occurrences for each number
        solver.Add(dice_flat.Distribute(counts));

        // Order of the number of each die, lowest first
        for (int i = 0; i < m; i++)
        {
            for (int j = 0; j < n - 1; j++)
            {
                solver.Add(dice[i, j] <= dice[i, j + 1]);
            }
        }

        // Nontransitivity
        for (int i = 0; i < m; i++)
        {
            solver.Add(comp[i, 0] > comp[i, 1]);
        }

        // Probability gap
        for (int i = 0; i < m; i++)
        {
            solver.Add(gap[i] == comp[i, 0] - comp[i, 1]);
            solver.Add(gap[i] > 0);
        }

        // And now we roll...
        // comp[] is the number of wins for [A vs B, B vs A]
        for (int d = 0; d < m; d++)
        {
            IntVar sum1 = (from r1 in Enumerable.Range(0, n) from r2 in Enumerable.Range(0, n)
                           select(dice[d % m, r1] > dice[(d + 1) % m, r2]))
                          .ToArray()
                          .Sum()
                          .Var();

            solver.Add(comp[d % m, 0] == sum1);

            IntVar sum2 = (from r1 in Enumerable.Range(0, n) from r2 in Enumerable.Range(0, n)
                           select(dice[(d + 1) % m, r1] > dice[d % m, r2]))
                          .ToArray()
                          .Sum()
                          .Var();

            solver.Add(comp[d % m, 1] == sum2);
        }

        //
        // Search
        //
        DecisionBuilder db = solver.MakePhase(all, Solver.INT_VAR_DEFAULT, Solver.ASSIGN_MIN_VALUE);

        if (minimize_val > 0)
        {
            Console.WriteLine("Minimizing max_val");

            OptimizeVar obj = max_val.Minimize(1);

            // Other experiments:
            // OptimizeVar obj = max_win.Maximize(1);
            // OptimizeVar obj = gap_sum.Maximize(1);

            solver.NewSearch(db, obj);
        }
        else
        {
            solver.NewSearch(db);
        }

        while (solver.NextSolution())
        {
            Console.WriteLine("gap_sum: {0}", gap_sum.Value());
            Console.WriteLine("gap: {0}",
                              (from i in Enumerable.Range(0, m) select gap[i].Value().ToString()).ToArray());
            Console.WriteLine("max_val: {0}", max_val.Value());
            Console.WriteLine("max_win: {0}", max_win.Value());
            Console.WriteLine("dice:");
            for (int i = 0; i < m; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    Console.Write(dice[i, j].Value() + " ");
                }
                Console.WriteLine();
            }
            Console.WriteLine("comp:");
            for (int i = 0; i < m; i++)
            {
                for (int j = 0; j < 2; j++)
                {
                    Console.Write(comp[i, j].Value() + " ");
                }
                Console.WriteLine();
            }
            Console.WriteLine("counts:");
            for (int i = 1; i < n * 2 + 1; i++)
            {
                int c = (int)counts[i].Value();
                if (c > 0)
                {
                    Console.Write("{0}({1}) ", i, c);
                }
            }
            Console.WriteLine("\n");
        }

        Console.WriteLine("\nSolutions: {0}", solver.Solutions());
        Console.WriteLine("WallTime: {0}ms", solver.WallTime());
        Console.WriteLine("Failures: {0}", solver.Failures());
        Console.WriteLine("Branches: {0} ", solver.Branches());

        solver.EndSearch();
    }
Example #9
0
    /**
     *
     * Assignment problem
     *
     * From Wayne Winston "Operations Research",
     * Assignment Problems, page 393f
     * (generalized version with added test column)
     *
     * See  See http://www.hakank.org/or-tools/assignment.py
     *
     */
    private static void Solve()
    {
        Solver solver = new Solver("Assignment");

        //
        // data
        //

        // Problem instance
        // hakank: I added the fifth column to make it more
        //         interesting
        int rows = 4;
        int cols = 5;

        int[,] cost = { { 14, 5, 8, 7, 15 }, { 2, 12, 6, 5, 3 }, { 7, 8, 3, 9, 7 }, { 2, 4, 6, 10, 1 } };

        //
        // Decision variables
        //
        IntVar[,] x = solver.MakeBoolVarMatrix(rows, cols, "x");
        IntVar[] x_flat = x.Flatten();

        //
        // Constraints
        //

        // Exacly one assignment per row (task),
        // i.e. all rows must be assigned with one worker
        for (int i = 0; i < rows; i++)
        {
            solver.Add((from j in Enumerable.Range(0, cols) select x[i, j]).ToArray().Sum() == 1);
        }

        // At most one assignments per column (worker)
        for (int j = 0; j < cols; j++)
        {
            solver.Add((from i in Enumerable.Range(0, rows) select x[i, j]).ToArray().Sum() <= 1);
        }

        // Total cost
        IntVar total_cost =
            (from i in Enumerable.Range(0, rows) from j in Enumerable.Range(0, cols) select(cost[i, j] * x[i, j]))
            .ToArray()
            .Sum()
            .Var();

        //
        // objective
        //
        OptimizeVar objective = total_cost.Minimize(1);

        //
        // Search
        //
        DecisionBuilder db = solver.MakePhase(x_flat, Solver.INT_VAR_DEFAULT, Solver.INT_VALUE_DEFAULT);

        solver.NewSearch(db, objective);

        while (solver.NextSolution())
        {
            Console.WriteLine("total_cost: {0}", total_cost.Value());
            for (int i = 0; i < rows; i++)
            {
                for (int j = 0; j < cols; j++)
                {
                    Console.Write(x[i, j].Value() + " ");
                }
                Console.WriteLine();
            }
            Console.WriteLine();
            Console.WriteLine("Assignments:");
            for (int i = 0; i < rows; i++)
            {
                Console.Write("Task " + i);
                for (int j = 0; j < cols; j++)
                {
                    if (x[i, j].Value() == 1)
                    {
                        Console.WriteLine(" is done by " + j);
                    }
                }
            }
            Console.WriteLine();
        }

        Console.WriteLine("\nSolutions: {0}", solver.Solutions());
        Console.WriteLine("WallTime: {0}ms", solver.WallTime());
        Console.WriteLine("Failures: {0}", solver.Failures());
        Console.WriteLine("Branches: {0} ", solver.Branches());

        solver.EndSearch();
    }
Example #10
0
    /**
     *
     * Solve the SEND+MOST=MONEY problem
     * where the object is to maximize MONEY
     * See http://www.hakank.org/google_or_tools/send_most_money.py
     *
     */
    private static long Solve(long MONEY)
    {
        Solver solver = new Solver("SendMostMoney");

        //
        // Decision variables
        //
        IntVar S = solver.MakeIntVar(0, 9, "S");
        IntVar E = solver.MakeIntVar(0, 9, "E");
        IntVar N = solver.MakeIntVar(0, 9, "N");
        IntVar D = solver.MakeIntVar(0, 9, "D");
        IntVar M = solver.MakeIntVar(0, 9, "M");
        IntVar O = solver.MakeIntVar(0, 9, "O");
        IntVar T = solver.MakeIntVar(0, 9, "T");
        IntVar Y = solver.MakeIntVar(0, 9, "Y");

        // for AllDifferent()
        IntVar[] x = new IntVar[] { S, E, N, D, M, O, T, Y };

        IntVar[] eq     = { S, E, N, D, M, O, S, T, M, O, N, E, Y };
        int[]    coeffs =
        {
            1000,     100,   10,   1,    //    S E N D +
            1000,     100,   10,   1,    //    M O S T
            -10000, -1000, -100, -10, -1 // == M O N E Y
        };
        solver.Add(eq.ScalProd(coeffs) == 0);

        // IntVar money = solver.MakeScalProd(new IntVar[] {M, O, N, E, Y},
        //                                    new int[] {10000, 1000, 100, 10,
        //                                    1}).Var();
        IntVar money =
            (new IntVar[] { M, O, N, E, Y }).ScalProd(new int[] { 10000, 1000, 100, 10, 1 }).Var();

        //
        // Constraints
        //
        solver.Add(x.AllDifferent());
        solver.Add(S > 0);
        solver.Add(M > 0);

        if (MONEY > 0)
        {
            solver.Add(money == MONEY);
        }

        //
        // Search
        //
        DecisionBuilder db = solver.MakePhase(x, Solver.CHOOSE_FIRST_UNBOUND, Solver.ASSIGN_MIN_VALUE);

        if (MONEY == 0)
        {
            OptimizeVar obj = money.Maximize(1);
            solver.NewSearch(db, obj);
        }
        else
        {
            solver.NewSearch(db);
        }

        long money_ret = 0;

        while (solver.NextSolution())
        {
            money_ret = money.Value();
            Console.WriteLine("money: {0}", money.Value());
            for (int i = 0; i < x.Length; i++)
            {
                Console.Write(x[i].Value() + " ");
            }
            Console.WriteLine();
        }

        Console.WriteLine("\nSolutions: {0}", solver.Solutions());
        Console.WriteLine("WallTime: {0}ms", solver.WallTime());
        Console.WriteLine("Failures: {0}", solver.Failures());
        Console.WriteLine("Branches: {0} ", solver.Branches());

        solver.EndSearch();

        return(money_ret);
    }
Example #11
0
    /**
     *
     * Secret Santa problem II in Google CP Solver.
     *
     * From Maple Primes: 'Secret Santa Graph Theory'
     * http://www.mapleprimes.com/blog/jpmay/secretsantagraphtheory
     * """
     * Every year my extended family does a 'secret santa' gift exchange.
     * Each person draws another person at random and then gets a gift for
     * them. At first, none of my siblings were married, and so the draw was
     * completely random. Then, as people got married, we added the restriction
     * that spouses should not draw each others names. This restriction meant
     * that we moved from using slips of paper on a hat to using a simple
     * computer program to choose names. Then people began to complain when
     * they would get the same person two years in a row, so the program was
     * modified to keep some history and avoid giving anyone a name in their
     * recent history. This year, not everyone was participating, and so after
     * removing names, and limiting the number of exclusions to four per person,
     * I had data something like this:
     *
     * Name: Spouse, Recent Picks
     *
     * Noah: Ava. Ella, Evan, Ryan, John
     * Ava: Noah, Evan, Mia, John, Ryan
     * Ryan: Mia, Ella, Ava, Lily, Evan
     * Mia: Ryan, Ava, Ella, Lily, Evan
     * Ella: John, Lily, Evan, Mia, Ava
     * John: Ella, Noah, Lily, Ryan, Ava
     * Lily: Evan, John, Mia, Ava, Ella
     * Evan: Lily, Mia, John, Ryan, Noah
     * """
     *
     *  Note: I interpret this as the following three constraints:
     * 1) One cannot be a Secret Santa of one's spouse
     * 2) One cannot be a Secret Santa for somebody two years in a row
     * 3) Optimization: maximize the time since the last time
     *
     *  This model also handle single persons, something the original
     *  problem don't mention.
     *
     *
     * Also see http://www.hakank.org/or-tools/secret_santa2.py
     *
     */
    private static void Solve(int single = 0)
    {
        Solver solver = new Solver("SecretSanta2");

        Console.WriteLine("\nSingle: {0}", single);

        //
        // The matrix version of earlier rounds.
        // M means that no earlier Santa has been assigned.
        // Note: Ryan and Mia has the same recipient for years 3 and 4,
        //       and Ella and John has for year 4.
        //       This seems to be caused by modification of
        //       original data.
        //
        int n_no_single = 8;
        int M           = n_no_single + 1;

        int[][] rounds_no_single =
        {
            // N  A  R  M  El J  L  Ev
            new int[] { 0, M, 3, M, 1, 4, M, 2 }, // Noah
            new int[] { M, 0, 4, 2, M, 3, M, 1 }, // Ava
            new int[] { M, 2, 0, M, 1, M, 3, 4 }, // Ryan
            new int[] { M, 1, M, 0, 2, M, 3, 4 }, // Mia
            new int[] { M, 4, M, 3, 0, M, 1, 2 }, // Ella
            new int[] { 1, 4, 3, M, M, 0, 2, M }, // John
            new int[] { M, 3, M, 2, 4, 1, 0, M }, // Lily
            new int[] { 4, M, 3, 1, M, 2, M, 0 } // Evan
        };

        //
        // Rounds with a single person (fake data)
        //
        int n_with_single = 9;

        M = n_with_single + 1;
        int[][] rounds_single =
        {
            // N  A  R  M  El J  L  Ev S
            new int[] { 0, M, 3, M, 1, 4, M, 2, 2 }, // Noah
            new int[] { M, 0, 4, 2, M, 3, M, 1, 1 }, // Ava
            new int[] { M, 2, 0, M, 1, M, 3, 4, 4 }, // Ryan
            new int[] { M, 1, M, 0, 2, M, 3, 4, 3 }, // Mia
            new int[] { M, 4, M, 3, 0, M, 1, 2, M }, // Ella
            new int[] { 1, 4, 3, M, M, 0, 2, M, M }, // John
            new int[] { M, 3, M, 2, 4, 1, 0, M, M }, // Lily
            new int[] { 4, M, 3, 1, M, 2, M, 0, M }, // Evan
            new int[] { 1, 2, 3, 4, M, 2, M, M, 0 } // Single
        };

        int Noah = 0;
        int Ava  = 1;
        int Ryan = 2;
        int Mia  = 3;
        int Ella = 4;
        int John = 5;
        int Lily = 6;
        int Evan = 7;

        int n = n_no_single;

        int[][] rounds = rounds_no_single;
        if (single == 1)
        {
            n      = n_with_single;
            rounds = rounds_single;
        }
        M = n + 1;

        IEnumerable <int> RANGE = Enumerable.Range(0, n);

        String[] persons = { "Noah", "Ava", "Ryan", "Mia", "Ella", "John", "Lily", "Evan", "Single" };

        int[] spouses =
        {
            Ava,  // Noah
            Noah, // Ava
            Mia,  // Rya
            Ryan, // Mia
            John, // Ella
            Ella, // John
            Evan, // Lily
            Lily, // Evan
            -1    // Single has no spouse
        };

        //
        // Decision variables
        //
        IntVar[] santas         = solver.MakeIntVarArray(n, 0, n - 1, "santas");
        IntVar[] santa_distance = solver.MakeIntVarArray(n, 0, M, "santa_distance");

        // total of "distance", to maximize
        IntVar z = santa_distance.Sum().VarWithName("z");

        //
        // Constraints
        //
        solver.Add(santas.AllDifferent());

        // Can't be one own"s Secret Santa
        // (i.e. ensure that there are no fix-point in the array.)
        foreach (int i in RANGE)
        {
            solver.Add(santas[i] != i);
        }

        // no Santa for a spouses
        foreach (int i in RANGE)
        {
            if (spouses[i] > -1)
            {
                solver.Add(santas[i] != spouses[i]);
            }
        }

        // optimize "distance" to earlier rounds:
        foreach (int i in RANGE)
        {
            solver.Add(santa_distance[i] == rounds[i].Element(santas[i]));
        }

        // cannot be a Secret Santa for the same person
        // two years in a row.
        foreach (int i in RANGE)
        {
            foreach (int j in RANGE)
            {
                if (rounds[i][j] == 1)
                {
                    solver.Add(santas[i] != j);
                }
            }
        }

        //
        // Objective (minimize the distances)
        //
        OptimizeVar obj = z.Maximize(1);

        //
        // Search
        //
        DecisionBuilder db =
            solver.MakePhase(santas, Solver.CHOOSE_MIN_SIZE_LOWEST_MIN, Solver.ASSIGN_CENTER_VALUE);

        solver.NewSearch(db, obj);

        while (solver.NextSolution())
        {
            Console.WriteLine("\ntotal distances: {0}", z.Value());
            Console.Write("santas:  ");
            for (int i = 0; i < n; i++)
            {
                Console.Write(santas[i].Value() + " ");
            }
            Console.WriteLine();
            foreach (int i in RANGE)
            {
                Console.WriteLine("{0}\tis a Santa to {1} (distance {2})", persons[i],
                                  persons[santas[i].Value()], santa_distance[i].Value());
            }
        }

        Console.WriteLine("\nSolutions: {0}", solver.Solutions());
        Console.WriteLine("WallTime: {0}ms", solver.WallTime());
        Console.WriteLine("Failures: {0}", solver.Failures());
        Console.WriteLine("Branches: {0} ", solver.Branches());

        solver.EndSearch();
    }
Example #12
0
    /**
     *
     * Solves a set covering problem.
     * See  See http://www.hakank.org/or-tools/set_covering3.py
     *
     */
    private static void Solve()
    {
        Solver solver = new Solver("SetCovering3");

        //
        // data
        //

        // Set covering problem from
        // Katta G. Murty: 'Optimization Models for Decision Making',
        // page 302f
        // http://ioe.engin.umich.edu/people/fac/books/murty/opti_model/junior-7.pdf
        int num_groups   = 6;
        int num_senators = 10;

        // which group does a senator belong to?
        int[,] belongs = { { 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 },   // 1 southern
                           { 0, 0, 0, 0, 0, 1, 1, 1, 1, 1 },   // 2 northern
                           { 0, 1, 1, 0, 0, 0, 0, 1, 1, 1 },   // 3 liberals
                           { 1, 0, 0, 0, 1, 1, 1, 0, 0, 0 },   // 4 conservative
                           { 0, 0, 1, 1, 1, 1, 1, 0, 1, 0 },   // 5 democrats
                           { 1, 1, 0, 0, 0, 0, 0, 1, 0, 1 } }; // 6 republicans

        //
        // Decision variables
        //
        IntVar[] x = solver.MakeIntVarArray(num_senators, 0, 1, "x");
        // number of assigned senators, to be minimized
        IntVar z = x.Sum().Var();

        //
        // Constraints
        //

        // ensure that each group is covered by at least
        // one senator
        for (int i = 0; i < num_groups; i++)
        {
            IntVar[] b = new IntVar[num_senators];
            for (int j = 0; j < num_senators; j++)
            {
                b[j] = (x[j] * belongs[i, j]).Var();
            }
            solver.Add(b.Sum() >= 1);
        }

        //
        // objective
        //
        OptimizeVar objective = z.Minimize(1);

        //
        // Search
        //
        DecisionBuilder db = solver.MakePhase(x, Solver.INT_VAR_DEFAULT, Solver.INT_VALUE_DEFAULT);

        solver.NewSearch(db, objective);

        while (solver.NextSolution())
        {
            Console.WriteLine("z: " + z.Value());
            Console.Write("x: ");
            for (int j = 0; j < num_senators; j++)
            {
                Console.Write(x[j].Value() + " ");
            }
            Console.WriteLine();

            // More details
            for (int j = 0; j < num_senators; j++)
            {
                if (x[j].Value() == 1)
                {
                    Console.Write("Senator " + (1 + j) + " belongs to these groups: ");
                    for (int i = 0; i < num_groups; i++)
                    {
                        if (belongs[i, j] == 1)
                        {
                            Console.Write((1 + i) + " ");
                        }
                    }
                    Console.WriteLine();
                }
            }
        }

        Console.WriteLine("\nSolutions: {0}", solver.Solutions());
        Console.WriteLine("WallTime: {0}ms", solver.WallTime());
        Console.WriteLine("Failures: {0}", solver.Failures());
        Console.WriteLine("Branches: {0} ", solver.Branches());

        solver.EndSearch();
    }
Example #13
0
    /**
     *
     * Finding an optimal wedding seating chart.
     *
     * From
     * Meghan L. Bellows and J. D. Luc Peterson
     * "Finding an optimal seating chart for a wedding"
     * http://www.improbable.com/news/2012/Optimal-seating-chart.pdf
     * http://www.improbable.com/2012/02/12/finding-an-optimal-seating-chart-for-a-wedding
     *
     * """
     * Every year, millions of brides (not to mention their mothers, future
     * mothers-in-law, and occasionally grooms) struggle with one of the
     * most daunting tasks during the wedding-planning process: the
     * seating chart. The guest responses are in, banquet hall is booked,
     * menu choices have been made. You think the hard parts are over,
     * but you have yet to embark upon the biggest headache of them all.
     * In order to make this process easier, we present a mathematical
     * formulation that models the seating chart problem. This model can
     * be solved to find the optimal arrangement of guests at tables.
     * At the very least, it can provide a starting point and hopefully
     * minimize stress and arguments…
     * """
     *
     *
     * Also see http://www.hakank.org/minizinc/wedding_optimal_chart.mzn
     *
     */
    private static void Solve()
    {
        Solver solver = new Solver("WeddingOptimalChart");

        //
        // Data
        //

        // Easy problem (from the paper)
        int n = 2;  // number of tables
        int a = 10; // maximum number of guests a table can seat
        int b = 1;  // minimum number of people each guest knows at their table

        /*
         * // Sligthly harder problem (also from the paper)
         * int n = 5; // number of tables
         * int a = 4; // maximum number of guests a table can seat
         * int b = 1; // minimum number of people each guest knows at their table
         */

        //  j   Guest         Relation
        //  -------------------------------------
        //  1   Deb           mother of the bride
        //  2   John          father of the bride
        //  3   Martha        sister of the bride
        //  4   Travis        boyfriend of Martha
        //  5   Allan         grandfather of the bride
        //  6   Lois          wife of Allan
        //  7   Jayne         aunt of the bride
        //  8   Brad          uncle of the bride
        //  9   Abby          cousin of the bride
        // 10   Mary Helen    mother of the groom
        // 11   Lee           father of the groom
        // 12   Annika        sister of the groom
        // 13   Carl          brother of the groom
        // 14   Colin         brother of the groom
        // 15   Shirley       grandmother of the groom
        // 16   DeAnn         aunt of the groom
        // 17   Lori          aunt of the groom

        // Connection matrix: who knows who, and how strong
        // is the relation
        int[,] C = { {  1, 50,  1,  1,  1,  1,  1,  1,  1,  0,  0, 0, 0, 0, 0, 0, 0 },
                     { 50,  1,  1,  1,  1,  1,  1,  1,  1,  0,  0, 0, 0, 0, 0, 0, 0 },
                     {  1,  1,  1, 50,  1,  1,  1,  1, 10,  0,  0, 0, 0, 0, 0, 0, 0 },
                     {  1,  1, 50,  1,  1,  1,  1,  1,  1,  0,  0, 0, 0, 0, 0, 0, 0 },
                     {  1,  1,  1,  1,  1, 50,  1,  1,  1,  0,  0, 0, 0, 0, 0, 0, 0 },
                     {  1,  1,  1,  1, 50,  1,  1,  1,  1,  0,  0, 0, 0, 0, 0, 0, 0 },
                     {  1,  1,  1,  1,  1,  1,  1, 50,  1,  0,  0, 0, 0, 0, 0, 0, 0 },
                     {  1,  1,  1,  1,  1,  1, 50,  1,  1,  0,  0, 0, 0, 0, 0, 0, 0 },
                     {  1,  1, 10,  1,  1,  1,  1,  1,  1,  0,  0, 0, 0, 0, 0, 0, 0 },
                     {  0,  0,  0,  0,  0,  0,  0,  0,  0,  1, 50, 1, 1, 1, 1, 1, 1 },
                     {  0,  0,  0,  0,  0,  0,  0,  0,  0, 50,  1, 1, 1, 1, 1, 1, 1 },
                     {  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1, 1, 1, 1, 1, 1, 1 },
                     {  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1, 1, 1, 1, 1, 1, 1 },
                     {  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1, 1, 1, 1, 1, 1, 1 },
                     {  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1, 1, 1, 1, 1, 1, 1 },
                     {  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1, 1, 1, 1, 1, 1, 1 },
                     {  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1, 1, 1, 1, 1, 1, 1 } };

        // Names of the guests. B: Bride side, G: Groom side
        String[] names = { "Deb (B)",   "John (B)",   "Martha (B)", "Travis (B)", "Allan (B)",
                           "Lois (B)",  "Jayne (B)",  "Brad (B)",   "Abby (B)",   "Mary Helen (G)",
                           "Lee (G)",   "Annika (G)", "Carl (G)",   "Colin (G)",  "Shirley (G)",
                           "DeAnn (G)", "Lori (G)" };

        int m = C.GetLength(0); // number of quests

        IEnumerable <int> NRANGE = Enumerable.Range(0, n);
        IEnumerable <int> MRANGE = Enumerable.Range(0, m);

        //
        // Decision variables
        //
        IntVar[] tables = solver.MakeIntVarArray(m, 0, n - 1, "tables");
        IntVar   z      = (from j in MRANGE from k in MRANGE where j <
                           k select C[j, k] * tables[j] ==
                           tables[k])
                          .ToArray()
                          .Sum()
                          .VarWithName("z");

        //
        // Constraints
        //
        foreach (int i in NRANGE)
        {
            solver.Add((from j in MRANGE from k in MRANGE where j < k &&
                        C[j, k] > 0 select(tables[j] == i) * (tables[k] == i))
                       .ToArray()
                       .Sum() >= b);

            solver.Add((from j in MRANGE select tables[j] == i).ToArray().Sum() <= a);
        }

        // Symmetry breaking
        solver.Add(tables[0] == 0);

        //
        // Objective
        //
        OptimizeVar obj = z.Maximize(1);

        //
        // Search
        //
        DecisionBuilder db = solver.MakePhase(tables, Solver.INT_VAR_DEFAULT, Solver.INT_VALUE_DEFAULT);

        solver.NewSearch(db, obj);
        while (solver.NextSolution())
        {
            Console.WriteLine("z: {0}", z.Value());
            Console.Write("Table: ");
            foreach (int j in MRANGE)
            {
                Console.Write(tables[j].Value() + " ");
            }
            Console.WriteLine();

            foreach (int i in NRANGE)
            {
                Console.Write("Table {0}: ", i);
                foreach (int j in MRANGE)
                {
                    if (tables[j].Value() == i)
                    {
                        Console.Write(names[j] + " ");
                    }
                }
                Console.WriteLine();
            }
            Console.WriteLine();
        }

        Console.WriteLine("\nSolutions: {0}", solver.Solutions());
        Console.WriteLine("WallTime: {0}ms", solver.WallTime());
        Console.WriteLine("Failures: {0}", solver.Failures());
        Console.WriteLine("Branches: {0} ", solver.Branches());

        solver.EndSearch();
    }
Example #14
0
    /**
     *
     * Crew allocation problem  in Google CP Solver.
     *
     * From Gecode example crew
     * examples/crew.cc
     * """
     * Example: Airline crew allocation
     *
     * Assign 20 flight attendants to 10 flights. Each flight needs a certain
     * number of cabin crew, and they have to speak certain languages.
     * Every cabin crew member has two flights off after an attended flight.
     * """
     *
     * Also see http://www.hakank.org/or-tools/crew.pl
     *
     */
    private static void Solve(int sols = 1, int minimize = 0)
    {
        Solver solver = new Solver("Crew");

        //
        // Data
        //
        string[] names = { "Tom",
                           "David",
                           "Jeremy",
                           "Ron",
                           "Joe",
                           "Bill",
                           "Fred",
                           "Bob",
                           "Mario",
                           "Ed",
                           "Carol",
                           "Janet",
                           "Tracy",
                           "Marilyn",
                           "Carolyn",
                           "Cathy",
                           "Inez",
                           "Jean",
                           "Heather",
                           "Juliet" };

        int num_persons = names.Length;


        //
        // Attributes of the crew
        //
        int[,] attributes =
        {
            // steward, hostess, french, spanish, german, other duties done in hours(per week)
            { 1, 0, 0, 0, 1, 1 }, // Tom     = 0
            { 1, 0, 0, 0, 0, 2 }, // David   = 1
            { 1, 0, 0, 0, 1, 0 }, // Jeremy  = 2
            { 1, 0, 0, 0, 0, 1 }, // Ron     = 3
            { 1, 0, 0, 1, 0, 1 }, // Joe     = 4
            { 1, 0, 1, 1, 0, 0 }, // Bill    = 5
            { 1, 0, 0, 1, 0, 1 }, // Fred    = 6
            { 1, 0, 0, 0, 0, 2 }, // Bob     = 7
            { 1, 0, 0, 1, 1, 1 }, // Mario   = 8
            { 1, 0, 0, 0, 0, 1 }, // Ed      = 9
            { 0, 1, 0, 0, 0, 9 }, // Carol   = 10
            { 0, 1, 0, 0, 0, 1 }, // Janet   = 11
            { 0, 1, 0, 0, 0, 2 }, // Tracy   = 12
            { 0, 1, 0, 1, 1, 0 }, // Marilyn = 13
            { 0, 1, 0, 0, 0, 1 }, // Carolyn = 14
            { 0, 1, 0, 0, 0, 1 }, // Cathy   = 15
            { 0, 1, 1, 1, 1, 1 }, // Inez    = 16
            { 0, 1, 1, 0, 0, 2 }, // Jean    = 17
            { 0, 1, 0, 1, 1, 1 }, // Heather = 18
            { 0, 1, 1, 0, 0, 1 } // Juliet  = 19
        };


        //
        // Required number of crew members.
        //
        // The columns are in the following order:
        // staff     : Overall number of cabin crew needed
        // stewards  : How many stewards are required
        // hostesses : How many hostesses are required
        // french    : How many French speaking employees are required
        // spanish   : How many Spanish speaking employees are required
        // german    : How many German speaking employees are required
        // duration(flight)  : How long is the flight
        // isNight   : Is night flight
        int[,] required_crew =
        {
            { 4, 1, 1, 1, 1, 1,  8, 1 }, //0 Flight 1
            { 5, 1, 1, 1, 1, 1,  5, 1 }, //1 Flight 2
            { 5, 1, 1, 1, 1, 1,  2, 1 }, //2 ..
            { 6, 2, 2, 1, 1, 1,  6, 1 }, //3
            { 7, 3, 3, 1, 1, 1,  5, 1 }, //4
            { 4, 1, 1, 1, 1, 1,  1, 0 }, //5
            { 5, 1, 1, 1, 1, 1,  6, 0 }, //6
            { 6, 1, 1, 1, 1, 1,  5, 0 }, //7
            { 6, 2, 2, 1, 1, 1,  6, 0 }, //8 ...
            { 7, 3, 3, 1, 1, 1, 10, 0 } //9 Flight 10
        };

        int num_flights = required_crew.GetLength(0);


        //
        // Decision variables
        //
        IntVar[,] crew = solver.MakeIntVarMatrix(num_flights, num_persons,
                                                 0, 1, "crew");
        IntVar[] crew_flat = crew.Flatten();

        // number of working persons
        // The MakeIntVar(i, j, name) method is a factory method that creates an integer variable whose domain is [i,j] = {i,i+1,...,j−1,j}
        //and has a name name. It returns a pointer to an IntVar
        IntVar num_working = solver.MakeIntVar(1, num_persons, "num_working"); // 1..20

        //
        // Constraints
        //

        // number of working persons
        IntVar[] nw = new IntVar[num_persons];
        for (int p = 0; p < num_persons; p++)
        {
            IntVar[] tmp = new IntVar[num_flights];
            for (int f = 0; f < num_flights; f++)
            {
                tmp[f] = crew[f, p];
            }
            nw[p] = tmp.Sum() > 0;
        }
        solver.Add(nw.Sum() == num_working);

        for (int f = 0; f < num_flights; f++)
        {
            // size of crew
            IntVar[] tmp = new IntVar[num_persons];
            for (int p = 0; p < num_persons; p++)
            {
                tmp[p] = crew[f, p];
            }
            solver.Add(tmp.Sum() == required_crew[f, 0]);

            // attributes and requirements
            for (int a = 0; a < 5; a++)
            {
                IntVar[] tmp2 = new IntVar[num_persons];
                for (int p = 0; p < num_persons; p++)
                {
                    tmp2[p] = (crew[f, p] * attributes[p, a]).Var();
                }
                solver.Add(tmp2.Sum() >= required_crew[f, a + 1]);
            }
        }

        // after a flight, break for at least two flights
        //for(int f = 0; f < num_flights - 2; f++) {
        //  for(int i = 0; i < num_persons; i++) {
        //    solver.Add(crew[f,i] + crew[f+1,i] + crew[f+2,i] <= 1);
        //  }
        //}

        // extra contraint: all must work at least two of the flights

        /*
         * for(int p = 0; p < num_persons; p++) {
         * IntVar[] tmp = new IntVar[num_flights];
         * for(int f = 0; f < num_flights; f++) {
         *  tmp[f] = crew[f,p];
         * }
         * solver.Add(tmp.Sum() >= 2);
         * }
         */


        // all memebers should only work less than 30 hours in flight
        for (int p = 0; p < num_persons; p++)
        {
            IntVar[] tmp3 = new IntVar[num_flights];
            for (int f = 0; f < num_flights; f++)
            {
                tmp3[f] = (crew[f, p] * required_crew[f, 6]).Var();
            }

            solver.Add(tmp3.Sum() <= 30);
        }

        ///Maximum Duty time per 1 week  
        //for (int p = 0; p < num_persons; p++)
        //{
        //    IntVar[] tmp4 = new IntVar[num_flights];
        //    for (int f = 0; f < num_flights; f++)
        //    {
        //        tmp4[f] = ((crew[f, p] * required_crew[f, 6]) + attributes[p, 5]).Var();
        //    }

        //    solver.Add(tmp4.Sum() <= 40);
        //}

        //assignment should not exceed maximum consecutive night duties of 2
        for (int f = 0; f < num_flights - 2; f++)
        {
            for (int i = 0; i < num_persons; i++)
            {
                solver.Add((crew[f, i] * required_crew[f, 7]) + (crew[f + 1, i] * required_crew[f, 7]) + (crew[f + 2, i] * required_crew[f, 7]) <= 2);
                //solver.Add((crew[f, i] * required_crew[f, 7]) + (crew[f + 1, i] * required_crew[f, 7])  <= 1);
            }
        }


        //
        // Search
        //
        DecisionBuilder db = solver.MakePhase(crew_flat,
                                              Solver.CHOOSE_FIRST_UNBOUND,
                                              Solver.ASSIGN_MIN_VALUE);

        if (minimize > 0)
        {
            OptimizeVar obj = num_working.Minimize(1);
            solver.NewSearch(db, obj);
        }
        else
        {
            solver.NewSearch(db);
        }

        int num_solutions = 0;

        while (solver.NextSolution())
        {
            num_solutions++;
            Console.WriteLine("Solution #{0}", num_solutions);
            Console.WriteLine("Number working: {0}", num_working.Value());


            //IList<Flight> FlightSchedule = new List<Flight>();
            for (int f = 0; f < num_flights; f++)
            {
                //Flight flight = new Flight();

                for (int p = 0; p < num_persons; p++)
                {
                    Console.Write(crew[f, p].Value() + " ");
                }
                Console.WriteLine();
            }
            Console.WriteLine("\nFlights: ");
            for (int f = 0; f < num_flights; f++)
            {
                Console.Write("Flight #{0}: ", f);
                for (int p = 0; p < num_persons; p++)
                {
                    if (crew[f, p].Value() == 1)
                    {
                        Console.Write(names[p] + " ");
                    }
                }
                Console.WriteLine();
            }

            Console.WriteLine("\nCrew:");
            for (int p = 0; p < num_persons; p++)
            {
                Console.Write("{0,-10}", names[p]);
                for (int f = 0; f < num_flights; f++)
                {
                    if (crew[f, p].Value() == 1)
                    {
                        Console.Write(f + " ");
                    }
                }
                Console.WriteLine();
            }

            Console.WriteLine();

            if (num_solutions >= sols)
            {
                break;
            }
        }

        Console.WriteLine("\nSolutions: {0}", solver.Solutions());
        Console.WriteLine("WallTime: {0}ms", solver.WallTime());
        Console.WriteLine("Failures: {0}", solver.Failures());
        Console.WriteLine("Branches: {0} ", solver.Branches());

        solver.EndSearch();
    }
Example #15
0
        static void Main(string[] args)
        {
            InitTaskList();
            int taskCount = GetTaskCount();

            Solver solver = new Solver("ResourceConstraintScheduling");

            IntervalVar[] tasks       = new IntervalVar[taskCount];
            IntVar[]      taskChoosed = new IntVar[taskCount];
            IntVar[]      makeSpan    = new IntVar[GetEndTaskCount()];

            int endJobCounter = 0;

            foreach (Job j in myJobList)
            {
                IntVar[] tmp = new IntVar[j.AlternativeTasks.Count];
                int      i   = 0;
                foreach (Task t in j.AlternativeTasks)
                {
                    long ti = taskIndexes[t.Name];
                    taskChoosed[ti] = solver.MakeIntVar(0, 1, t.Name + "_choose");
                    tmp[i++]        = taskChoosed[ti];
                    tasks[ti]       = solver.MakeFixedDurationIntervalVar(
                        0, 100000, t.Duration, false, t.Name + "_interval");
                    if (j.Successor == null)
                    {
                        makeSpan[endJobCounter++] = tasks[ti].EndExpr().Var();
                    }
                    if (!tasksToEquipment.ContainsKey(t.Equipment))
                    {
                        tasksToEquipment[t.Equipment] = new List <IntervalVar>();
                    }
                    tasksToEquipment[t.Equipment].Add(tasks[ti]);
                }
                solver.Add(IntVarArrayHelper.Sum(tmp) == 1);
            }

            List <SequenceVar> all_seq = new List <SequenceVar>();

            foreach (KeyValuePair <long, List <IntervalVar> > pair in tasksToEquipment)
            {
                DisjunctiveConstraint dc = solver.MakeDisjunctiveConstraint(
                    pair.Value.ToArray(), pair.Key.ToString());
                solver.Add(dc);
                all_seq.Add(dc.SequenceVar());
            }

            IntVar      objective_var     = solver.MakeMax(makeSpan).Var();
            OptimizeVar objective_monitor = solver.MakeMinimize(objective_var, 1);

            DecisionBuilder sequence_phase =
                solver.MakePhase(all_seq.ToArray(), Solver.SEQUENCE_DEFAULT);
            DecisionBuilder objective_phase =
                solver.MakePhase(objective_var, Solver.CHOOSE_FIRST_UNBOUND,
                                 Solver.ASSIGN_MIN_VALUE);
            DecisionBuilder main_phase = solver.Compose(sequence_phase, objective_phase);

            const int     kLogFrequency = 1000000;
            VoidToString  prefix        = new Prefix();
            SearchMonitor search_log    =
                solver.MakeSearchLog(kLogFrequency, objective_monitor, prefix);

            SolutionCollector collector = solver.MakeLastSolutionCollector();

            collector.Add(all_seq.ToArray());
            collector.AddObjective(objective_var);

            if (solver.Solve(main_phase, search_log, objective_monitor, null, collector))
            {
                Console.Out.WriteLine("Optimal solution = " + collector.ObjectiveValue(0));
            }
            else
            {
                Console.Out.WriteLine("No solution.");
            }
        }
Example #16
0
    /**
     *
     * Moving furnitures (scheduling) problem in Google CP Solver.
     *
     * Marriott & Stukey: 'Programming with constraints', page  112f
     *
     * The model implements an decomposition of the global constraint
     * cumulative (see above).
     *
     * Also see http://www.hakank.org/or-tools/furniture_moving.py
     *
     */
    private static void Solve()
    {
        Solver solver = new Solver("FurnitureMoving");

        int n = 4;

        int[] duration    = { 30, 10, 15, 15 };
        int[] demand      = { 3, 1, 3, 2 };
        int   upper_limit = 160;


        //
        // Decision variables
        //
        IntVar[] start_times = solver.MakeIntVarArray(n, 0, upper_limit, "start_times");
        IntVar[] end_times   = solver.MakeIntVarArray(n, 0, upper_limit * 2, "end_times");
        IntVar   end_time    = solver.MakeIntVar(0, upper_limit * 2, "end_time");

        // number of needed resources, to be minimized or constrained
        IntVar num_resources = solver.MakeIntVar(0, 10, "num_resources");


        //
        // Constraints
        //
        for (int i = 0; i < n; i++)
        {
            solver.Add(end_times[i] == start_times[i] + duration[i]);
        }

        solver.Add(end_time == end_times.Max());
        MyCumulative(solver, start_times, duration, demand, num_resources);


        //
        // Some extra constraints to play with
        //

        // all tasks must end within an hour
        // solver.Add(end_time <= 60);

        // All tasks should start at time 0
        // for(int i = 0; i < n; i++) {
        //   solver.Add(start_times[i] == 0);
        // }


        // limitation of the number of people
        // solver.Add(num_resources <= 3);
        solver.Add(num_resources <= 4);


        //
        // Objective
        //

        // OptimizeVar obj = num_resources.Minimize(1);
        OptimizeVar obj = end_time.Minimize(1);

        //
        // Search
        //
        DecisionBuilder db = solver.MakePhase(start_times,
                                              Solver.CHOOSE_FIRST_UNBOUND,
                                              Solver.ASSIGN_MIN_VALUE);

        solver.NewSearch(db, obj);

        while (solver.NextSolution())
        {
            Console.WriteLine("num_resources: {0} end_time: {1}",
                              num_resources.Value(), end_time.Value());
            for (int i = 0; i < n; i++)
            {
                Console.WriteLine("Task {0,1}: {1,2} -> {2,2} -> {3,2} (demand: {4})",
                                  i,
                                  start_times[i].Value(),
                                  duration[i],
                                  end_times[i].Value(),
                                  demand[i]);
            }
            Console.WriteLine();
        }

        Console.WriteLine("\nSolutions: {0}", solver.Solutions());
        Console.WriteLine("WallTime: {0}ms", solver.WallTime());
        Console.WriteLine("Failures: {0}", solver.Failures());
        Console.WriteLine("Branches: {0} ", solver.Branches());

        solver.EndSearch();
    }
Example #17
0
    /**
     *
     * Solves a set covering problem.
     * See  See http://www.hakank.org/or-tools/set_covering_opl.py
     *
     */
    private static void Solve()
    {
        Solver solver = new Solver("SetCoveringOPL");

        //
        // data
        //
        int num_workers = 32;
        int num_tasks   = 15;

        // Which worker is qualified for each task.
        // Note: This is 1-based and will be made 0-base below.
        int[][] qualified =
        {
            new int[] {  1,  9, 19, 22, 25, 28, 31 },
            new int[] {  2, 12, 15, 19, 21, 23,27, 29, 30, 31, 32 },
            new int[] {  3, 10, 19, 24, 26, 30, 32 },
            new int[] {  4, 21, 25, 28,32 },
            new int[] {  5, 11, 16, 22, 23, 27, 31 },
            new int[] {  6, 20, 24, 26, 30,32 },
            new int[] {  7, 12, 17, 25, 30,31 },
            new int[] {  8, 17, 20, 22,23 },
            new int[] {  9, 13, 14, 26, 29, 30, 31 },
            new int[] { 10, 21, 25, 31,32 },
            new int[] { 14, 15, 18, 23, 24, 27,30, 32 },
            new int[] { 18, 19, 22, 24, 26, 29, 31 },
            new int[] { 11, 20, 25, 28, 30,32 },
            new int[] { 16, 19, 23,31 },
            new int[] {  9, 18, 26, 28, 31, 32 }
        };

        int[] cost = { 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3,
                       3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 8, 9 };


        //
        // Decision variables
        //
        IntVar[] hire       = solver.MakeIntVarArray(num_workers, 0, 1, "workers");
        IntVar   total_cost = hire.ScalProd(cost).Var();

        //
        // Constraints
        //

        for (int j = 0; j < num_tasks; j++)
        {
            // Sum the cost for hiring the qualified workers
            // (also, make 0-base).
            int      len = qualified[j].Length;
            IntVar[] tmp = new IntVar[len];
            for (int c = 0; c < len; c++)
            {
                tmp[c] = hire[qualified[j][c] - 1];
            }
            solver.Add(tmp.Sum() >= 1);
        }


        //
        // objective
        //
        OptimizeVar objective = total_cost.Minimize(1);


        //
        // Search
        //
        DecisionBuilder db = solver.MakePhase(hire,
                                              Solver.CHOOSE_FIRST_UNBOUND,
                                              Solver.ASSIGN_MIN_VALUE);

        solver.NewSearch(db, objective);

        while (solver.NextSolution())
        {
            Console.WriteLine("Cost: " + total_cost.Value());
            Console.Write("Hire: ");
            for (int i = 0; i < num_workers; i++)
            {
                if (hire[i].Value() == 1)
                {
                    Console.Write(i + " ");
                }
            }
            Console.WriteLine("\n");
        }

        Console.WriteLine("\nSolutions: {0}", solver.Solutions());
        Console.WriteLine("WallTime: {0}ms", solver.WallTime());
        Console.WriteLine("Failures: {0}", solver.Failures());
        Console.WriteLine("Branches: {0} ", solver.Branches());

        solver.EndSearch();
    }
Example #18
0
    /**
     *
     * Set covering.
     *
     * Example from Steven Skiena, The Stony Brook Algorithm Repository
     * http://www.cs.sunysb.edu/~algorith/files/set-cover.shtml
     * """
     * Input Description: A set of subsets S_1, ..., S_m of the
     * universal set U = {1,...,n}.
     *
     * Problem: What is the smallest subset of subsets T subset S such
     * that \cup_{t_i in T} t_i = U?
     * """
     * Data is from the pictures INPUT/OUTPUT.
     *
     *
     * Also see http://www.hakank.org/or-tools/set_covering_skiena.py
     *
     */
    private static void Solve()
    {
        Solver solver = new Solver("SetCoveringSkiena");

        int num_sets               = 7;
        int num_elements           = 12;
        IEnumerable <int> Sets     = Enumerable.Range(0, num_sets);
        IEnumerable <int> Elements = Enumerable.Range(0, num_elements);

        // Which element belongs to which set
        int[,] belongs =
        {
            // 1 2 3 4 5 6 7 8 9 0 1 2  elements
            { 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Set 1
            { 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 }, //     2
            { 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0 }, //     3
            { 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0 }, //     4
            { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0 }, //     5
            { 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0 }, //     6
            { 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1 } //     7
        };


        //
        // Decision variables
        //
        IntVar[] x = solver.MakeIntVarArray(num_sets, 0, 1, "x");
        IntVar   z = x.Sum().VarWithName("z");
        // total number of elements in the choosen sets
        IntVar tot_elements = solver.MakeIntVar(0, num_sets * num_elements, "tot_elements");


        //
        // Constraints
        //

        // all sets must be used
        foreach (int j in Elements)
        {
            solver.Add((from i in Sets select belongs[i, j] * x[i])
                       .ToArray().Sum() >= 1);
        }

        // number of used elements
        solver.Add((from i in Sets from j in Elements select x[i] * belongs[i, j])
                   .ToArray().Sum() == tot_elements);

        //
        // Objective
        //
        OptimizeVar obj = z.Minimize(1);

        //
        // Search
        //
        DecisionBuilder db = solver.MakePhase(x,
                                              Solver.INT_VAR_DEFAULT,
                                              Solver.INT_VALUE_DEFAULT);

        solver.NewSearch(db, obj);

        while (solver.NextSolution())
        {
            Console.WriteLine("z: {0}", z.Value());
            Console.WriteLine("tot_elements: {0}", tot_elements.Value());
            Console.WriteLine(
                "x: {0}",
                String.Join(" ", (from i in Enumerable.Range(0, num_sets)
                                  select x[i].Value().ToString()).ToArray()));
        }

        Console.WriteLine("\nSolutions: {0}", solver.Solutions());
        Console.WriteLine("WallTime: {0}ms", solver.WallTime());
        Console.WriteLine("Failures: {0}", solver.Failures());
        Console.WriteLine("Branches: {0} ", solver.Branches());

        solver.EndSearch();
    }
Example #19
0
    private static void Solve(int first_slot)
    {
        Console.WriteLine("----------------------------------------------------");
        Solver solver = new Solver("SpeakerScheduling");

        // the slots each speaker is available
        int[][] speaker_availability =
        {
            new int[] {  1,  3,  4,  6,  7, 10, 12, 13, 14, 15, 16, 18, 19, 20, 21, 22, 23, 24, 25, 33, 34, 35, 36, 37, 38, 39, 40, 41, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 54, 55, 56, 57, 58, 59 },
            new int[] {  1,  2,  7,  8, 10, 11, 16, 17, 18, 21, 22, 23, 24, 25, 33, 34, 35, 36, 37, 38, 39, 40, 42, 43, 44, 45, 46, 47, 48, 49, 52, 53, 54, 55, 56, 57, 58, 59,60 },
            new int[] {  5,  6,  7, 10, 12, 14, 16, 17, 21, 22, 23, 24, 33, 35, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 51, 53, 55, 56, 57, 58,59 },
            new int[] {  1,  2,  3,  4,  5,  6,  7, 11, 13, 14, 15, 16, 20, 24, 25, 33, 34, 35, 37, 38, 39, 40, 41, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 58, 59,60 },
            new int[] {  4,  7,  8,  9, 16, 17, 19, 20, 21, 22, 23, 24, 25, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 49, 50, 51, 53, 55, 56, 57, 58, 59,60 },
            new int[] {  4,  7,  9, 11, 12, 13, 14, 15, 16, 17, 18, 22, 23, 24, 33, 34, 35, 36, 38, 39, 42, 44, 46, 48, 49, 51, 53, 54, 55, 56,57 },
            new int[] {  1,  2,  3,  4,  5,  6,  7, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 54, 55, 56, 57, 58, 59,60 },
            new int[] {  1,  3, 11, 14, 15, 16, 17, 21, 22, 23, 24, 25, 33, 35, 36, 37, 39, 40, 41, 42, 43, 44, 45, 47, 48, 49, 51, 52, 53, 54, 55, 56, 57, 58, 59,60 },
            new int[] {  1,  2,  3,  4,  5,  7,  8,  9, 10, 11, 13, 18, 19, 20, 21, 22, 23, 24, 25, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 50, 51, 52, 53, 54, 55, 56, 57, 59,60 },
            new int[] { 24, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 45, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,60 },
            new int[] {  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 16, 17, 18, 19, 20, 22, 23, 24, 25, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 52, 53,55, 56, 57, 58, 59, 60 },
            new int[] {  3,  4,  5,  6, 13, 15, 16, 17, 18, 19, 21, 22, 24, 25, 33, 34, 35, 36, 37, 39, 40, 41, 42, 43, 44, 45, 47, 52, 53, 55, 57, 58, 59,60 },
            new int[] {  4,  5,  6,  8, 11, 12, 13, 14, 17, 19, 20, 22, 23, 24, 25, 33, 34, 35, 36, 37, 39, 40, 41, 42, 43, 47, 48, 49, 50, 51, 52, 55, 56,57 },
            new int[] {  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,52, 53, 54, 55, 56, 57, 58, 59, 60 },
            new int[] { 12, 25, 33, 35, 36, 37, 39, 41, 42, 43, 48, 51, 52, 53, 54, 57, 59,60 },
            new int[] {  4,  8, 16, 17, 19, 23, 25, 33, 34, 35, 37, 41, 44, 45, 47, 48, 49,50 },
            new int[] {  3, 23, 24, 25, 33, 35, 36, 37, 38, 39, 40, 42, 43, 44, 49, 50, 53, 54, 55, 56, 57, 58,60 },
            new int[] {  7, 13, 19, 20, 22, 23, 24, 25, 33, 34, 35, 38, 40, 41, 42, 44, 45, 46, 47, 48, 49, 52, 53, 54, 58, 59, 60 }
        };

        // how long each talk lasts for each speaker
        int[] durations        = { 1, 2, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
        int   sum_of_durations = durations.Sum();

        int number_of_speakers = durations.Length;
        // calculate the total number of slots (maximum in the availability array)
        // (and add the max durations)
        int last_slot = (from s in Enumerable.Range(0, number_of_speakers)
                         select speaker_availability[s].Max()).Max();

        Console.WriteLine(
            "Scheduling {0} speakers, for a total of {1} slots, during [{2}..{3}]",
            number_of_speakers, sum_of_durations, first_slot, last_slot);

        // Start variable for all talks.
        IntVar[] starts = new IntVar[number_of_speakers];
        // We store the possible starts for all talks filtered from the
        // duration and the speaker availability.
        int[][] possible_starts = new int[number_of_speakers][];

        for (int speaker = 0; speaker < number_of_speakers; ++speaker)
        {
            int duration = durations[speaker];
            // Let's filter the possible starts.
            List <int> filtered_starts = new List <int>();
            int        availability    = speaker_availability[speaker].Length;
            for (int index = 0; index < availability; ++index)
            {
                bool ok   = true;
                int  slot = speaker_availability[speaker][index];
                if (slot < first_slot)
                {
                    continue;
                }
                for (int offset = 1; offset < durations[speaker]; ++offset)
                {
                    if (index + offset >= availability ||
                        speaker_availability[speaker][index + offset] != slot + offset)
                    {
                        // discontinuity.
                        ok = false;
                        break;
                    }
                }
                if (ok)
                {
                    filtered_starts.Add(slot);
                }
                possible_starts[speaker] = filtered_starts.ToArray();
            }
            starts[speaker] =
                solver.MakeIntVar(possible_starts[speaker], "start[" + speaker + "]");
        }

        List <IntVar>[] contributions_per_slot =
            new List <IntVar> [last_slot + 1];
        for (int slot = first_slot; slot <= last_slot; ++slot)
        {
            contributions_per_slot[slot] = new List <IntVar>();
        }
        for (int speaker = 0; speaker < number_of_speakers; ++speaker)
        {
            int    duration  = durations[speaker];
            IntVar start_var = starts[speaker];
            foreach (int start in possible_starts[speaker])
            {
                for (int offset = 0; offset < duration; ++offset)
                {
                    contributions_per_slot[start + offset].Add(start_var.IsEqual(start));
                }
            }
        }
        // Force the schedule to be consistent.
        for (int slot = first_slot; slot <= last_slot; ++slot)
        {
            solver.Add(
                solver.MakeSumLessOrEqual(contributions_per_slot[slot].ToArray(), 1));
        }

        // Add minimum start info.
        for (int speaker = 0; speaker < number_of_speakers; ++speaker)
        {
            solver.Add(starts[speaker] >= first_slot);
        }

        // Creates makespan.
        IntVar[] end_times = new IntVar[number_of_speakers];
        for (int speaker = 0; speaker < number_of_speakers; speaker++)
        {
            end_times[speaker] = (starts[speaker] + (durations[speaker] - 1)).Var();
        }
        IntVar last_slot_var = end_times.Max().VarWithName("last_slot");

        // Add trivial bound to objective.
        last_slot_var.SetMin(first_slot + sum_of_durations - 1);

        // Redundant scheduling constraint.
        IntervalVar[] intervals =
            solver.MakeFixedDurationIntervalVarArray(starts, durations, "intervals");
        DisjunctiveConstraint disjunctive =
            solver.MakeDisjunctiveConstraint(intervals, "disjunctive");

        solver.Add(disjunctive);

        //
        // Search
        //
        List <IntVar> short_talks = new List <IntVar>();
        List <IntVar> long_talks  = new List <IntVar>();

        for (int speaker = 0; speaker < number_of_speakers; ++speaker)
        {
            if (durations[speaker] == 1)
            {
                short_talks.Add(starts[speaker]);
            }
            else
            {
                long_talks.Add(starts[speaker]);
            }
        }
        OptimizeVar     objective_monitor = solver.MakeMinimize(last_slot_var, 1);
        DecisionBuilder long_phase        =
            solver.MakePhase(long_talks.ToArray(),
                             Solver.CHOOSE_MIN_SIZE_LOWEST_MIN,
                             Solver.ASSIGN_MIN_VALUE);
        DecisionBuilder short_phase =
            new FlowAssign(short_talks.ToArray(), first_slot, last_slot_var);
        DecisionBuilder obj_phase =
            solver.MakePhase(last_slot_var,
                             Solver.CHOOSE_FIRST_UNBOUND,
                             Solver.ASSIGN_MIN_VALUE);
        DecisionBuilder main_phase =
            solver.Compose(long_phase, short_phase, obj_phase);

        solver.NewSearch(main_phase, objective_monitor);
        while (solver.NextSolution())
        {
            Console.WriteLine("\nLast used slot: " + (last_slot_var.Value()));
            Console.WriteLine("Speakers (start..end):");
            for (int s = 0; s < number_of_speakers; s++)
            {
                long sstart = starts[s].Value();
                Console.WriteLine("  - speaker {0,2}: {1,2}..{2,2}", (s + 1),
                                  sstart, (sstart + durations[s] - 1));
            }
        }

        Console.WriteLine("\nSolutions: {0}", solver.Solutions());
        Console.WriteLine("WallTime: {0}ms", solver.WallTime());
        Console.WriteLine("Failures: {0}", solver.Failures());
        Console.WriteLine("Branches: {0} ", solver.Branches());
        solver.EndSearch();
    }
Example #20
0
    /**
     *
     * Combinatorial auction.
     *
     * This is a more general model for the combinatorial example
     * in the Numberjack Tutorial, pages 9 and 24 (slides  19/175 and
     * 51/175).
     *
     * See http://www.hakank.org/or-tools/combinatorial_auction2.py
     *
     * The original and more talkative model is here:
     * http://www.hakank.org/numberjack/combinatorial_auction.py
     *
     */
    private static void Solve()
    {
        Solver solver = new Solver("CombinatorialAuction2");

        //
        // Data
        //
        int n = 5;

        // the items for each bid
        int[][] items =
        {
            new int[] { 0, 1 }, // A,B
            new int[] { 0, 2 }, // A, C
            new int[] { 1, 3 }, // B,D
            new int[] { 1,2, 3 }, // B,C,D
            new int[] { 0 } // A
        };

        int[] bid_ids    = { 0, 1, 2, 3 };
        int[] bid_amount = { 10, 20, 30, 40, 14 };

        //
        // Decision variables
        //
        IntVar[] x = solver.MakeIntVarArray(n, 0, 1, "x");
        IntVar   z = x.ScalProd(bid_amount).VarWithName("z");

        //
        // Constraints
        //

        foreach (int bid_id in bid_ids)
        {
            var tmp2 = (from item in Enumerable.Range(0, n)
                        from i in Enumerable.Range(0, items[item].Length)
                        where items[item][i] == bid_id
                        select x[item]);

            solver.Add(tmp2.ToArray().Sum() <= 1);
        }



        //
        // Objective
        //
        OptimizeVar obj = z.Maximize(1);

        //
        // Search
        //
        DecisionBuilder db = solver.MakePhase(x,
                                              Solver.CHOOSE_FIRST_UNBOUND,
                                              Solver.ASSIGN_MIN_VALUE);

        solver.NewSearch(db, obj);

        while (solver.NextSolution())
        {
            Console.Write("z: {0,2} x: ", z.Value());
            for (int i = 0; i < n; i++)
            {
                Console.Write(x[i].Value() + " ");
            }
            Console.WriteLine();
        }

        Console.WriteLine("\nSolutions: {0}", solver.Solutions());
        Console.WriteLine("WallTime: {0}ms", solver.WallTime());
        Console.WriteLine("Failures: {0}", solver.Failures());
        Console.WriteLine("Branches: {0} ", solver.Branches());

        solver.EndSearch();
    }
Example #21
0
    /**
     *
     * Golomb Ruler problem.
     *
     * This C# implementation is based on Charles Prud'homme's
     * or-tools/Java model:
     * http://code.google.com/p/or-tools/source/browse/trunk/com/google/ortools/constraintsolver/samples/GolombRuler.java
     *
     */
    private static void Solve(int m = 8)
    {
        Solver solver = new Solver("GolombRuler");


        //
        // Decision variables
        //
        IntVar[] ticks = solver.MakeIntVarArray(m,
                                                0,
                                                ((m < 31) ? (1 << (m + 1)) - 1 : 9999),
                                                "ticks");

        IntVar[] diff = new IntVar[(m * m - m) / 2];


        //
        // Constraints
        //
        solver.Add(ticks[0] == 0);

        for (int i = 0; i < ticks.Length - 1; i++)
        {
            solver.Add(ticks[i] < ticks[i + 1]);
        }


        for (int k = 0, i = 0; i < m - 1; i++)
        {
            for (int j = i + 1; j < m; j++, k++)
            {
                diff[k] = (ticks[j] - ticks[i]).Var();
                solver.Add(diff[k] >= (j - i) * (j - i + 1) / 2);
            }
        }

        solver.Add(diff.AllDifferent());

        // break symetries
        if (m > 2)
        {
            solver.Add(diff[0] < diff[diff.Length - 1]);
        }


        //
        // Optimization
        //
        OptimizeVar opt = ticks[m - 1].Minimize(1);


        //
        // Search
        //
        DecisionBuilder db = solver.MakePhase(ticks,
                                              Solver.CHOOSE_MIN_SIZE_LOWEST_MIN,
                                              Solver.ASSIGN_MIN_VALUE);

        // We just want the debug info for larger instances.
        if (m >= 11)
        {
            SearchMonitor log = solver.MakeSearchLog(10000, opt);
            solver.NewSearch(db, opt, log);
        }
        else
        {
            solver.NewSearch(db, opt);
        }


        while (solver.NextSolution())
        {
            Console.Write("opt: {0}  [ ", ticks[m - 1].Value());
            for (int i = 0; i < m; i++)
            {
                Console.Write("{0} ", ticks[i].Value());
            }
            Console.WriteLine("]");
        }

        Console.WriteLine("\nSolutions: {0}", solver.Solutions());
        Console.WriteLine("WallTime: {0}ms", solver.WallTime());
        Console.WriteLine("Failures: {0}", solver.Failures());
        Console.WriteLine("Branches: {0} ", solver.Branches());

        solver.EndSearch();
    }
Example #22
0
    /**
     *
     * A programming puzzle from Einav.
     *
     * From
     * "A programming puzzle from Einav"
     * http://gcanyon.wordpress.com/2009/10/28/a-programming-puzzle-from-einav/
     * """
     * My friend Einav gave me this programming puzzle to work on. Given
     * this array of positive and negative numbers:
     * 33   30  -10 -6  18   7  -11 -23   6
     * ...
     * -25   4  16  30  33 -23  -4   4 -23
     *
     * You can flip the sign of entire rows and columns, as many of them
     * as you like. The goal is to make all the rows and columns sum to positive
     * numbers (or zero), and then to find the solution (there are more than one)
     * that has the smallest overall sum. So for example, for this array:
     * 33  30 -10
     * -16  19   9
     * -17 -12 -14
     * You could flip the sign for the bottom row to get this array:
     * 33  30 -10
     * -16  19   9
     * 17  12  14
     * Now all the rows and columns have positive sums, and the overall total is
     * 108.
     * But you could instead flip the second and third columns, and the second
     * row, to get this array:
     * 33  -30  10
     * 16   19    9
     * -17   12   14
     * All the rows and columns still total positive, and the overall sum is just
     * 66. So this solution is better (I don't know if it's the best)
     * A pure brute force solution would have to try over 30 billion solutions.
     * I wrote code to solve this in J. I'll post that separately.
     * """
     *
     * Note:
     * This is a port of Larent Perrons's Python version of my own einav_puzzle.py.
     * He removed some of the decision variables and made it more efficient.
     * Thanks!
     *
     * Also see http://www.hakank.org/or-tools/einav_puzzle2.py
     *
     */
    private static void Solve()
    {
        Solver solver = new Solver("EinavPuzzle2");

        //
        // Data
        //

        // Small problem
        // int rows = 3;
        // int cols = 3;
        // int[,] data = {
        //   { 33,  30, -10},
        //   {-16,  19,   9},
        //   {-17, -12, -14}
        // };


        // Full problem
        int rows = 27;
        int cols = 9;

        int[,] data =
        {
            {  33,  30,  10,  -6,  18,  -7, -11,  23,  -6 },
            {  16, -19,   9, -26,  -8, -19,  -8, -21, -14 },
            {  17,  12, -14,  31, -30,  13, -13,  19,  16 },
            {  -6, -11,   1,  17, -12,  -4,  -7,  14, -21 },
            {  18, -31,  34, -22,  17, -19,  20,  24,   6 },
            {  33, -18,  17, -15,  31,  -5,   3,  27,  -3 },
            { -18, -20, -18,  31,   6,   4,  -2, -12,  24 },
            {  27,  14,   4, -29,  -3,   5, -29,   8, -12 },
            { -15,  -7, -23,  23,  -9,  -8,   6,   8, -12 },
            {  33, -23, -19,  -4,  -8,  -7,  11, -12,  31 },
            { -20,  19, -15, -30,  11,  32,   7,  14,  -5 },
            { -23,  18, -32,  -2, -31,  -7,   8,  24,  16 },
            {  32,  -4, -10, -14,  -6,  -1,   0,  23,  23 },
            {  25,   0, -23,  22,  12,  28, -27,  15,   4 },
            { -30, -13, -16,  -3,  -3, -32,  -3,  27, -31 },
            {  22,   1,  26,   4,  -2, -13,  26,  17,  14 },
            {  -9, -18,   3, -20, -27, -32, -11,  27,  13 },
            { -17,  33,  -7,  19, -32,  13, -31,  -2, -24 },
            { -31,  27, -31, -29,  15,   2,  29, -15,  33 },
            { -18, -23,  15,  28,   0,  30,  -4,  12, -32 },
            {  -3,  34,  27, -25, -18,  26,   1,  34,  26 },
            { -21, -31, -10, -13, -30, -17, -12, -26,  31 },
            {  23, -31, -19,  21, -17, -10,   2, -23,  23 },
            {  -3,   6,   0,  -3, -32,   0, -10, -25,  14 },
            { -19,   9,  14, -27,  20,  15,  -5, -27,  18 },
            {  11,  -6,  24,   7, -17,  26,  20, -31, -25 },
            { -25,   4, -16,  30,  33,  23,  -4,  -4,  23 }
        };


        IEnumerable <int> ROWS = Enumerable.Range(0, rows);
        IEnumerable <int> COLS = Enumerable.Range(0, cols);

        //
        // Decision variables
        //
        IntVar[,] x = solver.MakeIntVarMatrix(rows, cols, -100, 100, "x");
        IntVar[] x_flat = x.Flatten();

        int[] signs_domain = { -1, 1 };
        // This don't work at the moment...
        IntVar[] row_signs = solver.MakeIntVarArray(rows, signs_domain, "row_signs");
        IntVar[] col_signs = solver.MakeIntVarArray(cols, signs_domain, "col_signs");



        // To optimize
        IntVar total_sum = x_flat.Sum().VarWithName("total_sum");

        //
        // Constraints
        //
        foreach (int i in ROWS)
        {
            foreach (int j in COLS)
            {
                solver.Add(x[i, j] == data[i, j] * row_signs[i] * col_signs[j]);
            }
        }

        // row sums
        IntVar[] row_sums = (from i in ROWS
                             select(from j in COLS
                                    select x[i, j]
                                    ).ToArray().Sum().Var()).ToArray();

        foreach (int i in ROWS)
        {
            row_sums[i].SetMin(0);
        }

        // col sums
        IntVar[] col_sums = (from j in COLS
                             select(from i in ROWS
                                    select x[i, j]
                                    ).ToArray().Sum().Var()).ToArray();

        foreach (int j in COLS)
        {
            col_sums[j].SetMin(0);
        }


        //
        // Objective
        //
        OptimizeVar obj = total_sum.Minimize(1);


        //
        // Search
        //
        DecisionBuilder db = solver.MakePhase(col_signs.Concat(row_signs).ToArray(),
                                              Solver.CHOOSE_MIN_SIZE_LOWEST_MIN,
                                              Solver.ASSIGN_MAX_VALUE);

        solver.NewSearch(db, obj);

        while (solver.NextSolution())
        {
            Console.WriteLine("Sum: {0}", total_sum.Value());
            Console.Write("row_sums: ");
            foreach (int i in ROWS)
            {
                Console.Write(row_sums[i].Value() + " ");
            }
            Console.Write("\nrow_signs: ");
            foreach (int i in ROWS)
            {
                Console.Write(row_signs[i].Value() + " ");
            }

            Console.Write("\ncol_sums: ");
            foreach (int j in COLS)
            {
                Console.Write(col_sums[j].Value() + " ");
            }
            Console.Write("\ncol_signs: ");
            foreach (int j in COLS)
            {
                Console.Write(col_signs[j].Value() + " ");
            }
            Console.WriteLine("\n");
            foreach (int i in ROWS)
            {
                foreach (int j in COLS)
                {
                    Console.Write("{0,3} ", x[i, j].Value());
                }
                Console.WriteLine();
            }
            Console.WriteLine();
        }

        Console.WriteLine("\nSolutions: {0}", solver.Solutions());
        Console.WriteLine("WallTime: {0}ms", solver.WallTime());
        Console.WriteLine("Failures: {0}", solver.Failures());
        Console.WriteLine("Branches: {0} ", solver.Branches());

        solver.EndSearch();
    }
Example #23
0
    /**
     *
     * P-median problem.
     *
     * Model and data from the OPL Manual, which describes the problem:
     * """
     * The P-Median problem is a well known problem in Operations Research.
     * The problem can be stated very simply, like this: given a set of customers
     * with known amounts of demand, a set of candidate locations for warehouses,
     * and the distance between each pair of customer-warehouse, choose P
     * warehouses to open that minimize the demand-weighted distance of serving
     * all customers from those P warehouses.
     * """
     *
     * Also see http://www.hakank.org/or-tools/p_median.py
     *
     */
    private static void Solve()
    {
        Solver solver = new Solver("PMedian");

        //
        // Data
        //
        int p                       = 2;
        int num_customers           = 4;
        IEnumerable <int> CUSTOMERS = Enumerable.Range(0, num_customers);

        int num_warehouses           = 3;
        IEnumerable <int> WAREHOUSES = Enumerable.Range(0, num_warehouses);

        int[] demand = { 100, 80, 80, 70 };
        int[,] distance = { { 2, 10, 50 }, { 2, 10, 52 }, { 50, 60, 3 }, { 40, 60, 1 } };

        //
        // Decision variables
        //

        IntVar[] open = solver.MakeIntVarArray(num_warehouses, 0, num_warehouses, "open");
        IntVar[,] ship = solver.MakeIntVarMatrix(num_customers, num_warehouses, 0, 1, "ship");
        IntVar z = solver.MakeIntVar(0, 1000, "z");

        //
        // Constraints
        //

        solver.Add(
            (from c in CUSTOMERS from w in WAREHOUSES select(demand[c] * distance[c, w] * ship[c, w]))
            .ToArray()
            .Sum() == z);

        solver.Add(open.Sum() == p);

        foreach (int c in CUSTOMERS)
        {
            foreach (int w in WAREHOUSES)
            {
                solver.Add(ship[c, w] <= open[w]);
            }

            solver.Add((from w in WAREHOUSES select ship[c, w]).ToArray().Sum() == 1);
        }

        //
        // Objective
        //
        OptimizeVar obj = z.Minimize(1);

        //
        // Search
        //
        DecisionBuilder db = solver.MakePhase(open.Concat(ship.Flatten()).ToArray(),
                                              Solver.CHOOSE_FIRST_UNBOUND, Solver.ASSIGN_MIN_VALUE);

        solver.NewSearch(db, obj);

        while (solver.NextSolution())
        {
            Console.WriteLine("z: {0}", z.Value());
            Console.Write("open:");
            foreach (int w in WAREHOUSES)
            {
                Console.Write(open[w].Value() + " ");
            }
            Console.WriteLine();
            foreach (int c in CUSTOMERS)
            {
                foreach (int w in WAREHOUSES)
                {
                    Console.Write(ship[c, w].Value() + " ");
                }
                Console.WriteLine();
            }
            Console.WriteLine();
        }

        Console.WriteLine("\nSolutions: {0}", solver.Solutions());
        Console.WriteLine("WallTime: {0}ms", solver.WallTime());
        Console.WriteLine("Failures: {0}", solver.Failures());
        Console.WriteLine("Branches: {0} ", solver.Branches());

        solver.EndSearch();
    }
Example #24
0
    /**
     *
     * Crew allocation problem  in Google CP Solver.
     *
     * From Gecode example crew
     * examples/crew.cc
     * """
     * Example: Airline crew allocation
     *
     * Assign 20 flight attendants to 10 flights. Each flight needs a certain
     * number of cabin crew, and they have to speak certain languages.
     * Every cabin crew member has two flights off after an attended flight.
     * """
     *
     * Also see http://www.hakank.org/or-tools/crew.pl
     *
     */
    private static void Solve(int sols = 1, int minimize = 0)
    {
        Solver solver = new Solver("Crew");

        //
        // Data
        //
        string[] names = { "Tom",     "David", "Jeremy", "Ron",   "Joe",     "Bill",  "Fred",
                           "Bob",     "Mario", "Ed",     "Carol", "Janet",   "Tracy", "Marilyn",
                           "Carolyn", "Cathy", "Inez",   "Jean",  "Heather", "Juliet" };

        int num_persons = names.Length;

        //
        // Attributes of the crew
        //
        int[,] attributes =
        {
            // steward, hostess, french, spanish, german
            { 1, 0, 0, 0, 1 }, // Tom     = 0
            { 1, 0, 0, 0, 0 }, // David   = 1
            { 1, 0, 0, 0, 1 }, // Jeremy  = 2
            { 1, 0, 0, 0, 0 }, // Ron     = 3
            { 1, 0, 0, 1, 0 }, // Joe     = 4
            { 1, 0, 1, 1, 0 }, // Bill    = 5
            { 1, 0, 0, 1, 0 }, // Fred    = 6
            { 1, 0, 0, 0, 0 }, // Bob     = 7
            { 1, 0, 0, 1, 1 }, // Mario   = 8
            { 1, 0, 0, 0, 0 }, // Ed      = 9
            { 0, 1, 0, 0, 0 }, // Carol   = 10
            { 0, 1, 0, 0, 0 }, // Janet   = 11
            { 0, 1, 0, 0, 0 }, // Tracy   = 12
            { 0, 1, 0, 1, 1 }, // Marilyn = 13
            { 0, 1, 0, 0, 0 }, // Carolyn = 14
            { 0, 1, 0, 0, 0 }, // Cathy   = 15
            { 0, 1, 1, 1, 1 }, // Inez    = 16
            { 0, 1, 1, 0, 0 }, // Jean    = 17
            { 0, 1, 0, 1, 1 }, // Heather = 18
            { 0, 1, 1, 0, 0 } // Juliet  = 19
        };

        //
        // Required number of crew members.
        //
        // The columns are in the following order:
        // staff     : Overall number of cabin crew needed
        // stewards  : How many stewards are required
        // hostesses : How many hostesses are required
        // french    : How many French speaking employees are required
        // spanish   : How many Spanish speaking employees are required
        // german    : How many German speaking employees are required
        //
        int[,] required_crew =
        {
            { 4, 1, 1, 1, 1, 1 },                                             // Flight 1
            { 5, 1, 1, 1, 1, 1 },                                             // Flight 2
            { 5, 1, 1, 1, 1, 1 },                                             // ..
            { 6, 2, 2, 1, 1, 1 }, { 7, 3, 3, 1, 1, 1 }, { 4, 1, 1, 1, 1, 1 },
            { 5, 1, 1, 1, 1, 1 }, { 6, 1, 1, 1, 1, 1 }, { 6, 2, 2, 1, 1, 1 }, // ...
            { 7, 3, 3, 1, 1, 1 }                                              // Flight 10
        };

        int num_flights = required_crew.GetLength(0);

        //
        // Decision variables
        //
        IntVar[,] crew = solver.MakeIntVarMatrix(num_flights, num_persons, 0, 1, "crew");
        IntVar[] crew_flat = crew.Flatten();

        // number of working persons
        IntVar num_working = solver.MakeIntVar(1, num_persons, "num_working");

        //
        // Constraints
        //

        // number of working persons
        IntVar[] nw = new IntVar[num_persons];
        for (int p = 0; p < num_persons; p++)
        {
            IntVar[] tmp = new IntVar[num_flights];
            for (int f = 0; f < num_flights; f++)
            {
                tmp[f] = crew[f, p];
            }
            nw[p] = tmp.Sum() > 0;
        }
        solver.Add(nw.Sum() == num_working);

        for (int f = 0; f < num_flights; f++)
        {
            // size of crew
            IntVar[] tmp = new IntVar[num_persons];
            for (int p = 0; p < num_persons; p++)
            {
                tmp[p] = crew[f, p];
            }
            solver.Add(tmp.Sum() == required_crew[f, 0]);

            // attributes and requirements
            for (int a = 0; a < 5; a++)
            {
                IntVar[] tmp2 = new IntVar[num_persons];
                for (int p = 0; p < num_persons; p++)
                {
                    tmp2[p] = (crew[f, p] * attributes[p, a]).Var();
                }
                solver.Add(tmp2.Sum() >= required_crew[f, a + 1]);
            }
        }

        // after a flight, break for at least two flights
        for (int f = 0; f < num_flights - 2; f++)
        {
            for (int i = 0; i < num_persons; i++)
            {
                solver.Add(crew[f, i] + crew[f + 1, i] + crew[f + 2, i] <= 1);
            }
        }

        // extra contraint: all must work at least two of the flights

        /*
         * for(int p = 0; p < num_persons; p++) {
         * IntVar[] tmp = new IntVar[num_flights];
         * for(int f = 0; f < num_flights; f++) {
         *  tmp[f] = crew[f,p];
         * }
         * solver.Add(tmp.Sum() >= 2);
         * }
         */

        //
        // Search
        //
        DecisionBuilder db =
            solver.MakePhase(crew_flat, Solver.CHOOSE_FIRST_UNBOUND, Solver.ASSIGN_MIN_VALUE);

        if (minimize > 0)
        {
            OptimizeVar obj = num_working.Minimize(1);
            solver.NewSearch(db, obj);
        }
        else
        {
            solver.NewSearch(db);
        }

        int num_solutions = 0;

        while (solver.NextSolution())
        {
            num_solutions++;
            Console.WriteLine("Solution #{0}", num_solutions);
            Console.WriteLine("Number working: {0}", num_working.Value());

            for (int f = 0; f < num_flights; f++)
            {
                for (int p = 0; p < num_persons; p++)
                {
                    Console.Write(crew[f, p].Value() + " ");
                }
                Console.WriteLine();
            }
            Console.WriteLine("\nFlights: ");
            for (int f = 0; f < num_flights; f++)
            {
                Console.Write("Flight #{0}: ", f);
                for (int p = 0; p < num_persons; p++)
                {
                    if (crew[f, p].Value() == 1)
                    {
                        Console.Write(names[p] + " ");
                    }
                }
                Console.WriteLine();
            }

            Console.WriteLine("\nCrew:");
            for (int p = 0; p < num_persons; p++)
            {
                Console.Write("{0,-10}", names[p]);
                for (int f = 0; f < num_flights; f++)
                {
                    if (crew[f, p].Value() == 1)
                    {
                        Console.Write(f + " ");
                    }
                }
                Console.WriteLine();
            }

            Console.WriteLine();

            if (num_solutions >= sols)
            {
                break;
            }
        }

        Console.WriteLine("\nSolutions: {0}", solver.Solutions());
        Console.WriteLine("WallTime: {0}ms", solver.WallTime());
        Console.WriteLine("Failures: {0}", solver.Failures());
        Console.WriteLine("Branches: {0} ", solver.Branches());

        solver.EndSearch();
    }
Example #25
0
    /**
     *
     * Solves a set covering problem.
     * See  See http://www.hakank.org/or-tools/set_covering4.py
     *
     */
    private static void Solve(int set_partition)
    {
        Solver solver = new Solver("SetCovering4");

        //
        // data
        //

        // Set partition and set covering problem from
        // Example from the Swedish book
        // Lundgren, Roennqvist, Vaebrand
        // 'Optimeringslaera' (translation: 'Optimization theory'),
        // page 408.
        int num_alternatives = 10;
        int num_objects      = 8;

        // costs for the alternatives
        int[] costs = { 19, 16, 18, 13, 15, 19, 15, 17, 16, 15 };

        // the alternatives, and their objects
        int[,] a =                      // 1 2 3 4 5 6 7 8    the objects
        {
            { 1, 0, 0, 0, 0, 1, 0, 0 }, // alternative 1
            { 0, 1, 0, 0, 0, 1, 0, 1 }, // alternative 2
            { 1, 0, 0, 1, 0, 0, 1, 0 }, // alternative 3
            { 0, 1, 1, 0, 1, 0, 0, 0 }, // alternative 4
            { 0, 1, 0, 0, 1, 0, 0, 0 }, // alternative 5
            { 0, 1, 1, 0, 0, 0, 0, 0 }, // alternative 6
            { 0, 1, 1, 1, 0, 0, 0, 0 }, // alternative 7
            { 0, 0, 0, 1, 1, 0, 0, 1 }, // alternative 8
            { 0, 0, 1, 0, 0, 1, 0, 1 }, // alternative 9
            { 1, 0, 0, 0, 0, 1, 1, 0 }
        };                              // alternative 10

        //
        // Decision variables
        //
        IntVar[] x = solver.MakeIntVarArray(num_alternatives, 0, 1, "x");
        // number of assigned senators, to be minimized
        IntVar z = x.ScalProd(costs).VarWithName("z");

        //
        // Constraints
        //

        for (int j = 0; j < num_objects; j++)
        {
            IntVar[] b = new IntVar[num_alternatives];
            for (int i = 0; i < num_alternatives; i++)
            {
                b[i] = (x[i] * a[i, j]).Var();
            }

            if (set_partition == 1)
            {
                solver.Add(b.Sum() >= 1);
            }
            else
            {
                solver.Add(b.Sum() == 1);
            }
        }

        //
        // objective
        //
        OptimizeVar objective = z.Minimize(1);

        //
        // Search
        //
        DecisionBuilder db = solver.MakePhase(x, Solver.INT_VAR_DEFAULT, Solver.INT_VALUE_DEFAULT);

        solver.NewSearch(db, objective);

        while (solver.NextSolution())
        {
            Console.WriteLine("z: " + z.Value());
            Console.Write("Selected alternatives: ");
            for (int i = 0; i < num_alternatives; i++)
            {
                if (x[i].Value() == 1)
                {
                    Console.Write((i + 1) + " ");
                }
            }
            Console.WriteLine("\n");
        }

        Console.WriteLine("\nSolutions: {0}", solver.Solutions());
        Console.WriteLine("WallTime: {0}ms", solver.WallTime());
        Console.WriteLine("Failures: {0}", solver.Failures());
        Console.WriteLine("Branches: {0} ", solver.Branches());

        solver.EndSearch();
    }
Example #26
0
    /**
     *
     * Solves a set covering problem.
     * See  See http://www.hakank.org/or-tools/set_covering2.py
     *
     */
    private static void Solve()
    {
        Solver solver = new Solver("SetCovering2");

        //
        // data
        //

        // Example 9.1-2 from
        // Taha "Operations Research - An Introduction",
        // page 354ff.
        // Minimize the number of security telephones in street
        // corners on a campus.

        int n           = 8;  // maximum number of corners
        int num_streets = 11; // number of connected streets

        // corners of each street
        // Note: 1-based (handled below)
        int[,] corner = { { 1, 2 }, { 2, 3 }, { 4, 5 }, { 7, 8 }, { 6, 7 }, { 2, 6 },
                          { 1, 6 }, { 4, 7 }, { 2, 4 }, { 5, 8 }, { 3, 5 } };

        //
        // Decision variables
        //
        IntVar[] x = solver.MakeIntVarArray(n, 0, 1, "x");
        // number of telephones, to be minimized
        IntVar z = x.Sum().Var();

        //
        // Constraints
        //

        // ensure that all streets are covered
        for (int i = 0; i < num_streets; i++)
        {
            solver.Add(x[corner[i, 0] - 1] + x[corner[i, 1] - 1] >= 1);
        }

        //
        // objective
        //
        OptimizeVar objective = z.Minimize(1);

        //
        // Search
        //
        DecisionBuilder db = solver.MakePhase(x, Solver.INT_VAR_DEFAULT, Solver.INT_VALUE_DEFAULT);

        solver.NewSearch(db, objective);

        while (solver.NextSolution())
        {
            Console.WriteLine("z: {0}", z.Value());
            Console.Write("x: ");
            for (int i = 0; i < n; i++)
            {
                Console.Write(x[i].Value() + " ");
            }
            Console.WriteLine();
        }

        Console.WriteLine("\nSolutions: {0}", solver.Solutions());
        Console.WriteLine("WallTime: {0}ms", solver.WallTime());
        Console.WriteLine("Failures: {0}", solver.Failures());
        Console.WriteLine("Branches: {0} ", solver.Branches());

        solver.EndSearch();
    }
    /**
     *
     * Moving furnitures (scheduling) problem in Google CP Solver.
     *
     * Marriott & Stukey: 'Programming with constraints', page  112f
     *
     * Also see http://www.hakank.org/or-tools/furniture_moving.py
     *
     */
    private static void Solve()
    {
        Solver solver = new Solver("FurnitureMovingIntervals");

        const int n = 4;

        int[]     durations       = { 30, 10, 15, 15 };
        int[]     demand          = { 3, 1, 3, 2 };
        const int upper_limit     = 160;
        const int max_num_workers = 5;

        //
        // Decision variables
        //
        IntervalVar[] tasks = new IntervalVar[n];
        for (int i = 0; i < n; ++i)
        {
            tasks[i] =
                solver.MakeFixedDurationIntervalVar(0, upper_limit - durations[i], durations[i], false, "task_" + i);
        }

        // Fillers that span the whole resource and limit the available
        // number of workers.
        IntervalVar[] fillers = new IntervalVar[max_num_workers];
        for (int i = 0; i < max_num_workers; ++i)
        {
            fillers[i] = solver.MakeFixedDurationIntervalVar(0, 0, upper_limit, true, "filler_" + i);
        }

        // Number of needed resources, to be minimized or constrained.
        IntVar num_workers = solver.MakeIntVar(0, max_num_workers, "num_workers");

        // Links fillers and num_workers.
        for (int i = 0; i < max_num_workers; ++i)
        {
            solver.Add((num_workers > i) + fillers[i].PerformedExpr() == 1);
        }

        // Creates makespan.
        IntVar[] ends = new IntVar[n];
        for (int i = 0; i < n; ++i)
        {
            ends[i] = tasks[i].EndExpr().Var();
        }
        IntVar end_time = ends.Max().VarWithName("end_time");

        //
        // Constraints
        //
        IntervalVar[] all_tasks   = new IntervalVar[n + max_num_workers];
        int[]         all_demands = new int[n + max_num_workers];
        for (int i = 0; i < n; ++i)
        {
            all_tasks[i]   = tasks[i];
            all_demands[i] = demand[i];
        }
        for (int i = 0; i < max_num_workers; ++i)
        {
            all_tasks[i + n]   = fillers[i];
            all_demands[i + n] = 1;
        }
        solver.Add(all_tasks.Cumulative(all_demands, max_num_workers, "workers"));

        //
        // Some extra constraints to play with
        //

        // all tasks must end within an hour
        // solver.Add(end_time <= 60);

        // All tasks should start at time 0
        // for(int i = 0; i < n; i++) {
        //   solver.Add(tasks[i].StartAt(0));
        // }

        // limitation of the number of people
        // solver.Add(num_workers <= 3);
        solver.Add(num_workers <= 4);

        //
        // Objective
        //

        // OptimizeVar obj = num_workers.Minimize(1);
        OptimizeVar obj = end_time.Minimize(1);

        //
        // Search
        //
        DecisionBuilder db = solver.MakePhase(all_tasks, Solver.INTERVAL_DEFAULT);

        solver.NewSearch(db, obj);

        while (solver.NextSolution())
        {
            Console.WriteLine(num_workers.ToString() + ", " + end_time.ToString());
            for (int i = 0; i < n; i++)
            {
                Console.WriteLine("{0} (demand:{1})", tasks[i].ToString(), demand[i]);
            }
            Console.WriteLine();
        }

        Console.WriteLine("Solutions: {0}", solver.Solutions());
        Console.WriteLine("WallTime: {0} ms", solver.WallTime());
        Console.WriteLine("Failures: {0}", solver.Failures());
        Console.WriteLine("Branches: {0} ", solver.Branches());

        solver.EndSearch();
    }
Example #28
0
        private static long Run(int[][] costs, long bestCost = 0)
        {
            bool   finalSearch = bestCost > 0;
            long   result      = 0;
            Solver solver      = new Solver("Assignment");

            int bots  = costs.Length;    // rows
            int tasks = costs[0].Length; // cols

            // Decision variables
            IntVar[,] x = solver.MakeBoolVarMatrix(bots, tasks, "x");
            IntVar[] x_flat = x.Flatten();

            // Dynamic Constraints
            if (bots > tasks)
            {
                // Each bot is assigned to at most 1 task
                for (int i = 0; i < bots; i++)
                {
                    solver.Add((from j in Enumerable.Range(0, tasks)
                                select x[i, j]).ToArray().Sum() <= 1);
                }

                // Each task is assigned to exactly one bot
                for (int j = 0; j < tasks; j++)
                {
                    solver.Add((from i in Enumerable.Range(0, bots)
                                select x[i, j]).ToArray().Sum() == 1);
                }
            }
            else
            {
                // Each task is assigned to exactly one bot
                for (int i = 0; i < bots; i++)
                {
                    solver.Add((from j in Enumerable.Range(0, tasks)
                                select x[i, j]).ToArray().Sum() == 1);
                }

                // Each bot is assigned to at most 1 task
                for (int j = 0; j < tasks; j++)
                {
                    solver.Add((from i in Enumerable.Range(0, bots)
                                select x[i, j]).ToArray().Sum() <= 1);
                }
            }

            // Total cost
            IntVar total_cost = (from i in Enumerable.Range(0, bots)
                                 from j in Enumerable.Range(0, tasks)
                                 select(costs[i][j] * x[i, j])).ToArray().Sum().Var();

            if (bestCost > 0)
            {
                solver.Add(total_cost == bestCost);
            }

            // Search
            DecisionBuilder db = solver.MakePhase(x_flat,
                                                  Solver.INT_VAR_DEFAULT,
                                                  Solver.INT_VALUE_DEFAULT);

            if (!finalSearch)
            {
                // Objective
                OptimizeVar objective = total_cost.Minimize(1);
                solver.NewSearch(db, objective);
            }
            else
            {
                solver.NewSearch(db);
            }

            while (solver.NextSolution())
            {
                output.Clear();
                result = total_cost.Value();
                Console.WriteLine($"total_cost: {result}");
                if (finalSearch)
                {
                    for (int i = 0; i < bots; i++)
                    {
                        for (int j = 0; j < tasks; j++)
                        {
                            Console.Write(x[i, j].Value() + " ");
                        }
                        Console.WriteLine();
                    }
                }

                for (int i = 0; i < bots; i++)
                {
                    bool isAssigned = false;
                    for (int j = 0; j < tasks; j++)
                    {
                        if (x[i, j].Value() == 1)
                        {
                            output.Add(new Tuple <int, int>(i, j));
                            isAssigned = true;
                        }
                    }
                    if (!isAssigned)
                    {
                        output.Add(new Tuple <int, int>(i, -1));
                    }
                }
            }

            Console.WriteLine("\nSolutions: {0}", solver.Solutions());
            Console.WriteLine("WallTime: {0}ms", solver.WallTime());
            Console.WriteLine("Failures: {0}", solver.Failures());
            Console.WriteLine("Branches: {0} ", solver.Branches());
            Console.WriteLine("Number of constraints = " + solver.Constraints());

            solver.EndSearch();
            return(result);
        }
Example #29
0
    /**
     *
     * Solves the Diet problem
     *
     * See http://www.hakank.org/google_or_tools/diet1.py
     *
     */
    private static void Solve()
    {
        Solver solver = new Solver("Diet");

        int n = 4;

        int[] price = { 50, 20, 30, 80 }; // in cents

        // requirements for each nutrition type
        int[]    limits   = { 500, 6, 10, 8 };
        string[] products = { "A", "B", "C", "D" };

        // nutritions for each product
        int[] calories  = { 400, 200, 150, 500 };
        int[] chocolate = { 3, 2, 0, 0 };
        int[] sugar     = { 2, 2, 4, 4 };
        int[] fat       = { 2, 4, 1, 5 };

        //
        // Decision variables
        //
        IntVar[] x    = solver.MakeIntVarArray(n, 0, 100, "x");
        IntVar   cost = x.ScalProd(price).Var();

        //
        // Constraints
        //

        // solver.Add(solver.MakeScalProdGreaterOrEqual(x, calories,  limits[0]));
        solver.Add(x.ScalProd(calories) >= limits[0]);
        solver.Add(x.ScalProd(chocolate) >= limits[1]);
        solver.Add(x.ScalProd(sugar) >= limits[2]);
        solver.Add(x.ScalProd(fat) >= limits[3]);

        //
        // Objective
        //
        OptimizeVar obj = cost.Minimize(1);

        //
        // Search
        //
        DecisionBuilder db = solver.MakePhase(x, Solver.CHOOSE_PATH, Solver.ASSIGN_MIN_VALUE);

        solver.NewSearch(db, obj);
        while (solver.NextSolution())
        {
            Console.WriteLine("cost: {0}", cost.Value());
            Console.WriteLine("Products: ");
            for (int i = 0; i < n; i++)
            {
                Console.WriteLine("{0}: {1}", products[i], x[i].Value());
            }

            Console.WriteLine();
        }

        Console.WriteLine("\nSolutions: {0}", solver.Solutions());
        Console.WriteLine("WallTime: {0}ms", solver.WallTime());
        Console.WriteLine("Failures: {0}", solver.Failures());
        Console.WriteLine("Branches: {0} ", solver.Branches());

        solver.EndSearch();
    }
Example #30
0
    /**
     *
     * Magic squares and cards problem.
     *
     * Martin Gardner (July 1971)
     * """
     * Allowing duplicates values, what is the largest constant sum for an order-3
     * magic square that can be formed with nine cards from the deck.
     * """
     *
     *
     * Also see http://www.hakank.org/or-tools/magic_square_and_cards.py
     *
     */
    private static void Solve(int n = 3)
    {
        Solver solver = new Solver("MagicSquareAndCards");

        IEnumerable <int> RANGE = Enumerable.Range(0, n);

        //
        // Decision variables
        //
        IntVar[,] x = solver.MakeIntVarMatrix(n, n, 1, 13, "x");
        IntVar[] x_flat = x.Flatten();

        IntVar s = solver.MakeIntVar(1, 13 * 4, "s");

        IntVar[] counts = solver.MakeIntVarArray(14, 0, 4, "counts");

        //
        // Constraints
        //

        solver.Add(x_flat.Distribute(counts));

        // the standard magic square constraints (sans all_different)
        foreach (int i in RANGE)
        {
            // rows
            solver.Add((from j in RANGE select x[i, j]).ToArray().Sum() == s);

            // columns
            solver.Add((from j in RANGE select x[j, i]).ToArray().Sum() == s);
        }

        // diagonals
        solver.Add((from i in RANGE select x[i, i]).ToArray().Sum() == s);
        solver.Add((from i in RANGE select x[i, n - i - 1]).ToArray().Sum() == s);

        // redundant constraint
        solver.Add(counts.Sum() == n * n);

        //
        // Objective
        //
        OptimizeVar obj = s.Maximize(1);

        //
        // Search
        //
        DecisionBuilder db = solver.MakePhase(x_flat, Solver.CHOOSE_FIRST_UNBOUND, Solver.ASSIGN_MAX_VALUE);

        solver.NewSearch(db, obj);

        while (solver.NextSolution())
        {
            Console.WriteLine("s: {0}", s.Value());
            Console.Write("counts:");
            for (int i = 0; i < 14; i++)
            {
                Console.Write(counts[i].Value() + " ");
            }
            Console.WriteLine();
            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    Console.Write(x[i, j].Value() + " ");
                }
                Console.WriteLine();
            }
            Console.WriteLine();
        }

        Console.WriteLine("\nSolutions: {0}", solver.Solutions());
        Console.WriteLine("WallTime: {0}ms", solver.WallTime());
        Console.WriteLine("Failures: {0}", solver.Failures());
        Console.WriteLine("Branches: {0} ", solver.Branches());

        solver.EndSearch();
    }
Example #31
0
    /**
     *
     * Photo problem.
     *
     * Problem statement from Mozart/Oz tutorial:
     * http://www.mozart-oz.org/home/doc/fdt/node37.html#section.reified.photo
     * """
     * Betty, Chris, Donald, Fred, Gary, Mary, and Paul want to align in one
     * row for taking a photo. Some of them have preferences next to whom
     * they want to stand:
     *
     *  1. Betty wants to stand next to Gary and Mary.
     *  2. Chris wants to stand next to Betty and Gary.
     * 3. Fred wants to stand next to Mary and Donald.
     * 4. Paul wants to stand next to Fred and Donald.
     *
     * Obviously, it is impossible to satisfy all preferences. Can you find
     * an alignment that maximizes the number of satisfied preferences?
     * """
     *
     *  Oz solution:
     *     6 # alignment(betty:5  chris:6  donald:1  fred:3  gary:7   mary:4
     * paul:2) [5, 6, 1, 3, 7, 4, 2]
     *
     *
     * Also see http://www.hakank.org/or-tools/photo_problem.py
     *
     */
    private static void Solve(int show_all_max = 0)
    {
        Solver solver = new Solver("PhotoProblem");

        //
        // Data
        //
        String[]          persons = { "Betty", "Chris", "Donald", "Fred", "Gary", "Mary", "Paul" };
        int               n       = persons.Length;
        IEnumerable <int> RANGE   = Enumerable.Range(0, n);

        int[,] preferences =
        {
            // 0 1 2 3 4 5 6
            // B C D F G M P
            { 0, 0, 0, 0, 1, 1, 0 }, // Betty  0
            { 1, 0, 0, 0, 1, 0, 0 }, // Chris  1
            { 0, 0, 0, 0, 0, 0, 0 }, // Donald 2
            { 0, 0, 1, 0, 0, 1, 0 }, // Fred   3
            { 0, 0, 0, 0, 0, 0, 0 }, // Gary   4
            { 0, 0, 0, 0, 0, 0, 0 }, // Mary   5
            { 0, 0, 1, 1, 0, 0, 0 } // Paul   6
        };

        Console.WriteLine("Preferences:");
        Console.WriteLine("1. Betty wants to stand next to Gary and Mary.");
        Console.WriteLine("2. Chris wants to stand next to Betty and Gary.");
        Console.WriteLine("3. Fred wants to stand next to Mary and Donald.");
        Console.WriteLine("4. Paul wants to stand next to Fred and Donald.\n");

        //
        // Decision variables
        //
        IntVar[] positions = solver.MakeIntVarArray(n, 0, n - 1, "positions");
        // successful preferences (to Maximize)
        IntVar z = solver.MakeIntVar(0, n * n, "z");

        //
        // Constraints
        //
        solver.Add(positions.AllDifferent());

        // calculate all the successful preferences
        solver.Add((from i in RANGE from j in RANGE where preferences[i, j] ==
                    1 select(positions[i] - positions[j]).Abs() == 1)
                   .ToArray()
                   .Sum() == z);

        //
        // Symmetry breaking (from the Oz page):
        //    Fred is somewhere left of Betty
        solver.Add(positions[3] < positions[0]);

        //
        // Objective
        //
        OptimizeVar obj = z.Maximize(1);

        if (show_all_max > 0)
        {
            Console.WriteLine("Showing all maximum solutions (z == 6).\n");
            solver.Add(z == 6);
        }

        //
        // Search
        //
        DecisionBuilder db =
            solver.MakePhase(positions, Solver.CHOOSE_FIRST_UNBOUND, Solver.ASSIGN_MAX_VALUE);

        solver.NewSearch(db, obj);

        while (solver.NextSolution())
        {
            Console.WriteLine("z: {0}", z.Value());
            int[] p = new int[n];
            Console.Write("p: ");
            for (int i = 0; i < n; i++)
            {
                p[i] = (int)positions[i].Value();
                Console.Write(p[i] + " ");
            }
            Console.WriteLine();
            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    if (p[j] == i)
                    {
                        Console.Write(persons[j] + " ");
                    }
                }
            }
            Console.WriteLine();
            Console.WriteLine("Successful preferences:");
            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    if (preferences[i, j] == 1 && Math.Abs(p[i] - p[j]) == 1)
                    {
                        Console.WriteLine("\t{0} {1}", persons[i], persons[j]);
                    }
                }
            }
            Console.WriteLine();
        }

        Console.WriteLine("\nSolutions: " + solver.Solutions());
        Console.WriteLine("WallTime: " + solver.WallTime() + "ms ");
        Console.WriteLine("Failures: " + solver.Failures());
        Console.WriteLine("Branches: " + solver.Branches());

        solver.EndSearch();
    }