예제 #1
0
        public static Constraint Transition(this IntVar[] vars, IntTupleSet transitions,
                                            long initial_state, int[] final_states)
        {
            Solver solver = GetSolver(vars);

            return(solver.MakeTransitionConstraint(vars, transitions, initial_state, final_states));
        }
예제 #2
0
        // Allowed assignment
        public static Constraint AllowedAssignments(this IntVar[] vars,
                                                    IntTupleSet tuples)
        {
            Solver solver = GetSolver(vars);

            return(solver.MakeAllowedAssignments(vars, tuples));
        }
예제 #3
0
    /*
     * Build closeness pairs for consecutive numbers.
     *
     * Build set of allowed pairs such that two consecutive numbers touch
     * each other in the grid.
     *
     * Returns:
     * A list of pairs for allowed consecutive position of numbers.
     *
     * Args:
     * rows: the number of rows in the grid
     *  cols: the number of columns in the grid
     */
    public static IntTupleSet BuildPairs(int rows, int cols)
    {
        int[] ix         = { -1, 0, 1 };
        var   result_tmp = (from x in Enumerable.Range(0, rows)
                            from y in Enumerable.Range(0, cols)
                            from dx in ix
                            from dy in ix
                            where
                            x + dx >= 0 &&
                            x + dx < rows &&
                            y + dy >= 0 &&
                            y + dy < cols &&
                            (dx != 0 || dy != 0)
                            select new int[] { x *cols + y, (x + dx) * cols + (y + dy) }
                            ).ToArray();

        // Convert to len x 2 matrix
        int         len    = result_tmp.Length;
        IntTupleSet result = new IntTupleSet(2);

        foreach (int[] r in result_tmp)
        {
            result.Insert(r);
        }
        return(result);
    }
예제 #4
0
파일: rogo2.cs 프로젝트: RickOne16/or-tools
  /**
   *
   * Build the table of valid connections of the grid.
   *
   */
  public static IntTupleSet ValidConnections(int rows, int cols)
  {

    IEnumerable<int> ROWS = Enumerable.Range(0, rows);
    IEnumerable<int> COLS = Enumerable.Range(0, cols);
    var result_tmp = (
                      from i1 in ROWS
                      from j1 in COLS
                      from i2 in ROWS
                      from j2 in COLS
                      where
                      (Math.Abs(j1-j2) == 1 && i1 == i2) ||
                      (Math.Abs(i1-i2) == 1 && j1 % cols == j2 % cols)
                      select new int[] {i1*cols+j1, i2*cols+j2}
                      ).ToArray();

    // Convert to len x 2 matrix
    int len = result_tmp.Length;
    IntTupleSet result = new IntTupleSet(2);
    foreach(int[] r in result_tmp) {
      result.Insert(r);
    }
    return result;

  }
    static void MyContiguity(Solver solver, IntVar[] x)
    {
        // the DFA (for regular)
        int initial_state = 1;

        // all states are accepting states
        int[] accepting_states = { 1, 2, 3 };

        // The regular expression 0*1*0* {state, input, next state}
        long[][] transition_tuples =
        {
            new long[] { 1, 0, 1 },
            new long[] { 1, 1, 2 },
            new long[] { 2, 0, 3 },
            new long[] { 2, 1, 2 },
            new long[] { 3, 0, 3 }
        };

        IntTupleSet result = new IntTupleSet(3);

        result.InsertAll(transition_tuples);

        solver.Add(x.Transition(result,
                                initial_state,
                                accepting_states));
    }
예제 #6
0
파일: rogo2.cs 프로젝트: njb0401/JobShop
    /**
     *
     * Build the table of valid connections of the grid.
     *
     */
    public static IntTupleSet ValidConnections(int rows, int cols)
    {
        IEnumerable <int> ROWS = Enumerable.Range(0, rows);
        IEnumerable <int> COLS = Enumerable.Range(0, cols);
        var result_tmp         = (
            from i1 in ROWS
            from j1 in COLS
            from i2 in ROWS
            from j2 in COLS
            where
            (Math.Abs(j1 - j2) == 1 && i1 == i2) ||
            (Math.Abs(i1 - i2) == 1 && j1 % cols == j2 % cols)
            select new int[] { i1 *cols + j1, i2 *cols + j2 }
            ).ToArray();

        // Convert to len x 2 matrix
        int         len    = result_tmp.Length;
        IntTupleSet result = new IntTupleSet(2);

        foreach (int[] r in result_tmp)
        {
            result.Insert(r);
        }
        return(result);
    }
