internal OrToolsCache()
 {
     this.singletonVariableMap = new Dictionary <string, Tuple <SingletonVariableModel, IntVar> >();
     this.aggregateVariableMap = new Dictionary <string, Tuple <AggregateVariableModel, IntVarVector> >();
     this.bucketMap            = new Dictionary <string, OrBucketVariableMap>();
     Variables = new IntVarVector();
 }
示例#2
0
        private static void assignNursesToDifferentShiftsEachDay(IntVar[,] nurses, IntVar[,] shifts, Solver solver)
        {
            for (int d = 0; d < numberDays; d++)
            {
                IntVarVector x = Enumerable.Range(0, numberNurses).Select(n => shifts[n, d]).ToArray();
                solver.Add(solver.MakeAllDifferent(x));

                IntVarVector y = Enumerable.Range(0, numberShifts).Select(s => nurses[s, d]).ToArray();
                solver.Add(solver.MakeAllDifferent(y));
            }
        }
示例#3
0
        public override IEnumerable <Constraint> GetConstraints(Solver solver)
        {
            var s = solver;

            foreach (var cell in Cells.Flatten())
            {
                var c = s.MakeBetweenCt(cell, Min, Max);
                s.Add(c);
                yield return(c);
            }

            for (var i = 0; i < Size; i++)
            {
                var perpIdx        = Enumerable.Range(0, Size).ToArray();
                var rowOrColumnIdx = new[] { i };

                {
                    var vect = new IntVarVector(GetGroup(rowOrColumnIdx, perpIdx).ToList()).TrackClrObject(this);
                    var c    = s.MakeAllDifferent(vect).TrackClrObject(this);
                    s.Add(c);
                    yield return(c);
                }

                {
                    var vect = new IntVarVector(GetGroup(perpIdx, rowOrColumnIdx).ToList()).TrackClrObject(this);
                    var c    = s.MakeAllDifferent(vect).TrackClrObject(this);
                    s.Add(c);
                    yield return(c);
                }
            }

            for (var i = 0; i < Div; i++)
            {
                var rowIdx = Enumerable.Range(i * Div, Div).ToArray();

                for (var j = 0; j < Div; j++)
                {
                    var columnIdx = Enumerable.Range(j * Div, Div).ToArray();
                    var vect      = new IntVarVector(GetGroup(rowIdx, columnIdx).ToList()).TrackClrObject(this);
                    var c         = s.MakeAllDifferent(vect).TrackClrObject(this);
                    s.Add(c);
                    yield return(c);
                }
            }
        }
        // TODO: TBD: PrepareSearchMonitors is perhaps closer to a fluent style...

        /// <summary>
        /// Override to prepare the <see cref="SearchMonitor"/> or monitors for the
        /// <paramref name="agent"/> and corresponding <see cref="Solver"/>. If called, the base
        /// method should be called after preparing any other required Monitors. By default, a
        /// single <see cref="SolutionCollector"/> is prepared.
        /// </summary>
        /// <param name="agent"></param>
        /// <param name="variables"></param>
        /// <returns></returns>
        protected virtual ISearchAgent PrepareSearchMonitors(ISearchAgent agent, params IntVar[] variables)
        {
            if (!agent.HasSolutionCollector <SolutionCollector>())
            {
                // Start with a single all-solution-collector.
                agent.Monitor(a =>
                {
                    var m    = a.Solver.MakeAllSolutionCollector();
                    var vect = new IntVarVector().TrackClrObject(this);
                    foreach (var v in variables)
                    {
                        vect.Add(v);
                    }
                    m.Add(vect);
                    return(m);
                });
            }

            return(agent);
        }
