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! :-("); } }
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); } }
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(); }
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); } }
/** * * 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(); }
/** * * 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(); }
/** * * 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(); }
/* * 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(); }
/** * * 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(); }
/** * * 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(); }
/** * * 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(); }
/** * * 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(); }
/** * * 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(); }
/** * * 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(); }
/** * * 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(); }
/** * * 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(); }
/** * * 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(); }
/** * * 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(); }
/** * * 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(); }
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); }
/** * * 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(); }
/** * * 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(); }
/** * * 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(); }
/** * * 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(); }