예제 #7
0
  static void MyContiguity(Solver solver, IntVar[] x) {

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

    // all states are accepting states
    int[] accepting_states = {1,2,3};

    // The regular expression 0*1*0* {state, input, next state}
    int[,] transition_tuples = { {1, 0, 1},
                                 {1, 1, 2},
                                 {2, 0, 3},
                                 {2, 1, 2},
                                 {3, 0, 3} };

    IntTupleSet result = new IntTupleSet(3);
    result.InsertAll(transition_tuples);

    solver.Add(x.Transition(result,
                            initial_state,
                            accepting_states));
  }
예제 #8
0
  /*
   * Build closeness pairs for consecutive numbers.
   *
   * Build set of allowed pairs such that two consecutive numbers touch
   * each other in the grid.
   *
   * Returns:
   * A list of pairs for allowed consecutive position of numbers.
   *
   * Args:
   * rows: the number of rows in the grid
   *  cols: the number of columns in the grid
   */
  public static IntTupleSet BuildPairs(int rows, int cols)
  {
    int[] ix = {-1, 0, 1};
    var result_tmp = (from x in Enumerable.Range(0, rows)
                      from y in Enumerable.Range(0, cols)
                      from dx in ix
                      from dy in ix
                      where
                      x + dx >= 0 &&
                      x + dx < rows &&
                      y + dy >= 0 &&
                      y + dy < cols &&
                      (dx != 0 || dy != 0)
                   select new int[] {x * cols + y, (x + dx) * cols + (y + dy)}
                      ).ToArray();

    // Convert to len x 2 matrix
    int len = result_tmp.Length;
    IntTupleSet result = new IntTupleSet(2);
    foreach(int[] r in result_tmp) {
      result.Insert(r);
    }
    return result;
  }
    /**
     *
     * Nurse rostering
     *
     * This is a simple nurse rostering model using a DFA and
     * the built-in TransitionConstraint.
     *
     * The DFA is from MiniZinc Tutorial, Nurse Rostering example:
     * - one day off every 4 days
     * - no 3 nights in a row.
     *
     * Also see:
     *  - http://www.hakank.org/or-tools/nurse_rostering.py
     *  - http://www.hakank.org/or-tools/nurse_rostering_regular.cs
     *    which use (a decomposition of) regular constraint
     *
     */
    private static void Solve(int nurse_multiplier, int week_multiplier)
    {
        Console.WriteLine("Starting Nurse Rostering");
        Console.WriteLine("  - {0} teams of 7 nurses", nurse_multiplier);
        Console.WriteLine("  - {0} blocks of 14 days", week_multiplier);

        Solver solver = new Solver("NurseRostering");

        //
        // Data
        //

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

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

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

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

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

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

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

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

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

        //
        // Decision variables
        //

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

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

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

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

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

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

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

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

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

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

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

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

        SearchMonitor log = solver.MakeSearchLog(1000000);

        solver.NewSearch(db, log);

        int num_solutions = 0;

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

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

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

            // We just show 2 solutions
            if (num_solutions > 1)
            {
                break;
            }
        }

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

        solver.EndSearch();
    }
