/**
   *
   * 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 #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;
    }
Beispiel #3
0
  /**
   *
   * Costas array
   * 
   * From http://mathworld.wolfram.com/CostasArray.html:
   * """
   * An order-n Costas array is a permutation on {1,...,n} such
   * that the distances in each row of the triangular difference
   * table are distinct. For example, the permutation {1,3,4,2,5}
   * has triangular difference table {2,1,-2,3}, {3,-1,1}, {1,2},
   * and {4}. Since each row contains no duplications, the permutation
   * is therefore a Costas array.
   * """
   * 
   * Also see
   * http://en.wikipedia.org/wiki/Costas_array
   * http://hakank.org/or-tools/costas_array.py
   *
   */
  private static void Solve(int n = 6)
  {

    Solver solver = new Solver("CostasArray");

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

    //
    // Decision variables
    //
    IntVar[] costas = solver.MakeIntVarArray(n, 1, n, "costas");
    IntVar[,] differences = solver.MakeIntVarMatrix(n, n, -n+1, n-1,
                                                    "differences");

    //
    // Constraints
    //
    
    // Fix the values in the lower triangle in the
    // difference matrix to -n+1. This removes variants
    // of the difference matrix for the the same Costas array.
    for(int i = 0; i < n; i++) {
      for(int j = 0; j <= i; j++ ) {
        solver.Add(differences[i,j] == -n+1);
      }
    }

    // hakank: All the following constraints are from
    // Barry O'Sullivans's original model.
    //
    solver.Add(costas.AllDifferent());


    // "How do the positions in the Costas array relate
    //  to the elements of the distance triangle."
    for(int i = 0; i < n; i++) {
      for(int j = 0; j < n; j++) {
        if (i < j) {
          solver.Add( differences[i,j] - (costas[j] - costas[j-i-1]) == 0);
        }
      }
    }


    // "All entries in a particular row of the difference
    //  triangle must be distint."
    for(int i = 0; i < n-2; i++) {
      IntVar[] tmp = (
                      from j in Enumerable.Range(0, n) 
                      where j > i
                      select differences[i,j]).ToArray();
      solver.Add(tmp.AllDifferent());

    }
    
    //
    // "All the following are redundant - only here to speed up search."
    //

    // "We can never place a 'token' in the same row as any other."
    for(int i = 0; i < n; i++) {
      for(int j = 0; j < n; j++) {
        if (i < j) {
          solver.Add(differences[i,j] != 0);
          solver.Add(differences[i,j] != 0);
        }
      }
    }

    for(int k = 2; k < n; k++) {
      for(int l = 2; l < n; l++) {
        if (k < l) {
          solver.Add(
                     (differences[k-2,l-1] + differences[k,l]) - 
                     (differences[k-1,l-1] + differences[k-1,l]) == 0
                     );
        }
      }
    }


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


    solver.NewSearch(db);

    while (solver.NextSolution()) {
      Console.Write("costas: ");
      for(int i = 0; i < n; i++) {
        Console.Write("{0} ", costas[i].Value());
      }
      Console.WriteLine("\ndifferences:");
      for(int i = 0; i < n; i++) {
        for(int j = 0; j < n; j++) {
          long v = differences[i,j].Value();
          if (v == -n+1) {
            Console.Write("   ");
          } else {
            Console.Write("{0,2} ", v);
          }
        }
        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 #4
0
  /**
   *
   * Solves a Sudoku problem.
   *
   * This is a very simple 4x4 problem instance:
   * Problem 26: Shidoku from
   * "Taking Sudoku Seriously", page 61
   *   4 _  _ _
   *   3 1  _ _
   *
   *   _ _  4 1
   *   _ _  _ 2
   *
   */
  private static void Solve()
  {
    Solver solver = new Solver("Sudoku");

    //
    // data
    //
    int block_size = 2;
    IEnumerable<int> BLOCK = Enumerable.Range(0, block_size);
    int n = block_size * block_size;
    IEnumerable<int> RANGE = Enumerable.Range(0, n);

    // 0 marks an unknown value
    int[,] initial_grid = {{4, 0,  0, 0},
                           {3, 1,  0, 0},

                           {0, 0,  4, 1},
                           {0, 0,  0, 2}};
    

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

    //
    // Constraints
    //  

    // init
    foreach(int i in RANGE) {
      foreach(int j in RANGE) {
        if (initial_grid[i,j] > 0) {
          solver.Add(grid[i,j] == initial_grid[i,j]);
        }
      }
    }

    
    foreach(int i in RANGE) {

      // rows
      solver.Add( (from j in RANGE
                   select grid[i,j]).ToArray().AllDifferent());

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

    }

    // blocks
    foreach(int i in BLOCK) {
      foreach(int j in BLOCK) {
        solver.Add( (from di in BLOCK
                     from dj in BLOCK
                     select grid[i*block_size+di, j*block_size+dj]
                     ).ToArray().AllDifferent());
      }
    }        


    //
    // Search
    //
    DecisionBuilder db = solver.MakePhase(grid_flat,
                                          Solver.INT_VAR_SIMPLE,
                                          Solver.INT_VALUE_SIMPLE);

    solver.NewSearch(db);

    while (solver.NextSolution()) {
      for(int i = 0; i < n; i++) {
        for(int j = 0; j < n; j++){ 
          Console.Write("{0} ", grid[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();

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

  }
Beispiel #6
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();

  }
  /**
   *
   * 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 #8
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();

  }
Beispiel #9
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 #10
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();

  }
  /**
   *
   * 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 int[,] { {1,1,2},
                                             {1,2,3},
                                             {1,3,1},
                                             {2,1,4},
                                             {2,2,4},
                                             {2,3,1},
                                             {3,1,4},
                                             {3,2,5},
                                             {3,3,1},
                                             {4,1,6},
                                             {4,2,6},
                                             {4,3,1},
                                             {5,1,6},
                                             {5,3,1},
                                             {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 #12
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 #13
0
  /**
   *
   * Set partition problem.
   *
   * Problem formulation from
   * http://www.koalog.com/resources/samples/PartitionProblem.java.html
   * """
   * This is a partition problem.
   * Given the set S = {1, 2, ..., n},
   * it consists in finding two sets A and B such that:
   *
   *  A U B = S,
   *  |A| = |B|,
   *  sum(A) = sum(B),
   *  sum_squares(A) = sum_squares(B)
   *
   * """
   *
   * This model uses a binary matrix to represent the sets.
   *
   *
   * Also see http://www.hakank.org/or-tools/set_partition.py
   *
   */
  private static void Solve(int n=16, int num_sets=2)
  {

    Solver solver = new Solver("SetPartition");

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

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


    //
    // Decision variables
    //
    IntVar[,] a = solver.MakeIntVarMatrix(num_sets, n, 0, 1, "a");
    IntVar[] a_flat = a.Flatten();


    //
    // Constraints
    //

    // partition set
    partition_sets(solver, a, num_sets, n);

    foreach(int i in Sets) {
      foreach(int j in Sets) {

        // same cardinality
        solver.Add(
                   (from k in NRange select a[i,k]).ToArray().Sum()
                   ==
                   (from k in NRange select a[j,k]).ToArray().Sum());

        // same sum
        solver.Add(
                   (from k in NRange select (k*a[i,k])).ToArray().Sum()
                   ==
                   (from k in NRange select (k*a[j,k])).ToArray().Sum());


        // same sum squared
        solver.Add(
                   (from k in NRange select (k*a[i,k]*k*a[i,k])).ToArray().Sum()
                   ==
                   (from k in NRange select (k*a[j,k]*k*a[j,k])).ToArray().Sum());
      }
    }


    // symmetry breaking for num_sets == 2
    if (num_sets == 2) {
      solver.Add(a[0,0] == 1);
    }

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

    solver.NewSearch(db);

    while (solver.NextSolution()) {

      int[,] a_val = new int[num_sets, n];
      foreach(int i in Sets) {
        foreach(int j in NRange) {
          a_val[i,j] = (int)a[i,j].Value();
        }
      }
      Console.WriteLine("sums: {0}",
                        (from j in NRange
                         select (j+1)*a_val[0,j]).ToArray().Sum());

      Console.WriteLine("sums squared: {0}",
                        (from j in NRange
                         select (int)Math.Pow((j+1)*a_val[0,j],2)).ToArray().Sum());

      // Show the numbers in each set
      foreach(int i in Sets) {
        if ( (from j in NRange select a_val[i,j]).ToArray().Sum() > 0 ) {
          Console.Write(i+1 + ": ");
          foreach(int j in NRange) {
            if (a_val[i,j] == 1) {
              Console.Write((j+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();

  }
  /**
   *
   * 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 #15
0
  /**
   *
   * Max flow problem.
   *
   * From Winston 'Operations Research', page 420f, 423f
   * Sunco Oil example.
   *
   *
   * Also see http://www.hakank.org/or-tools/max_flow_winston1.py
   *
   */
  private static void Solve()
  {

    Solver solver = new Solver("MaxFlowWinston1");

    //
    // Data
    //
    int n     = 5;
    IEnumerable<int> NODES = Enumerable.Range(0, n);

    // The arcs
    // Note:
    // This is 1-based to be compatible with other implementations.
    //
    int[,] arcs1 = {
      {1, 2},
      {1, 3},
      {2, 3},
      {2, 4},
      {3, 5},
      {4, 5},
      {5, 1}
    };

    // Capacities
    int [] cap = {2,3,3,4,2,1,100};

    // Convert arcs to 0-based
    int num_arcs = arcs1.GetLength(0);
    IEnumerable<int> ARCS = Enumerable.Range(0, num_arcs);
    int[,] arcs = new int[num_arcs, 2];
    foreach(int i in ARCS) {
      for(int j = 0; j < 2; j++) {
        arcs[i,j] = arcs1[i,j] - 1;
      }
    }

    // Convert arcs to matrix (for sanity checking below)
    int[,] mat = new int[num_arcs, num_arcs];
    foreach(int i in NODES) {
      foreach(int j in NODES) {
        int c = 0;
        foreach(int k in ARCS) {
          if (arcs[k,0] == i && arcs[k,1] == j) {
            c = 1;
          }
        }
        mat[i,j] = c;
      }
    }

    //
    // Decision variables
    //
    IntVar[,] flow = solver.MakeIntVarMatrix(n, n, 0, 200, "flow");
    IntVar z = flow[n-1, 0].VarWithName("z");

    //
    // Constraints
    //

    // capacity of arcs
    foreach(int i in ARCS) {
      solver.Add(flow[arcs[i,0], arcs[i,1]] <= cap[i]);
    }

    // inflows == outflows
    foreach(int i in NODES) {
      var s1 = (from k in ARCS
                where arcs[k,1] == i
                select flow[arcs[k,0], arcs[k,1]]
                ).ToArray().Sum();

      var s2 = (from k in ARCS
                where arcs[k,0] == i
                select flow[arcs[k,0], arcs[k,1]]
                ).ToArray().Sum();

      solver.Add(s1 == s2);

    }

    // Sanity check: just arcs with connections can have a flow.
    foreach(int i in NODES) {
      foreach(int j in NODES) {
        if (mat[i,j] == 0) {
          solver.Add(flow[i,j] == 0);
        }
      }
    }


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

    //
    // Search
    //
    DecisionBuilder db = solver.MakePhase(flow.Flatten(),
                                          Solver.INT_VAR_DEFAULT,
                                          Solver.ASSIGN_MAX_VALUE);
    solver.NewSearch(db, obj);

    while (solver.NextSolution()) {
      Console.WriteLine("z: {0}",z.Value());
      foreach(int i in NODES) {
        foreach(int j in NODES) {
          Console.Write(flow[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) {
      int ix = generator.Next(n);
      Console.WriteLine("The sum of s must be divisible by the number of subsets. Adjusting index " + ix);
      s[ix] = 1 + generator.Next(max);
    }

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

    int the_sum = (int)s.Sum() / num_subsets;
    Console.WriteLine("The sum: " + the_sum);


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

    //
    // Decision variables
    //

    // To which subset (s) do x[s, 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()
    //                );
    // }

    for(int p = 0; p < num_subsets; p++) {
      solver.Add(
                 (from k in NRange select (s[k]*x[p,k])).ToArray().Sum() == the_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 #17
0
  /**
   *
   * Solves a Strimko problem.
   * See http://www.hakank.org/google_or_tools/strimko2.py
   *
   */
  private static void Solve()
  {

    Solver solver = new Solver("Strimko2");

    //
    // data
    //
    int[,] streams = {{1,1,2,2,2,2,2},
                      {1,1,2,3,3,3,2},
                      {1,4,1,3,3,5,5},
                      {4,4,3,1,3,5,5},
                      {4,6,6,6,7,7,5},
                      {6,4,6,4,5,5,7},
                      {6,6,4,7,7,7,7}};

    // Note: This is 1-based
    int[,] placed = {{2,1,1},
                     {2,3,7},
                     {2,5,6},
                     {2,7,4},
                     {3,2,7},
                     {3,6,1},
                     {4,1,4},
                     {4,7,5},
                     {5,2,2},
                     {5,6,6}};

    int n = streams.GetLength(0);
    int num_placed = placed.GetLength(0);

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

    //
    // Constraints
    //
    // all rows and columns must be unique, i.e. a Latin Square
    for(int i = 0; i < n; i++) {
      IntVar[] row = new IntVar[n];
      IntVar[] col = new IntVar[n];
      for(int j = 0; j < n; j++) {
        row[j] = x[i,j];
        col[j] = x[j,i];
      }

      solver.Add(row.AllDifferent());
      solver.Add(col.AllDifferent());
    }

    // streams
    for(int s = 1; s <= n; s++) {
      IntVar[] tmp = (from i in Enumerable.Range(0, n)
                      from j in Enumerable.Range(0, n)
                      where streams[i,j] == s
                      select x[i,j]).ToArray();
      solver.Add(tmp.AllDifferent());

    }

    // placed
    for(int i = 0; i <  num_placed; i++) {
      // note: also adjust to 0-based
      solver.Add(x[placed[i,0] - 1,placed[i,1] - 1] ==  placed[i,2]);
    }

    //
    // 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
  /**
   *
   * 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();

  }
  /**
   *
   * Solves the Quasigroup Completion problem.
   * See http://www.hakank.org/or-tools/quasigroup_completion.py
   *
   */
  private static void Solve()
  {
    Solver solver = new Solver("QuasigroupCompletion");

    //
    // data
    //
    Console.WriteLine("Problem:");
    for(int i = 0; i < n; i++) {
      for(int j = 0; j < n; j++) {
        Console.Write(problem[i,j] + " ");
      }
      Console.WriteLine();
    }
    Console.WriteLine();


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

    //
    // Constraints
    //  
   for(int i = 0; i < n; i++) {
      for(int j = 0; j < n; j++) {
        if (problem[i,j] > X) {
          solver.Add(x[i,j] == problem[i,j]);
        }
      }
    }

    //
    // rows and columns must be different
    //

    // rows
    for(int i = 0; i < n; i++) {
      IntVar[] row = new IntVar[n];
      for(int j = 0; j < n; j++) {
        row[j] = x[i,j];
      }
      solver.Add(row.AllDifferent());
    }

    // columns
    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.AllDifferent());
    }


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

    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("{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();

  }
  /**
   *
   * 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()
  {

    Solver solver = new Solver("PartitionSets");

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

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

    while (solver.NextSolution()) {

      foreach(int i in Sets) {
        Console.Write("subset " + i + ": ");
        foreach(int j in NRange) {

          if ((int)x[i,j].Value() == 1) {
            Console.Write(s[j] + " ");
          }
        }
        Console.WriteLine();
      }
      Console.WriteLine();

    }

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

    solver.EndSearch();

  }
Beispiel #22
0
  /**
   *
   * Solves the Minesweeper problems.
   *
   * See http://www.hakank.org/google_or_tools/minesweeper.py
   *
   */
  private static void Solve()
  {
    Solver solver = new Solver("Minesweeper");

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

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


    //
    // Decision variables
    //
    IntVar[,] mines = solver.MakeIntVarMatrix(r, c, 0, 1, "mines");
    // for branching
    IntVar[] mines_flat = mines.Flatten();

    //
    // Constraints
    //  
    for(int i = 0; i < r; i++) {
      for(int j = 0; j < c; j++) {
        if (game[i,j] >= 0) {
          solver.Add( mines[i,j] == 0);

          // this cell is the sum of all its neighbours
          var tmp = from a in S from b in S where 
            i + a >= 0 &&
            j + b >= 0 &&
            i + a < r &&
            j + b < c
            select(mines[i+a,j+b]);

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

        }

        if (game[i,j] > X) {
          // This cell cannot be a mine since it 
          // has some value assigned to it
          solver.Add(mines[i,j] == 0);
        }
      }
    }


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

    solver.NewSearch(db);

    int sol = 0;
    while (solver.NextSolution()) {
      sol++;
      Console.WriteLine("Solution #{0} ", sol + " ");
      for(int i = 0; i < r; i++) {
        for(int j = 0; j < c; j++){ 
          Console.Write("{0} ", mines[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 #23
0
  /**
   *
   * P-median problem.
   *
   * Model and data from the OPL Manual, which describes the problem:
   * """
   * The P-Median problem is a well known problem in Operations Research.
   * The problem can be stated very simply, like this: given a set of customers
   * with known amounts of demand, a set of candidate locations for warehouses,
   * and the distance between each pair of customer-warehouse, choose P
   * warehouses to open that minimize the demand-weighted distance of serving
   * all customers from those P warehouses.
   * """
   *
   * Also see http://www.hakank.org/or-tools/p_median.py
   *
   */
  private static void Solve()
  {

    Solver solver = new Solver("PMedian");

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

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

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

    //
    // Decision variables
    //

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


    //
    // Constraints
    //

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

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

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

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


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

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

    solver.NewSearch(db, obj);

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

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

    solver.EndSearch();

  }
  /**
   *
   * 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 #25
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();

  }
Beispiel #26
0
  /**
   *
   * Kakuru puzzle.
   *
   * http://en.wikipedia.org/wiki/Kakuro
   * """
   * The object of the puzzle is to insert a digit from 1 to 9 inclusive
   * into each white cell such that the sum of the numbers in each entry
   * matches the clue associated with it and that no digit is duplicated in
   * any entry. It is that lack of duplication that makes creating Kakuro
   * puzzles with unique solutions possible, and which means solving a Kakuro
   * puzzle involves investigating combinations more, compared to Sudoku in
   * which the focus is on permutations. There is an unwritten rule for
   * making Kakuro puzzles that each clue must have at least two numbers
   * that add up to it. This is because including one number is mathematically
   * trivial when solving Kakuro puzzles; one can simply disregard the
   * number entirely and subtract it from the clue it indicates.
   * """
   *
   * This model solves the problem at the Wikipedia page.
   * For a larger picture, see
   * http://en.wikipedia.org/wiki/File:Kakuro_black_box.svg
   *
   * The solution:
   *  9 7 0 0 8 7 9
   *  8 9 0 8 9 5 7
   *  6 8 5 9 7 0 0
   *  0 6 1 0 2 6 0
   *  0 0 4 6 1 3 2
   *  8 9 3 1 0 1 4
   *  3 1 2 0 0 2 1
   *
   * Also see http://www.hakank.org/or-tools/kakuro.py
   * though this C# model has another representation of
   * the problem instance.
   *
   */
  private static void Solve()
  {

    Solver solver = new Solver("Kakuro");

    // size of matrix
    int n = 7;

    // segments:
    //  sum, the segments
    // Note: this is 1-based
    int[][] problem =
      {
        new int[] {16,  1,1, 1,2},
        new int[] {24,  1,5, 1,6, 1,7},
        new int[] {17,  2,1, 2,2},
        new int[] {29,  2,4, 2,5, 2,6, 2,7},
        new int[] {35,  3,1, 3,2, 3,3, 3,4, 3,5},
        new int[] { 7,  4,2, 4,3},
        new int[] { 8,  4,5, 4,6},
        new int[] {16,  5,3, 5,4, 5,5, 5,6, 5,7},
        new int[] {21,  6,1, 6,2, 6,3, 6,4},
        new int[] { 5,  6,6, 6,7},
        new int[] { 6,  7,1, 7,2, 7,3},
        new int[] { 3,  7,6, 7,7},

        new int[] {23,  1,1, 2,1, 3,1},
        new int[] {30,  1,2, 2,2, 3,2, 4,2},
        new int[] {27,  1,5, 2,5, 3,5, 4,5, 5,5},
        new int[] {12,  1,6, 2,6},
        new int[] {16,  1,7, 2,7},
        new int[] {17,  2,4, 3,4},
        new int[] {15,  3,3, 4,3, 5,3, 6,3, 7,3},
        new int[] {12,  4,6, 5,6, 6,6, 7,6},
        new int[] { 7,  5,4, 6,4},
        new int[] { 7,  5,7, 6,7, 7,7},
        new int[] {11,  6,1, 7,1},
        new int[] {10,  6,2, 7,2}

      };


    int num_p = 24; // Number of segments

    // The blanks
    // Note: 1-based
    int[,] blanks = {
      {1,3}, {1,4},
      {2,3},
      {3,6}, {3,7},
      {4,1}, {4,4}, {4,7},
      {5,1}, {5,2},
      {6,5},
      {7,4}, {7,5}
    };

    int num_blanks = blanks.GetLength(0);


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

    //
    // Constraints
    //

    // fill the blanks with 0
    for(int i = 0; i < num_blanks; i++) {
      solver.Add(x[blanks[i,0]-1,blanks[i,1]-1]==0);
    }

    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.CHOOSE_FIRST_UNBOUND,
                                          Solver.ASSIGN_MIN_VALUE);

    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 #27
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 #28
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();

  }
Beispiel #29
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 #30
0
  /**
   *
   * Solves the Coins Grid problm.
   * See http://www.hakank.org/google_or_tools/coins_grid.py
   *
   */
  private static void Solve(int n = 31, int c = 14)
  {
    Solver solver = new Solver("CoinsGrid");

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

    //
    // Constraints
    //

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

    // quadratic horizonal distance
    IntVar[] obj_tmp = new IntVar[n * n];
    for(int i = 0; i < n; i++) {
      for(int j = 0; j < n; j++) {
        obj_tmp[i * n + j] = (x[i,j] * (i - j) * (i - j)).Var();
      }
    }
    IntVar obj_var = obj_tmp.Sum().Var();

    //
    // Objective
    //
    OptimizeVar obj = obj_var.Minimize(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("obj: " + obj_var.Value());
      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();

  }