Пример #1
0
    public static void Main(String[] args)
    {
        // [START data]
        const int numNurses = 5;
        const int numDays   = 7;
        const int numShifts = 3;

        int[] allNurses = Enumerable.Range(0, numNurses).ToArray();
        int[] allDays   = Enumerable.Range(0, numDays).ToArray();
        int[] allShifts = Enumerable.Range(0, numShifts).ToArray();

        int[,,] shiftRequests = new int[, , ] {
            {
                { 0, 0, 1 },
                { 0, 0, 0 },
                { 0, 0, 0 },
                { 0, 0, 0 },
                { 0, 0, 1 },
                { 0, 1, 0 },
                { 0, 0, 1 },
            },
            {
                { 0, 0, 0 },
                { 0, 0, 0 },
                { 0, 1, 0 },
                { 0, 1, 0 },
                { 1, 0, 0 },
                { 0, 0, 0 },
                { 0, 0, 1 },
            },
            {
                { 0, 1, 0 },
                { 0, 1, 0 },
                { 0, 0, 0 },
                { 1, 0, 0 },
                { 0, 0, 0 },
                { 0, 1, 0 },
                { 0, 0, 0 },
            },
            {
                { 0, 0, 1 },
                { 0, 0, 0 },
                { 1, 0, 0 },
                { 0, 1, 0 },
                { 0, 0, 0 },
                { 1, 0, 0 },
                { 0, 0, 0 },
            },
            {
                { 0, 0, 0 },
                { 0, 0, 1 },
                { 0, 1, 0 },
                { 0, 0, 0 },
                { 1, 0, 0 },
                { 0, 1, 0 },
                { 0, 0, 0 },
            },
        };
        // [END data]

        // Creates the model.
        // [START model]
        CpModel model = new CpModel();
        // [END model]

        // Creates shift variables.
        // shifts[(n, d, s)]: nurse 'n' works shift 's' on day 'd'.
        // [START variables]
        Dictionary <Tuple <int, int, int>, IntVar> shifts = new Dictionary <Tuple <int, int, int>, IntVar>();

        foreach (int n in allNurses)
        {
            foreach (int d in allDays)
            {
                foreach (int s in allShifts)
                {
                    shifts.Add(Tuple.Create(n, d, s), model.NewBoolVar($"shifts_n{n}d{d}s{s}"));
                }
            }
        }
        // [END variables]

        // Each shift is assigned to exactly one nurse in the schedule period.
        // [START exactly_one_nurse]
        foreach (int d in allDays)
        {
            foreach (int s in allShifts)
            {
                IntVar[] x = new IntVar[numNurses];
                foreach (int n in allNurses)
                {
                    var key = Tuple.Create(n, d, s);
                    x[n] = shifts[key];
                }
                model.Add(LinearExpr.Sum(x) == 1);
            }
        }
        // [END exactly_one_nurse]

        // Each nurse works at most one shift per day.
        // [START at_most_one_shift]
        foreach (int n in allNurses)
        {
            foreach (int d in allDays)
            {
                IntVar[] x = new IntVar[numShifts];
                foreach (int s in allShifts)
                {
                    var key = Tuple.Create(n, d, s);
                    x[s] = shifts[key];
                }
                model.Add(LinearExpr.Sum(x) <= 1);
            }
        }
        // [END at_most_one_shift]

        // [START assign_nurses_evenly]
        // Try to distribute the shifts evenly, so that each nurse works
        // minShiftsPerNurse shifts. If this is not possible, because the total
        // number of shifts is not divisible by the number of nurses, some nurses will
        // be assigned one more shift.
        int minShiftsPerNurse = (numShifts * numDays) / numNurses;
        int maxShiftsPerNurse;

        if ((numShifts * numDays) % numNurses == 0)
        {
            maxShiftsPerNurse = minShiftsPerNurse;
        }
        else
        {
            maxShiftsPerNurse = minShiftsPerNurse + 1;
        }
        foreach (int n in allNurses)
        {
            IntVar[] numShiftsWorked = new IntVar[numDays * numShifts];
            foreach (int d in allDays)
            {
                foreach (int s in allShifts)
                {
                    var key = Tuple.Create(n, d, s);
                    numShiftsWorked[d * numShifts + s] = shifts[key];
                }
            }
            model.AddLinearConstraint(LinearExpr.Sum(numShiftsWorked), minShiftsPerNurse, maxShiftsPerNurse);
        }
        // [END assign_nurses_evenly]

        // [START objective]
        IntVar[] flatShifts        = new IntVar[numNurses * numDays * numShifts];
        int[]    flatShiftRequests = new int[numNurses * numDays * numShifts];
        foreach (int n in allNurses)
        {
            foreach (int d in allDays)
            {
                foreach (int s in allShifts)
                {
                    var key = Tuple.Create(n, d, s);
                    flatShifts[n * numDays * numShifts + d * numShifts + s]        = shifts[key];
                    flatShiftRequests[n * numDays * numShifts + d * numShifts + s] = shiftRequests[n, d, s];
                }
            }
        }
        model.Maximize(LinearExpr.ScalProd(flatShifts, flatShiftRequests));
        // [END objective]

        // Solve
        // [START solve]
        CpSolver       solver = new CpSolver();
        CpSolverStatus status = solver.Solve(model);

        Console.WriteLine($"Solve status: {status}");
        // [END solve]

        // [START print_solution]
        if (status == CpSolverStatus.Optimal || status == CpSolverStatus.Feasible)
        {
            Console.WriteLine("Solution:");
            foreach (int d in allDays)
            {
                Console.WriteLine($"Day {d}");
                foreach (int n in allNurses)
                {
                    bool isWorking = false;
                    foreach (int s in allShifts)
                    {
                        var key = Tuple.Create(n, d, s);
                        if (solver.Value(shifts[key]) == 1L)
                        {
                            if (shiftRequests[n, d, s] == 1)
                            {
                                Console.WriteLine($"  Nurse {n} work shift {s} (requested).");
                            }
                            else
                            {
                                Console.WriteLine($"  Nurse {n} work shift {s} (not requested).");
                            }
                        }
                    }
                }
            }
            Console.WriteLine(
                $"Number of shift requests met = {solver.ObjectiveValue} (out of {numNurses * minShiftsPerNurse}).");
        }
        else
        {
            Console.WriteLine("No solution found.");
        }
        // [END print_solution]

        // [START statistics]
        Console.WriteLine("Statistics");
        Console.WriteLine($"  conflicts: {solver.NumConflicts()}");
        Console.WriteLine($"  branches : {solver.NumBranches()}");
        Console.WriteLine($"  wall time: {solver.WallTime()}s");
        // [END statistics]
    }