예제 #10
0
    /**
     *
     * Traffic lights problem.
     *
     * CSPLib problem 16
     * http://www.cs.st-andrews.ac.uk/~ianm/CSPLib/prob/prob016/index.html
     * """
     * Specification:
     * Consider a four way traffic junction with eight traffic lights. Four of the traffic
     * lights are for the vehicles and can be represented by the variables V1 to V4 with domains
     * {r,ry,g,y} (for red, red-yellow, green and yellow). The other four traffic lights are
     * for the pedestrians and can be represented by the variables P1 to P4 with domains {r,g}.
     *
     * The constraints on these variables can be modelled by quaternary constraints on
     * (Vi, Pi, Vj, Pj ) for 1<=i<=4, j=(1+i)mod 4 which allow just the tuples
     * {(r,r,g,g), (ry,r,y,r), (g,g,r,r), (y,r,ry,r)}.
     *
     * It would be interesting to consider other types of junction (e.g. five roads
     * intersecting) as well as modelling the evolution over time of the traffic light sequence.
     * ...
     *
     * Results
     * Only 2^2 out of the 2^12 possible assignments are solutions.
     *
     * (V1,P1,V2,P2,V3,P3,V4,P4) =
     * {(r,r,g,g,r,r,g,g), (ry,r,y,r,ry,r,y,r), (g,g,r,r,g,g,r,r), (y,r,ry,r,y,r,ry,r)}
     * [(1,1,3,3,1,1,3,3), ( 2,1,4,1, 2,1,4,1), (3,3,1,1,3,3,1,1), (4,1, 2,1,4,1, 2,1)}
     * The problem has relative few constraints, but each is very
     * tight. Local propagation appears to be rather ineffective on this
     * problem.
     *
     * """
     * Note: In this model we use only the constraint
     *  solver.AllowedAssignments().
     *
     *
     * See http://www.hakank.org/or-tools/traffic_lights.py
     *
     */
    private static void Solve()
    {
        Solver solver = new Solver("TrafficLights");

        //
        // data
        //
        int n = 4;

        int r  = 0;
        int ry = 1;
        int g  = 2;
        int y  = 3;

        string[] lights = { "r", "ry", "g", "y" };

        // The allowed combinations
        IntTupleSet allowed = new IntTupleSet(4);

        allowed.InsertAll(new int[, ] {
            { r, r, g, g },
            { ry, r, y, r },
            { g, g, r, r },
            { y, r, ry, r }
        });
        //
        // Decision variables
        //
        IntVar[] V = solver.MakeIntVarArray(n, 0, n - 1, "V");
        IntVar[] P = solver.MakeIntVarArray(n, 0, n - 1, "P");

        // for search
        IntVar[] VP = new IntVar[2 * n];
        for (int i = 0; i < n; i++)
        {
            VP[i]     = V[i];
            VP[i + n] = P[i];
        }

        //
        // Constraints
        //
        for (int i = 0; i < n; i++)
        {
            int      j   = (1 + i) % n;
            IntVar[] tmp = new IntVar[] { V[i], P[i], V[j], P[j] };
            solver.Add(tmp.AllowedAssignments(allowed));
        }

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


        solver.NewSearch(db);

        while (solver.NextSolution())
        {
            for (int i = 0; i < n; i++)
            {
                Console.Write("{0,2} {1,2} ",
                              lights[V[i].Value()],
                              lights[P[i].Value()]);
            }
            Console.WriteLine();
        }

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

        solver.EndSearch();
    }
