Beispiel #1
0
        public void doWork()
        {
            Solver solver = new Solver("MagicSquares");

            // Calculate magic number --> Be carefull with very large numbers! --> (int) casting!
            int magicNumber = (int)((Math.Pow(this.size, 3) + this.size) / 2);

            // n x n Matrix of Decision Variables:
            IntVar[,] board = solver.MakeIntVarMatrix(this.size, this.size, 1, size * size);

            // Set all squares different
            solver.Add(board.Flatten().AllDifferent());

            // Handy C# LINQ type for sequences:
            IEnumerable <int> RANGE = Enumerable.Range(0, this.size);

            // Each sum of row/column equals the magic number:
            foreach (int i in RANGE)
            {
                // Rows:
                solver.Add((from j in RANGE select board[i, j]).ToArray().Sum() == magicNumber);

                // Columns:
                solver.Add((from j in RANGE select board[j, i]).ToArray().Sum() == magicNumber);
            }

            // Now the two diagonal parts
            solver.Add((from j in RANGE select board[j, j]).ToArray().Sum() == magicNumber);
            solver.Add((from j in RANGE select board[j, this.size - 1 - j]).ToArray().Sum() == magicNumber);

            DecisionBuilder db = solver.MakePhase(
                board.Flatten(),
                Solver.INT_VAR_SIMPLE,
                Solver.INT_VALUE_SIMPLE);

            solver.NewSearch(db);

            // Calculate first result for this solution
            // If more solutions are necessary, you can extend this part with a while(...)-Loop
            if (solver.NextSolution())
            {
                printSquare(board);
            }

            solver.EndSearch();

            if (solver.Solutions() == 0)
            {
                Console.WriteLine("No possible solution was found for the given magic Square! :-(");
            }
        }
Beispiel #2
0
    private static long Solve(long num_buses_check = 0)
    {
        SolverParameters sPrm = new SolverParameters();

        sPrm.compress_trail = 0;
        sPrm.trace_level    = 0;
        sPrm.profile_level  = 0;
        Solver solver = new Solver("OrTools", sPrm);

        //this works
        // IntVar[,] x = solver.MakeIntVarMatrix(2,2, new int[] {-2,0,1,2}, "x");

        //this doesn't work
        IntVar[,] x = solver.MakeIntVarMatrix(2, 2, new int[] { 0, 1, 2 }, "x");

        for (int w = 0; w < 2; w++)
        {
            IntVar[] b = new IntVar[2];
            for (int i = 0; i < 2; i++)
            {
                b[i] = solver.MakeIsEqualCstVar(x[w, i], 0);
            }
            solver.Add(solver.MakeSumGreaterOrEqual(b, 2));
        }

        IntVar[]        x_flat = x.Flatten();
        DecisionBuilder db     = solver.MakePhase(x_flat,
                                                  Solver.CHOOSE_FIRST_UNBOUND,
                                                  Solver.ASSIGN_MIN_VALUE);

        solver.NewSearch(db);
        while (solver.NextSolution())
        {
            Console.WriteLine("x: ");
            for (int j = 0; j < 2; j++)
            {
                Console.Write("worker" + (j + 1).ToString() + ":");
                for (int i = 0; i < 2; i++)
                {
                    Console.Write(" {0,2} ", x[j, i].Value());
                }
                Console.Write("\n");
            }
            Console.WriteLine("End   at---->" + DateTime.Now);
        }

        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(1);
    }
        public static void Solve(int sideLength)
        {
            var solver = new Solver("Magic Square");
            IEnumerable <int> range = Enumerable.Range(0, sideLength);

            IntVar[,] square = solver.MakeIntVarMatrix(sideLength, sideLength, 1, sideLength * sideLength);
            IntVar sum = solver.MakeIntVar(1, sideLength * sideLength * sideLength);

            // Add constraints
            // All different numbers
            solver.Add(square.Flatten().AllDifferent());
            foreach (var i in range)
            {
                // Rows should all have the same sum
                solver.Add((from j in range select square[i, j]).ToArray().Sum() == sum);
                // Columns should also all have the same sum
                solver.Add((from j in range select square[j, i]).ToArray().Sum() == sum);
            }

            // Diagonals should also both have the same sum
            solver.Add((from j in range select square[j, j]).ToArray().Sum() == sum);
            solver.Add((from j in range select square[j, sideLength - 1 - j]).ToArray().Sum() == sum);

            DecisionBuilder decisionBuilder =
                solver.MakePhase(square.Flatten(), Solver.INT_VAR_SIMPLE, Solver.INT_VALUE_SIMPLE);

            solver.NewSearch(decisionBuilder);
            while (solver.NextSolution())
            {
                PrintSolution(square);
                Console.WriteLine("Magic square constant: " + sum.Value());
                Console.Write("\n");
            }

            Console.WriteLine("Finished printing solutions");
            Console.WriteLine("Time: " + solver.WallTime());
            Console.WriteLine("Solutions: " + solver.Solutions());
            solver.EndSearch();
        }
        public void Solve(GrilleSudoku s)
        {
            //Création d'un solver Or-tools

            Solver solver = new Solver("Sudoku");

            //Création de la grille de variables

            IntVar[,] grid = solver.MakeIntVarMatrix(9, 9, 1, 9, "grid");
            IntVar[] grid_flat = grid.Flatten();



            //Masque de résolution
            foreach (int i in cellIndices)
            {
                foreach (int j in cellIndices)
                {
                    if (s.GetCellule(i, j) > 0)
                    {
                        solver.Add(grid[i, j] == s.GetCellule(i, j));
                    }
                }
            }

            //Un chiffre ne figure qu'une seule fois par ligne/colonne/cellule
            foreach (int i in cellIndices)
            {
                // Lignes
                solver.Add((from j in cellIndices
                            select grid[i, j]).ToArray().AllDifferent());

                // Colonnes
            }

            //Cellules



            //Début de la résolution
            DecisionBuilder db = solver.MakePhase(grid_flat,
                                                  Solver.INT_VAR_SIMPLE,
                                                  Solver.INT_VALUE_SIMPLE);

            solver.NewSearch(db);

            //Mise à jour du sudoku
        }
        public override IEnumerable <IntVar> GetVariables(Solver source)
        {
            Cells = new IntVar[Size, Size];

            for (var row = MinimumValue; row < MaximumValue; row++)
            {
                for (var col = MinimumValue; col < MaximumValue; col++)
                {
                    Cells[row, col] = source.MakeIntVar(MinimumValue + 1, MaximumValue, $"[{row},{col}]");
                }
            }

            foreach (var c in Cells.Flatten())
            {
                yield return(c);
            }
        }
Beispiel #6
0
        static void Main(string[] args)
        {
            var solver = new Solver("schedule_shifts");

            IntVar[,] shifts = createShifts(solver);
            IntVar[,] nurses = createNurses(solver);

            // Set relationships between shifts and nurses.
            setRelationshipBetweenNursesAndShifts(nurses, shifts, solver);

            // Make assignments different on each day
            assignNursesToDifferentShiftsEachDay(nurses, shifts, solver);

            // Each nurse works 5 or 6 days in a week.
            makeNursesWorkFiveOrSixDays(shifts, solver);

            // Create works_shift variables. works_shift[(i, j)] is True if nurse
            // i works shift j at least once during the week.
            IntVar[,] worksShift = createWorksShift(shifts, solver);

            // For each shift (other than 0), at most 2 nurses are assigned to that shift
            // during the week.
            makeMaxTwoNursesForShiftDuringWeek(worksShift, solver);

            // If s nurses works shifts 2 or 3 on, he must also work that shift the previous
            // day or the following day.
            constrainShiftPattern(nurses, solver);

            IntVar[] shiftsFlat = shifts.Flatten();

            // Create the decision builder.
            var db = solver.MakePhase(shiftsFlat,
                                      Solver.CHOOSE_FIRST_UNBOUND,
                                      Solver.ASSIGN_MIN_VALUE);

            var solution = solver.MakeAssignment();

            solution.Add(shiftsFlat);

            findSolutions(solution, solver, db, shifts);

            Console.ReadKey();
        }