Пример #2
0
    static void RankTasks(CpModel model, IntVar[] starts, ILiteral[] presences, IntVar[] ranks)
    {
        int num_tasks = starts.Length;

        // Creates precedence variables between pairs of intervals.
        ILiteral[,] precedences = new ILiteral[num_tasks, num_tasks];
        for (int i = 0; i < num_tasks; ++i)
        {
            for (int j = 0; j < num_tasks; ++j)
            {
                if (i == j)
                {
                    precedences[i, i] = presences[i];
                }
                else
                {
                    BoolVar prec = model.NewBoolVar(String.Format("{0} before {1}", i, j));
                    precedences[i, j] = prec;
                    model.Add(starts[i] < starts[j]).OnlyEnforceIf(prec);
                }
            }
        }

        // Treats optional intervals.
        for (int i = 0; i < num_tasks - 1; ++i)
        {
            for (int j = i + 1; j < num_tasks; ++j)
            {
                List <ILiteral> tmp_array = new List <ILiteral>();
                tmp_array.Add(precedences[i, j]);
                tmp_array.Add(precedences[j, i]);
                tmp_array.Add(presences[i].Not());
                // Makes sure that if i is not performed, all precedences are false.
                model.AddImplication(presences[i].Not(), precedences[i, j].Not());
                model.AddImplication(presences[i].Not(), precedences[j, i].Not());
                tmp_array.Add(presences[j].Not());
                // Makes sure that if j is not performed, all precedences are false.
                model.AddImplication(presences[j].Not(), precedences[i, j].Not());
                model.AddImplication(presences[j].Not(), precedences[j, i].Not());
                // The following bool_or will enforce that for any two intervals:
                //    i precedes j or j precedes i or at least one interval is not
                //        performed.
                model.AddBoolOr(tmp_array);
                // Redundant constraint: it propagates early that at most one precedence
                // is true.
                model.AddImplication(precedences[i, j], precedences[j, i].Not());
                model.AddImplication(precedences[j, i], precedences[i, j].Not());
            }
        }

        // Links precedences and ranks.
        for (int i = 0; i < num_tasks; ++i)
        {
            List <IntVar> tasks = new List <IntVar>();
            for (int j = 0; j < num_tasks; ++j)
            {
                tasks.Add((IntVar)precedences[j, i]);
            }
            model.Add(ranks[i] == LinearExpr.Sum(tasks) - 1);
        }
    }
Пример #3
0
    static void Main()
    {
        CpModel model = new CpModel();
        // Three weeks.
        int horizon   = 100;
        int num_tasks = 4;

        IntVar[]      starts    = new IntVar[num_tasks];
        IntVar[]      ends      = new IntVar[num_tasks];
        IntervalVar[] intervals = new IntervalVar[num_tasks];
        ILiteral[]    presences = new ILiteral[num_tasks];
        IntVar[]      ranks     = new IntVar[num_tasks];

        ILiteral true_var = model.TrueLiteral();

        // Creates intervals, half of them are optional.
        for (int t = 0; t < num_tasks; ++t)
        {
            starts[t] = model.NewIntVar(0, horizon, String.Format("start_{0}", t));
            int duration = t + 1;
            ends[t] = model.NewIntVar(0, horizon, String.Format("end_{0}", t));
            if (t < num_tasks / 2)
            {
                intervals[t] = model.NewIntervalVar(starts[t], duration, ends[t], String.Format("interval_{0}", t));
                presences[t] = true_var;
            }
            else
            {
                presences[t] = model.NewBoolVar(String.Format("presence_{0}", t));
                intervals[t] = model.NewOptionalIntervalVar(starts[t], duration, ends[t], presences[t],
                                                            String.Format("o_interval_{0}", t));
            }

            // Ranks = -1 if and only if the tasks is not performed.
            ranks[t] = model.NewIntVar(-1, num_tasks - 1, String.Format("rank_{0}", t));
        }

        // Adds NoOverlap constraint.
        model.AddNoOverlap(intervals);

        // Adds ranking constraint.
        RankTasks(model, starts, presences, ranks);

        // Adds a constraint on ranks.
        model.Add(ranks[0] < ranks[1]);

        // Creates makespan variable.
        IntVar makespan = model.NewIntVar(0, horizon, "makespan");

        for (int t = 0; t < num_tasks; ++t)
        {
            model.Add(ends[t] <= makespan).OnlyEnforceIf(presences[t]);
        }
        // Minimizes makespan - fixed gain per tasks performed.
        // As the fixed cost is less that the duration of the last interval,
        // the solver will not perform the last interval.
        IntVar[] presences_as_int_vars = new IntVar[num_tasks];
        for (int t = 0; t < num_tasks; ++t)
        {
            presences_as_int_vars[t] = (IntVar)presences[t];
        }
        model.Minimize(2 * makespan - 7 * LinearExpr.Sum(presences_as_int_vars));

        // Creates a solver and solves the model.
        CpSolver       solver = new CpSolver();
        CpSolverStatus status = solver.Solve(model);

        if (status == CpSolverStatus.Optimal)
        {
            Console.WriteLine(String.Format("Optimal cost: {0}", solver.ObjectiveValue));
            Console.WriteLine(String.Format("Makespan: {0}", solver.Value(makespan)));
            for (int t = 0; t < num_tasks; ++t)
            {
                if (solver.BooleanValue(presences[t]))
                {
                    Console.WriteLine(String.Format("Task {0} starts at {1} with rank {2}", t, solver.Value(starts[t]),
                                                    solver.Value(ranks[t])));
                }
                else
                {
                    Console.WriteLine(
                        String.Format("Task {0} in not performed and ranked at {1}", t, solver.Value(ranks[t])));
                }
            }
        }
        else
        {
            Console.WriteLine(String.Format("Solver exited with nonoptimal status: {0}", status));
        }
    }
Пример #4
0
    public static void Main(String[] args)
    {
        // Instantiate the data problem.
        // [START data]
        int[] Weights  = { 48, 30, 42, 36, 36, 48, 42, 42, 36, 24, 30, 30, 42, 36, 36 };
        int[] Values   = { 10, 30, 25, 50, 35, 30, 15, 40, 30, 35, 45, 10, 20, 30, 25 };
        int   NumItems = Weights.Length;

        int[] allItems = Enumerable.Range(0, NumItems).ToArray();

        int[] BinCapacities = { 100, 100, 100, 100, 100 };
        int   NumBins       = BinCapacities.Length;

        int[] allBins = Enumerable.Range(0, NumBins).ToArray();
        // [END data]

        // Model.
        // [START model]
        CpModel model = new CpModel();

        // [END model]

        // Variables.
        // [START variables]
        IntVar[,] x = new IntVar[NumItems, NumBins];
        foreach (int i in allItems)
        {
            foreach (int b in allBins)
            {
                x[i, b] = model.NewBoolVar($"x_{i}_{b}");
            }
        }
        // [END variables]

        // Constraints.
        // [START constraints]
        // Each item is assigned to at most one bin.
        foreach (int i in allItems)
        {
            IntVar[] vars = new IntVar[NumBins];
            foreach (int b in allBins)
            {
                vars[b] = x[i, b];
            }
            model.Add(LinearExpr.Sum(vars) <= 1);
        }

        // The amount packed in each bin cannot exceed its capacity.
        foreach (int b in allBins)
        {
            IntVar[] vars = new IntVar[NumItems];
            foreach (int i in allItems)
            {
                vars[i] = x[i, b];
            }
            model.Add(LinearExpr.ScalProd(vars, Weights) <= BinCapacities[b]);
        }
        // [END constraints]

        // Objective.
        // [START objective]
        IntVar[] objectiveVars   = new IntVar[NumItems * NumBins];
        int[]    objectiveValues = new int[NumItems * NumBins];
        foreach (int i in allItems)
        {
            foreach (int b in allBins)
            {
                int k = i * NumBins + b;
                objectiveVars[k]   = x[i, b];
                objectiveValues[k] = Values[i];
            }
        }
        model.Maximize(LinearExpr.ScalProd(objectiveVars, objectiveValues));
        //  [END objective]

        // Solve
        // [START solve]
        CpSolver       solver = new CpSolver();
        CpSolverStatus status = solver.Solve(model);

        // [END solve]

        // Print solution.
        // [START print_solution]
        // Check that the problem has a feasible solution.
        if (status == CpSolverStatus.Optimal || status == CpSolverStatus.Feasible)
        {
            Console.WriteLine($"Total packed value: {solver.ObjectiveValue}");
            double TotalWeight = 0.0;
            foreach (int b in allBins)
            {
                double BinWeight = 0.0;
                double BinValue  = 0.0;
                Console.WriteLine($"Bin {b}");
                foreach (int i in allItems)
                {
                    if (solver.Value(x[i, b]) == 1)
                    {
                        Console.WriteLine($"Item {i} weight: {Weights[i]} values: {Values[i]}");
                        BinWeight += Weights[i];
                        BinValue  += Values[i];
                    }
                }
                Console.WriteLine("Packed bin weight: " + BinWeight);
                Console.WriteLine("Packed bin value: " + BinValue);
                TotalWeight += BinWeight;
            }
            Console.WriteLine("Total packed weight: " + TotalWeight);
        }
        else
        {
            Console.WriteLine("No solution found.");
        }
        // [END print_solution]

        // [START statistics]
        Console.WriteLine("Statistics");
        Console.WriteLine($"  conflicts: {solver.NumConflicts()}");
        Console.WriteLine($"  branches : {solver.NumBranches()}");
        Console.WriteLine($"  wall time: {solver.WallTime()}s");
        // [END statistics]
    }