示例#5
0
        private static void CreateConstraints(Solver model, IntVar[] x)
        {
            for (int group = 0; group < 9; group++)
            {
                // Create row constraints
                IntVarVector row = new IntVarVector();
                for (int i = 0; i < 9; i++)
                {
                    int index = (group * 9) + i;
                    row.Add(x[index]);
                }
                var rowConstraint = model.MakeAllDifferent(row);
                model.Add(rowConstraint);

                // Create column constraints
                IntVarVector col = new IntVarVector();
                for (int i = 0; i < 9; i++)
                {
                    int index = (i * 9) + group;
                    col.Add(x[index]);
                }
                var colConstraint = model.MakeAllDifferent(col);
                model.Add(colConstraint);

                // Create region constraints
                int          regionStartX = (group % 3) * 3;
                int          regionStartY = (group / 3) * 3;
                IntVarVector region       = new IntVarVector();
                for (int i = 0; i < 9; i++)
                {
                    int deltaX = (i % 3);
                    int deltaY = (i / 3);
                    int xLoc   = regionStartX + deltaX;
                    int yLoc   = regionStartY + deltaY;
                    int index  = (yLoc * 9) + xLoc;
                    region.Add(x[index]);
                }
                var regionConstraint = model.MakeAllDifferent(region);
                model.Add(regionConstraint);
            }
        }
        public override IEnumerable <Constraint> GetConstraints(Solver source)
        {
            for (var i = MinimumValue; i < MaximumValue; i++)
            {
                var perpendicularIndexes = Enumerable.Range(0, Size).ToArray();
                var rowOrColumnIndexes   = new[] { i };

                {
                    var vector = new IntVarVector(GetGroup(rowOrColumnIndexes, perpendicularIndexes).ToList()).TrackClrObject(this);
                    var c      = source.MakeAllDifferent(vector).TrackClrObject(this);
                    source.Add(c);
                    yield return(c);
                }

                {
                    var vector = new IntVarVector(GetGroup(perpendicularIndexes, rowOrColumnIndexes).ToList()).TrackClrObject(this);
                    var c      = source.MakeAllDifferent(vector).TrackClrObject(this);
                    source.Add(c);
                    yield return(c);
                }
            }

            for (var i = MinimumValue; i < BlockSize; i++)
            {
                var rowIndexes = Enumerable.Range(i * BlockSize, BlockSize).ToArray();

                for (var j = MinimumValue; j < BlockSize; j++)
                {
                    var columnIndexes = Enumerable.Range(j * BlockSize, BlockSize).ToArray();
                    var vector        = new IntVarVector(GetGroup(rowIndexes, columnIndexes).ToList()).TrackClrObject(this);
                    var c             = source.MakeAllDifferent(vector).TrackClrObject(this);
                    source.Add(c);
                    yield return(c);
                }
            }
        }
示例#7
0
 /// <summary>
 /// Provides a helpful C-Sharp friendly extension method for <see
 /// cref="Solver.MakePhase(IntVarVector, VariableChooser, int)"/>.
 /// </summary>
 /// <param name="solver"></param>
 /// <param name="variables"></param>
 /// <param name="varChooser"></param>
 /// <param name="evalStrategy"></param>
 /// <returns></returns>
 public static DecisionBuilder MakePhase(this Solver solver, IntVarVector variables,
                                         VariableChooser varChooser, EvaluatorStrategy evalStrategy)
 => solver.MakePhase(variables, varChooser, evalStrategy.ToInt());
示例#8
0
 /// <summary>
 /// Provides a helpful C-Sharp friendly extension method for <see
 /// cref="Solver.MakePhase(IntVarVector, int, int)"/>.
 /// </summary>
 /// <param name="solver"></param>
 /// <param name="variables"></param>
 /// <param name="varStrategy"></param>
 /// <param name="valStrategy"></param>
 /// <returns></returns>
 public static DecisionBuilder MakePhase(this Solver solver, IntVarVector variables,
                                         IntVarStrategy varStrategy, IntValueStrategy valStrategy)
 => solver.MakePhase(variables, varStrategy.ToInt(), valStrategy.ToInt());