예제 #11
0
    /**
     *
     * Hidato puzzle in Google CP Solver.
     *
     * http://www.hidato.com/
     * """
     * Puzzles start semi-filled with numbered tiles.
     * The first and last numbers are circled.
     * Connect the numbers together to win. Consecutive
     * number must touch horizontally, vertically, or
     * diagonally.
     * """
     *
     * This is a port of the Python model hidato_table.py
     * made by Laurent Perron (using AllowedAssignments),
     * based on my (much slower) model hidato.py.
     *
     */
    private static void Solve(int model = 1)
    {
        Solver solver = new Solver("HidatoTable");

        //
        // models, a 0 indicates an open cell which number is not yet known.
        //

        int[,] puzzle = null;
        if (model == 1)
        {
            // Simple problem

            // Solution 1:
            // 6  7  9
            // 5  2  8
            // 1  4  3
            int[,] puzzle1 = { { 6, 0, 9 }, { 0, 2, 8 }, { 1, 0, 0 } };
            puzzle         = puzzle1;
        }
        else if (model == 2)
        {
            int[,] puzzle2 = { { 0, 44, 41,  0,  0, 0,  0 }, {  0, 43, 0, 28, 29, 0, 0 }, { 0,  1, 0, 0,  0, 33, 0 },
                               { 0,  2, 25,  4, 34, 0, 36 }, { 49, 16, 0, 23,  0, 0, 0 }, { 0, 19, 0, 0, 12,  7, 0 },
                               { 0,  0,  0, 14,  0, 0,  0 } };
            puzzle = puzzle2;
        }
        else if (model == 3)
        {
            // Problems from the book:
            // Gyora Bededek: "Hidato: 2000 Pure Logic Puzzles"
            // Problem 1 (Practice)
            int[,] puzzle3 =
            {
                { 0, 0, 20, 0, 0 }, { 0, 0, 0, 16, 18 }, { 22, 0, 15, 0, 0 }, { 23, 0, 1, 14, 11 }, { 0, 25, 0, 0, 12 }
            };
            puzzle = puzzle3;
        }
        else if (model == 4)
        {
            // problem 2 (Practice)
            int[,] puzzle4 =
            {
                { 0, 0, 0, 0, 14 }, { 0, 18, 12, 0, 0 }, { 0, 0, 17, 4, 5 }, { 0, 0, 7, 0, 0 }, { 9, 8, 25, 1, 0 }
            };
            puzzle = puzzle4;
        }
        else if (model == 5)
        {
            // problem 3 (Beginner)
            int[,] puzzle5 = { { 0, 26, 0, 0,  0, 18 }, { 0, 0, 27, 0, 0, 19 }, { 31, 23, 0,  0, 14, 0 },
                               { 0, 33, 8, 0, 15,  1 }, { 0, 0,  0, 5, 0,  0 }, { 35, 36, 0, 10,  0, 0 } };
            puzzle = puzzle5;
        }
        else if (model == 6)
        {
            // Problem 15 (Intermediate)
            int[,] puzzle6 = { { 64, 0, 0,  0,  0, 0,  0,  0 }, {  1, 63,  0, 59, 15, 57, 53,  0 },
                               {  0, 4, 0, 14,  0, 0,  0,  0 }, {  3,  0, 11,  0, 20, 19,  0, 50 },
                               {  0, 0, 0,  0, 22, 0, 48, 40 }, {  9,  0,  0, 32, 23,  0,  0, 41 },
                               { 27, 0, 0,  0, 36, 0, 46,  0 }, { 28, 30,  0, 35,  0,  0,  0,  0 } };
            puzzle = puzzle6;
        }

        int r = puzzle.GetLength(0);
        int c = puzzle.GetLength(1);

        Console.WriteLine();
        Console.WriteLine("----- Solving problem {0} -----", model);
        Console.WriteLine();

        PrintMatrix(puzzle);

        //
        // Decision variables
        //
        IntVar[] positions = solver.MakeIntVarArray(r * c, 0, r * c - 1, "p");

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

        //
        // Fill in the clues
        //
        for (int i = 0; i < r; i++)
        {
            for (int j = 0; j < c; j++)
            {
                if (puzzle[i, j] > 0)
                {
                    solver.Add(positions[puzzle[i, j] - 1] == i * c + j);
                }
            }
        }

        // Consecutive numbers much touch each other in the grid.
        // We use an allowed assignment constraint to model it.
        IntTupleSet close_tuples = BuildPairs(r, c);

        for (int k = 1; k < r * c - 1; k++)
        {
            IntVar[] tmp = new IntVar[] { positions[k], positions[k + 1] };
            solver.Add(tmp.AllowedAssignments(close_tuples));
        }

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

        solver.NewSearch(db);

        int num_solution = 0;

        while (solver.NextSolution())
        {
            num_solution++;
            PrintOneSolution(positions, r, c, num_solution);
        }

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

        solver.EndSearch();
    }