Пример #5
0
    static void Main(string[] args)
    {
        int numberGroups = 10;
        int numberItems  = 100;
        int numberColors = 3;
        int minItemsOfSameColorPerGroup = 4;

        var allGroups = Enumerable.Range(0, numberGroups).ToArray();
        var allItems  = Enumerable.Range(0, numberItems).ToArray();
        var allColors = Enumerable.Range(0, numberColors).ToArray();

        var values = allItems.Select(i => 1 + i + (i * i / 200)).ToArray();
        var colors = allItems.Select(i => i % numberColors).ToArray();

        var sumOfValues        = values.Sum();
        var averageSumPerGroup = sumOfValues / numberGroups;
        var numItemsPerGroup   = numberItems / numberGroups;

        var itemsPerColor = new Dictionary <int, List <int> >();

        foreach (var color in allColors)
        {
            itemsPerColor[color] = new List <int>();
            foreach (var item in allItems)
            {
                if (colors[item] == color)
                {
                    itemsPerColor[color].Add(item);
                }
            }
        }

        Console.WriteLine($"Model has {numberItems}, {numberGroups} groups and {numberColors} colors");
        Console.WriteLine($"    Average sum per group = {averageSumPerGroup}");

        var model = new CpModel();

        var itemInGroup = new BoolVar[numberItems, numberGroups];

        foreach (var item in allItems)
        {
            foreach (var @group in allGroups)
            {
                itemInGroup[item, @group] = model.NewBoolVar($"item {item} in group {@group}");
            }
        }

        // Each group must have the same size.
        foreach (var @group in allGroups)
        {
            var itemsInGroup = allItems.Select(x => itemInGroup[x, @group]).ToArray();
            model.AddLinearConstraint(LinearExpr.Sum(itemsInGroup), numItemsPerGroup, numItemsPerGroup);
        }

        //# One item must belong to exactly one group.
        foreach (var item in allItems)
        {
            var groupsForItem = allGroups.Select(x => itemInGroup[item, x]).ToArray();
            model.Add(LinearExpr.Sum(groupsForItem) == 1);
        }

        // The deviation of the sum of each items in a group against the average.
        var e = model.NewIntVar(0, 550, "epsilon");

        // Constrain the sum of values in one group around the average sum per
        // group.
        foreach (var @group in allGroups)
        {
            var itemValues = allItems.Select(x => itemInGroup[x, @group]).ToArray();

            var sum = LinearExpr.WeightedSum(itemValues, values);
            model.Add(sum <= averageSumPerGroup + e);
            model.Add(sum >= averageSumPerGroup - e);
        }

        // colorInGroup variables.
        var colorInGroup = new BoolVar[numberColors, numberGroups];

        foreach (var @group in allGroups)
        {
            foreach (var color in allColors)
            {
                colorInGroup[color, @group] = model.NewBoolVar($"color {color} is in group {@group}");
            }
        }

        // Item is in a group implies its color is in that group.
        foreach (var item in allItems)
        {
            foreach (var @group in allGroups)
            {
                model.AddImplication(itemInGroup[item, @group], colorInGroup[colors[item], @group]);
            }
        }

        // If a color is in a group, it must contains at least
        // min_items_of_same_color_per_group items from that color.
        foreach (var color in allColors)
        {
            foreach (var @group in allGroups)
            {
                var literal = colorInGroup[color, @group];
                var items   = itemsPerColor[color].Select(x => itemInGroup[x, @group]).ToArray();
                model.Add(LinearExpr.Sum(items) >= minItemsOfSameColorPerGroup).OnlyEnforceIf(literal);
            }
        }

        // Compute the maximum number of colors in a group.
        int maxColor = numItemsPerGroup / minItemsOfSameColorPerGroup;

        // Redundant constraint: The problem does not solve in reasonable time
        // without it.
        if (maxColor < numberColors)
        {
            foreach (var @group in allGroups)
            {
                var all = allColors.Select(x => colorInGroup[x, @group]).ToArray();
                model.Add(LinearExpr.Sum(all) <= maxColor);
            }
        }

        // Minimize epsilon
        model.Minimize(e);

        var solver = new CpSolver();

        var solutionPrinter = new SolutionPrinter(values, colors, allGroups, allItems, itemInGroup);

        var status = solver.Solve(model, solutionPrinter);
    }