示例#9
0
        public static void Solve(FlexibleJobShopData data, bool chatty = false)
        {
            // Compute horizon
            var horizon = data.JobList.Sum(
                j => j.TaskList.Sum(
                    t => t.Durations.Max()));


            // ----- Create all intervals and vars -----

            /*
             * // Use some profiling and change the default parameters of the solver
             * SolverParameters solverParams = new SolverParameters();
             * // Change the profile level
             * solverParams.profile_level = SolverParameters.NORMAL_PROFILING;
             * // Constraint programming engine
             * Solver solver = new Solver("JobShop", solverParams);
             */
            // Constraint programming engine
            Solver solver = new Solver($"FlexibleJobShop: {data.Name}");

            // Initialize dictionaries to hold references to task intervals
            var tasksByJobId = new Dictionary <uint, List <TaskAlternative> >();

            foreach (var job in data.JobList)
            {
                tasksByJobId[job.Id] = new List <TaskAlternative>(job.TaskList.Count);
            }
            var tasksByMachineId = new Dictionary <uint, IntervalVarVector>();

            foreach (var machine in data.MachineList)
            {
                tasksByMachineId[machine.Id] = new IntervalVarVector();
            }

            // Creates all individual interval variables and collect in dictionaries
            foreach (var job in data.JobList)
            {
                foreach (var task in job.TaskList)
                {
                    var alternative = new TaskAlternative(job.Id);
                    tasksByJobId[job.Id].Add(alternative);
                    var activeVariables = new IntVarVector();
                    var hasAlternatives = task.AlternativesCount > 1;
                    for (int alt = 0; alt < task.AlternativesCount; alt++)
                    {
                        var         machine  = task.Machines[alt];
                        var         duration = task.Durations[alt];
                        var         name     = $"{task.Name}; Alternative {alt}: {machine.Name}, Duration {duration}";
                        IntervalVar interval = solver.MakeFixedDurationIntervalVar(0, horizon, duration, hasAlternatives, name);
                        alternative.Add(interval);
                        tasksByMachineId[machine.Id].Add(interval);
                        if (hasAlternatives)
                        {
                            activeVariables.Add(interval.PerformedExpr().Var());
                        }
                    }
                    alternative.AlternativeVar = solver.MakeIntVar(0, task.AlternativesCount - 1, task.Name);
                    if (hasAlternatives)
                    {
                        solver.Add(solver.MakeMapDomain(alternative.AlternativeVar, activeVariables));
                    }
                }
            }


            // ----- Create model -----

            // Create precedences inside jobs
            foreach (var taskAltList in tasksByJobId.Values)
            {
                for (int i = 0; i < taskAltList.Count - 1; i++)
                {
                    TaskAlternative currentTaskAlt = taskAltList[i];
                    TaskAlternative nextTaskAlt    = taskAltList[i + 1];
                    foreach (var alt1 in currentTaskAlt)
                    {
                        foreach (var alt2 in nextTaskAlt)
                        {
                            solver.Add(solver.MakeIntervalVarRelation(
                                           alt2, Solver.STARTS_AFTER_END, alt1));
                        }
                    }
                }
            }

            // Collect alternative variables.
            IntVarVector alternativeVariableVec = new IntVarVector();

            foreach (var taskAltList in tasksByJobId.Values)
            {
                foreach (var taskAlt in taskAltList)
                {
                    if (!taskAlt.AlternativeVar.Bound())
                    {
                        alternativeVariableVec.Add(taskAlt.AlternativeVar);
                    }
                }
            }

            // Add disjunctive constraints on unary resources, and create
            // sequence variables. A sequence variable is a dedicated variable
            // whose job is to sequence interval variables.
            SequenceVarVector allSequences = new SequenceVarVector();

            foreach (var machine in data.MachineList)
            {
                DisjunctiveConstraint disjCt = solver.MakeDisjunctiveConstraint(
                    tasksByMachineId[machine.Id], machine.Name);
                solver.Add(disjCt);
                allSequences.Add(disjCt.SequenceVar());
            }

            // Create array of end_times of jobs
            IntVarVector endsVec = new IntVarVector();

            foreach (var taskAltList in tasksByJobId.Values)
            {
                TaskAlternative lastTaskAlt = taskAltList.Last();
                foreach (var alt in lastTaskAlt)
                {
                    endsVec.Add(alt.SafeEndExpr(-1).Var());
                }
            }

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


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

            // This decision builder will assign all alternative variables.
            DecisionBuilder alternativePhase = solver.MakePhase(alternativeVariableVec, Solver.CHOOSE_MIN_SIZE, Solver.ASSIGN_MIN_VALUE);

            // 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 is
            // conveniently done by fixing the objective variable to its
            // minimum value.
            DecisionBuilder objectivePhase = solver.MakePhase(objectiveVar, Solver.CHOOSE_FIRST_UNBOUND, Solver.ASSIGN_MIN_VALUE);

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

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

            const long  FLAGS_time_limit_in_ms = 1000 * 60 * 20;
            SearchLimit limit = null;

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

            SolutionCollector collector = solver.MakeLastSolutionCollector();

            collector.AddObjective(objectiveVar);
            collector.Add(alternativeVariableVec);
            collector.Add(allSequences);

            foreach (var taskVec in tasksByMachineId.Values)
            {
                foreach (var task in taskVec)
                {
                    collector.Add(task.StartExpr().Var());
                }
            }


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

                Console.WriteLine();
                uint machineIdx = 0;
                foreach (var seq in allSequences)
                {
                    machineIdx++;
                    var taskSeq = collector.ForwardSequence(SOLUTION_INDEX, seq);
                    Console.WriteLine($"{seq.Name()}:");
                    Console.WriteLine("  Tasks: " + string.Join(", ", taskSeq));

                    //foreach (var taskIndex in storedSequence)
                    //{
                    //    IntervalVar task = sequence.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}.");
                    //    }
                    //}


                    Console.WriteLine();
                    Console.Write("  Starting times:");
                    foreach (var s in taskSeq)
                    {
                        Console.Write(" " + collector.Value(0, tasksByMachineId[machineIdx][s].StartExpr().Var()).ToString());
                    }
                    Console.WriteLine();
                }
                //var x = tasksByMachineId[1][0].StartExpr().Var();
                //var xValStr = collector.Value(0, x).ToString();
                Console.WriteLine("objective function value = " + solution.ObjectiveValue());  //TEMP
            }

            // Save profile in file
            //solver.ExportProfilingOverview("profile.txt");

            // Done
            solver.EndSearch();
        }