Beispiel #7
0
        public override IEnumerable <IntVar> GetVariables(Solver solver)
        {
            var s = solver;

            Cells = new IntVar[Size, Size];

            for (var i = 0; i < Size; i++)
            {
                for (var j = 0; j < Size; j++)
                {
                    Cells[i, j] = s.MakeIntVar(Min, Max, $@"[{i},{j}]");
                }
            }

            foreach (var c in Cells.Flatten())
            {
                yield return(c);
            }
        }
Beispiel #8
0
    /**
     *
     * Solving a simple crossword.
     * See http://www.hakank.org/or-tools/crossword2.py
     *
     *
     */
    private static void Solve()
    {
        Solver solver = new Solver("Crossword");

        //
        // data
        //
        String[] alpha = { "_", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m",
                           "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z" };

        int a = 1;
        int b = 2;
        int c = 3;
        int d = 4;
        int e = 5;
        int f = 6;
        int g = 7;
        int h = 8;
        int i = 9;
        int j = 10;
        int k = 11;
        int l = 12;
        int m = 13;
        int n = 14;
        int o = 15;
        int p = 16;
        int q = 17;
        int r = 18;
        int s = 19;
        int t = 20;
        int u = 21;
        int v = 22;
        int w = 23;
        int x = 24;
        int y = 25;
        int z = 26;

        const int num_words = 15;
        int       word_len  = 5;

        int[,] AA = { { h, o, s, e, s },   //  HOSES
                      { l, a, s, e, r },   //  LASER
                      { s, a, i, l, s },   //  SAILS
                      { s, h, e, e, t },   //  SHEET
                      { s, t, e, e, r },   //  STEER
                      { h, e, e, l, 0 },   //  HEEL
                      { h, i, k, e, 0 },   //  HIKE
                      { k, e, e, l, 0 },   //  KEEL
                      { k, n, o, t, 0 },   //  KNOT
                      { l, i, n, e, 0 },   //  LINE
                      { a, f, t, 0, 0 },   //  AFT
                      { a, l, e, 0, 0 },   //  ALE
                      { e, e, l, 0, 0 },   //  EEL
                      { l, e, e, 0, 0 },   //  LEE
                      { t, i, e, 0, 0 } }; //  TIE

        int num_overlapping = 12;

        int[,] overlapping = { { 0, 2, 1, 0 },   //  s
                               { 0, 4, 2, 0 },   //  s

                               { 3, 1, 1, 2 },   //  i
                               { 3, 2, 4, 0 },   //  k
                               { 3, 3, 2, 2 },   //  e

                               { 6, 0, 1, 3 },   //  l
                               { 6, 1, 4, 1 },   //  e
                               { 6, 2, 2, 3 },   //  e

                               { 7, 0, 5, 1 },   //  l
                               { 7, 2, 1, 4 },   //  s
                               { 7, 3, 4, 2 },   //  e
                               { 7, 4, 2, 4 } }; //  r

        int N = 8;

        //
        // Decision variables
        //
        // for labeling on A and E
        IntVar[,] A = solver.MakeIntVarMatrix(num_words, word_len, 0, 26, "A");
        IntVar[] A_flat = A.Flatten();
        IntVar[] all    = new IntVar[(num_words * word_len) + N];
        for (int I = 0; I < num_words; I++)
        {
            for (int J = 0; J < word_len; J++)
            {
                all[I * word_len + J] = A[I, J];
            }
        }

        IntVar[] E = solver.MakeIntVarArray(N, 0, num_words, "E");
        for (int I = 0; I < N; I++)
        {
            all[num_words * word_len + I] = E[I];
        }

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

        for (int I = 0; I < num_words; I++)
        {
            for (int J = 0; J < word_len; J++)
            {
                solver.Add(A[I, J] == AA[I, J]);
            }
        }

        // This contraint handles the overlappings.
        //
        // It's coded in MiniZinc as
        //
        //   forall(i in 1..num_overlapping) (
        //      A[E[overlapping[i,1]], overlapping[i,2]] =
        //      A[E[overlapping[i,3]], overlapping[i,4]]
        //   )
        // and in or-tools/Python as
        //   solver.Add(
        //      solver.Element(A_flat,E[overlapping[I][0]]*word_len+overlapping[I][1])
        //      ==
        //      solver.Element(A_flat,E[overlapping[I][2]]*word_len+overlapping[I][3]))
        //
        for (int I = 0; I < num_overlapping; I++)
        {
            solver.Add(A_flat.Element(E[overlapping[I, 0]] * word_len + overlapping[I, 1]) ==
                       A_flat.Element(E[overlapping[I, 2]] * word_len + overlapping[I, 3]));
        }

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

        solver.NewSearch(db);

        while (solver.NextSolution())
        {
            Console.WriteLine("E: ");
            for (int ee = 0; ee < N; ee++)
            {
                int e_val = (int)E[ee].Value();
                Console.Write(ee + ": (" + e_val + ") ");
                for (int ii = 0; ii < word_len; ii++)
                {
                    Console.Write(alpha[(int)A[ee, ii].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();
    }
Beispiel #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();
    }
Beispiel #10
0
    /**
     *
     * Implements Young tableaux and partitions.
     * See http://www.hakank.org/or-tools/young_tableuax.py
     *
     */
    private static void Solve(int n)
    {
        Solver solver = new Solver("YoungTableaux");

        //
        // data
        //
        Console.WriteLine("n: {0}\n", n);

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

        // partition structure
        IntVar[] p = solver.MakeIntVarArray(n, 0, n + 1, "p");

        //
        // Constraints
        //
        // 1..n is used exactly once
        for (int i = 1; i <= n; i++)
        {
            solver.Add(x_flat.Count(i, 1));
        }

        solver.Add(x[0, 0] == 1);

        // row wise
        for (int i = 0; i < n; i++)
        {
            for (int j = 1; j < n; j++)
            {
                solver.Add(x[i, j] >= x[i, j - 1]);
            }
        }

        // column wise
        for (int j = 0; j < n; j++)
        {
            for (int i = 1; i < n; i++)
            {
                solver.Add(x[i, j] >= x[i - 1, j]);
            }
        }

        // calculate the structure (i.e. the partition)
        for (int i = 0; i < n; i++)
        {
            IntVar[] b = new IntVar[n];
            for (int j = 0; j < n; j++)
            {
                b[j] = x[i, j] <= n;
            }
            solver.Add(p[i] == b.Sum());
        }

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

        for (int i = 1; i < n; i++)
        {
            solver.Add(p[i - 1] >= p[i]);
        }

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

        solver.NewSearch(db);

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

            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    long val = x[i, j].Value();
                    if (val <= n)
                    {
                        Console.Write(val + " ");
                    }
                }
                if (p[i].Value() > 0)
                {
                    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();
    }
Beispiel #11
0
        /*
         * Create Model and Solve Sudoku:
         */

        public static void Solve(string[,] input)
        {
            if (input.Length != 81)
            {
                throw new ArgumentException("This is not a valid 9x9 Sudoku Puzzle.");
            }

            const int cellSize  = 3;
            const int boardSize = cellSize * cellSize;

            var solver = new Solver("Sudoku");

            IEnumerable <int> cell  = Enumerable.Range(0, cellSize);
            IEnumerable <int> range = Enumerable.Range(0, boardSize);

            // Sudoku Board as 9x9 Matrix of Decision Variables in {1..9}:
            IntVar[,] board = solver.MakeIntVarMatrix(boardSize, boardSize, 1, boardSize);

            // Pre-Assignments:
            for (int i = 0; i < boardSize; i++)
            {
                for (int j = 0; j < boardSize; j++)
                {
                    if (!string.IsNullOrEmpty(input[i, j]))
                    {
                        int number = Convert.ToInt32(input[i, j]);
                        solver.Add(board[i, j] == number);
                    }
                }
            }

            // Each Row / Column contains only different values:
            foreach (int i in range)
            {
                // Rows:
                solver.Add((from j in range select board[i, j]).ToArray().AllDifferent());

                // Columns:
                solver.Add((from j in range select board[j, i]).ToArray().AllDifferent());
            }


            // Each Sub-Matrix contains only different values:
            foreach (int i in cell)
            {
                foreach (int j in cell)
                {
                    solver.Add(
                        (from di in cell from dj in cell select board[i * cellSize + di, j * cellSize + dj]).ToArray()
                        .AllDifferent());
                }
            }

            // Start Solver:

            DecisionBuilder db = solver.MakePhase(board.Flatten(), Solver.INT_VAR_SIMPLE, Solver.INT_VALUE_SIMPLE);

            Console.WriteLine("Sudoku:\n\n");

            solver.NewSearch(db);

            while (solver.NextSolution())
            {
                PrintSolution(board);
                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();

            Console.ReadKey();
        }
Beispiel #12
0
    /**
     *
     * Solves the Magic Square problem.
     * See http://www.hakank.org/or-tools/magic_square.py
     *
     */
    private static void Solve(int n = 4, int num = 0, int print = 1)
    {
        Solver solver = new Solver("MagicSquare");

        Console.WriteLine("n: {0}", n);

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

        //
        // Constraints
        //
        long s = (n * (n * n + 1)) / 2;

        Console.WriteLine("s: " + s);

        IntVar[] diag1 = new IntVar[n];
        IntVar[] diag2 = new IntVar[n];
        for (int i = 0; i < n; i++)
        {
            IntVar[] row = new IntVar[n];
            for (int j = 0; j < n; j++)
            {
                row[j] = x[i, j];
            }
            // sum row to s
            solver.Add(row.Sum() == s);

            diag1[i] = x[i, i];
            diag2[i] = x[i, n - i - 1];
        }

        // sum diagonals to s
        solver.Add(diag1.Sum() == s);
        solver.Add(diag2.Sum() == s);

        // sum columns to s
        for (int j = 0; j < n; j++)
        {
            IntVar[] col = new IntVar[n];
            for (int i = 0; i < n; i++)
            {
                col[i] = x[i, j];
            }
            solver.Add(col.Sum() == s);
        }

        // all are different
        solver.Add(x_flat.AllDifferent());

        // symmetry breaking: upper left is 1
        // solver.Add(x[0,0] == 1);

        //
        // Search
        //

        DecisionBuilder db =
            solver.MakePhase(x_flat, Solver.CHOOSE_FIRST_UNBOUND, Solver.ASSIGN_CENTER_VALUE);

        solver.NewSearch(db);

        int c = 0;

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

            c++;
            if (num > 0 && c >= num)
            {
                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();
    }
Beispiel #13
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();
    }
Beispiel #14
0
    /**
     *
     * Implements the Who killed Agatha problem.
     * See http://www.hakank.org/google_or_tools/who_killed_agatha.py
     *
     */
    private static void Solve()
    {
        Solver solver = new Solver("WhoKilledAgatha");

        int n       = 3;
        int agatha  = 0;
        int butler  = 1;
        int charles = 2;

        //
        // Decision variables
        //
        IntVar the_killer = solver.MakeIntVar(0, 2, "the_killer");
        IntVar the_victim = solver.MakeIntVar(0, 2, "the_victim");

        IntVar[,] hates = solver.MakeIntVarMatrix(n, n, 0, 1, "hates");
        IntVar[] hates_flat = hates.Flatten();
        IntVar[,] richer = solver.MakeIntVarMatrix(n, n, 0, 1, "richer");
        IntVar[] richer_flat = richer.Flatten();

        IntVar[] all = new IntVar[2 * n * n]; // for branching
        for (int i = 0; i < n * n; i++)
        {
            all[i]           = hates_flat[i];
            all[(n * n) + i] = richer_flat[i];
        }

        //
        // Constraints
        //

        // Agatha, the butler, and Charles live in Dreadsbury Mansion, and
        // are the only ones to live there.

        // A killer always hates, and is no richer than his victim.
        //     hates[the_killer, the_victim] == 1
        //     hates_flat[the_killer * n + the_victim] == 1
        solver.Add(hates_flat.Element(the_killer * n + the_victim) == 1);

        //    richer[the_killer, the_victim] == 0
        solver.Add(richer_flat.Element(the_killer * n + the_victim) == 0);

        // define the concept of richer:
        //     no one is richer than him-/herself...
        for (int i = 0; i < n; i++)
        {
            solver.Add(richer[i, i] == 0);
        }

        // (contd...) if i is richer than j then j is not richer than i
        //   if (i != j) =>
        //       ((richer[i,j] = 1) <=> (richer[j,i] = 0))
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < n; j++)
            {
                if (i != j)
                {
                    solver.Add((richer[i, j] == 1) - (richer[j, i] == 0) == 0);
                }
            }
        }

        // Charles hates no one that Agatha hates.
        //    forall i in 0..2:
        //       (hates[agatha, i] = 1) => (hates[charles, i] = 0)
        for (int i = 0; i < n; i++)
        {
            solver.Add((hates[agatha, i] == 1) - (hates[charles, i] == 0) <= 0);
        }

        // Agatha hates everybody except the butler.
        solver.Add(hates[agatha, charles] == 1);
        solver.Add(hates[agatha, agatha] == 1);
        solver.Add(hates[agatha, butler] == 0);

        // The butler hates everyone not richer than Aunt Agatha.
        //    forall i in 0..2:
        //       (richer[i, agatha] = 0) => (hates[butler, i] = 1)
        for (int i = 0; i < n; i++)
        {
            solver.Add((richer[i, agatha] == 0) - (hates[butler, i] == 1) <= 0);
        }

        // The butler hates everyone whom Agatha hates.
        //     forall i : 0..2:
        //         (hates[agatha, i] = 1) => (hates[butler, i] = 1)
        for (int i = 0; i < n; i++)
        {
            solver.Add((hates[agatha, i] == 1) - (hates[butler, i] == 1) <= 0);
        }

        // Noone hates everyone.
        //     forall i in 0..2:
        //         (sum j in 0..2: hates[i,j]) <= 2
        for (int i = 0; i < n; i++)
        {
            solver.Add((from j in Enumerable.Range(0, n) select hates[i, j]).ToArray().Sum() <= 2);
        }

        // Who killed Agatha?
        solver.Add(the_victim == agatha);

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

        solver.NewSearch(db);

        while (solver.NextSolution())
        {
            Console.WriteLine("the_killer: " + the_killer.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();
    }
    /**
     *
     * Nurse rostering
     *
     * This is a simple nurse rostering model using a DFA and
     * my decomposition of regular constraint.
     *
     * The DFA is from MiniZinc Tutorial, Nurse Rostering example:
     * - one day off every 4 days
     * - no 3 nights in a row.
     *
     * Also see http://www.hakank.org/or-tools/nurse_rostering.py
     *
     */
    private static void Solve()
    {
        Solver solver = new Solver("NurseRostering");

        //
        // Data
        //

        // Note: If you change num_nurses or num_days,
        //       please also change the constraints
        //       on nurse_stat and/or day_stat.
        int num_nurses = 7;
        int num_days   = 14;

        // Note: I had to add a dummy shift.
        int dummy_shift = 0;
        int day_shift   = 1;
        int night_shift = 2;
        int off_shift   = 3;

        int[] shifts       = { dummy_shift, day_shift, night_shift, off_shift };
        int[] valid_shifts = { day_shift, night_shift, off_shift };

        // the DFA (for regular)
        int n_states      = 6;
        int input_max     = 3;
        int initial_state = 1; // 0 is for the failing state

        int[] accepting_states = { 1, 2, 3, 4, 5, 6 };

        int[,] transition_fn =
        {
            // d,n,o
            { 2, 3, 1 }, // state 1
            { 4, 4, 1 }, // state 2
            { 4, 5, 1 }, // state 3
            { 6, 6, 1 }, // state 4
            { 6, 0, 1 }, // state 5
            { 0, 0, 1 }  // state 6
        };

        string[] days = { "d", "n", "o" }; // for presentation

        //
        // Decision variables
        //

        // For regular
        IntVar[,] x = solver.MakeIntVarMatrix(num_nurses, num_days, valid_shifts, "x");
        IntVar[] x_flat = x.Flatten();

        // summary of the nurses
        IntVar[] nurse_stat = solver.MakeIntVarArray(num_nurses, 0, num_days, "nurse_stat");

        // summary of the shifts per day
        int num_shifts = shifts.Length;

        IntVar[,] day_stat = new IntVar[num_days, num_shifts];
        for (int i = 0; i < num_days; i++)
        {
            for (int j = 0; j < num_shifts; j++)
            {
                day_stat[i, j] = solver.MakeIntVar(0, num_nurses, "day_stat");
            }
        }

        //
        // Constraints
        //
        for (int i = 0; i < num_nurses; i++)
        {
            IntVar[] reg_input = new IntVar[num_days];
            for (int j = 0; j < num_days; j++)
            {
                reg_input[j] = x[i, j];
            }
            MyRegular(solver, reg_input, n_states, input_max, transition_fn, initial_state, accepting_states);
        }

        //
        // Statistics and constraints for each nurse
        //
        for (int i = 0; i < num_nurses; i++)
        {
            // Number of worked days (either day or night shift)
            IntVar[] b = new IntVar[num_days];
            for (int j = 0; j < num_days; j++)
            {
                b[j] = ((x[i, j] == day_shift) + (x[i, j] == night_shift)).Var();
            }
            solver.Add(b.Sum() == nurse_stat[i]);

            // Each nurse must work between 7 and 10
            // days/nights during this period
            solver.Add(nurse_stat[i] >= 7);
            solver.Add(nurse_stat[i] <= 10);
        }

        //
        // Statistics and constraints for each day
        //
        for (int j = 0; j < num_days; j++)
        {
            for (int t = 0; t < num_shifts; t++)
            {
                IntVar[] b = new IntVar[num_nurses];
                for (int i = 0; i < num_nurses; i++)
                {
                    b[i] = x[i, j] == t;
                }
                solver.Add(b.Sum() == day_stat[j, t]);
            }

            //
            // Some constraints for each day:
            //
            // Note: We have a strict requirements of
            //       the number of shifts.
            //       Using atleast constraints is harder
            //       in this model.
            //
            if (j % 7 == 5 || j % 7 == 6)
            {
                // special constraints for the weekends
                solver.Add(day_stat[j, day_shift] == 2);
                solver.Add(day_stat[j, night_shift] == 1);
                solver.Add(day_stat[j, off_shift] == 4);
            }
            else
            {
                // for workdays:

                // - exactly 3 on day shift
                solver.Add(day_stat[j, day_shift] == 3);
                // - exactly 2 on night
                solver.Add(day_stat[j, night_shift] == 2);
                // - exactly 2 off duty
                solver.Add(day_stat[j, off_shift] == 2);
            }
        }

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

        solver.NewSearch(db);

        int num_solutions = 0;

        while (solver.NextSolution())
        {
            num_solutions++;
            for (int i = 0; i < num_nurses; i++)
            {
                Console.Write("Nurse #{0,-2}: ", i);
                var occ = new Dictionary <int, int>();
                for (int j = 0; j < num_days; j++)
                {
                    int v = (int)x[i, j].Value() - 1;
                    if (!occ.ContainsKey(v))
                    {
                        occ[v] = 0;
                    }
                    occ[v]++;
                    Console.Write(days[v] + " ");
                }

                Console.Write(" #workdays: {0,2}", nurse_stat[i].Value());
                foreach (int s in valid_shifts)
                {
                    int v = 0;
                    if (occ.ContainsKey(s - 1))
                    {
                        v = occ[s - 1];
                    }
                    Console.Write("  {0}:{1}", days[s - 1], v);
                }
                Console.WriteLine();
            }
            Console.WriteLine();

            Console.WriteLine("Statistics per day:\nDay      d n o");
            for (int j = 0; j < num_days; j++)
            {
                Console.Write("Day #{0,2}: ", j);
                foreach (int t in valid_shifts)
                {
                    Console.Write(day_stat[j, t].Value() + " ");
                }
                Console.WriteLine();
            }
            Console.WriteLine();

            // We just show 2 solutions
            if (num_solutions > 1)
            {
                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();
    }
Beispiel #16
0
    /**
     *
     * Fill-a-Pix problem
     *
     * From
     * http://www.conceptispuzzles.com/index.aspx?uri=puzzle/fill-a-pix/basiclogic
     * """
     * Each puzzle consists of a grid containing clues in various places. The
     * object is to reveal a hidden picture by painting the squares around each
     * clue so that the number of painted squares, including the square with
     * the clue, matches the value of the clue.
     * """
     *
     * http://www.conceptispuzzles.com/index.aspx?uri=puzzle/fill-a-pix/rules
     * """
     * Fill-a-Pix is a Minesweeper-like puzzle based on a grid with a pixilated
     * picture hidden inside. Using logic alone, the solver determines which
     * squares are painted and which should remain empty until the hidden picture
     * is completely exposed.
     * """
     *
     * Fill-a-pix History:
     * http://www.conceptispuzzles.com/index.aspx?uri=puzzle/fill-a-pix/history
     *
     * Also see http://www.hakank.org/google_or_tools/fill_a_pix.py
     *
     *
     */
    private static void Solve()
    {
        Solver solver = new Solver("FillAPix");

        //
        // data
        //
        int[] S = { -1, 0, 1 };

        Console.WriteLine("Problem:");
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < n; j++)
            {
                if (puzzle[i, j] > X)
                {
                    Console.Write(puzzle[i, j] + " ");
                }
                else
                {
                    Console.Write("X ");
                }
            }
            Console.WriteLine();
        }
        Console.WriteLine();

        //
        // Decision variables
        //
        IntVar[,] pict = solver.MakeIntVarMatrix(n, n, 0, 1, "pict");
        IntVar[] pict_flat = pict.Flatten(); // for branching

        //
        // Constraints
        //
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < n; j++)
            {
                if (puzzle[i, j] > X)
                {
                    // this cell is the sum of all surrounding cells
                    var tmp = from a in S from b in S
                              where i +
                              a >= 0 && j + b >= 0 && i + a < n && j + b < n select(pict[i + a, j + b]);

                    solver.Add(tmp.ToArray().Sum() == puzzle[i, j]);
                }
            }
        }

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

        solver.NewSearch(db);

        int sol = 0;

        while (solver.NextSolution())
        {
            sol++;
            Console.WriteLine("Solution #{0} ", sol + " ");
            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    Console.Write(pict[i, j].Value() == 1 ? "#" : " ");
                }
                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();
    }
Beispiel #17
0
    /**
     *
     * KenKen puzzle.
     *
     * http://en.wikipedia.org/wiki/KenKen
     * """
     * KenKen or KEN-KEN is a style of arithmetic and logical puzzle sharing
     * several characteristics with sudoku. The name comes from Japanese and
     * is translated as 'square wisdom' or 'cleverness squared'.
     * ...
     * The objective is to fill the grid in with the digits 1 through 6 such that:
     *
     * * Each row contains exactly one of each digit
     * * Each column contains exactly one of each digit
     * * Each bold-outlined group of cells is a cage containing digits which
     *   achieve the specified result using the specified mathematical operation:
     *     addition (+),
     *     subtraction (-),
     *     multiplication (x),
     *     and division (/).
     *    (Unlike in Killer sudoku, digits may repeat within a group.)
     *
     * ...
     * More complex KenKen problems are formed using the principles described
     * above but omitting the symbols +, -, x and /, thus leaving them as
     * yet another unknown to be determined.
     * """
     *
     * The solution is:
     *
     *    5 6 3 4 1 2
     *    6 1 4 5 2 3
     *    4 5 2 3 6 1
     *    3 4 1 2 5 6
     *    2 3 6 1 4 5
     *    1 2 5 6 3 4
     *
     *
     * Also see http://www.hakank.org/or-tools/kenken2.py
     * though this C# model has another representation of
     * the problem instance.
     *
     */
    private static void Solve()
    {
        Solver solver = new Solver("KenKen2");

        // size of matrix
        int n = 6;
        IEnumerable <int> RANGE = Enumerable.Range(0, n);

        // For a better view of the problem, see
        //  http://en.wikipedia.org/wiki/File:KenKenProblem.svg

        // hints
        //  sum, the hints
        // Note: this is 1-based
        int[][] problem = { new int[] {  11, 1, 1, 2, 1 },
                            new int[] {   2, 1, 2, 1, 3 },
                            new int[] {  20, 1, 4, 2, 4 },
                            new int[] {   6, 1, 5, 1,6, 2, 6, 3, 6 },
                            new int[] {   3, 2, 2, 2, 3 },
                            new int[] {   3, 2, 5, 3, 5 },
                            new int[] { 240, 3, 1, 3,2, 4, 1, 4, 2 },
                            new int[] {   6, 3, 3, 3, 4 },
                            new int[] {   6, 4, 3, 5, 3 },
                            new int[] {   7, 4, 4, 5,4, 5, 5 },
                            new int[] {  30, 4, 5, 4, 6 },
                            new int[] {   6, 5, 1, 5, 2 },
                            new int[] {   9, 5, 6, 6, 6 },
                            new int[] {   8, 6, 1, 6,2, 6, 3 },
                            new int[] {   2, 6, 4, 6, 5 } };

        int num_p = problem.GetLength(0); // Number of segments

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

        //
        // Constraints
        //

        //
        //  alldifferent rows and columns
        foreach (int i in RANGE)
        {
            // rows
            solver.Add((from j in RANGE select x[i, j]).ToArray().AllDifferent());

            // cols
            solver.Add((from j in RANGE select x[j, i]).ToArray().AllDifferent());
        }

        // Calculate the segments
        for (int i = 0; i < num_p; i++)
        {
            int[] segment = problem[i];

            // Remove the sum from the segment
            int   len = segment.Length - 1;
            int[] s2  = new int[len];
            Array.Copy(segment, 1, s2, 0, len);

            // sum this segment
            calc(solver, s2, x, segment[0]);
        }

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

        solver.NewSearch(db);

        while (solver.NextSolution())
        {
            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();
    }
Beispiel #18
0
    /**
     *
     * Futoshiki problem.
     *
     * From http://en.wikipedia.org/wiki/Futoshiki
     * """
     * The puzzle is played on a square grid, such as 5 x 5. The objective
     * is to place the numbers 1 to 5 (or whatever the dimensions are)
     * such that each row, and column contains each of the digits 1 to 5.
     * Some digits may be given at the start. In addition, inequality
     * constraints are also initially specifed between some of the squares,
     * such that one must be higher or lower than its neighbour. These
     * constraints must be honoured as the grid is filled out.
     * """
     *
     * Also see http://www.hakank.org/or-tools/futoshiki.py
     *
     */
    private static void Solve(int[,] values, int[,] lt)
    {
        Solver solver = new Solver("Futoshiki");

        int size = values.GetLength(0);
        IEnumerable <int> RANGE = Enumerable.Range(0, size);
        IEnumerable <int> NUMQD = Enumerable.Range(0, lt.GetLength(0));

        //
        // Decision variables
        //
        IntVar[,] field = solver.MakeIntVarMatrix(size, size, 1, size, "field");
        IntVar[] field_flat = field.Flatten();

        //
        // Constraints
        //

        // set initial values
        foreach (int row in RANGE)
        {
            foreach (int col in RANGE)
            {
                if (values[row, col] > 0)
                {
                    solver.Add(field[row, col] == values[row, col]);
                }
            }
        }

        // all rows have to be different
        foreach (int row in RANGE)
        {
            solver.Add((from col in RANGE select field[row, col]).ToArray().AllDifferent());
        }

        // all columns have to be different
        foreach (int col in RANGE)
        {
            solver.Add((from row in RANGE select field[row, col]).ToArray().AllDifferent());
        }

        // all < constraints are satisfied
        // Also: make 0-based
        foreach (int i in NUMQD)
        {
            solver.Add(field[lt[i, 0] - 1, lt[i, 1] - 1] < field[lt[i, 2] - 1, lt[i, 3] - 1]);
        }

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

        solver.NewSearch(db);

        while (solver.NextSolution())
        {
            foreach (int i in RANGE)
            {
                foreach (int j in RANGE)
                {
                    Console.Write("{0} ", field[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();
    }
Beispiel #19
0
    /**
     *
     * Discrete tomography
     *
     * Problem from http://eclipse.crosscoreop.com/examples/tomo.ecl.txt
     * """
     * This is a little 'tomography' problem, taken from an old issue
     * of Scientific American.
     *
     * A matrix which contains zeroes and ones gets "x-rayed" vertically and
     * horizontally, giving the total number of ones in each row and column.
     * The problem is to reconstruct the contents of the matrix from this
     * information. Sample run:
     *
     * ?- go.
     *    0 0 7 1 6 3 4 5 2 7 0 0
     * 0
     * 0
     * 8      * * * * * * * *
     * 2      *             *
     * 6      *   * * * *   *
     * 4      *   *     *   *
     * 5      *   *   * *   *
     * 3      *   *         *
     * 7      *   * * * * * *
     * 0
     * 0
     *
     * Eclipse solution by Joachim Schimpf, IC-Parc
     * """
     *
     * See  http://www.hakank.org/or-tools/discrete_tomography.py
     *
     */
    private static void Solve(int[] rowsums, int[] colsums)
    {
        Solver solver = new Solver("DiscreteTomography");

        //
        // Data
        //
        int r = rowsums.Length;
        int c = colsums.Length;

        Console.Write("rowsums: ");
        for (int i = 0; i < r; i++)
        {
            Console.Write(rowsums[i] + " ");
        }
        Console.Write("\ncolsums: ");
        for (int j = 0; j < c; j++)
        {
            Console.Write(colsums[j] + " ");
        }
        Console.WriteLine("\n");

        //
        // Decision variables
        //
        IntVar[,] x = solver.MakeIntVarMatrix(r, c, 0, 1, "x");
        IntVar[] x_flat = x.Flatten();

        //
        // Constraints
        //

        // row sums
        for (int i = 0; i < r; i++)
        {
            var tmp = from j in Enumerable.Range(0, c) select x[i, j];
            solver.Add(tmp.ToArray().Sum() == rowsums[i]);
        }

        // cols sums
        for (int j = 0; j < c; j++)
        {
            var tmp = from i in Enumerable.Range(0, r) select x[i, j];
            solver.Add(tmp.ToArray().Sum() == colsums[j]);
        }

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

        solver.NewSearch(db);

        while (solver.NextSolution())
        {
            for (int i = 0; i < r; i++)
            {
                for (int j = 0; j < c; j++)
                {
                    Console.Write("{0} ", x[i, j].Value() == 1 ? "#" : ".");
                }
                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();
    }
Beispiel #20
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();
    }
Beispiel #21
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();
    }
    /**
     *
     * From Programmers Stack Exchange (C#)
     * http://programmers.stackexchange.com/questions/153184/partitioning-set-into-subsets-with-respect-to-equality-of-sum-among-subsets
     * Partitioning set into subsets with respect to equality of sum among subsets
     * """
     * let say i have {3, 1, 1, 2, 2, 1,5,2,7} set of numbers, I need to split the
     * numbers such that sum of subset1 should be equal to sum of subset2
     * {3,2,7} {1,1,2,1,5,2}. First we should identify whether we can split number(one
     * way might be dividable by 2 without any remainder) and if we can, we should
     * write our algorithm two create s1 and s2 out of s.
     *
     * How to proceed with this approach? I read partition problem in wiki and even in some
     * articles but i am not able to get anything. Can someone help me to find the
     * right algorithm and its explanation in simple English?
     *
     *
     * Also see http://www.hakank.org/or-tools/set_partition.cs
     *
     *
     * Model by Hakan Kjellerstrand ([email protected])
     * See other or-tools/C# models at http://www.hakank.org/or-tools/#csharp
     *
     */
    private static void Solve(int n = 10, int max = 10, int num_subsets = 2, int sols_to_show = 0)
    {
        Solver solver = new Solver("PartitionSets");

        Console.WriteLine("n: " + n);
        Console.WriteLine("max: " + max);
        Console.WriteLine("num_subsets: " + num_subsets);
        Console.WriteLine("sols_to_show: " + sols_to_show);


        //
        // Data
        //
        // int[] s = {3, 1, 1, 2, 2, 1, 5, 2, 7};
        // int n = s.Length;

        int    seed      = (int)DateTime.Now.Ticks;
        Random generator = new Random(seed);

        int[] s = new int[n];
        for (int i = 0; i < n; i++)
        {
            s[i] = 1 + generator.Next(max);
        }

        while (s.Sum() % num_subsets != 0)
        {
            Console.WriteLine("The sum of s must be divisible by the number of subsets. Adjusting the last entry.");
            s[n - 1] = 1 + generator.Next(max);
        }

        Console.WriteLine("\n" + n + " numbers generated\n");

        IEnumerable <int> NRange = Enumerable.Range(0, n);
        IEnumerable <int> Sets   = Enumerable.Range(0, num_subsets);

        //
        // Decision variables
        //

        // To which subset do x[i] belong?
        IntVar[,] x = solver.MakeIntVarMatrix(num_subsets, n, 0, 1, "x");
        IntVar[] x_flat = x.Flatten();

        //
        // Constraints
        //

        // Ensure that a number is in exact one subset
        for (int k = 0; k < n; k++)
        {
            solver.Add((from p in Sets select(x[p, k])).ToArray().Sum() == 1);
        }

        // Ensure that the sum of all subsets are the same.
        for (int p = 0; p < num_subsets - 1; p++)
        {
            solver.Add(
                (from k in NRange select(s[k] * x[p, k])).ToArray().Sum()
                ==
                (from k in NRange select(s[k] * x[p + 1, k])).ToArray().Sum()
                );
        }

        // symmetry breaking: assign first number to subset 1
        solver.Add(x[0, 0] == 1);


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

        solver.NewSearch(db);

        int sols = 0;

        while (solver.NextSolution())
        {
            sols++;
            foreach (int i in Sets)
            {
                Console.Write("subset " + i + ": ");
                int sum = 0;
                foreach (int j in NRange)
                {
                    if ((int)x[i, j].Value() == 1)
                    {
                        Console.Write(s[j] + " ");
                        sum += s[j];
                    }
                }
                Console.WriteLine("   sum: " + sum);
            }
            Console.WriteLine();

            if (sols_to_show > 0 && sols >= sols_to_show)
            {
                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();
    }
Beispiel #23
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();
    }
Beispiel #24
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();
    }
Beispiel #25
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);
        }
Beispiel #26
0
    /**
     *
     * Solves the Seseman convent problem.
     * See http://www.hakank.org/google_or_tools/seseman.py
     *
     */
    private static void Solve(int n = 3)
    {
        Solver solver = new Solver("Seseman");

        //
        // data
        //
        int border_sum = n * n;

        //
        // Decision variables
        //
        IntVar[,] x = solver.MakeIntVarMatrix(n, n, 0, n * n, "x");
        IntVar[] x_flat    = x.Flatten();
        IntVar   total_sum = x_flat.Sum().Var();

        //
        // Constraints
        //

        // zero in all middle cells
        for (int i = 1; i < n - 1; i++)
        {
            for (int j = 1; j < n - 1; j++)
            {
                solver.Add(x[i, j] == 0);
            }
        }

        // all borders must be >= 1
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < n; j++)
            {
                if (i == 0 || j == 0 || i == n - 1 || j == n - 1)
                {
                    solver.Add(x[i, j] >= 1);
                }
            }
        }

        // sum the four borders
        IntVar[] border1 = new IntVar[n];
        IntVar[] border2 = new IntVar[n];
        IntVar[] border3 = new IntVar[n];
        IntVar[] border4 = new IntVar[n];
        for (int i = 0; i < n; i++)
        {
            border1[i] = x[i, 0];
            border2[i] = x[i, n - 1];
            border3[i] = x[0, i];
            border4[i] = x[n - 1, i];
        }
        solver.Add(border1.Sum() == border_sum);
        solver.Add(border2.Sum() == border_sum);
        solver.Add(border3.Sum() == border_sum);
        solver.Add(border4.Sum() == border_sum);

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

        solver.NewSearch(db);
        while (solver.NextSolution())
        {
            Console.WriteLine("total_sum: {0} ", total_sum.Value());
            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    Console.Write("{0} ", 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();
    }
    /**
     *
     * Nurse rostering
     *
     * This is a simple nurse rostering model using a DFA and
     * the built-in TransitionConstraint.
     *
     * The DFA is from MiniZinc Tutorial, Nurse Rostering example:
     * - one day off every 4 days
     * - no 3 nights in a row.
     *
     * Also see:
     *  - http://www.hakank.org/or-tools/nurse_rostering.py
     *  - http://www.hakank.org/or-tools/nurse_rostering_regular.cs
     *    which use (a decomposition of) regular constraint
     *
     */
    private static void Solve(int nurse_multiplier, int week_multiplier)
    {
        Console.WriteLine("Starting Nurse Rostering");
        Console.WriteLine("  - {0} teams of 7 nurses", nurse_multiplier);
        Console.WriteLine("  - {0} blocks of 14 days", week_multiplier);

        Solver solver = new Solver("NurseRostering");

        //
        // Data
        //

        // Note: If you change num_nurses or num_days,
        //       please also change the constraints
        //       on nurse_stat and/or day_stat.
        int num_nurses = 7 * nurse_multiplier;
        int num_days   = 14 * week_multiplier;

        // Note: I had to add a dummy shift.
        int dummy_shift = 0;
        int day_shift   = 1;
        int night_shift = 2;
        int off_shift   = 3;

        int[] shifts       = { dummy_shift, day_shift, night_shift, off_shift };
        int[] valid_shifts = { day_shift, night_shift, off_shift };

        // the DFA (for regular)
        int initial_state = 1;

        int[] accepting_states = { 1, 2, 3, 4, 5, 6 };

        /*
         * // This is the transition function
         * // used in nurse_rostering_regular.cs
         * int[,] transition_fn = {
         * // d,n,o
         * {2,3,1}, // state 1
         * {4,4,1}, // state 2
         * {4,5,1}, // state 3
         * {6,6,1}, // state 4
         * {6,0,1}, // state 5
         * {0,0,1}  // state 6
         * };
         */

        // For TransitionConstraint
        IntTupleSet transition_tuples = new IntTupleSet(3);

        // state, input, next state
        transition_tuples.InsertAll(new long[][] {
            new long[] { 1, 1, 2 },
            new long[] { 1, 2, 3 },
            new long[] { 1, 3, 1 },
            new long[] { 2, 1, 4 },
            new long[] { 2, 2, 4 },
            new long[] { 2, 3, 1 },
            new long[] { 3, 1, 4 },
            new long[] { 3, 2, 5 },
            new long[] { 3, 3, 1 },
            new long[] { 4, 1, 6 },
            new long[] { 4, 2, 6 },
            new long[] { 4, 3, 1 },
            new long[] { 5, 1, 6 },
            new long[] { 5, 3, 1 },
            new long[] { 6, 3, 1 }
        });

        string[] days = { "d", "n", "o" }; // for presentation

        //
        // Decision variables
        //

        //
        // For TransitionConstraint
        //
        IntVar[,] x =
            solver.MakeIntVarMatrix(num_nurses, num_days, valid_shifts, "x");
        IntVar[] x_flat = x.Flatten();

        //
        // summary of the nurses
        //
        IntVar[] nurse_stat = new IntVar[num_nurses];

        //
        // summary of the shifts per day
        //
        int num_shifts = shifts.Length;

        IntVar[,] day_stat = new IntVar[num_days, num_shifts];
        for (int i = 0; i < num_days; i++)
        {
            for (int j = 0; j < num_shifts; j++)
            {
                day_stat[i, j] = solver.MakeIntVar(0, num_nurses, "day_stat");
            }
        }

        //
        // Constraints
        //
        for (int i = 0; i < num_nurses; i++)
        {
            IntVar[] reg_input = new IntVar[num_days];
            for (int j = 0; j < num_days; j++)
            {
                reg_input[j] = x[i, j];
            }

            solver.Add(reg_input.Transition(transition_tuples,
                                            initial_state,
                                            accepting_states));
        }

        //
        // Statistics and constraints for each nurse
        //
        for (int nurse = 0; nurse < num_nurses; nurse++)
        {
            // Number of worked days (either day or night shift)
            IntVar[] nurse_days = new IntVar[num_days];
            for (int day = 0; day < num_days; day++)
            {
                nurse_days[day] =
                    x[nurse, day].IsMember(new int[] { day_shift, night_shift });
            }
            nurse_stat[nurse] = nurse_days.Sum().Var();

            // Each nurse must work between 7 and 10
            // days/nights during this period
            solver.Add(nurse_stat[nurse] >= 7 * week_multiplier / nurse_multiplier);
            solver.Add(nurse_stat[nurse] <= 10 * week_multiplier / nurse_multiplier);
        }

        //
        // Statistics and constraints for each day
        //
        for (int day = 0; day < num_days; day++)
        {
            IntVar[] nurses = new IntVar[num_nurses];
            for (int nurse = 0; nurse < num_nurses; nurse++)
            {
                nurses[nurse] = x[nurse, day];
            }
            IntVar[] stats = new IntVar[num_shifts];
            for (int shift = 0; shift < num_shifts; ++shift)
            {
                stats[shift] = day_stat[day, shift];
            }
            solver.Add(nurses.Distribute(stats));

            //
            // Some constraints for each day:
            //
            // Note: We have a strict requirements of
            //       the number of shifts.
            //       Using atleast constraints is harder
            //       in this model.
            //
            if (day % 7 == 5 || day % 7 == 6)
            {
                // special constraints for the weekends
                solver.Add(day_stat[day, day_shift] == 2 * nurse_multiplier);
                solver.Add(day_stat[day, night_shift] == nurse_multiplier);
                solver.Add(day_stat[day, off_shift] == 4 * nurse_multiplier);
            }
            else
            {
                // for workdays:

                // - exactly 3 on day shift
                solver.Add(day_stat[day, day_shift] == 3 * nurse_multiplier);
                // - exactly 2 on night
                solver.Add(day_stat[day, night_shift] == 2 * nurse_multiplier);
                // - exactly 2 off duty
                solver.Add(day_stat[day, off_shift] == 2 * nurse_multiplier);
            }
        }

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

        SearchMonitor log = solver.MakeSearchLog(1000000);

        solver.NewSearch(db, log);

        int num_solutions = 0;

        while (solver.NextSolution())
        {
            num_solutions++;
            for (int i = 0; i < num_nurses; i++)
            {
                Console.Write("Nurse #{0,-2}: ", i);
                var occ = new Dictionary <int, int>();
                for (int j = 0; j < num_days; j++)
                {
                    int v = (int)x[i, j].Value() - 1;
                    if (!occ.ContainsKey(v))
                    {
                        occ[v] = 0;
                    }
                    occ[v]++;
                    Console.Write(days[v] + " ");
                }

                Console.Write(" #workdays: {0,2}", nurse_stat[i].Value());
                foreach (int s in valid_shifts)
                {
                    int v = 0;
                    if (occ.ContainsKey(s - 1))
                    {
                        v = occ[s - 1];
                    }
                    Console.Write("  {0}:{1}", days[s - 1], v);
                }
                Console.WriteLine();
            }
            Console.WriteLine();

            Console.WriteLine("Statistics per day:\nDay      d n o");
            for (int j = 0; j < num_days; j++)
            {
                Console.Write("Day #{0,2}: ", j);
                foreach (int t in valid_shifts)
                {
                    Console.Write(day_stat[j, t].Value() + " ");
                }
                Console.WriteLine();
            }
            Console.WriteLine();

            // We just show 2 solutions
            if (num_solutions > 1)
            {
                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();
    }
Beispiel #28
0
    /**
     *
     * Killer Sudoku.
     *
     * http://en.wikipedia.org/wiki/Killer_Sudoku
     * """
     * Killer sudoku (also killer su doku, sumdoku, sum doku, addoku, or
     * samunamupure) is a puzzle that combines elements of sudoku and kakuro.
     * Despite the name, the simpler killer sudokus can be easier to solve
     * than regular sudokus, depending on the solver's skill at mental arithmetic;
     * the hardest ones, however, can take hours to crack.
     *
     * ...
     *
     * The objective is to fill the grid with numbers from 1 to 9 in a way that
     * the following conditions are met:
     *
     * - Each row, column, and nonet contains each number exactly once.
     * - The sum of all numbers in a cage must match the small number printed
     *   in its corner.
     * - No number appears more than once in a cage. (This is the standard rule
     *   for killer sudokus, and implies that no cage can include more
     *   than 9 cells.)
     *
     * In 'Killer X', an additional rule is that each of the long diagonals
     * contains each number once.
     * """
     *
     * Here we solve the problem from the Wikipedia page, also shown here
     * http://en.wikipedia.org/wiki/File:Killersudoku_color.svg
     *
     * The output is:
     *   2 1 5 6 4 7 3 9 8
     *   3 6 8 9 5 2 1 7 4
     *   7 9 4 3 8 1 6 5 2
     *   5 8 6 2 7 4 9 3 1
     *   1 4 2 5 9 3 8 6 7
     *   9 7 3 8 1 6 4 2 5
     *   8 2 1 7 3 9 5 4 6
     *   6 5 9 4 2 8 7 1 3
     *   4 3 7 1 6 5 2 8 9
     *
     * Also see http://www.hakank.org/or-tools/killer_sudoku.py
     * though this C# model has another representation of
     * the problem instance.
     *
     */
    private static void Solve()
    {
        Solver solver = new Solver("KillerSudoku");

        // size of matrix
        int cell_size          = 3;
        IEnumerable <int> CELL = Enumerable.Range(0, cell_size);
        int n = cell_size * cell_size;
        IEnumerable <int> RANGE = Enumerable.Range(0, n);

        // For a better view of the problem, see
        //  http://en.wikipedia.org/wiki/File:Killersudoku_color.svg

        // hints
        //  sum, the hints
        // Note: this is 1-based
        int[][] problem = { new int[] {  3, 1, 1, 1, 2 },
                            new int[] { 15, 1, 3, 1,4, 1, 5 },
                            new int[] { 22, 1, 6, 2,5, 2, 6, 3, 5 },
                            new int[] {  4, 1, 7, 2, 7 },
                            new int[] { 16, 1, 8, 2, 8 },
                            new int[] { 15, 1, 9, 2,9, 3, 9, 4, 9 },
                            new int[] { 25, 2, 1, 2,2, 3, 1, 3, 2 },
                            new int[] { 17, 2, 3, 2, 4 },
                            new int[] {  9, 3, 3, 3,4, 4, 4 },
                            new int[] {  8, 3, 6, 4,6, 5, 6 },
                            new int[] { 20, 3, 7, 3,8, 4, 7 },
                            new int[] {  6, 4, 1, 5, 1 },
                            new int[] { 14, 4, 2, 4, 3 },
                            new int[] { 17, 4, 5, 5,5, 6, 5 },
                            new int[] { 17, 4, 8, 5,7, 5, 8 },
                            new int[] { 13, 5, 2, 5,3, 6, 2 },
                            new int[] { 20, 5, 4, 6,4, 7, 4 },
                            new int[] { 12, 5, 9, 6, 9 },
                            new int[] { 27, 6, 1, 7,1, 8, 1, 9, 1 },
                            new int[] {  6, 6, 3, 7,2, 7, 3 },
                            new int[] { 20, 6, 6, 7,6, 7, 7 },
                            new int[] {  6, 6, 7, 6, 8 },
                            new int[] { 10, 7, 5, 8,4, 8, 5, 9, 4 },
                            new int[] { 14, 7, 8, 7,9, 8, 8, 8, 9 },
                            new int[] {  8, 8, 2, 9, 2 },
                            new int[] { 16, 8, 3, 9, 3 },
                            new int[] { 15, 8, 6, 8, 7 },
                            new int[] { 13, 9, 5, 9,6, 9, 7 },
                            new int[] { 17, 9, 8, 9, 9 } };

        int num_p = 29; // Number of segments

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

        //
        // Constraints
        //

        //
        // The first three constraints is the same as for sudokus.cs
        //
        //  alldifferent rows and columns
        foreach (int i in RANGE)
        {
            // rows
            solver.Add((from j in RANGE select x[i, j]).ToArray().AllDifferent());

            // cols
            solver.Add((from j in RANGE select x[j, i]).ToArray().AllDifferent());
        }

        // cells
        foreach (int i in CELL)
        {
            foreach (int j in CELL)
            {
                solver.Add(
                    (from di in CELL from dj in CELL select x[i * cell_size + di, j * cell_size + dj])
                    .ToArray()
                    .AllDifferent());
            }
        }

        // Sum the segments and ensure alldifferent
        for (int i = 0; i < num_p; i++)
        {
            int[] segment = problem[i];

            // Remove the sum from the segment
            int[] s2 = new int[segment.Length - 1];
            for (int j = 1; j < segment.Length; j++)
            {
                s2[j - 1] = segment[j];
            }

            // sum this segment
            calc(solver, s2, x, segment[0]);

            // all numbers in this segment must be distinct
            int len = segment.Length / 2;
            solver.Add((from j in Enumerable.Range(0, len) select x[s2[j * 2] - 1, s2[j * 2 + 1] - 1])
                       .ToArray()
                       .AllDifferent());
        }

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

        solver.NewSearch(db);

        while (solver.NextSolution())
        {
            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    int v = (int)x[i, j].Value();
                    if (v > 0)
                    {
                        Console.Write(v + " ");
                    }
                    else
                    {
                        Console.Write("  ");
                    }
                }
                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();
    }
Beispiel #29
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();
    }
Beispiel #30
0
    /**
     *
     * Word square.
     *
     * From http://en.wikipedia.org/wiki/Word_square
     * """
     * A word square is a special case of acrostic. It consists of a set of words,
     * all having the same number of letters as the total number of words (the
     * 'order' of the square); when the words are written out in a square grid
     * horizontally, the same set of words can be read vertically.
     * """
     *
     * See http://www.hakank.org/or-tools/word_square.py
     *
     */
    private static void Solve(String[] words, int word_len, int num_answers)
    {
        Solver solver = new Solver("WordSquare");

        int num_words = words.Length;

        Console.WriteLine("num_words: " + num_words);
        int n = word_len;
        IEnumerable <int> WORDLEN = Enumerable.Range(0, word_len);

        //
        //  convert a character to integer
        //

        String    alpha = "abcdefghijklmnopqrstuvwxyz";
        Hashtable d     = new Hashtable();
        Hashtable rev   = new Hashtable();
        int       count = 1;

        for (int a = 0; a < alpha.Length; a++)
        {
            d[alpha[a]] = count;
            rev[count]  = a;
            count++;
        }

        int num_letters = alpha.Length;

        //
        // Decision variables
        //
        IntVar[,] A = solver.MakeIntVarMatrix(num_words, word_len,
                                              0, num_letters, "A");
        IntVar[] A_flat = A.Flatten();
        IntVar[] E      = solver.MakeIntVarArray(n, 0, num_words, "E");



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

        // copy the words to a matrix
        for (int i = 0; i < num_words; i++)
        {
            char[] s = words[i].ToArray();
            foreach (int j in WORDLEN)
            {
                int t = (int)d[s[j]];
                solver.Add(A[i, j] == t);
            }
        }

        foreach (int i in WORDLEN)
        {
            foreach (int j in WORDLEN)
            {
                solver.Add(A_flat.Element(E[i] * word_len + j) ==
                           A_flat.Element(E[j] * word_len + i));
            }
        }


        //
        // Search
        //
        DecisionBuilder db = solver.MakePhase(E.Concat(A_flat).ToArray(),
                                              Solver.CHOOSE_FIRST_UNBOUND,
                                              Solver.ASSIGN_MIN_VALUE);

        solver.NewSearch(db);

        int num_sols = 0;

        while (solver.NextSolution())
        {
            num_sols++;
            for (int i = 0; i < n; i++)
            {
                Console.WriteLine(words[E[i].Value()] + " ");
            }
            Console.WriteLine();

            if (num_answers > 0 && num_sols >= num_answers)
            {
                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();
    }