Пример #6
0
    public static void Main(String[] args)
    {
        // Data.
        // [START data]
        int[,] costs =
        {
            { 90,  76,  75,  70,  50,  74 }, { 35,  85,  55, 65, 48, 101 }, { 125, 95,  90, 105,  59, 120 },
            { 45, 110,  95, 115, 104,  83 }, { 60, 105,  80, 75, 59,  62 }, {  45, 65, 110,  95,  47,  31 },
            { 38,  51, 107,  41,  69,  99 }, { 47,  85,  57, 71, 92,  77 }, {  39, 63,  97,  49, 118,  56 },
            { 47, 101,  71,  60,  88, 109 }, { 17,  39, 103, 64, 61,  92 }, { 101, 45,  83,  59,  92,  27 },
        };
        int numWorkers = costs.GetLength(0);
        int numTasks   = costs.GetLength(1);

        int[] allWorkers = Enumerable.Range(0, numWorkers).ToArray();
        int[] allTasks   = Enumerable.Range(0, numTasks).ToArray();
        // [END data]

        // Allowed groups of workers:
        // [START allowed_groups]
        long[,] group1 =
        {
            { 0, 0, 1, 1 }, // Workers 2, 3
            { 0, 1, 0, 1 }, // Workers 1, 3
            { 0, 1, 1, 0 }, // Workers 1, 2
            { 1, 1, 0, 0 }, // Workers 0, 1
            { 1, 0, 1, 0 }, // Workers 0, 2
        };

        long[,] group2 =
        {
            { 0, 0, 1, 1 }, // Workers 6, 7
            { 0, 1, 0, 1 }, // Workers 5, 7
            { 0, 1, 1, 0 }, // Workers 5, 6
            { 1, 1, 0, 0 }, // Workers 4, 5
            { 1, 0, 0, 1 }, // Workers 4, 7
        };

        long[,] group3 =
        {
            { 0, 0, 1, 1 }, // Workers 10, 11
            { 0, 1, 0, 1 }, // Workers 9, 11
            { 0, 1, 1, 0 }, // Workers 9, 10
            { 1, 0, 1, 0 }, // Workers 8, 10
            { 1, 0, 0, 1 }, // Workers 8, 11
        };
        // [END allowed_groups]

        // Model.
        // [START model]
        CpModel model = new CpModel();

        // [END model]

        // Variables.
        // [START variables]
        BoolVar[,] x = new BoolVar[numWorkers, numTasks];
        // Variables in a 1-dim array.
        foreach (int worker in allWorkers)
        {
            foreach (int task in allTasks)
            {
                x[worker, task] = model.NewBoolVar($"x[{worker},{task}]");
            }
        }
        // [END variables]

        // Constraints
        // [START constraints]
        // Each worker is assigned to at most one task.
        foreach (int worker in allWorkers)
        {
            List <ILiteral> tasks = new List <ILiteral>();
            foreach (int task in allTasks)
            {
                tasks.Add(x[worker, task]);
            }
            model.AddAtMostOne(tasks);
        }

        // Each task is assigned to exactly one worker.
        foreach (int task in allTasks)
        {
            List <ILiteral> workers = new List <ILiteral>();
            foreach (int worker in allWorkers)
            {
                workers.Add(x[worker, task]);
            }
            model.AddExactlyOne(workers);
        }
        // [END constraints]

        // [START assignments]
        // Create variables for each worker, indicating whether they work on some task.
        BoolVar[] work = new BoolVar[numWorkers];
        foreach (int worker in allWorkers)
        {
            work[worker] = model.NewBoolVar($"work[{worker}]");
        }

        foreach (int worker in allWorkers)
        {
            List <ILiteral> tasks = new List <ILiteral>();
            foreach (int task in allTasks)
            {
                tasks.Add(x[worker, task]);
            }
            model.Add(work[worker] == LinearExpr.Sum(tasks));
        }

        // Define the allowed groups of worders
        model.AddAllowedAssignments(new IntVar[] { work[0], work[1], work[2], work[3] }).AddTuples(group1);
        model.AddAllowedAssignments(new IntVar[] { work[4], work[5], work[6], work[7] }).AddTuples(group2);
        model.AddAllowedAssignments(new IntVar[] { work[8], work[9], work[10], work[11] }).AddTuples(group3);
        // [END assignments]

        // Objective
        // [START objective]
        LinearExprBuilder obj = LinearExpr.NewBuilder();

        foreach (int worker in allWorkers)
        {
            foreach (int task in allTasks)
            {
                obj.AddTerm(x[worker, task], costs[worker, task]);
            }
        }
        model.Minimize(obj);
        // [END objective]

        // Solve
        // [START solve]
        CpSolver       solver = new CpSolver();
        CpSolverStatus status = solver.Solve(model);

        Console.WriteLine($"Solve status: {status}");
        // [END solve]

        // Print solution.
        // [START print_solution]
        // Check that the problem has a feasible solution.
        if (status == CpSolverStatus.Optimal || status == CpSolverStatus.Feasible)
        {
            Console.WriteLine($"Total cost: {solver.ObjectiveValue}\n");
            foreach (int worker in allWorkers)
            {
                foreach (int task in allTasks)
                {
                    if (solver.Value(x[worker, task]) > 0.5)
                    {
                        Console.WriteLine($"Worker {worker} assigned to task {task}. " +
                                          $"Cost: {costs[worker, task]}");
                    }
                }
            }
        }
        else
        {
            Console.WriteLine("No solution found.");
        }
        // [END print_solution]

        Console.WriteLine("Statistics");
        Console.WriteLine($"  - conflicts : {solver.NumConflicts()}");
        Console.WriteLine($"  - branches  : {solver.NumBranches()}");
        Console.WriteLine($"  - wall time : {solver.WallTime()}s");
    }
Пример #7
0
    // [END solution_printer]

    public static void Main(String[] args)
    {
        // [START data]
        const int numNurses = 4;
        const int numDays   = 3;
        const int numShifts = 3;

        int[] allNurses = Enumerable.Range(0, numNurses).ToArray();
        int[] allDays   = Enumerable.Range(0, numDays).ToArray();
        int[] allShifts = Enumerable.Range(0, numShifts).ToArray();
        // [END data]

        // Creates the model.
        // [START model]
        CpModel model = new CpModel();
        // [END model]

        // Creates shift variables.
        // shifts[(n, d, s)]: nurse 'n' works shift 's' on day 'd'.
        // [START variables]
        Dictionary <Tuple <int, int, int>, IntVar> shifts = new Dictionary <Tuple <int, int, int>, IntVar>();

        foreach (int n in allNurses)
        {
            foreach (int d in allDays)
            {
                foreach (int s in allShifts)
                {
                    shifts.Add(Tuple.Create(n, d, s), model.NewBoolVar($"shifts_n{n}d{d}s{s}"));
                }
            }
        }
        // [END variables]

        // Each shift is assigned to exactly one nurse in the schedule period.
        // [START exactly_one_nurse]
        foreach (int d in allDays)
        {
            foreach (int s in allShifts)
            {
                IntVar[] x = new IntVar[numNurses];
                foreach (int n in allNurses)
                {
                    var key = Tuple.Create(n, d, s);
                    x[n] = shifts[key];
                }
                model.Add(LinearExpr.Sum(x) == 1);
            }
        }
        // [END exactly_one_nurse]

        // Each nurse works at most one shift per day.
        // [START at_most_one_shift]
        foreach (int n in allNurses)
        {
            foreach (int d in allDays)
            {
                IntVar[] x = new IntVar[numShifts];
                foreach (int s in allShifts)
                {
                    var key = Tuple.Create(n, d, s);
                    x[s] = shifts[key];
                }
                model.Add(LinearExpr.Sum(x) <= 1);
            }
        }
        // [END at_most_one_shift]

        // [START assign_nurses_evenly]
        // Try to distribute the shifts evenly, so that each nurse works
        // minShiftsPerNurse shifts. If this is not possible, because the total
        // number of shifts is not divisible by the number of nurses, some nurses will
        // be assigned one more shift.
        int minShiftsPerNurse = (numShifts * numDays) / numNurses;
        int maxShiftsPerNurse;

        if ((numShifts * numDays) % numNurses == 0)
        {
            maxShiftsPerNurse = minShiftsPerNurse;
        }
        else
        {
            maxShiftsPerNurse = minShiftsPerNurse + 1;
        }
        foreach (int n in allNurses)
        {
            IntVar[] numShiftsWorked = new IntVar[numDays * numShifts];
            foreach (int d in allDays)
            {
                foreach (int s in allShifts)
                {
                    var key = Tuple.Create(n, d, s);
                    numShiftsWorked[d * numShifts + s] = shifts[key];
                }
            }
            model.AddLinearConstraint(LinearExpr.Sum(numShiftsWorked), minShiftsPerNurse, maxShiftsPerNurse);
        }
        // [END assign_nurses_evenly]

        // [START parameters]
        CpSolver solver = new CpSolver();

        solver.StringParameters += "linearization_level:0 ";
        // Tell the solver to enumerate all solutions.
        solver.StringParameters += "enumerate_all_solutions:true ";
        // [END parameters]

        // Display the first five solutions.
        // [START solution_printer_instantiate]
        const int       solutionLimit = 5;
        SolutionPrinter cb            = new SolutionPrinter(allNurses, allDays, allShifts, shifts, solutionLimit);
        // [END solution_printer_instantiate]

        // Solve
        // [START solve]
        CpSolverStatus status = solver.Solve(model, cb);

        Console.WriteLine($"Solve status: {status}");
        // [END solve]

        // [START statistics]
        Console.WriteLine("Statistics");
        Console.WriteLine($"  conflicts: {solver.NumConflicts()}");
        Console.WriteLine($"  branches : {solver.NumBranches()}");
        Console.WriteLine($"  wall time: {solver.WallTime()}s");
        // [END statistics]
    }
