public void Sequence() {
   Solver solver = new Solver("Solver");
   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);
   Assert.Equal(3, seq.Length);
 }
示例#2
0
        private void PostTransitionTimeConstraints(int t, bool postTransitionsConstraint = true)
        {
            Tool tool = factoryData.Tools[t];

            // if it is a inspection, we make sure there are no transitiontimes
            if (tool.CanPerformTaskType(factoryData.Inspection))
            {
                tool2TransitionTimes[t].Add(null);
            }
            else
            {
                int[,] tt = tool.TravellingTime;

                SequenceVar seq          = allToolSequences[t];
                long        s            = seq.Size();
                IntVar[]    nextLocation = new IntVar[s + 1];

                // The seq.Next(i) represents the task performed after the i-th
                // task in the sequence seq.Next(0) represents the first task
                // performed for extracting travelling times we need to get the
                // related location In case a task is not performed (seq.Next(i)
                // == i), i.e. it's pointing to itself The last performed task
                // (or pre-start task, if no tasks are performed) will have
                // seq.Next(i) == s + 1 therefore we add a virtual location
                // whose travelling time is equal to 0
                //
                // NOTE: The index of a SequenceVar are 0..n, but the domain
                // range is 1..(n+1), this is due to that the start node = 0 is
                // a dummy node, and the node where seq.Next(i) == n+1 is the
                // end node

                // Extra elements for the unreachable start node (0), and the
                // end node whose next task takes place in a virtual location
                int[] taskIndex2locationId = new int[s + 2];
                taskIndex2locationId[0] = -10;
                for (int i = 0; i < s; i++)
                {
                    taskIndex2locationId[i + 1] = tasks[toolIntervalVar2TaskId[t][i]].LocationId;
                }

                // this is the virtual location for unperformed tasks
                taskIndex2locationId[s + 1] = factoryData.NbWorkLocations;

                // Build the travelling time matrix with the additional virtual location
                int[][] ttWithVirtualLocation = new int [factoryData.NbWorkLocations + 1][];
                for (int d1 = 0; d1 < ttWithVirtualLocation.Length; d1++)
                {
                    ttWithVirtualLocation[d1] = new int[factoryData.NbWorkLocations + 1];
                    for (int d2 = 0; d2 < ttWithVirtualLocation.Length; d2++)
                    {
                        if (d1 == factoryData.NbWorkLocations)
                        {
                            ttWithVirtualLocation[d1][d2] = 0;
                        }
                        else
                        {
                            ttWithVirtualLocation[d1][d2] = (d2 == factoryData.NbWorkLocations) ? 0 : tt[d1, d2];
                        }
                    }
                }

                for (int i = 0; i < nextLocation.Length; i++)
                {
                    // this is the next-location associated with the i-th task
                    nextLocation[i] = solver.MakeElement(taskIndex2locationId, seq.Next(i)).Var();

                    int d = (i == 0) ? tool.InitialLocationId
                           : tasks[toolIntervalVar2TaskId[t][i - 1]].LocationId;
                    if (i == 0)
                    {
                        // To be changed - right now we don't have meaningful indata
                        // of previous location Ugly way of setting initial travel
                        // time to = 0, as this is how we find common grounds
                        // between benchmark algorithm and this
                        tool2TransitionTimes[t].Add(
                            solver.MakeElement(new int[ttWithVirtualLocation[d].Length], nextLocation[i])
                            .Var());
                    }
                    else
                    {
                        tool2TransitionTimes[t].Add(
                            solver.MakeElement(ttWithVirtualLocation[d], nextLocation[i]).Var());
                    }
                }

                // Extra elements for the unreachable start node (0), and the
                // end node whose next task takes place in a virtual location
                startingTimes[t] = new IntVar[s + 2];
                endTimes[t]      = new IntVar[s + 2];

                startingTimes[t][0] = solver.MakeIntConst(0);
                // Tbd: Set this endtime to the estimated time of finishing
                // previous task for the current tool
                endTimes[t][0] = solver.MakeIntConst(0);

                for (int i = 0; i < s; i++)
                {
                    startingTimes[t][i + 1] = tool2Task[t][i].SafeStartExpr(-1).Var();
                    endTimes[t][i + 1]      = tool2Task[t][i].SafeEndExpr(-1).Var();
                }
                startingTimes[t][s + 1] = solver.MakeIntConst(factoryData.Horizon);
                endTimes[t][s + 1]      = solver.MakeIntConst(factoryData.Horizon);

                // Enforce (or not) that each task is separated by the
                // transition time to the next task
                for (int i = 0; i < nextLocation.Length; i++)
                {
                    IntVar nextStart = solver.MakeElement(startingTimes[t], seq.Next(i).Var()).Var();
                    if (postTransitionsConstraint)
                    {
                        solver.Add(endTimes[t][i] + tool2TransitionTimes[t][i] <= nextStart);
                    }
                }
            }
        }
    /**
     *
     *
     * Organizing a day.
     *
     * Simple scheduling problem.
     *
     * Problem formulation from ECLiPSe:
     * Slides on (Finite Domain) Constraint Logic Programming, page 38f
     * http://eclipseclp.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();
    }
示例#4
0
文件: JobShop.cs 项目: wsgan001/TPM
    public void RunJobShopScheduling(String solverType)
    {
        Solver solver = new Solver(solverType);

        if (solver == null)
        {
            Console.WriteLine("JobShop failed to create a solver " + solverType);
            return;
        }

        // All tasks
        Dictionary <string, IntervalVar> allTasks = new Dictionary <string, IntervalVar>();

        // Creates jobs
        for (int i = 0; i < allJobs.Count; i++)
        {
            for (int j = 0; j < machines.ElementAt(i).Count; j++)
            {
                IntervalVar oneTask = solver.MakeFixedDurationIntervalVar(0,
                                                                          horizon,
                                                                          processingTimes.ElementAt(i).ElementAt(j),
                                                                          false,
                                                                          "Job_" + i + "_" + j);
                //Console.WriteLine("Job_" + i + "_" + j);
                allTasks.Add("Job_" + i + "_" + j, oneTask);
            }
        }

        // Create sequence variables and add disjuctive constraints
        List <SequenceVar> allSequences = new List <SequenceVar>();

        foreach (var machine in allMachines)
        {
            List <IntervalVar> machinesJobs = new List <IntervalVar>();
            for (int i = 0; i < allJobs.Count; i++)
            {
                for (int k = 0; k < machines.ElementAt(i).Count; k++)
                {
                    if (machines.ElementAt(i).ElementAt(k) == machine)
                    {
                        machinesJobs.Add(allTasks["Job_" + i + "_" + k]);
                    }
                }
            }

            DisjunctiveConstraint disj = solver.MakeDisjunctiveConstraint(machinesJobs.ToArray(),
                                                                          "machine " + machine);
            allSequences.Add(disj.SequenceVar());
            solver.Add(disj);
        }

        // Add conjunctive constraints
        foreach (var job in allJobs)
        {
            for (int j = 0; j < machines.ElementAt(job).Count - 1; j++)
            {
                solver.Add(allTasks["Job_" + job + "_" + (j + 1)].StartsAfterEnd(allTasks["Job_" + job + "_" + j]));
            }
        }

        // Set the objective
        IntVar[] allEnds = new IntVar[jobsCount];
        for (int i = 0; i < allJobs.Count; i++)
        {
            allEnds[i] = allTasks["Job_" + i + "_" + (machines.ElementAt(i).Count - 1)].EndExpr().Var();
        }

        // Objective: minimize the makespan (maximum end times of all tasks)
        // of the problem.
        IntVar      objectiveVar     = solver.MakeMax(allEnds).Var();
        OptimizeVar objectiveMonitor = solver.MakeMinimize(objectiveVar, 1);

        // Create search phases
        DecisionBuilder sequencePhase = solver.MakePhase(allSequences.ToArray(), Solver.SEQUENCE_DEFAULT);
        DecisionBuilder varsPhase     = solver.MakePhase(objectiveVar, Solver.CHOOSE_FIRST_UNBOUND, Solver.ASSIGN_MIN_VALUE);

        // The main decision builder (ranks all tasks, then fixes the
        // objectiveVariable).
        DecisionBuilder mainPhase = solver.Compose(sequencePhase, varsPhase);

        SolutionCollector collector = solver.MakeLastSolutionCollector();

        collector.Add(allSequences.ToArray());
        collector.Add(objectiveVar);

        foreach (var i in allMachines)
        {
            SequenceVar sequence      = allSequences.ElementAt(i);
            long        sequenceCount = sequence.Size();
            for (int j = 0; j < sequenceCount; j++)
            {
                IntervalVar t = sequence.Interval(j);
                collector.Add(t.StartExpr().Var());
                collector.Add(t.EndExpr().Var());
            }
        }

        // Search.
        bool solutionFound = solver.Solve(mainPhase, null, objectiveMonitor, null, collector);

        if (solutionFound)
        {
            //The index of the solution from the collector
            const int  SOLUTION_INDEX = 0;
            Assignment solution       = collector.Solution(SOLUTION_INDEX);

            string solLine      = "";
            string solLineTasks = "";
            Console.WriteLine("Time Intervals for Tasks\n");

            List <List <TimeSpan> > tuplesSolution = new List <List <TimeSpan> >();

            for (int m = 0; m < this.machinesCount; m++)
            {
                //Console.WriteLine("MachineCount: " + this.machinesCount);
                solLine      = "Machine " + m + " :";
                solLineTasks = "Machine " + m + ": ";

                SequenceVar seq            = allSequences.ElementAt(m);
                int[]       storedSequence = collector.ForwardSequence(SOLUTION_INDEX, seq);

                foreach (int taskIndex in storedSequence)
                {
                    //Console.WriteLine("taskIndex: " + taskIndex);
                    IntervalVar task = seq.Interval(taskIndex);
                    solLineTasks += task.Name() + " ";
                    //Console.WriteLine("Len: " + storedSequence.Length);
                }

                // First GreenTime
                //TimeSpan timeToAdd = tuplesSolution.First().Last();
                TimeSpan timeEndBucket   = this.bucketInfo.EndBucket;
                TimeSpan timeStartBucket = this.bucketInfo.StartBucket;


                int  solutionSize = tuplesSolution.Count;
                bool isEnd        = false;

                List <int> list_id = jobIds.ElementAt(m);
                // Adding GreenTime to Solution
                while (timeStartBucket.CompareTo(timeEndBucket) < 0)
                {
                    foreach (int taskIndex in storedSequence)
                    {
                        IntervalVar task = seq.Interval(taskIndex);

                        var startValue = TimeSpan.FromSeconds(collector.Value(0, task.StartExpr().Var()));
                        var endValue   = TimeSpan.FromSeconds(collector.Value(0, task.EndExpr().Var()));

                        TimeSpan greenTime = endValue.Subtract(startValue);
                        TimeSpan timeEnd;

                        timeEnd = timeStartBucket.Add(greenTime);


                        List <TimeSpan> tuple = new List <TimeSpan>();
                        tuple.Add(timeStartBucket);
                        if (timeEndBucket.CompareTo(timeEnd) < 0)
                        {
                            timeEnd = timeEndBucket;
                            isEnd   = true;
                        }

                        tuple.Add(timeEnd);
                        tuplesSolution.Add(tuple);
                        if (taskIndex + 1 < list_id.Count() && list_id.ElementAt(taskIndex) == list_id.ElementAt(taskIndex + 1))
                        {
                            timeStartBucket = timeStartBucket.Add(TimeSpan.FromSeconds(this.cycleTime));
                        }
                        else
                        {
                            timeStartBucket = timeEnd;
                        }
                        if (isEnd)
                        {
                            break;
                        }
                    }
                }

                //
                // Saving the Solution to a XML file
                //
                JobShop.save(m, tuplesSolution);

                //solLine += "\n";
                //solLineTasks += "\n";

                //Console.WriteLine(solLineTasks);
                //Console.WriteLine(solLine);
            }
        }
        else
        {
            Console.WriteLine("No solution found!");
        }
    }
示例#5
0
文件: JobShop.cs 项目: wsgan001/TPM
    public void RunJobShopScheduling(String solverType)
    {
        Solver solver = new Solver(solverType);

        if (solver == null)
        {
            Console.WriteLine("JobShop failed to create a solver " + solverType);
            return;
        }

        // All tasks
        Dictionary <string, IntervalVar> allTasks = new Dictionary <string, IntervalVar>();

        // Creates jobs
        for (int i = 0; i < allJobs.Count; i++)
        {
            for (int j = 0; j < machines.ElementAt(i).Count; j++)
            {
                IntervalVar oneTask = solver.MakeFixedDurationIntervalVar(0,
                                                                          horizon,
                                                                          processingTimes.ElementAt(i).ElementAt(j),
                                                                          false,
                                                                          "Job_" + i + "_" + j);

                allTasks.Add("Job_" + i + "_" + j, oneTask);
            }
        }

        // Create sequence variables and add disjuctive constraints
        List <SequenceVar> allSequences = new List <SequenceVar>();

        foreach (var machine in allMachines)
        {
            List <IntervalVar> machinesJobs = new List <IntervalVar>();
            for (int i = 0; i < allJobs.Count; i++)
            {
                for (int k = 0; k < machines.ElementAt(i).Count; k++)
                {
                    if (machines.ElementAt(i).ElementAt(k) == machine)
                    {
                        machinesJobs.Add(allTasks["Job_" + i + "_" + k]);
                    }
                }
            }

            DisjunctiveConstraint disj = solver.MakeDisjunctiveConstraint(machinesJobs.ToArray(),
                                                                          "machine " + machine);
            allSequences.Add(disj.SequenceVar());
            solver.Add(disj);
        }

        // Add conjunctive constraints
        foreach (var job in allJobs)
        {
            for (int j = 0; j < machines.ElementAt(job).Count - 1; j++)
            {
                solver.Add(allTasks["Job_" + job + "_" + (j + 1)].StartsAfterEnd(allTasks["Job_" + job + "_" + j]));
            }
        }

        // Set the objective
        IntVar[] allEnds = new IntVar[jobsCount];
        for (int i = 0; i < allJobs.Count; i++)
        {
            allEnds[i] = allTasks["Job_" + i + "_" + (machines.ElementAt(i).Count - 1)].EndExpr().Var();
        }

        // Objective: minimize the makespan (maximum end times of all tasks)
        // of the problem.
        IntVar      objectiveVar     = solver.MakeMax(allEnds).Var();
        OptimizeVar objectiveMonitor = solver.MakeMinimize(objectiveVar, 1);

        // Create search phases
        DecisionBuilder sequencePhase = solver.MakePhase(allSequences.ToArray(), Solver.SEQUENCE_DEFAULT);
        DecisionBuilder varsPhase     = solver.MakePhase(objectiveVar, Solver.CHOOSE_FIRST_UNBOUND, Solver.ASSIGN_MIN_VALUE);

        // The main decision builder (ranks all tasks, then fixes the
        // objectiveVariable).
        DecisionBuilder mainPhase = solver.Compose(sequencePhase, varsPhase);

        SolutionCollector collector = solver.MakeLastSolutionCollector();

        collector.Add(allSequences.ToArray());
        collector.Add(objectiveVar);

        foreach (var i in allMachines)
        {
            SequenceVar sequence      = allSequences.ElementAt(i);
            long        sequenceCount = sequence.Size();
            for (int j = 0; j < sequenceCount; j++)
            {
                IntervalVar t = sequence.Interval(j);
                collector.Add(t.StartExpr().Var());
                collector.Add(t.EndExpr().Var());
            }
        }

        // Search.
        bool solutionFound = solver.Solve(mainPhase, null, objectiveMonitor, null, collector);

        if (solutionFound)
        {
            //The index of the solution from the collector
            const int  SOLUTION_INDEX = 0;
            Assignment solution       = collector.Solution(SOLUTION_INDEX);

            string solLine      = "";
            string solLineTasks = "";
            Console.WriteLine("Time Intervals for Tasks\n");

            for (int m = 0; m < this.machinesCount; m++)
            {
                //Console.WriteLine("MachineCount: " + this.machinesCount);
                solLine      = "Machine " + m + " :";
                solLineTasks = "Machine " + m + ": ";

                SequenceVar seq            = allSequences.ElementAt(m);
                int[]       storedSequence = collector.ForwardSequence(SOLUTION_INDEX, seq);

                foreach (int taskIndex in storedSequence)
                {
                    //Console.WriteLine("taskIndex: " + taskIndex);
                    IntervalVar task = seq.Interval(taskIndex);
                    solLineTasks += task.Name() + " ";
                    //Console.WriteLine("Len: " + storedSequence.Length);
                }

                foreach (int taskIndex in storedSequence)
                {
                    IntervalVar task    = seq.Interval(taskIndex);
                    string      solTemp = "[" + collector.Value(0, task.StartExpr().Var()) + ",";
                    solTemp += collector.Value(0, task.EndExpr().Var()) + "] ";
                    solLine += solTemp;
                }

                //solLine += "\n";
                solLineTasks += "\n";

                //Console.WriteLine(solLineTasks);
                Console.WriteLine(solLine);
            }
        }
        else
        {
            Console.WriteLine("No solution found!");
        }
    }
示例#6
0
    /**
       *
       *
       * 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();
    }
示例#7
0
    public static void Main(String[] args)
    {
        InitTaskList();
        Solver solver = new Solver("Jobshop");

        // ----- Creates all Intervals and vars -----

        // All tasks
        List <IntervalVar> allTasks = new List <IntervalVar>();
        // Stores all tasks attached interval variables per job.
        List <List <IntervalVar> >
        jobsToTasks = new List <List <IntervalVar> >(jobsCount);
        // machinesToTasks stores the same interval variables as above, but
        // grouped my machines instead of grouped by jobs.
        List <List <IntervalVar> >
        machinesToTasks = new List <List <IntervalVar> >(machinesCount);

        for (int i = 0; i < machinesCount; i++)
        {
            machinesToTasks.Add(new List <IntervalVar>());
        }

        // Creates all individual interval variables.
        foreach (List <Task> job in myJobList)
        {
            jobsToTasks.Add(new List <IntervalVar>());
            foreach (Task task in job)
            {
                IntervalVar oneTask = solver.MakeFixedDurationIntervalVar(
                    0, horizon, task.Duration, false, task.Name);
                jobsToTasks[task.JobId].Add(oneTask);
                allTasks.Add(oneTask);
                machinesToTasks[task.Machine].Add(oneTask);
            }
        }

        // ----- Creates model -----

        // Creates precedences inside jobs.
        foreach (List <IntervalVar> jobToTask in jobsToTasks)
        {
            int tasksCount = jobToTask.Count;
            for (int task_index = 0; task_index < tasksCount - 1; ++task_index)
            {
                IntervalVar t1   = jobToTask[task_index];
                IntervalVar t2   = jobToTask[task_index + 1];
                Constraint  prec =
                    solver.MakeIntervalVarRelation(t2, Solver.STARTS_AFTER_END, t1);
                solver.Add(prec);
            }
        }

        // Adds disjunctive constraints on unary resources, and creates
        // sequence variables. A sequence variable is a dedicated variable
        // whose job is to sequence interval variables.
        SequenceVar[] allSequences = new SequenceVar[machinesCount];
        for (int machineId = 0; machineId < machinesCount; ++machineId)
        {
            string name = "Machine_" + machineId;
            DisjunctiveConstraint ct =
                solver.MakeDisjunctiveConstraint(machinesToTasks[machineId].ToArray(),
                                                 name);
            solver.Add(ct);
            allSequences[machineId] = ct.SequenceVar();
        }
        // Creates array of end_times of jobs.
        IntVar[] allEnds = new IntVar[jobsCount];
        for (int i = 0; i < jobsCount; i++)
        {
            IntervalVar task = jobsToTasks[i].Last();
            allEnds[i] = task.EndExpr().Var();
        }

        // Objective: minimize the makespan (maximum end times of all tasks)
        // of the problem.
        IntVar      objectiveVar     = solver.MakeMax(allEnds).Var();
        OptimizeVar objectiveMonitor = solver.MakeMinimize(objectiveVar, 1);

        // ----- Search monitors and decision builder -----

        // This decision builder will rank all tasks on all machines.
        DecisionBuilder sequencePhase =
            solver.MakePhase(allSequences, Solver.SEQUENCE_DEFAULT);

        // After the ranking of tasks, the schedule is still loose and any
        // task can be postponed at will. But, because the problem is now a PERT
        // (http://en.wikipedia.org/wiki/Program_Evaluation_and_Review_Technique),
        // we can schedule each task at its earliest start time. This iscs
        // conveniently done by fixing the objective variable to its
        // minimum value.
        DecisionBuilder objPhase = solver.MakePhase(
            objectiveVar, Solver.CHOOSE_FIRST_UNBOUND, Solver.ASSIGN_MIN_VALUE);

        // The main decision builder (ranks all tasks, then fixes the
        // objectiveVariable).
        DecisionBuilder mainPhase = solver.Compose(sequencePhase, objPhase);

        // Search log.
        const int     kLogFrequency = 1000000;
        SearchMonitor searchLog     =
            solver.MakeSearchLog(kLogFrequency, objectiveMonitor);

        SearchLimit limit = null;

        if (timeLimitInMs > 0)
        {
            limit = solver.MakeTimeLimit(timeLimitInMs);
        }


        SolutionCollector collector = solver.MakeLastSolutionCollector();

        collector.Add(allSequences);
        collector.Add(allTasks.ToArray());
        // Search.
        bool solutionFound = solver.Solve(mainPhase, searchLog, objectiveMonitor,
                                          limit, collector);

        if (solutionFound)
        {
            //The index of the solution from the collector
            const int  SOLUTION_INDEX = 0;
            Assignment solution       = collector.Solution(SOLUTION_INDEX);
            for (int m = 0; m < machinesCount; ++m)
            {
                Console.WriteLine("Machine " + m + " :");
                SequenceVar seq            = allSequences[m];
                int[]       storedSequence = collector.ForwardSequence(SOLUTION_INDEX, seq);
                foreach (int taskIndex in storedSequence)
                {
                    IntervalVar task     = seq.Interval(taskIndex);
                    long        startMin = solution.StartMin(task);
                    long        startMax = solution.StartMax(task);
                    if (startMin == startMax)
                    {
                        Console.WriteLine("Task " + task.Name() + " starts at " +
                                          startMin + ".");
                    }
                    else
                    {
                        Console.WriteLine("Task " + task.Name() + " starts between " +
                                          startMin + " and " + startMax + ".");
                    }
                }
            }
        }
        else
        {
            Console.WriteLine("No solution found!");
        }
    }