예제 #12
0
    /**
       *
       * Traffic lights problem.
       *
       * CSPLib problem 16
       * http://www.csplib.org/Problems/prob016
       * """
       * Specification:
       * Consider a four way traffic junction with eight traffic lights. Four of the traffic
       * lights are for the vehicles and can be represented by the variables V1 to V4 with domains
       * {r,ry,g,y} (for red, red-yellow, green and yellow). The other four traffic lights are
       * for the pedestrians and can be represented by the variables P1 to P4 with domains {r,g}.
       *
       * The constraints on these variables can be modelled by quaternary constraints on
       * (Vi, Pi, Vj, Pj ) for 1<=i<=4, j=(1+i)mod 4 which allow just the tuples
       * {(r,r,g,g), (ry,r,y,r), (g,g,r,r), (y,r,ry,r)}.
       *
       * It would be interesting to consider other types of junction (e.g. five roads
       * intersecting) as well as modelling the evolution over time of the traffic light sequence.
       * ...
       *
       * Results
       * Only 2^2 out of the 2^12 possible assignments are solutions.
       *
       * (V1,P1,V2,P2,V3,P3,V4,P4) =
       * {(r,r,g,g,r,r,g,g), (ry,r,y,r,ry,r,y,r), (g,g,r,r,g,g,r,r), (y,r,ry,r,y,r,ry,r)}
       * [(1,1,3,3,1,1,3,3), ( 2,1,4,1, 2,1,4,1), (3,3,1,1,3,3,1,1), (4,1, 2,1,4,1, 2,1)}
       * The problem has relative few constraints, but each is very
       * tight. Local propagation appears to be rather ineffective on this
       * problem.
       *
       * """
       * Note: In this model we use only the constraint
       *  solver.AllowedAssignments().
       *
       *
       * See http://www.hakank.org/or-tools/traffic_lights.py
       *
       */
    private static void Solve()
    {
        Solver solver = new Solver("TrafficLights");

        //
        // data
        //
        int n = 4;

        int r = 0;
        int ry = 1;
        int g = 2;
        int y = 3;

        string[] lights = {"r", "ry", "g", "y"};

        // The allowed combinations
        IntTupleSet allowed = new IntTupleSet(4);
        allowed.InsertAll(new int[,] {{r,r,g,g},
                                  {ry,r,y,r},
                                  {g,g,r,r},
                                  {y,r,ry,r}});
        //
        // Decision variables
        //
        IntVar[] V = solver.MakeIntVarArray(n, 0, n-1, "V");
        IntVar[] P = solver.MakeIntVarArray(n, 0, n-1, "P");

        // for search
        IntVar[] VP = new IntVar[2 * n];
        for(int i = 0; i < n; i++) {
          VP[i] = V[i];
          VP[i+n] = P[i];
        }

        //
        // Constraints
        //
        for(int i = 0; i < n; i++) {
          int j = (1+i) % n;
          IntVar[] tmp = new IntVar[] {V[i],P[i],V[j],P[j]};
          solver.Add(tmp.AllowedAssignments(allowed));
        }

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

        solver.NewSearch(db);

        while (solver.NextSolution()) {
          for(int i = 0; i < n; i++) {
        Console.Write("{0,2} {1,2} ",
                      lights[V[i].Value()],
                      lights[P[i].Value()]);
          }
          Console.WriteLine();
        }

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

        solver.EndSearch();
    }