Пример #8
0
        private static void Witi_SOLUTION()
        {
            Solver solver = Solver.CreateSolver("SimpleMipProgram", "CBC_MIXED_INTEGER_PROGRAMMING");

            string[] text      = File.ReadAllLines(@"test.txt"); //SPD/SPD/BIN/DEBUG
            string   dataStart = text[0];

            string[] result = dataStart.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
            HowManyTasks = Convert.ToInt32(result[0]);
            List <WiTi> witiTasks = new List <WiTi>();

            for (int i = 1; i <= HowManyTasks; i++)
            {
                result = text[i].Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                witiTasks.Add(new WiTi {
                    P = Convert.ToInt32(result[0]), W = Convert.ToInt32(result[1]), D = Convert.ToInt32(result[2])
                });
            }
            int Time = 0;
            int variablesMaxValue = 0;

            foreach (var element in witiTasks)
            {
                Time += element.P;
                int kara = 0;
                if (element.D < Time)
                {
                    kara = element.W * (Time - element.D);
                }
                variablesMaxValue += kara;
                Console.WriteLine(variablesMaxValue + " | " + Time);
            }
            var alfas = solver.MakeIntVarMatrix(witiTasks.Count, witiTasks.Count, 0, 1);

            var starts = solver.MakeIntVarArray(witiTasks.Count, 0, Time);

            var ends = solver.MakeIntVarArray(witiTasks.Count, 0, Time);

            var cmax = solver.MakeIntVar(0, variablesMaxValue, "cmax");



            //int helpTime = 0;
            var suma = new LinearExpr();

            for (int i = 0; i < witiTasks.Count; i++)
            {
                solver.Add(ends[i] >= starts[i] + witiTasks[i].P);
                solver.Add(ends[i] >= witiTasks[i].D);
                solver.Add(cmax >= witiTasks[i].W * (ends[i] - witiTasks[i].D) + suma);


                suma += witiTasks[i].W * (ends[i] - witiTasks[i].D);
            }

            for (int i = 0; i < witiTasks.Count; i++)
            {
                for (int j = i + 1; j < witiTasks.Count; j++)
                {
                    solver.Add(starts[i] + witiTasks[i].P <= starts[j] + alfas[i, j] * variablesMaxValue);
                    solver.Add(starts[j] + witiTasks[j].P <= starts[i] + alfas[j, i] * variablesMaxValue);
                    solver.Add(alfas[i, j] + alfas[j, i] == 1);
                }
            }

            solver.Minimize(cmax);
            Solver.ResultStatus resultStatus = solver.Solve();
            if (resultStatus != Solver.ResultStatus.OPTIMAL)
            {
                Console.WriteLine("Solve nie znalazl optymala");
            }
            else
            {
                Console.WriteLine("Obiect_value = " + solver.Objective().Value());
            }
        }
Пример #9
0
        public static LinearExpr Sum <TSource>(this IEnumerable <TSource> source, Func <TSource, LinearExpr> selector)
        {
            var zeroExpr = new LinearExpr();

            return(source.Aggregate(zeroExpr, (current, entry) => current + selector(entry)));
        }
Пример #10
0
 /** <summary>The size expression of the interval</summary> */
 public LinearExpr SizeExpr()
 {
     return(LinearExpr.RebuildLinearExprFromLinearExpressionProto(interval_.Size, model_));
 }
Пример #11
0
 /** <summary>The end expression of the interval</summary> */
 public LinearExpr EndExpr()
 {
     return(LinearExpr.RebuildLinearExprFromLinearExpressionProto(interval_.End, model_));
 }
Пример #12
0
    static void Main()
    {
        // Data.
        int bin_capacity   = 100;
        int slack_capacity = 20;
        int num_bins       = 5;

        int[,] items = new int[, ] {
            { 20, 6 }, { 15, 6 }, { 30, 4 }, { 45, 3 }
        };
        int num_items = items.GetLength(0);

        // Model.
        CpModel model = new CpModel();

        // Main variables.
        IntVar[,] x = new IntVar[num_items, num_bins];
        for (int i = 0; i < num_items; ++i)
        {
            int num_copies = items[i, 1];
            for (int b = 0; b < num_bins; ++b)
            {
                x[i, b] = model.NewIntVar(0, num_copies, String.Format("x_{0}_{1}", i, b));
            }
        }

        // Load variables.
        IntVar[] load = new IntVar[num_bins];
        for (int b = 0; b < num_bins; ++b)
        {
            load[b] = model.NewIntVar(0, bin_capacity, String.Format("load_{0}", b));
        }

        // Slack variables.
        IntVar[] slacks = new IntVar[num_bins];
        for (int b = 0; b < num_bins; ++b)
        {
            slacks[b] = model.NewBoolVar(String.Format("slack_{0}", b));
        }

        // Links load and x.
        int[] sizes = new int[num_items];
        for (int i = 0; i < num_items; ++i)
        {
            sizes[i] = items[i, 0];
        }
        for (int b = 0; b < num_bins; ++b)
        {
            IntVar[] tmp = new IntVar[num_items];
            for (int i = 0; i < num_items; ++i)
            {
                tmp[i] = x[i, b];
            }
            model.Add(load[b] == LinearExpr.ScalProd(tmp, sizes));
        }

        // Place all items.
        for (int i = 0; i < num_items; ++i)
        {
            IntVar[] tmp = new IntVar[num_bins];
            for (int b = 0; b < num_bins; ++b)
            {
                tmp[b] = x[i, b];
            }
            model.Add(LinearExpr.Sum(tmp) == items[i, 1]);
        }

        // Links load and slack.
        int safe_capacity = bin_capacity - slack_capacity;

        for (int b = 0; b < num_bins; ++b)
        {
            //  slack[b] => load[b] <= safe_capacity.
            model.Add(load[b] <= safe_capacity).OnlyEnforceIf(slacks[b]);
            // not(slack[b]) => load[b] > safe_capacity.
            model.Add(load[b] > safe_capacity).OnlyEnforceIf(slacks[b].Not());
        }

        // Maximize sum of slacks.
        model.Maximize(LinearExpr.Sum(slacks));

        // Solves and prints out the solution.
        CpSolver       solver = new CpSolver();
        CpSolverStatus status = solver.Solve(model);

        Console.WriteLine(String.Format("Solve status: {0}", status));
        if (status == CpSolverStatus.Optimal)
        {
            Console.WriteLine(String.Format("Optimal objective value: {0}", solver.ObjectiveValue));
            for (int b = 0; b < num_bins; ++b)
            {
                Console.WriteLine(String.Format("load_{0} = {1}", b, solver.Value(load[b])));
                for (int i = 0; i < num_items; ++i)
                {
                    Console.WriteLine(string.Format("  item_{0}_{1} = {2}", i, b, solver.Value(x[i, b])));
                }
            }
        }
        Console.WriteLine("Statistics");
        Console.WriteLine(String.Format("  - conflicts : {0}", solver.NumConflicts()));
        Console.WriteLine(String.Format("  - branches  : {0}", solver.NumBranches()));
        Console.WriteLine(String.Format("  - wall time : {0} s", solver.WallTime()));
    }
