/**
       *
       *
       * Organizing a day.
       *
       * Simple scheduling problem.
       *
       * Problem formulation from ECLiPSe:
       * Slides on (Finite Domain) Constraint Logic Programming, page 38f
       * http://eclipse-clp.org/reports/eclipse.ppt
       *
       *
       * Also see http://www.hakank.org/google_or_tools/organize_day.py
       *
       */
    private static void Solve()
    {
        Solver solver = new Solver("OrganizeDayIntervals");

        int n = 4;

        int work = 0;
        int mail = 1;
        int shop = 2;
        int bank = 3;
        // the valid times of the day
        int begin = 9;
        int end   = 17;
        // tasks
        int[] tasks = {work, mail, shop, bank};
        // durations
        int[] durations = {4,1,2,1};
        // Arrays for interval variables.
        int[] starts_max = { begin,begin,begin,begin };
        int[] ends_max = { end -4, end - 1, end - 2, end - 1  };

        // task [i,0] must be finished before task [i,1]
        int[,] before_tasks = {
          {bank, shop},
          {mail, work}
        };

        //
        // Decision variables
        //
        IntervalVar[] intervals =
        solver.MakeFixedDurationIntervalVarArray(n,
                                                 starts_max,
                                                 ends_max,
                                                 durations,
                                                 false,
                                                 "task");
        //
        // Constraints
        //
        DisjunctiveConstraint disjunctive = intervals.Disjunctive("Sequence");
        solver.Add(disjunctive);

        // specific constraints
        for(int t = 0; t < before_tasks.GetLength(0); t++) {
          int before = before_tasks[t, 0];
          int after = before_tasks[t, 1];
          solver.Add(intervals[after].StartsAfterEnd(intervals[before]));
        }

        solver.Add(intervals[work].StartsAfter(11));

        //
        // Search
        //
        SequenceVar var = disjunctive.SequenceVar();
        SequenceVar[] seq_array = new SequenceVar[] { var };
        DecisionBuilder db = solver.MakePhase(seq_array, Solver.SEQUENCE_DEFAULT);

        solver.NewSearch(db);

        while (solver.NextSolution()) {
          foreach(int t in tasks) {
        Console.WriteLine(intervals[t].ToString());
          }
          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
 static void SequenceTest()
 {
   Solver solver = new Solver("TestSequence");
   IntervalVar[] intervals =
       solver.MakeFixedDurationIntervalVarArray(10, 0, 10, 5, false, "task");
   DisjunctiveConstraint disjunctive = intervals.Disjunctive("Sequence");
   SequenceVar var = disjunctive.SequenceVar();
   Assignment ass = solver.MakeAssignment();
   ass.Add(var);
   ass.SetForwardSequence(var, new int[] { 1, 3, 5 });
   int[] seq = ass.ForwardSequence(var);
   Console.WriteLine(seq.Length);
 }
  private static void Solve(int first_slot)
  {
    Console.WriteLine("----------------------------------------------------");
    Solver solver = new Solver("SpeakerScheduling");

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

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

    int number_of_speakers = durations.Length;
    // calculate the total number of slots (maximum in the availability array)
    // (and add the max durations)
    int last_slot = (from s in Enumerable.Range(0, number_of_speakers)
                    select speaker_availability[s].Max()).Max();
    Console.WriteLine(
        "Scheduling {0} speakers, for a total of {1} slots, during [{2}..{3}]",
        number_of_speakers, sum_of_durations, first_slot, last_slot);

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

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

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

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

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

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

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

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

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

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