예제 #13
0
파일: rogo2.cs 프로젝트: njb0401/JobShop
    /**
     *
     * Rogo puzzle solver.
     *
     * From http://www.rogopuzzle.co.nz/
     * """
     * The object is to collect the biggest score possible using a given
     * number of steps in a loop around a grid. The best possible score
     * for a puzzle is given with it, so you can easily check that you have
     * solved the puzzle. Rogo puzzles can also include forbidden squares,
     * which must be avoided in your loop.
     * """
     *
     * Also see Mike Trick:
     * "Operations Research, Sudoko, Rogo, and Puzzles"
     * http://mat.tepper.cmu.edu/blog/?p=1302
     *
     *
     * Also see, http://www.hakank.org/or-tools/rogo2.py
     * though this model differs in a couple of central points
     * which makes it much faster:
     *
     * - it use a table (
     * AllowedAssignments) with the valid connections
     * - instead of two coordinates arrays, it use a single path array
     *
     */
    private static void Solve()
    {
        Solver solver = new Solver("Rogo2");


        Console.WriteLine("\n");
        Console.WriteLine("**********************************************");
        Console.WriteLine("    {0}", problem_name);
        Console.WriteLine("**********************************************\n");

        //
        // Data
        //
        int B = -1;

        Console.WriteLine("Rows: {0} Cols: {1} Max Steps: {2}", rows, cols, max_steps);

        int[] problem_flatten = problem.Cast <int>().ToArray();
        int   max_point       = problem_flatten.Max();
        int   max_sum         = problem_flatten.Sum();

        Console.WriteLine("max_point: {0} max_sum: {1} best: {2}", max_point, max_sum, best);

        IEnumerable <int> STEPS  = Enumerable.Range(0, max_steps);
        IEnumerable <int> STEPS1 = Enumerable.Range(0, max_steps - 1);

        // the valid connections, to be used with AllowedAssignments
        IntTupleSet valid_connections = ValidConnections(rows, cols);


        //
        // Decision variables
        //
        IntVar[] path       = solver.MakeIntVarArray(max_steps, 0, rows * cols - 1, "path");
        IntVar[] points     = solver.MakeIntVarArray(max_steps, 0, best, "points");
        IntVar   sum_points = points.Sum().VarWithName("sum_points");


        //
        // Constraints
        //

        foreach (int s in STEPS)
        {
            // calculate the points (to maximize)
            solver.Add(points[s] == problem_flatten.Element(path[s]));

            // ensure that there are no black cells in
            // the path
            solver.Add(problem_flatten.Element(path[s]) != B);
        }

        solver.Add(path.AllDifferent());


        // valid connections
        foreach (int s in STEPS1)
        {
            solver.Add(new IntVar[] { path[s], path[s + 1] }.
                       AllowedAssignments(valid_connections));
        }
        // around the corner
        solver.Add(new IntVar[] { path[max_steps - 1], path[0] }.
                   AllowedAssignments(valid_connections));


        // Symmetry breaking
        for (int s = 1; s < max_steps; s++)
        {
            solver.Add(path[0] < path[s]);
        }


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


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

        solver.NewSearch(db, obj);

        while (solver.NextSolution())
        {
            Console.WriteLine("sum_points: {0}", sum_points.Value());
            Console.Write("path: ");
            foreach (int s in STEPS)
            {
                Console.Write("{0} ", path[s].Value());
            }
            Console.WriteLine();
            Console.WriteLine("(Adding 1 to coords...)");
            int[,] sol = new int[rows, cols];
            foreach (int s in STEPS)
            {
                int p = (int)path[s].Value();
                int x = (int)(p / cols);
                int y = (int)(p % cols);
                Console.WriteLine("{0,2},{1,2} ({2} points)", x + 1, y + 1, points[s].Value());
                sol[x, y] = 1;
            }
            Console.WriteLine("\nThe path is marked by 'X's:");
            for (int i = 0; i < rows; i++)
            {
                for (int j = 0; j < cols; j++)
                {
                    String p = sol[i, j] == 1 ? "X" : " ";
                    String q = problem[i, j] == B ? "B" :
                               problem[i, j] == 0 ? "." : problem[i, j].ToString();
                    Console.Write("{0,2}{1} ", q, p);
                }
                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();
    }
예제 #14
0
        /// <summary>
        ///     Get a new schedule based on number of teams and days.
        ///     Provide a rule set for transitions and day and employee constraints
        /// </summary>
        /// <param name="ruleSet">Rule set to use for transitions</param>
        /// <param name="shiftEmployees">Participating employees for the shifts</param>
        /// <param name="startDate">Schedule start date</param>
        /// <param name="numberOfDays">Number of days in each cycle</param>
        /// <param name="teamSize">Number of employees in each team</param>
        /// <param name="minShiftsPerCycle">Required number of shifts per cycle</param>
        /// <param name="startHour">Starting hour of the day shift</param>
        /// <param name="shiftHours">Hours in every shift, up to 12</param>
        /// <param name="maxSolutions">Max returned results</param>
        /// <returns></returns>
        public Task <List <Schedule> > CreateNewScheduleAsync(
            RuleSet ruleSet,
            IList <Employee> shiftEmployees,
            DateTime startDate,
            int numberOfDays,
            int teamSize,
            int minShiftsPerCycle,
            int startHour,
            int shiftHours,
            int maxSolutions = 1)
        {
            // Some sanity checks
            if (ruleSet == null)
            {
                throw new ArgumentOutOfRangeException($"Rule set is empty.");
            }
            if (shiftEmployees == null || shiftEmployees.Count < 1)
            {
                throw new ArgumentOutOfRangeException($"Employee collection is empty.");
            }
            if (numberOfDays < 1)
            {
                throw new ArgumentOutOfRangeException($"Invalid number for days in a cycle.");
            }
            if (teamSize < 1)
            {
                throw new ArgumentOutOfRangeException($"Invalid number for employees in each shift.");
            }
            if (minShiftsPerCycle < 0)
            {
                throw new ArgumentOutOfRangeException($"Invalid number for minimum shifts per cycle.");
            }
            if (startHour > 12)
            {
                throw new ArgumentOutOfRangeException(
                          $"Starting hour is bigger than expected. Please provide a number between 0-12");
            }
            if (shiftHours > 12)
            {
                throw new ArgumentOutOfRangeException(
                          $"Shift hours cannot be bigger than twelve. Please provide a number between 1-12");
            }

            var numberOfEmployees = shiftEmployees.Count;

            LastError = null;

            AddDiagnostics("Starting to solve a new schedule\n\n");
            AddDiagnostics("This is a schedule for {0} employees in {1} days\n", numberOfEmployees, numberOfDays);
            AddDiagnostics("Shift team size: {0}, minimum shifts per employee: {1}\n\n", teamSize, minShiftsPerCycle);

            /*
             * Solver
             */

            // Initiate a new solver
            var solver = new Solver("Schedule");

            int[] shifts      = { ShiftConsts.None, ShiftConsts.Day, ShiftConsts.Night, ShiftConsts.Off };
            int[] validShifts = { ShiftConsts.Day, ShiftConsts.Night, ShiftConsts.Off };

            /*
             * DFA and Transitions
             */
            var initialState = ruleSet.InitialState; // Everybody starts at this state

            int[] acceptingStates = ruleSet.AcceptingStates;

            // Transition tuples For TransitionConstraint
            var transitionTuples = new IntTupleSet(3);

            // Every tuple contains { state, input, next state }
            transitionTuples.InsertAll(ruleSet.Tuples);

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

            /*
             * Decision variables
             */

            // TransitionConstraint
            var x =
                solver.MakeIntVarMatrix(numberOfEmployees, numberOfDays, validShifts, "x");

            var flattenedX = x.Flatten();

            // Shift count
            var shiftCount = shifts.Length;

            // Shifts per day statistics
            var dayStats = new IntVar[numberOfDays, shiftCount];

            for (var i = 0; i < numberOfDays; i++)
            {
                for (var j = 0; j < shiftCount; j++)
                {
                    dayStats[i, j] = solver.MakeIntVar(0, numberOfEmployees, "dayStats");
                }
            }

            // Team statistics
            var teamStats = new IntVar[numberOfEmployees];

            /*
             * Constraints
             */
            for (var i = 0; i < numberOfEmployees; i++)
            {
                var regInput = new IntVar[numberOfDays];
                for (var j = 0; j < numberOfDays; j++)
                {
                    regInput[j] = x[i, j];
                }

                solver.Add(regInput.Transition(transitionTuples, initialState, acceptingStates));
            }

            // Statistics and constraints for each team
            for (var team = 0; team < numberOfEmployees; team++)
            {
                // Number of worked days (either day or night shift)
                var teamDays = new IntVar[numberOfDays];
                for (var day = 0; day < numberOfDays; day++)
                {
                    teamDays[day] = x[team, day].IsMember(new[] { ShiftConsts.Day, ShiftConsts.Night });
                }

                teamStats[team] = teamDays.Sum().Var();

                // At least two shifts per cycle
                solver.Add(teamStats[team] >= minShiftsPerCycle);
            }

            // Statistics and constraints for each day
            for (var day = 0; day < numberOfDays; day++)
            {
                var teams = new IntVar[numberOfEmployees];
                for (var team = 0; team < numberOfEmployees; team++)
                {
                    teams[team] = x[team, day];
                }

                var stats = new IntVar[shiftCount];
                for (var shift = 0; shift < shiftCount; ++shift)
                {
                    stats[shift] = dayStats[day, shift];
                }

                solver.Add(teams.Distribute(stats));

                // Constraints for each day

                // - exactly teamSize on day shift
                solver.Add(dayStats[day, ShiftConsts.Day] == teamSize);
                // - exactly teamSize on night shift
                solver.Add(dayStats[day, ShiftConsts.Night] == teamSize);
                // - The rest of the employees are off duty
                solver.Add(dayStats[day, ShiftConsts.Off] == numberOfEmployees - teamSize * 2);

                /* We can customize constraints even further
                 * For example, a special constraints for weekends(1 employee each shift as weekends are quiet):
                 * if (day % 7 == 5 || day % 7 == 6)
                 * {
                 *  solver.Add(dayStats[day, ShiftConsts.Day] == weekendTeamSize);
                 *  solver.Add(dayStats[day, ShiftConsts.Night] == weekendTeamSize);
                 *  solver.Add(dayStats[day, ShiftConsts.Off] == numberOfEmployees - weekendTeamSize * 2);
                 * }
                 */
            }

            /*
             * Decision Builder and Solution Search
             */

            // A simple random selection
            var db = solver.MakePhase(flattenedX, Solver.CHOOSE_DYNAMIC_GLOBAL_BEST, Solver.ASSIGN_RANDOM_VALUE);

            var log = solver.MakeSearchLog(1000000);

            // Don't search after a certain miliseconds
            var timeLimit = solver.MakeTimeLimit(1000); // a second

            // Start the search
            solver.NewSearch(db, log, timeLimit);

            // Return solutions as result
            var schedules = new List <Schedule>();

            var numSolutions = 0;

            while (solver.NextSolution())
            {
                numSolutions++;

                // A new schedule for the time period
                var schedule = new Schedule
                {
                    Id   = numSolutions,
                    Name = string.Format("Schedule for {0}-{1} for {2} employees, team size {3}",
                                         startDate.Date.ToShortDateString(), startDate.Date.AddDays(numberOfDays).ToShortDateString(),
                                         numberOfEmployees, teamSize),
                    StartDate = startDate.Date,
                    EndDate   = startDate.Date.AddDays(numberOfDays),
                    Shifts    = new List <Shift>()
                };

                var idCounter = 1;
                for (var i = 0; i < numberOfEmployees; i++)
                {
                    AddDiagnostics("Employee #{0,-2}: ", i + 1, shiftEmployees[i].ToString());

                    var occ = new Dictionary <int, int>();
                    for (var j = 0; j < numberOfDays; j++)
                    {
                        var shiftVal = (int)x[i, j].Value() - 1;
                        if (!occ.ContainsKey(shiftVal))
                        {
                            occ[shiftVal] = 0;
                        }
                        occ[shiftVal]++;

                        // Add a shift
                        var shiftType  = (ShiftType)shiftVal + 1;
                        var shiftStart = startDate.Date
                                         .AddDays(j)
                                         .AddHours(shiftType == ShiftType.Off
                                ? 0
                                : (shiftType == ShiftType.Day
                                    ? startHour
                                    : startHour + shiftHours)); // i.e Day shift starts at 07:00, night shift at 19:00

                        schedule.Shifts.Add(new Shift
                        {
                            Id        = idCounter,
                            Employee  = shiftEmployees[i],
                            Type      = shiftType,
                            StartDate = shiftStart,
                            EndDate   = shiftType == ShiftType.Off ? shiftStart : shiftStart.AddHours(shiftHours)
                        });
                        idCounter++;
                        AddDiagnostics(days[shiftVal] + " ");
                    }

                    AddDiagnostics(" #Total days: {0,2}", teamStats[i].Value());
                    foreach (var s in validShifts)
                    {
                        var v = 0;
                        if (occ.ContainsKey(s - 1))
                        {
                            v = occ[s - 1];
                        }
                        AddDiagnostics("  {0}:{1}", days[s - 1], v);
                    }

                    AddDiagnostics("\t- {0}\n", shiftEmployees[i].ToString());
                }

                AddDiagnostics("\n");

                AddDiagnostics("Daily Statistics\nDay\t\td n o\n");
                for (var j = 0; j < numberOfDays; j++)
                {
                    AddDiagnostics("Day #{0,2}: \t", j + 1);
                    foreach (var t in validShifts)
                    {
                        AddDiagnostics(dayStats[j, t].Value() + " ");
                    }
                    AddDiagnostics("\n");
                }

                AddDiagnostics("\n");

                // Add this schedule to list
                schedules.Add(schedule);

                // defaults to just the first one
                if (numSolutions >= maxSolutions)
                {
                    break;
                }
            }

            AddDiagnostics("\nSolutions: {0}", solver.Solutions());
            AddDiagnostics("\nFailures: {0}", solver.Failures());
            AddDiagnostics("\nBranches: {0} ", solver.Branches());
            AddDiagnostics("\nWallTime: {0}ms", solver.WallTime());

            solver.EndSearch();

            AddDiagnostics("\n\nFinished solving the schedule.");

            if (schedules.Count < 1)
            {
                LastError = "There's no solution in the model for your input.";
                // We reached the limit and there's no solution
                AddDiagnostics("\n\nThere's no solution in the model for your input.");
            }

            return(Task.FromResult(schedules));
        }
  /**
   *
   * 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();

  }