Пример #13
0
    public static void Main(String[] args)
    {
        // Data.
        // [START data]
        int[,] costs =
        {
            {  90,  76,  75,  70,  50,  74,  12, 68 }, { 35,  85,  55,  65,  48, 101,  70, 83 },
            { 125,  95,  90, 105,  59, 120,  36, 73 }, { 45, 110,  95, 115, 104,  83,  37, 71 },
            {  60, 105,  80,  75,  59,  62,  93, 88 }, { 45,  65, 110,  95,  47,  31,  81, 34 },
            {  38,  51, 107,  41,  69,  99, 115, 48 }, { 47,  85,  57,  71,  92,  77, 109, 36 },
            {  39,  63,  97,  49, 118,  56,  92, 61 }, { 47, 101,  71,  60,  88, 109,  52, 90 },
        };
        int numWorkers = costs.GetLength(0);
        int numTasks   = costs.GetLength(1);

        int[] allWorkers = Enumerable.Range(0, numWorkers).ToArray();
        int[] allTasks   = Enumerable.Range(0, numTasks).ToArray();

        int[] taskSizes = { 10, 7, 3, 12, 15, 4, 11, 5 };
        // Maximum total of task sizes for any worker
        int totalSizeMax = 15;
        // [END data]

        // Model.
        // [START model]
        CpModel model = new CpModel();

        // [END model]

        // Variables.
        // [START variables]
        BoolVar[,] x = new BoolVar[numWorkers, numTasks];
        foreach (int worker in allWorkers)
        {
            foreach (int task in allTasks)
            {
                x[worker, task] = model.NewBoolVar($"x[{worker},{task}]");
            }
        }
        // [END variables]

        // Constraints
        // [START constraints]
        // Each worker is assigned to at most max task size.
        foreach (int worker in allWorkers)
        {
            BoolVar[] vars = new BoolVar[numTasks];
            foreach (int task in allTasks)
            {
                vars[task] = x[worker, task];
            }
            model.Add(LinearExpr.WeightedSum(vars, taskSizes) <= totalSizeMax);
        }

        // Each task is assigned to exactly one worker.
        foreach (int task in allTasks)
        {
            List <ILiteral> workers = new List <ILiteral>();
            foreach (int worker in allWorkers)
            {
                workers.Add(x[worker, task]);
            }
            model.AddExactlyOne(workers);
        }
        // [END constraints]

        // Objective
        // [START objective]
        LinearExprBuilder obj = LinearExpr.NewBuilder();

        foreach (int worker in allWorkers)
        {
            foreach (int task in allTasks)
            {
                obj.AddTerm(x[worker, task], costs[worker, task]);
            }
        }
        model.Minimize(obj);
        // [END objective]

        // Solve
        // [START solve]
        CpSolver       solver = new CpSolver();
        CpSolverStatus status = solver.Solve(model);

        Console.WriteLine($"Solve status: {status}");
        // [END solve]

        // Print solution.
        // [START print_solution]
        // Check that the problem has a feasible solution.
        if (status == CpSolverStatus.Optimal || status == CpSolverStatus.Feasible)
        {
            Console.WriteLine($"Total cost: {solver.ObjectiveValue}\n");
            foreach (int worker in allWorkers)
            {
                foreach (int task in allTasks)
                {
                    if (solver.Value(x[worker, task]) > 0.5)
                    {
                        Console.WriteLine($"Worker {worker} assigned to task {task}. " +
                                          $"Cost: {costs[worker, task]}");
                    }
                }
            }
        }
        else
        {
            Console.WriteLine("No solution found.");
        }
        // [END print_solution]

        Console.WriteLine("Statistics");
        Console.WriteLine($"  - conflicts : {solver.NumConflicts()}");
        Console.WriteLine($"  - branches  : {solver.NumBranches()}");
        Console.WriteLine($"  - wall time : {solver.WallTime()}s");
    }
Пример #14
0
        private void ATSP_Flow()
        {
            var M = solverData.NumberOfVisits;

            foreach (var santa in Enumerable.Range(0, solverData.NumberOfSantas))
            {
                var santaWayFlow            = solverData.Variables.SantaWayFlow[santa];
                var santaWayHasFlow         = solverData.Variables.SantaWayHasFlow[santa];
                var santaUsesWay            = solverData.Variables.SantaUsesWay[santa];
                var numberOfVisitsInCluster = NumberOfSantaVisit(santa);
                // flow for start location if santa is in use
                foreach (var destination in Enumerable.Range(0, solverData.NumberOfVisits))
                {
                    Solver.Add(santaWayFlow[0, destination] == santaUsesWay[0, destination] * M);
                }

                //flow only possible if santa uses way
                foreach (var source in Enumerable.Range(0, solverData.NumberOfVisits))
                {
                    foreach (var destination in Enumerable.Range(0, solverData.NumberOfVisits))
                    {
                        Solver.Add(santaWayFlow[source, destination] <= santaUsesWay[source, destination] * M);
                        //ClusteringILPSolver.Add(santaWayFlow[source, destination] >= santaUsesWay[source, destination]);
                    }
                }

                // strengthen formulasation
                for (var source = 1; source < solverData.NumberOfVisits; source++)
                {
                    for (var destination = 1; source < solverData.NumberOfVisits; source++)
                    {
                        Solver.Add(santaWayFlow[source, destination] <= numberOfVisitsInCluster);
                    }
                }

                // flow only possible if neighbours have flow
                for (var source = 1; source < solverData.NumberOfVisits; source++)
                {
                    var sumFlowNeightbours = new LinearExpr();
                    foreach (var incomingNeighbours in Enumerable.Range(0, solverData.NumberOfVisits))
                    {
                        sumFlowNeightbours += santaWayFlow[incomingNeighbours, source];
                    }

                    // node has value of incoming flow
                    foreach (var destination in Enumerable.Range(0, solverData.NumberOfVisits))
                    {
                        Solver.Add(santaWayFlow[source, destination] <= sumFlowNeightbours - 1 * solverData.Variables.SantaVisit[santa, source]);
                    }
                }

                // hasFlow Variable
                foreach (var source in Enumerable.Range(0, solverData.NumberOfVisits))
                {
                    foreach (var destination in Enumerable.Range(0, solverData.NumberOfVisits))
                    {
                        Solver.Add(santaWayHasFlow[source, destination] <= santaWayFlow[source, destination]);
                        //ClusteringILPSolver.Add(santaWayFlow[source, destination] <= santaWayHasFlow[source, destination] * M); // this constraint makes it terrible slow
                    }
                }

                var sumOfFlow  = new LinearExpr();
                var sumOfEdges = new LinearExpr();
                foreach (var source in Enumerable.Range(0, solverData.NumberOfVisits))
                {
                    foreach (var destination in Enumerable.Range(0, solverData.NumberOfVisits))
                    {
                        sumOfFlow  += santaWayHasFlow[source, destination];
                        sumOfEdges += santaUsesWay[source, destination];
                    }
                }
                Solver.Add(sumOfFlow == sumOfEdges);
            }
        }
Пример #15
0
    static void Main()
    {
        // Data.
        int num_nurses = 4;
        // Nurse assigned to shift 0 means not working that day.
        int num_shifts = 4;
        int num_days   = 7;

        var all_nurses         = Enumerable.Range(0, num_nurses);
        var all_shifts         = Enumerable.Range(0, num_shifts);
        var all_working_shifts = Enumerable.Range(1, num_shifts - 1);
        var all_days           = Enumerable.Range(0, num_days);

        // Creates the model.
        CpModel model = new CpModel();

        // Creates shift variables.
        // shift[n, d, s]: nurse "n" works shift "s" on day "d".
        IntVar[,,] shift = new IntVar[num_nurses, num_days, num_shifts];
        foreach (int n in all_nurses)
        {
            foreach (int d in all_days)
            {
                foreach (int s in all_shifts)
                {
                    shift[n, d, s] =
                        model.NewBoolVar(String.Format("shift_n{0}d{1}s{2}", n, d, s));
                }
            }
        }

        // Makes assignments different on each day, that is each shift is
        // assigned at most one nurse. As we have the same number of
        // nurses and shifts, then each day, each shift is assigned to
        // exactly one nurse.
        foreach (int d in all_days)
        {
            foreach (int s in all_shifts)
            {
                IntVar[] tmp = new IntVar[num_nurses];
                foreach (int n in all_nurses)
                {
                    tmp[n] = shift[n, d, s];
                }
                model.Add(LinearExpr.Sum(tmp) == 1);
            }
        }

        // Nurses do 1 shift per day.
        foreach (int n in all_nurses)
        {
            foreach (int d in all_days)
            {
                IntVar[] tmp = new IntVar[num_shifts];
                foreach (int s in all_shifts)
                {
                    tmp[s] = shift[n, d, s];
                }
                model.Add(LinearExpr.Sum(tmp) == 1);
            }
        }

        // Each nurse works 5 or 6 days in a week.
        // That is each nurse works shift 0 at most 2 times.
        foreach (int n in all_nurses)
        {
            IntVar[] tmp = new IntVar[num_days];
            foreach (int d in all_days)
            {
                tmp[d] = shift[n, d, 0];
            }
            model.AddLinearConstraint(LinearExpr.Sum(tmp), 1, 2);
        }

        // works_shift[(n, s)] is 1 if nurse n works shift s at least one day in
        // the week.
        IntVar[,] works_shift = new IntVar[num_nurses, num_shifts];
        foreach (int n in all_nurses)
        {
            foreach (int s in all_shifts)
            {
                works_shift[n, s] =
                    model.NewBoolVar(String.Format("works_shift_n{0}s{1}", n, s));
                IntVar[] tmp = new IntVar[num_days];
                foreach (int d in all_days)
                {
                    tmp[d] = shift[n, d, s];
                }
                model.AddMaxEquality(works_shift[n, s], tmp);
            }
        }

        // For each working shift, at most 2 nurses are assigned to that shift
        // during the week.
        foreach (int s in all_working_shifts)
        {
            IntVar[] tmp = new IntVar[num_nurses];
            foreach (int n in all_nurses)
            {
                tmp[n] = works_shift[n, s];
            }
            model.Add(LinearExpr.Sum(tmp) <= 2);
        }

        // If a nurse works shifts 2 or 3 on, she must also work that
        // shift the previous day or the following day.  This means that
        // on a given day and shift, either she does not work that shift
        // on that day, or she works that shift on the day before, or the
        // day after.
        foreach (int n in all_nurses)
        {
            for (int s = 2; s <= 3; ++s)
            {
                foreach (int d in all_days)
                {
                    int yesterday = d == 0 ? num_days - 1 : d - 1;
                    int tomorrow  = d == num_days - 1 ? 0 : d + 1;
                    model.AddBoolOr(new ILiteral[] { shift[n, yesterday, s],
                                                     shift[n, d, s].Not(),
                                                     shift[n, tomorrow, s] });
                }
            }
        }

        // Creates the solver and solve.
        CpSolver solver = new CpSolver();
        // Display a few solutions picked at random.
        HashSet <int> to_print = new HashSet <int>();

        to_print.Add(859);
        to_print.Add(2034);
        to_print.Add(5091);
        to_print.Add(7003);
        NurseSolutionObserver cb = new NurseSolutionObserver(
            shift, num_nurses, num_days, num_shifts, to_print);
        CpSolverStatus status = solver.SearchAllSolutions(model, cb);

        // Statistics.
        Console.WriteLine("Statistics");
        Console.WriteLine(String.Format("  - solve status    : {0}", status));
        Console.WriteLine("  - conflicts       : " + solver.NumConflicts());
        Console.WriteLine("  - branches        : " + solver.NumBranches());
        Console.WriteLine("  - wall time       : " + solver.WallTime() + " ms");
        Console.WriteLine("  - #solutions      : " + cb.SolutionCount());
    }
Пример #16
0
    public static void Main(String[] args)
    {
        // Data.
        // [START data_model]
        int[,] costs =
        {
            { 90, 80, 75, 70 }, { 35, 85, 55, 65 }, { 125, 95, 90, 95 }, { 45, 110, 95, 115 }, { 50, 100, 90, 100 },
        };
        int numWorkers = costs.GetLength(0);
        int numTasks   = costs.GetLength(1);
        // [END data_model]

        // Model.
        // [START model]
        CpModel model = new CpModel();

        // [END model]

        // Variables.
        // [START variables]
        IntVar[,] x = new IntVar[numWorkers, numTasks];
        // Variables in a 1-dim array.
        IntVar[] xFlat     = new IntVar[numWorkers * numTasks];
        int[]    costsFlat = new int[numWorkers * numTasks];
        for (int i = 0; i < numWorkers; ++i)
        {
            for (int j = 0; j < numTasks; ++j)
            {
                x[i, j] = model.NewIntVar(0, 1, $"worker_{i}_task_{j}");
                int k = i * numTasks + j;
                xFlat[k]     = x[i, j];
                costsFlat[k] = costs[i, j];
            }
        }
        // [END variables]

        // Constraints
        // [START constraints]
        // Each worker is assigned to at most one task.
        for (int i = 0; i < numWorkers; ++i)
        {
            IntVar[] vars = new IntVar[numTasks];
            for (int j = 0; j < numTasks; ++j)
            {
                vars[j] = x[i, j];
            }
            model.Add(LinearExpr.Sum(vars) <= 1);
        }

        // Each task is assigned to exactly one worker.
        for (int j = 0; j < numTasks; ++j)
        {
            IntVar[] vars = new IntVar[numWorkers];
            for (int i = 0; i < numWorkers; ++i)
            {
                vars[i] = x[i, j];
            }
            model.Add(LinearExpr.Sum(vars) == 1);
        }
        // [END constraints]

        // Objective
        // [START objective]
        model.Minimize(LinearExpr.ScalProd(xFlat, costsFlat));
        // [END objective]

        // Solve
        // [START solve]
        CpSolver       solver = new CpSolver();
        CpSolverStatus status = solver.Solve(model);

        Console.WriteLine($"Solve status: {status}");
        // [END solve]

        // Print solution.
        // [START print_solution]
        // Check that the problem has a feasible solution.
        if (status == CpSolverStatus.Optimal || status == CpSolverStatus.Feasible)
        {
            Console.WriteLine($"Total cost: {solver.ObjectiveValue}\n");
            for (int i = 0; i < numWorkers; ++i)
            {
                for (int j = 0; j < numTasks; ++j)
                {
                    if (solver.Value(x[i, j]) > 0.5)
                    {
                        Console.WriteLine($"Worker {i} assigned to task {j}. Cost: {costs[i, j]}");
                    }
                }
            }
        }
        else
        {
            Console.WriteLine("No solution found.");
        }
        // [END print_solution]

        Console.WriteLine("Statistics");
        Console.WriteLine($"  - conflicts : {solver.NumConflicts()}");
        Console.WriteLine($"  - branches  : {solver.NumBranches()}");
        Console.WriteLine($"  - wall time : {solver.WallTime()}s");
    }
Пример #17
0
    static void Solve(int first_slot)
    {
        Console.WriteLine("----------------------------------------------------");

        // 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 {number_of_speakers} speakers, for a total of " +
                          $"{sum_of_durations} slots, during [{first_slot}..{last_slot}]");

        CpModel model = new CpModel();

        // We store the possible entries (var, start) for all talks filtered
        // from the duration and the speaker availability.
        List <Entry>[] entries = new List <Entry> [number_of_speakers];
        for (int speaker = 0; speaker < number_of_speakers; ++speaker)
        {
            entries[speaker] = new List <Entry>();
        }

        List <IntVar>[] contributions_per_slot = new List <IntVar> [last_slot + 1];
        for (int slot = 1; slot <= last_slot; ++slot)
        {
            contributions_per_slot[slot] = new List <IntVar>();
        }

        for (int speaker = 0; speaker < number_of_speakers; ++speaker)
        {
            List <IntVar> all_vars = new List <IntVar>();
            int           duration = durations[speaker];
            // Let's filter the possible starts.
            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)
                {
                    IntVar var = model.NewBoolVar("speaker " + (speaker + 1) + " starts at " + slot);
                    entries[speaker].Add(new Entry(var, slot));
                    all_vars.Add(var);
                    for (int offset = 0; offset < duration; ++offset)
                    {
                        contributions_per_slot[slot + offset].Add(var);
                    }
                }
            }
            model.Add(LinearExpr.Sum(all_vars) == 1);
        }
        // Force the schedule to be consistent.
        for (int slot = first_slot; slot <= last_slot; ++slot)
        {
            model.Add(LinearExpr.Sum(contributions_per_slot[slot]) <= 1);
        }

        // Creates last_slot.
        IntVar last_slot_var = model.NewIntVar(first_slot + sum_of_durations - 1, last_slot, "last_slot");

        for (int speaker = 0; speaker < number_of_speakers; speaker++)
        {
            int duration = durations[speaker];
            foreach (Entry e in entries[speaker])
            {
                model.Add(last_slot_var >= e.start + duration - 1).OnlyEnforceIf(e.var);
            }
        }

        model.Minimize(last_slot_var);

        // Creates the solver and solve.
        CpSolver solver = new CpSolver();

        solver.StringParameters = "num_search_workers:8";
        CpSolverStatus status = solver.Solve(model);

        if (status == CpSolverStatus.Optimal)
        {
            Console.WriteLine("\nLast used slot: " + solver.Value(last_slot_var));
            Console.WriteLine("Speakers (start..end):");
            for (int speaker = 0; speaker < number_of_speakers; speaker++)
            {
                foreach (Entry e in entries[speaker])
                {
                    if (solver.BooleanValue(e.var))
                    {
                        Console.WriteLine("  - speaker {0,2}: {1,2}..{2,2}", (speaker + 1), e.start,
                                          (e.start + durations[speaker] - 1));
                    }
                }
            }
        }

        // Statistics.
        Console.WriteLine(solver.ResponseStats());
    }
Пример #18
0
    public static void Main(String[] args)
    {
        // Data.
        // [START data]
        int[,] costs =
        {
            { 90,  76, 75,  70 }, { 35,  85, 55, 65 }, { 125, 95,  90, 105 },
            { 45, 110, 95, 115 }, { 60, 105, 80, 75 }, {  45, 65, 110,  95 },
        };
        int numWorkers = costs.GetLength(0);
        int numTasks   = costs.GetLength(1);

        int[] allWorkers = Enumerable.Range(0, numWorkers).ToArray();
        int[] allTasks   = Enumerable.Range(0, numTasks).ToArray();

        int[] team1 = { 0, 2, 4 };
        int[] team2 = { 1, 3, 5 };
        // Maximum total of tasks for any team
        int teamMax = 2;
        // [END data]

        // Model.
        // [START model]
        CpModel model = new CpModel();

        // [END model]

        // Variables.
        // [START variables]
        BoolVar[,] x = new BoolVar[numWorkers, numTasks];
        foreach (int worker in allWorkers)
        {
            foreach (int task in allTasks)
            {
                x[worker, task] = model.NewBoolVar($"x[{worker},{task}]");
            }
        }
        // [END variables]

        // Constraints
        // [START constraints]
        // Each worker is assigned to at most one task.
        foreach (int worker in allWorkers)
        {
            List <ILiteral> tasks = new List <ILiteral>();
            foreach (int task in allTasks)
            {
                tasks.Add(x[worker, task]);
            }
            model.AddAtMostOne(tasks);
        }

        // Each task is assigned to exactly one worker.
        foreach (int task in allTasks)
        {
            List <ILiteral> workers = new List <ILiteral>();
            foreach (int worker in allWorkers)
            {
                workers.Add(x[worker, task]);
            }
            model.AddExactlyOne(workers);
        }

        // Each team takes at most two tasks.
        List <IntVar> team1Tasks = new List <IntVar>();

        foreach (int worker in team1)
        {
            foreach (int task in allTasks)
            {
                team1Tasks.Add(x[worker, task]);
            }
        }
        model.Add(LinearExpr.Sum(team1Tasks.ToArray()) <= teamMax);

        List <IntVar> team2Tasks = new List <IntVar>();

        foreach (int worker in team2)
        {
            foreach (int task in allTasks)
            {
                team2Tasks.Add(x[worker, task]);
            }
        }
        model.Add(LinearExpr.Sum(team2Tasks.ToArray()) <= teamMax);
        // [END constraints]

        // Objective
        // [START objective]
        LinearExprBuilder obj = LinearExpr.NewBuilder();

        foreach (int worker in allWorkers)
        {
            foreach (int task in allTasks)
            {
                obj.AddTerm(x[worker, task], costs[worker, task]);
            }
        }
        model.Minimize(obj);
        // [END objective]

        // Solve
        // [START solve]
        CpSolver       solver = new CpSolver();
        CpSolverStatus status = solver.Solve(model);

        Console.WriteLine($"Solve status: {status}");
        // [END solve]

        // Print solution.
        // [START print_solution]
        // Check that the problem has a feasible solution.
        if (status == CpSolverStatus.Optimal || status == CpSolverStatus.Feasible)
        {
            Console.WriteLine($"Total cost: {solver.ObjectiveValue}\n");
            foreach (int worker in allWorkers)
            {
                foreach (int task in allTasks)
                {
                    if (solver.Value(x[worker, task]) > 0.5)
                    {
                        Console.WriteLine($"Worker {worker} assigned to task {task}. " +
                                          $"Cost: {costs[worker, task]}");
                    }
                }
            }
        }
        else
        {
            Console.WriteLine("No solution found.");
        }
        // [END print_solution]

        Console.WriteLine("Statistics");
        Console.WriteLine($"  - conflicts : {solver.NumConflicts()}");
        Console.WriteLine($"  - branches  : {solver.NumBranches()}");
        Console.WriteLine($"  - wall time : {solver.WallTime()}s");
    }