Пример #1
0
def solve_rpq_with_solver(instance: RPQ_Instance):
    """ W końcu funkcja rozwiązująca instancje problemu RPQ wykorzystując metodę CP z biblioteki or-tools"""
    from ortools.sat.python import cp_model  # importujemy model CP z biblioteki or-tools

    model = cp_model.CpModel(
    )  # inicjalizacja modelu - przechowa nasze zmienne oraz ograniczenia naszego problemu

    # Model będzie operować na zmiennych całkowitoliczbowych - jakie zmienne? Czas rozpoczęcia, czas zakończenia, cmax...
    # Potrzebujemy określić zakres tych zmiennych - najmniej 0, bo nasz problem nie może mieć negatywnych czasów rozpoczęcia, zakończenia czy cmax.
    # Co z maksymalną wartością? Spróbujmy policzyć najbardziej pesymistyczny scenariusz (możliwie złą kolejność):
    # Dla tej złej kolejności zaczniemy od zadania, które ma największe r, później pozostałe zadania i na koniec zadanie o największym q
    # Gdybyśmy nie znali problemu, moglibyśmy po prostu dodać wszystkie czasy, byłby to gorszy zakres, więcej roboty dla solvera.

    max_r = 0
    max_q = 0
    sum_p = 0
    for task_number in range(
            instance.tasks_number):  # iterujemy po wszystkich zadaniach:
        sum_p = sum_p + instance.get_p(task_number)
        max_r = max(max_r, instance.get_r(task_number))
        max_q = max(max_q, instance.get_q(task_number))

    variable_max_value = 1 + max_r + sum_p + max_q  # dla pewności o jeden za dużo
    variable_min_value = 0  # nic nie jest ujemne w naszym wypadku

    # Zaraz będziemy inicjalizować zmienne wewnątrz modelu, aby łatwo się do nich odwoływać - tworzymy na razie puste listy:
    model_start_vars = []  # tutaj będą czasy rozpoczęć zadań
    model_ends_vars = []  # tutaj będą czasy zakończeń zadań
    model_interval_vars = [
    ]  # tutaj będą przechowywane zmienne odpowiedzialne za zmienne interwałowe

    # teraz inicjalizacja zmiennych wewnątrz modelu:
    # zaczniemy od pojedynczej zmiennej, która będzie przechowywać cmax - proszę zauważyć, że jest to zmienna tworzona
    # wewnątrz modelu i nie jest to typowy int - próba sprawdzenia, czy jest to pythonowy typ int zwróci fałsz:
    # aby stworzyć tą zmienną musimy podać zakres oraz nazwę zmiennej
    cmax_optimalization_objective = model.NewIntVar(variable_min_value,
                                                    variable_max_value,
                                                    'cmax_makespan')
    print("type of cmax:", type(cmax_optimalization_objective),
          isinstance(cmax_optimalization_objective,
                     int))  # można zakomentować bez żalu

    # więcej zmiennych: dla czasu rozpoczęcia, zakończenia i interwałów, ale dla każdego zdania więc korzystamy z pętli
    for task_number in range(instance.tasks_number):
        suffix = f"t:{task_number}"  # do zmiennych należy dodawać nazwę - u nas będzie to po prostu numer zadania
        start_var = model.NewIntVar(
            variable_min_value, variable_max_value, 'start_' + suffix
        )  # zmienna wewnątrz solvera odpowiedzialna za czas rozpoczęcia
        end_var = model.NewIntVar(
            variable_min_value, variable_max_value, 'end_' + suffix
        )  # zmienna wewnątrz solvera odpowiedzialna za czas zakończenia
        # zmienna interwałowa "łączy" czas rozpoczęcia oraz czas zakonczenia - dodatkowo nasz wykonania zdania trwa dokładnie p:
        interval_var = model.NewIntervalVar(
            start_var, instance.get_p(task_number), end_var,
            'interval_' + suffix
        )  # zmienna interwałowa wewnątrz solvera odpowiedzialna za nie nakładanie się zadań

        # dodawanie zmiennych na listy pomocnicze:
        model_start_vars.append(start_var)
        model_ends_vars.append(end_var)
        model_interval_vars.append(interval_var)

    # Pora na dodanie ograniczeń - zacznimy od najtrudniejszego: nasze zadania nie mogą się na siebie "nakładać na siebie",
    # czyli jedyna maszyna w problemie RPQ może pracować na raz tylko nad jednym zadaniem.
    # W ramach CP jest to ograniczenie łatwe do dodania:
    model.AddNoOverlap(model_interval_vars)
    # Gdybyśmy mieli więcej maszyn to musielibyśmy trochę bardziej pokombinować, ale ponieważ w RPQ jest jedna maszyna to
    # dodajemy wszystkie interwały. W wypadku wielomaszynowym tylko interwały z tej samej maszyny nie mogły się nakładać.

    # Pora teraz na ograniczenie związane z czasem rozpoczęcia - tutaj sytuacja jest jasna: start zadania jest możliwy dopiero po upływie czasu rozpoczęcia (r)
    for task_number in range(instance.tasks_number):
        model.Add(model_start_vars[task_number] >= instance.get_r(task_number)
                  )  # dodajemy do modelu ograniczenie w postaci nierówność

    # Zostało nam ograniczenie związane z czasem dostarczenia...
    # My zawrzemy je w ramach obliczenia cmaxa - proszę zwrócić uwagę, że cmax to największy czas dostarczenia ze wszystkich zadań
    # łatwo to przedstawić jako odpowiednią nierówność - cmax musi być większy/równy od czasu dostarczenia dla każdego zadania
    for task_number in range(instance.tasks_number):
        model.Add(
            cmax_optimalization_objective >= model_ends_vars[task_number] +
            instance.get_q(task_number))

    # Pora dodać do modelu informacje czego właściwie szukamy - chcemy zminimalizować cmax więc:
    model.Minimize(cmax_optimalization_objective)

    # Inicjalizujemy solver, który spróbuje znaleźć rozwiązanie w ramach naszego modelu:
    solver = cp_model.CpSolver()
    solver.parameters.max_time_in_seconds = 300.0  # dodatkowo ograniczmy czas wykonywania obliczeń do maksymalnie 5 min

    # Wszystkie ograniczenia dodane! pora odpalić solver!
    status = solver.Solve(
        model
    )  # solver zwróci status, ale jako typ wyliczeniowy, więc troche nieczytelnie dla nas

    if (
            status is not cp_model.OPTIMAL
    ):  # sprawdzamy status, aby określić czy solver znalazł rozwiązanie optymalne
        status_readable = "not optimal solution :("
    else:
        status_readable = "optimum found!"

    # Oprócz cmaxa przydałoby się odczytać kolejność wykonywania zadań - dla RPQ będzie to łatwe.
    # Wystarczy, że sprawdzimy czasy rozpoczęć (lub zakończeń) dla poszczególnych zadań:
    # Tworzymy listę z parami: (numer zadania, czas rozpoczęcia), sortujemy po tej drugiej wartości.
    pi_order = []
    for task_number in range(instance.tasks_number):
        pi_order.append(
            (task_number, solver.Value(model_start_vars[task_number])))
    pi_order.sort(key=lambda x: x[1])
    pi_order = [
        x[0] for x in pi_order
    ]  # modyfikujemy naszą listę, aby przechowywać tylko numer zadań, bez czasów rozpoczęć

    return solver.ObjectiveValue(
    ), pi_order, status_readable  # zwracamy cmax, kolejność wykonywania zadań oraz informacje czy znaleźliśmy optimum
Пример #2
0
def schedule_retry2(data, companies):
    """Try it Schedule with less restrictions"""
    # Create the model.
    model = cp_model.CpModel()

    line_size = 12 # number of slots for meetings
    line = list(range(0, line_size))
    rows = list(range(len(data)))

    ls_m_c = [data[k].get('Companies') for k in rows]
    grid = {}
    for i in rows:
        for j in line:
            grid[(i, j)] =  model.NewIntVarFromDomain(cp_model.Domain.FromValues(ls_m_c[i]), 'grid %i %i' % (i, j))

    #AllDifferent on rows.
    for i in rows:
        model.AddAllDifferent([grid[(i, j)] for j in line])

    # AllDifferent on columns.
    for j in line:
        model.AddAllDifferent([grid[(i, j)] for i in rows])

    #Adding objectives:
    for i in rows:
        if ls_m_c[i][8] < 100 and ls_m_c[i][10] > 100:
            model.Add(grid[(i, 5)] >= 100)
            model.Add(grid[(i, 9)] >= 100)

        elif ls_m_c[i][7] < 100:
            model.Add((grid[(i,3)]) >= 100)
            model.Add((grid[(i,7)]) >= 100)
            model.Add((grid[(i,11)]) >= 100)

        elif ls_m_c[i][6] < 100:
            model.Add((grid[(i,3)] + grid[(i, 4)] + grid[(i, 5)]) < 100)
            model.Add((grid[(i,7)] + grid[(i,8)] + grid[(i,9)] + grid[(i,10)]) < 100)


        elif ls_m_c[i][5] < 100:
            model.Add((grid[(i,1)] + grid[(i,2)] + grid[(i, 3)]) < 100)
            model.Add((grid[(i, 5)] + grid[(i, 6)] + grid[(i, 7)]) < 100)

        elif ls_m_c[i][4] < 100:
            model.Add((grid[(i,1)] + grid[(i,2)]) < 100)
            model.Add((grid[(i,3)]) >= 100)
            model.Add((grid[(i, 4)] + grid[(i, 5)] + grid[(i, 6)]) < 100)

        elif ls_m_c[i][3] < 100:
            model.Add((grid[(i,7)] + grid[(i, 8)]) < 100)
            model.Add((grid[(i, 9)] + grid[(i, 10)]) < 100)

        elif ls_m_c[i][2] < 100:
            model.Add((grid[(i,8)] + grid[(i, 9)] + grid[(i,10)]) < 100)

        elif ls_m_c[i][1] < 100:
            model.Add((grid[(i,8)] + grid[(i, 9)]) < 100)


    # Solve and save a list with values.
    solver = cp_model.CpSolver()
    status = solver.Solve(model)
    if status == cp_model.OPTIMAL:
        ls = []
        for i in rows:
            ls.append([int(solver.Value(grid[(i, j)])) for j in line])

    try:
        #Removing fake ids
        for m in range(len(ls)):
            for cl in range(len(ls[m])):
                if ls[m][cl] > len(companies):
                    ls[m][cl] = np.nan

       # Change companies' ids by its name
        for l in range(len(ls)):
            for col in range(len(ls[l])):
                if ls[l][col]:
                    for c in companies:
                        if ls[l][col] in c:
                            com = c.get(ls[l][col])
                            ls[l][col] = com

        #Appending to ls: mentors' name, day and block, to have a more complete list for using it later to recreate the dataframe
        ls_mentors = [data[i].get('Name') for i in range(len(data))]
        for i in range(len(ls_mentors)):
            ls[i].append(ls_mentors[i])
            ls[i].append(data[i].get('Email'))
            ls[i].append(data[i].get('Day'))
            ls[i].append(data[i].get('AM/PM'))
        return (ls)

    except:
        #print('There is no deasible solution')
        return([])
Пример #3
0
    def cp_satoptim(self):
        # Instantiate a cp solver.
        model = cp_model.CpModel()
        t_ce = {}
        vars = []

        task_type = collections.namedtuple('task_type', 'start end interval')

        # Job Shop Scheduling
        # Variables
        horizon = self.ub
        all_tasks = {}
        for id in self.t_s.keys():
            core = self.tsk_placement[id]
            start_var = model.NewIntVar(0, horizon, 'start_%s_%s' % (id, core))
            duration = self.wf.node[id][core]
            end_var = model.NewIntVar(0, horizon, 'end_%s_%s' % (id, core))
            interval_var = model.NewIntervalVar(start_var, duration, end_var,
                                                'interval_%s_%s' % (id, core))
            all_tasks[id] = task_type(start=start_var,
                                      end=end_var,
                                      interval=interval_var)

        # Creates sequence variables and add disjunctive constraints.
        for core in self.crs.nodes():
            self.rbt_assignment[core] = [
                t for t in self.nd_list if self.tsk_placement[t] == core
            ]
            intervals = []
            for tsk in self.rbt_assignment[core]:
                intervals.append(all_tasks[tsk].interval)
            model.AddNoOverlap(intervals)

        # Add precedence contraints.
        for j in self.nd_list:
            for i in self.wf.predecessors(j):
                if self.tsk_placement[i] == self.tsk_placement[j]:
                    model.Add(all_tasks[j].start >= all_tasks[i].end)

                else:
                    k, l = self.tsk_placement[i], self.tsk_placement[j]
                    model.Add(all_tasks[j].start >= all_tasks[i].end +
                              round(self.wf[i][j]['data'] /
                                    self.crs[k][l]['bandwidth']))

        model.Minimize(all_tasks[self.des_node].end)

        # Solve model.
        solver = cp_model.CpSolver()
        status = solver.Solve(model)

        if status == cp_model.OPTIMAL:
            # Print out makespan.
            self.optimal_obj = solver.ObjectiveValue()
            # print('Optimal Schedule Length: %i' % solver.ObjectiveValue())
            # print()

            for id in self.t_s.keys():
                # if collector.Value(best_solution, x[i][j]) == 1:
                # self.t_s[id] = collector.Value(best_solution,t_cs[id])
                self.t_s[id] = solver.Value(all_tasks[id].start)
                self.t_e[id] = solver.Value(all_tasks[id].end)
                # print("ts%s=%d, te%s=%d" % (id, self.t_s[id], id, self.t_e[id]))

            self.rbt_occupy = {}
            for r in self.crs.nodes():
                t_list = [k for (k, v) in self.tsk_placement.items() if v == r]
                t_list.sort(key=lambda x: self.t_s[x])
                self.rbt_occupy[r] = t_list

        return self.optimal_obj
Пример #4
0
def _run_bipartite_sat(I, input_edges, adj, h_count, v_count, verbose, timeout,
                       return_walltime):
    """
    Python implementation for FT-BTE's constraint programming formulation using Google OR-Tools solver.
    """
    from ortools.sat.python import cp_model

    NL, NR = adj.shape
    assert NL == len(h_count)
    assert NR == len(v_count)

    model = cp_model.CpModel()

    # decision variables
    yl = np.array([[model.NewBoolVar(f"yl_{i}_{j}") for j in range(NL)]
                   for i in range(I)])
    yr = np.array([[model.NewBoolVar(f"yr_{i}_{j}") for j in range(NR)]
                   for i in range(I)])

    valid_edge = [(l, r) for l in range(NL) for r in range(NR)
                  if adj[l, r] == 1]

    if verbose:
        print(f"(NL: {NL} NR: {NR} Valid edges: {len(valid_edge)})")
        print("Building constraints...")

    # edge constraints
    for u, v in input_edges:
        or_terms = []
        for l, r in valid_edge:
            uv = model.NewBoolVar(f"lr_({u},{v})_({l},{r})")
            model.AddImplication(uv, yl[u, l])
            model.AddImplication(uv, yr[v, r])

            vu = model.NewBoolVar(f"lr_({v},{u})_({l},{r})")
            model.AddImplication(vu, yl[v, l])
            model.AddImplication(vu, yr[u, r])

            or_terms.extend((uv, vu))
        model.AddBoolOr(or_terms)

    # input nodes must be assigned to connected nodes
    for i in range(I):
        for l in range(NL):
            for r in range(NR):
                model.Add(yl[i, l] + yr[i, r] <= int(1 + adj[l, r]))

    # input nodes are assigned once per partition
    for i in range(I):
        model.Add(sum(yl[i, :]) <= 1)

    for i in range(I):
        model.Add(sum(yr[i, :]) <= 1)

    # template nodes are assigned max 1 input node
    for l in range(NL):
        model.Add(sum(yl[:, l]) <= h_count[l])

    for r in range(NR):
        model.Add(sum(yr[:, r]) <= v_count[r])

    if verbose:
        print("Finished building constraints")

    solver = cp_model.CpSolver()
    solver.parameters.use_pb_resolution = True
    solver.parameters.log_search_progress = verbose
    solver.parameters.max_time_in_seconds = timeout
    status = solver.Solve(model)

    if status != cp_model.OPTIMAL:
        return None

    result = np.full((I, 2), -1)
    for i in range(I):
        for l in range(NL):
            if solver.BooleanValue(yl[i, l]):
                result[i, 0] = l
                break
        for r in range(NR):
            if solver.BooleanValue(yr[i, r]):
                result[i, 1] = r
                break

    if return_walltime:
        return result, solver.WallTime()
    else:
        return result
Пример #5
0
def MinimalJobshopSat(jobs_data):
    """Minimal jobshop problem."""
    # Create the model.
    model = cp_model.CpModel()

    machines_count = 1 + max(task[0] for job in jobs_data for task in job)
    all_machines = range(machines_count)

    # Computes horizon dynamically as the sum of all durations.
    horizon = sum(task[1] for job in jobs_data for task in job)

    # Named tuple to store information about created variables.
    task_type = collections.namedtuple('task_type', 'start end interval')
    # Named tuple to manipulate solution information.
    assigned_task_type = collections.namedtuple('assigned_task_type',
                                                'start job index duration')

    # Creates job intervals and add to the corresponding machine lists.
    all_tasks = {}
    machine_to_intervals = collections.defaultdict(list)

    for job_id, job in enumerate(jobs_data):
        for task_id, task in enumerate(job):
            machine = task[0]
            duration = task[1]
            suffix = '_%i_%i' % (job_id, task_id)
            start_var = model.NewIntVar(0, horizon, 'start' + suffix)
            end_var = model.NewIntVar(0, horizon, 'end' + suffix)
            interval_var = model.NewIntervalVar(start_var, duration, end_var,
                                                'interval' + suffix)
            all_tasks[job_id, task_id] = task_type(start=start_var,
                                                   end=end_var,
                                                   interval=interval_var)
            machine_to_intervals[machine].append(interval_var)

    # Create and add disjunctive constraints.
    for machine in all_machines:
        model.AddNoOverlap(machine_to_intervals[machine])

    # Precedences inside a job.
    for job_id, job in enumerate(jobs_data):
        for task_id in range(len(job) - 1):
            model.Add(all_tasks[job_id, task_id +
                                1].start >= all_tasks[job_id, task_id].end)

    # Makespan objective.
    obj_var = model.NewIntVar(0, horizon, 'makespan')
    model.AddMaxEquality(obj_var, [
        all_tasks[job_id, len(job) - 1].end
        for job_id, job in enumerate(jobs_data)
    ])
    model.Minimize(obj_var)

    # Solve model.
    solver = cp_model.CpSolver()
    status = solver.Solve(model)

    if status == cp_model.OPTIMAL:
        # Create one list of assigned tasks per machine.
        assigned_jobs = collections.defaultdict(list)
        for job_id, job in enumerate(jobs_data):
            for task_id, task in enumerate(job):
                machine = task[0]
                assigned_jobs[machine].append(
                    assigned_task_type(start=solver.Value(
                        all_tasks[job_id, task_id].start),
                                       job=job_id,
                                       index=task_id,
                                       duration=task[1]))

        # Create per machine output lines.
        output = ''
        for machine in all_machines:
            # Sort by starting time.
            assigned_jobs[machine].sort()
            sol_line_tasks = 'Machine ' + str(machine) + ': '
            sol_line = '           '

            for assigned_task in assigned_jobs[machine]:
                name = 'job_%i_%i' % (assigned_task.job, assigned_task.index)
                # Add spaces to output to align columns.
                sol_line_tasks += '%-10s' % name

                start = assigned_task.start
                duration = assigned_task.duration
                sol_tmp = '[%i,%i]' % (start, start + duration)
                # Add spaces to output to align columns.
                sol_line += '%-10s' % sol_tmp

            sol_line += '\n'
            sol_line_tasks += '\n'
            output += sol_line_tasks
            output += sol_line

        # Finally print the solution found.
        print('Optimal Schedule Length: %i' % solver.ObjectiveValue())
        print(output)
Пример #6
0
def main():
    model = cp_model.CpModel()

    jobs = [[3, 3], [2, 5], [1, 3], [3, 7], [7, 3], [2, 2], [2, 2], [5, 5],
            [10, 2], [4, 3], [2, 6], [1, 2], [6, 8], [4, 5], [3, 7]]

    max_length = 10

    horizon = sum(t[0] for t in jobs)
    num_jobs = len(jobs)
    all_jobs = range(num_jobs)

    intervals = []
    intervals0 = []
    intervals1 = []
    performed = []
    starts = []
    ends = []
    demands = []

    for i in all_jobs:
        # Create main interval.
        start = model.NewIntVar(0, horizon, 'start_%i' % i)
        duration = jobs[i][0]
        end = model.NewIntVar(0, horizon, 'end_%i' % i)
        interval = model.NewIntervalVar(start, duration, end,
                                        'interval_%i' % i)
        starts.append(start)
        intervals.append(interval)
        ends.append(end)
        demands.append(jobs[i][1])

        performed_on_m0 = model.NewBoolVar('perform_%i_on_m0' % i)
        performed.append(performed_on_m0)

        # Create an optional copy of interval to be executed on machine 0.
        start0 = model.NewOptionalIntVar(0, horizon, performed_on_m0,
                                         'start_%i_on_m0' % i)
        end0 = model.NewOptionalIntVar(0, horizon, performed_on_m0,
                                       'end_%i_on_m0' % i)
        interval0 = model.NewOptionalIntervalVar(start0, duration, end0,
                                                 performed_on_m0,
                                                 'interval_%i_on_m0' % i)
        intervals0.append(interval0)

        # Create an optional copy of interval to be executed on machine 1.
        start1 = model.NewOptionalIntVar(0, horizon, performed_on_m0.Not(),
                                         'start_%i_on_m1' % i)
        end1 = model.NewOptionalIntVar(0, horizon, performed_on_m0.Not(),
                                       'end_%i_on_m1' % i)
        interval1 = model.NewOptionalIntervalVar(start1, duration, end1,
                                                 performed_on_m0.Not(),
                                                 'interval_%i_on_m1' % i)
        intervals1.append(interval1)

        # We only propagate the constraint if the tasks is performed on the machine.
        model.Add(start0 == start).OnlyEnforceIf(performed_on_m0)
        model.Add(start1 == start).OnlyEnforceIf(performed_on_m0.Not())

    # Max Length constraint (modeled as a cumulative)
    model.AddCumulative(intervals, demands, max_length)

    # Choose which machine to perform the jobs on.
    model.AddNoOverlap(intervals0)
    model.AddNoOverlap(intervals1)

    # Objective variable.
    makespan = model.NewIntVar(0, horizon, 'makespan')
    model.AddMaxEquality(makespan, ends)
    model.Minimize(makespan)

    # Symmetry breaking.
    model.Add(performed[0] == 0)

    # Solve model.
    solver = cp_model.CpSolver()
    solver.Solve(model)

    # Output solution.
    if visualization.RunFromIPython():
        output = visualization.SvgWrapper(solver.ObjectiveValue(), max_length,
                                          40.0)
        output.AddTitle('Makespan = %i' % solver.ObjectiveValue())
        color_manager = visualization.ColorManager()
        color_manager.SeedRandomColor(0)

        for i in all_jobs:
            performed_machine = 1 - solver.Value(performed[i])
            start = solver.Value(starts[i])
            dx = jobs[i][0]
            dy = jobs[i][1]
            sy = performed_machine * (max_length - dy)
            output.AddRectangle(start, sy, dx, dy, color_manager.RandomColor(),
                                'black', 'j%i' % i)

        output.AddXScale()
        output.AddYScale()
        output.Display()
    else:
        print('Solution')
        print('  - makespan = %i' % solver.ObjectiveValue())
        for i in all_jobs:
            performed_machine = 1 - solver.Value(performed[i])
            start = solver.Value(starts[i])
            print('  - Job %i starts at %i on machine %i' %
                  (i, start, performed_machine))
        print('Statistics')
        print('  - conflicts : %i' % solver.NumConflicts())
        print('  - branches  : %i' % solver.NumBranches())
        print('  - wall time : %f ms' % solver.WallTime())
Пример #7
0
def reschedule_retry(data, companies):
    """Rescheduling programm"""
    # Create the model.
    model = cp_model.CpModel()

    line_size = 12  # number of slots for meetings
    line = list(range(0, line_size))
    rows = list(range(len(data)))

    ls_m_c = [data[k].get('Companies') for k in rows]

    initial_grid = []
    initial_grid.append(list(np.zeros(12, dtype=int)))

    for ls in range(1, len(ls_m_c)):
        initial_grid.append(ls_m_c[ls])

    grid = {}
    for i in rows:
        for j in line:
            grid[(i, j)] = model.NewIntVarFromDomain(
                cp_model.Domain.FromValues(ls_m_c[i]), 'grid %i %i' % (i, j))

    #AllDifferent on rows.
    for i in rows:
        model.AddAllDifferent([grid[(i, j)] for j in line])

    # AllDifferent on columns.
    for j in line:
        model.AddAllDifferent([grid[(i, j)] for i in rows])

    #Adding objectives:
    #for i in rows:
    if ls_m_c[0][8] < 100 and ls_m_c[0][10] > 100:
        model.Add(grid[(0, 5)] >= 100)
        model.Add(grid[(0, 9)] >= 100)

    elif ls_m_c[0][7] < 100:
        model.Add((grid[(0, 0)] + grid[(0, 1)] + grid[(0, 2)]) < 100)
        model.Add((grid[(0, 3)]) >= 100)
        model.Add((grid[(0, 4)] + grid[(0, 5)] + grid[(0, 6)]) < 100)
        model.Add((grid[(0, 7)]) >= 100)
        model.Add((grid[(0, 8)] + grid[(0, 9)]) < 100)

    elif ls_m_c[0][6] < 100:
        model.Add((grid[(0, 3)] + grid[(0, 4)] + grid[(0, 5)]) < 100)
        model.Add(
            (grid[(0, 7)] + grid[(0, 8)] + grid[(0, 9)] + grid[(0, 10)]) < 100)

    elif ls_m_c[0][5] < 100:
        model.Add((grid[(0, 1)] + grid[(0, 2)] + grid[(0, 3)]) < 100)
        model.Add((grid[(0, 4)]) >= 100)
        model.Add((grid[(0, 5)] + grid[(0, 6)] + grid[(0, 7)]) < 100)

    elif ls_m_c[0][4] < 100:
        model.Add((grid[(0, 1)] + grid[(0, 2)]) < 100)
        model.Add((grid[(0, 3)]) >= 100)
        model.Add((grid[(0, 4)] + grid[(0, 5)] + grid[(0, 6)]) < 100)

    elif ls_m_c[0][3] < 100:
        model.Add((grid[(0, 7)] + grid[(0, 8)]) < 100)
        model.Add((grid[(0, 9)] + grid[(0, 10)]) < 100)

    elif ls_m_c[0][2] < 100:
        model.Add((grid[(0, 8)] + grid[(0, 9)] + grid[(0, 10)]) < 100)

    elif ls_m_c[0][1] < 100:
        model.Add((grid[(0, 8)] + grid[(0, 9)]) < 100)

    #Initial values.
    for i in rows:
        for j in line:
            if initial_grid[i][j] != 0:
                model.Add(grid[(i, j)] == initial_grid[i][j])

    # Solve and save a list with values.
    solver = cp_model.CpSolver()
    status = solver.Solve(model)

    if status == cp_model.OPTIMAL:
        ls = []
        for i in rows:
            ls.append([int(solver.Value(grid[(i, j)])) for j in line])

    try:
        #Removing fake ids
        for m in range(len(ls)):
            for cl in range(len(ls[m])):
                if ls[m][cl] > len(companies):
                    ls[m][cl] = np.nan

    # Change companies' ids by its name
        for l in range(len(ls)):
            for col in range(len(ls[l])):
                if ls[l][col]:
                    for c in companies:
                        if ls[l][col] in c:
                            com = c.get(ls[l][col])
                            ls[l][col] = com

        #Appending to ls: mentors' name, day and block, to have a more complete list for using it later to recreate the dataframe
        ls_mentors = [data[i].get('mentor_id') for i in range(len(data))]
        ls_mentors[0] = data[0].get('mentor')
        for i in range(len(ls_mentors)):
            ls[i].append(ls_mentors[i])
            #ls[i].append(data[i].get('Email'))
            ls[i].append(data[i].get('day_id'))
            ls[i].append(data[i].get('block_id'))
        return (ls)

    except:
        #print('There is no feasible solution')
        #retry = schedule_retry(data, companies)
        return ([])
Пример #8
0
def main():

    model = cp.CpModel()

    #
    # data
    #
    num_skis = 6
    num_skiers = 5
    ski_heights = [1, 2, 5, 7, 13, 21]
    skier_heights = [3, 4, 7, 11, 18]

    #
    # variables
    #

    # which ski to choose for each skier
    x = [
        model.NewIntVar(0, num_skis - 1, 'x[%i]' % i)
        for i in range(num_skiers)
    ]
    z = model.NewIntVar(0, sum(ski_heights), 'z')

    #
    # constraints
    #
    model.AddAllDifferent(x)

    # Old:
    # z_tmp = [
    #     abs(solver.Element(ski_heights, x[i]) - skier_heights[i])
    #     for i in range(num_skiers)
    # ]
    z_tmp = [model.NewIntVar(0, 100, "z_tmp") for i in range(num_skiers)]
    for i in range(num_skiers):
        t1 = model.NewIntVar(-100, 100, "t1")
        model.AddElement(x[i], ski_heights, t1)
        t2 = model.NewIntVar(-100, 100, "t1")
        model.Add(t2 == t1 - skier_heights[i])
        model.AddAbsEquality(z_tmp[i], t2)
    model.Add(z == sum(z_tmp))

    # objective
    model.Minimize(z)

    #
    # search and result
    #
    solver = cp.CpSolver()
    status = solver.Solve(model)

    if status == cp.OPTIMAL:
        print('total differences:', solver.Value(z))
        for i in range(num_skiers):
            x_val = solver.Value(x[i])
            ski_height = ski_heights[solver.Value(x[i])]
            diff = ski_height - skier_heights[i]
            print('Skier %i: Ski %i with length %2i (diff: %2i)' %\
                  (i, x_val, ski_height, diff))
        print()

    print()
    print('NumConflicts:', solver.NumConflicts())
    print('NumBranches:', solver.NumBranches())
    print('WallTime:', solver.WallTime())
def jobshop_with_maintenance():
    """Solves a jobshop with maintenance on one machine."""
    # Create the model.
    model = cp_model.CpModel()

    jobs_data = [  # task = (machine_id, processing_time).
        [(0, 3), (1, 2), (2, 2)],  # Job0
        [(0, 2), (2, 1), (1, 4)],  # Job1
        [(1, 4), (2, 3)],  # Job2
    ]

    machines_count = 1 + max(task[0] for job in jobs_data for task in job)
    all_machines = range(machines_count)

    # Computes horizon dynamically as the sum of all durations.
    horizon = sum(task[1] for job in jobs_data for task in job)

    # Named tuple to store information about created variables.
    task_type = collections.namedtuple('Task', 'start end interval')
    # Named tuple to manipulate solution information.
    assigned_task_type = collections.namedtuple('assigned_task_type',
                                                'start job index duration')

    # Creates job intervals and add to the corresponding machine lists.
    all_tasks = {}
    machine_to_intervals = collections.defaultdict(list)

    for job_id, job in enumerate(jobs_data):
        for task_id, task in enumerate(job):
            machine = task[0]
            duration = task[1]
            suffix = '_%i_%i' % (job_id, task_id)
            start_var = model.NewIntVar(0, horizon, 'start' + suffix)
            end_var = model.NewIntVar(0, horizon, 'end' + suffix)
            interval_var = model.NewIntervalVar(start_var, duration, end_var,
                                                'interval' + suffix)
            all_tasks[job_id, task_id] = task_type(start=start_var,
                                                   end=end_var,
                                                   interval=interval_var)
            machine_to_intervals[machine].append(interval_var)

    # Add maintenance interval (machine 0 is not available on time {4, 5, 6, 7}).
    machine_to_intervals[0].append(model.NewIntervalVar(4, 4, 8, 'weekend_0'))

    # Create and add disjunctive constraints.
    for machine in all_machines:
        model.AddNoOverlap(machine_to_intervals[machine])

    # Precedences inside a job.
    for job_id, job in enumerate(jobs_data):
        for task_id in range(len(job) - 1):
            model.Add(all_tasks[job_id, task_id +
                                1].start >= all_tasks[job_id, task_id].end)

    # Makespan objective.
    obj_var = model.NewIntVar(0, horizon, 'makespan')
    model.AddMaxEquality(obj_var, [
        all_tasks[job_id, len(job) - 1].end
        for job_id, job in enumerate(jobs_data)
    ])
    model.Minimize(obj_var)

    # Solve model.
    solver = cp_model.CpSolver()
    solution_printer = SolutionPrinter()
    status = solver.Solve(model, solution_printer)

    # Output solution.
    if status == cp_model.OPTIMAL:
        # Create one list of assigned tasks per machine.
        assigned_jobs = collections.defaultdict(list)
        for job_id, job in enumerate(jobs_data):
            for task_id, task in enumerate(job):
                machine = task[0]
                assigned_jobs[machine].append(
                    assigned_task_type(start=solver.Value(
                        all_tasks[job_id, task_id].start),
                                       job=job_id,
                                       index=task_id,
                                       duration=task[1]))

        # Create per machine output lines.
        output = ''
        for machine in all_machines:
            # Sort by starting time.
            assigned_jobs[machine].sort()
            sol_line_tasks = 'Machine ' + str(machine) + ': '
            sol_line = '           '

            for assigned_task in assigned_jobs[machine]:
                name = 'job_%i_%i' % (assigned_task.job, assigned_task.index)
                # Add spaces to output to align columns.
                sol_line_tasks += '%-10s' % name
                start = assigned_task.start
                duration = assigned_task.duration

                sol_tmp = '[%i,%i]' % (start, start + duration)
                # Add spaces to output to align columns.
                sol_line += '%-10s' % sol_tmp

            sol_line += '\n'
            sol_line_tasks += '\n'
            output += sol_line_tasks
            output += sol_line

        # Finally print the solution found.
        print('Optimal Schedule Length: %i' % solver.ObjectiveValue())
        print(output)
        print('Statistics')
        print('  - conflicts : %i' % solver.NumConflicts())
        print('  - branches  : %i' % solver.NumBranches())
        print('  - wall time : %f s' % solver.WallTime())
Пример #10
0
def main():
    # Data.
    num_groups = 10
    num_items = 100
    num_colors = 3
    min_items_of_same_color_per_group = 4

    all_groups = range(num_groups)
    all_items = range(num_items)
    all_colors = range(num_colors)

    # Values for each items.
    values = [1 + i + (i * i // 200) for i in all_items]
    # Color for each item (simple modulo).
    colors = [i % num_colors for i in all_items]

    sum_of_values = sum(values)
    average_sum_per_group = sum_of_values // num_groups

    num_items_per_group = num_items // num_groups

    # Collect all items in a given color.
    items_per_color = {}
    for c in all_colors:
        items_per_color[c] = []
        for i in all_items:
            if colors[i] == c:
                items_per_color[c].append(i)

    print('Model has %i items, %i groups, and %i colors' %
          (num_items, num_groups, num_colors))
    print('  average sum per group = %i' % average_sum_per_group)

    # Model.

    model = cp_model.CpModel()

    item_in_group = {}
    for i in all_items:
        for g in all_groups:
            item_in_group[(i, g)] = model.NewBoolVar('item %d in group %d' %
                                                     (i, g))

    # Each group must have the same size.
    for g in all_groups:
        model.Add(
            sum(item_in_group[(i, g)]
                for i in all_items) == num_items_per_group)

    # One item must belong to exactly one group.
    for i in all_items:
        model.Add(sum(item_in_group[(i, g)] for g in all_groups) == 1)

    # The deviation of the sum of each items in a group against the average.
    e = model.NewIntVar(0, 550, 'epsilon')

    # Constrain the sum of values in one group around the average sum per group.
    for g in all_groups:
        model.Add(
            sum(item_in_group[(i, g)] * values[i]
                for i in all_items) <= average_sum_per_group + e)
        model.Add(
            sum(item_in_group[(i, g)] * values[i]
                for i in all_items) >= average_sum_per_group - e)

    # color_in_group variables.
    color_in_group = {}
    for g in all_groups:
        for c in all_colors:
            color_in_group[(c, g)] = model.NewBoolVar(
                'color %d is in group %d' % (c, g))

    # Item is in a group implies its color is in that group.
    for i in all_items:
        for g in all_groups:
            model.AddImplication(item_in_group[(i, g)],
                                 color_in_group[(colors[i], g)])

    # If a color is in a group, it must contains at least
    # min_items_of_same_color_per_group items from that color.
    for c in all_colors:
        for g in all_groups:
            literal = color_in_group[(c, g)]
            model.Add(
                sum(item_in_group[(i, g)] for i in items_per_color[c]) >=
                min_items_of_same_color_per_group).OnlyEnforceIf(literal)

    # Compute the maximum number of colors in a group.
    max_color = num_items_per_group // min_items_of_same_color_per_group
    # Redundant contraint: The problem does not solve in reasonable time without it.
    if max_color < num_colors:
        for g in all_groups:
            model.Add(
                sum(color_in_group[(c, g)] for c in all_colors) <= max_color)

    # Minimize epsilon
    model.Minimize(e)

    solver = cp_model.CpSolver()
    solution_printer = SolutionPrinter(values, colors, all_groups, all_items,
                                       item_in_group)
    status = solver.SolveWithSolutionCallback(model, solution_printer)

    if status == cp_model.OPTIMAL:
        print('Optimal epsilon: %i' % solver.ObjectiveValue())
        print('Statistics')
        print('  - conflicts : %i' % solver.NumConflicts())
        print('  - branches  : %i' % solver.NumBranches())
        print('  - wall time : %f s' % solver.WallTime())
    else:
        print('No solution found')
Пример #11
0
def flexible_jobshop():
    """Solve a small flexible jobshop problem."""
    # Data part.
    # jobs = [[[(3, 0), (1, 1), (5, 2)], [(2, 0), (4, 1), (6, 2)], [(2, 0), (3, 1), (1, 2)]],
    #         [[(2, 0), (3, 1), (4, 2)], [(1, 0), (5, 1), (4, 2)], [(2, 0), (1, 1), (4, 2)]],
    #         [[(2, 0), (1, 1), (4, 2)], [(2, 0), (3, 1), (4, 2)], [(3, 0), (1, 1), (5, 2)]]
    # ] # yapf:disable

    jobs = [[[(3, 0), (3, 1), (3, 2)], [(2, 3), (2, 4)], [(1, 5), (1, 6)]],
            [[(3, 0), (3, 1), (3, 2)], [(2, 3), (2, 4)], [(1, 5), (1, 6)]],
            [[(3, 0), (3, 1), (3, 2)], [(2, 3), (2, 4)], [(1, 5), (1, 6)]],
            [[(3, 0), (3, 1), (3, 2)], [(2, 3), (2, 4)], [(1, 5), (1, 6)]],
            [[(3, 0), (3, 1), (3, 2)], [(2, 3), (2, 4)], [(1, 5), (1, 6)]],
            [[(3, 0), (3, 1), (3, 2)], [(2, 3), (2, 4)], [(1, 5), (1, 6)]],
            [[(3, 0), (3, 1), (3, 2)], [(2, 3), (2, 4)], [(1, 5), (1, 6)]],
            [[(3, 0), (3, 1), (3, 2)], [(2, 3), (2, 4)], [(1, 5), (1, 6)]],
            [[(3, 0), (3, 1), (3, 2)], [(2, 3), (2, 4)], [(1, 5), (1, 6)]],
            [[(3, 0), (3, 1), (3, 2)], [(2, 3), (2, 4)], [(1, 5), (1, 6)]],
            [[(3, 0), (3, 1), (3, 2)], [(2, 3), (2, 4)], [(1, 5), (1, 6)]],
            [[(3, 0), (3, 1), (3, 2)], [(2, 3), (2, 4)], [(1, 5), (1, 6)]],
            [[(2, 3), (2, 4)], [(1, 5), (1, 6)]],
            [[(2, 3), (2, 4)], [(1, 5), (1, 6)]],
            [[(2, 3), (2, 4)], [(1, 5), (1, 6)]],
            [[(2, 3), (2, 4)], [(1, 5), (1, 6)]],
            [[(2, 3), (2, 4)], [(1, 5), (1, 6)]],
            [[(1, 5), (1, 6)]],
            [[(1, 5), (1, 6)]],
            [[(1, 5), (1, 6)]],
    ] # yapf:disable


    ## 3个JOB
    num_jobs = len(jobs)
    ## JOB编号0,1,2
    all_jobs = range(num_jobs)
    ## 3台机器
    num_machines = 3
    ## 机器编号0,1,2
    all_machines = range(num_machines)

    # Model the flexible jobshop problem.
    model = cp_model.CpModel()

    horizon = 0
    for job in jobs:    ## [[(3, 0), (1, 1), (5, 2)], [(2, 0), (4, 1), (6, 2)], [(2, 0), (3, 1), (1, 2)]]
        for task in job:    ## [(3, 0), (1, 1), (5, 2)]
            max_task_duration = 0
            for alternative in task: ## (3, 0)
                max_task_duration = max(max_task_duration, alternative[0])
            horizon += max_task_duration

    print('Horizon = %i' % horizon)

    # Global storage of variables.
    intervals_per_resources = collections.defaultdict(list)
    starts = {}  # indexed by (job_id, task_id).
    presences = {}  # indexed by (job_id, task_id, alt_id).
    job_ends = []

    # Scan the jobs and create the relevant variables and intervals.
    for job_id in all_jobs:  # [0,1,2]
        job = jobs[job_id]   ## [[(3, 0), (1, 1), (5, 2)], [(2, 0), (4, 1), (6, 2)], [(2, 0), (3, 1), (1, 2)]]
        num_tasks = len(job) ## 一个job 三个task
        previous_end = None
        for task_id in range(num_tasks): # [0,1,2]
            task = job[task_id]          # [(3, 0), (1, 1), (5, 2)] -> [(2, 0), (4, 1), (6, 2)] -> [(2, 0), (3, 1), (1, 2)]

            min_duration = task[0][0]    # 初始化min
            max_duration = task[0][0]    # 初始化max

            num_alternatives = len(task) # 一个 task 有三个机器可以选
            all_alternatives = range(num_alternatives) # 可选编号0,1,2

            for alt_id in range(1, num_alternatives): # 从第二个开始比
                alt_duration = task[alt_id][0]
                min_duration = min(min_duration, alt_duration)
                max_duration = max(max_duration, alt_duration)

            # Create main interval for the task.
            suffix_name = '_j%i_t%i' % (job_id, task_id)
            start = model.NewIntVar(0, horizon, 'start' + suffix_name)
            duration = model.NewIntVar(min_duration, max_duration,
                                       'duration' + suffix_name)
            end = model.NewIntVar(0, horizon, 'end' + suffix_name)
            interval = model.NewIntervalVar(start, duration, end,
                                            'interval' + suffix_name)

            # Store the start for the solution.
            starts[(job_id, task_id)] = start

            # Add precedence with previous task in the same job.
            if previous_end:
                model.Add(start >= previous_end)
            previous_end = end

            # Create alternative intervals.
            if num_alternatives > 1:
                l_presences = []
                for alt_id in all_alternatives:# 可选编号0,1,2
                    alt_suffix = '_j%i_t%i_a%i' % (job_id, task_id, alt_id)
                    l_presence = model.NewBoolVar('presence' + alt_suffix)
                    l_start = model.NewIntVar(0, horizon, 'start' + alt_suffix)
                    l_duration = task[alt_id][0]
                    l_end = model.NewIntVar(0, horizon, 'end' + alt_suffix)
                    l_interval = model.NewOptionalIntervalVar(
                        l_start, l_duration, l_end, l_presence,
                        'interval' + alt_suffix)
                    l_presences.append(l_presence)

                    # Link the master variables with the local ones.
                    model.Add(start == l_start).OnlyEnforceIf(l_presence)
                    model.Add(duration == l_duration).OnlyEnforceIf(l_presence)
                    model.Add(end == l_end).OnlyEnforceIf(l_presence)

                    # Add the local interval to the right machine.
                    intervals_per_resources[task[alt_id][1]].append(l_interval)

                    # Store the presences for the solution.
                    presences[(job_id, task_id, alt_id)] = l_presence

                # Select exactly one presence variable.
                model.Add(sum(l_presences) == 1)
            else:
                intervals_per_resources[task[0][1]].append(interval)
                presences[(job_id, task_id, 0)] = model.NewConstant(1)

        job_ends.append(previous_end)

    # Create machines constraints.
    for machine_id in all_machines:
        intervals = intervals_per_resources[machine_id]
        if len(intervals) > 1:
            model.AddNoOverlap(intervals)

    # Makespan objective
    makespan = model.NewIntVar(0, horizon, 'makespan')
    model.AddMaxEquality(makespan, job_ends)
    model.Minimize(makespan)

    # Solve model.
    solver = cp_model.CpSolver()
    solution_printer = SolutionPrinter()
    status = solver.SolveWithSolutionCallback(model, solution_printer)

    # Print final solution.
    for job_id in all_jobs:
        print('Job %i:' % job_id)
        for task_id in range(len(jobs[job_id])):
            start_value = solver.Value(starts[(job_id, task_id)])
            machine = -1
            duration = -1
            selected = -1
            for alt_id in range(len(jobs[job_id][task_id])):
                if solver.Value(presences[(job_id, task_id, alt_id)]):
                    duration = jobs[job_id][task_id][alt_id][0]
                    machine = jobs[job_id][task_id][alt_id][1]
                    selected = alt_id
            print(
                '  task_%i_%i starts at %i (alt %i, machine %i, duration %i)' %
                (job_id, task_id, start_value, selected, machine, duration))

    print('Solve status: %s' % solver.StatusName(status))
    print('Optimal objective value: %i' % solver.ObjectiveValue())
    print('Statistics')
    print('  - conflicts : %i' % solver.NumConflicts())
    print('  - branches  : %i' % solver.NumBranches())
    print('  - wall time : %f s' % solver.WallTime())
Пример #12
0
def puzzle(problem=1):

    print("Problem", problem)

    model = cp.CpModel()

    n = 10

    # variables
    all = [model.NewIntVar(0, 9, f"all[{i}]") for i in range(n)]
    [x0, x1, x2, x3, _x4, x5, x6, x7, x8, x9] = all

    x = model.NewIntVar(0, 9, "x")

    if problem == 1:
        model.Add(x8 + x8 + x0 + x9 == 6)
        model.Add(x7 + x1 + x1 + x1 == 0)
        model.Add(x2 + x1 + x7 + x2 == 0)
        model.Add(x6 + x6 + x6 + x6 == 4)
        model.Add(x1 + x1 + x1 + x1 == 0)
        model.Add(x3 + x2 + x1 + x3 == 0)
        model.Add(x7 + x6 + x6 + x2 == 2)
        model.Add(x9 + x3 + x1 + x2 == 1)
        model.Add(x0 + x0 + x0 + x0 == 4)
        model.Add(x2 + x2 + x2 + x2 == 0)
        model.Add(x3 + x3 + x3 + x3 == 0)
        model.Add(x5 + x5 + x5 + x5 == 0)
        model.Add(x8 + x1 + x9 + x3 == 3)
        model.Add(x8 + x0 + x9 + x6 == 5)
        model.Add(x7 + x7 + x7 + x7 == 0)
        model.Add(x9 + x9 + x9 + x9 == 4)
        model.Add(x7 + x7 + x5 + x6 == 1)
        model.Add(x6 + x8 + x5 + x5 == 3)
        model.Add(x9 + x8 + x8 + x1 == 5)
        model.Add(x5 + x5 + x3 + x1 == 0)

        model.Add(x2 + x5 + x8 + x1 == x)

    else:
        # This yields two different values for x
        model.Add(x8 + x8 + x0 + x9 == 6)
        model.Add(x7 + x6 + x6 + x2 == 2)
        model.Add(x9 + x3 + x1 + x2 == 1)
        model.Add(x8 + x1 + x9 + x3 == 3)
        model.Add(x8 + x0 + x9 + x6 == 5)
        model.Add(x7 + x7 + x5 + x6 == 1)
        model.Add(x6 + x8 + x5 + x5 == 3)
        model.Add(x9 + x8 + x8 + x1 == 5)

        model.Add(x2 + x5 + x8 + x1 == x)

    solver = cp.CpSolver()
    solution_printer = SimpleSolutionPrinter2([x, all])
    status = solver.SearchForAllSolutions(model, solution_printer)

    if not status in [cp.OPTIMAL, cp.FEASIBLE]:
        print("No solution!")

    print()
    print("NumSolutions:", solution_printer.SolutionCount())
    print("NumConflicts:", solver.NumConflicts())
    print("NumBranches:", solver.NumBranches())
    print("WallTime:", solver.WallTime())
Пример #13
0
def Futoshiki(input, output):
    Cpmodel = cp_model.CpModel()
    CpSolver = cp_model.CpSolver()

    A1 = Cpmodel.NewIntVar(1, 4, 'A1')
    A2 = Cpmodel.NewIntVar(1, 4, 'A2')
    A3 = Cpmodel.NewIntVar(1, 4, 'A3')
    A4 = Cpmodel.NewIntVar(1, 4, 'A4')

    B1 = Cpmodel.NewIntVar(1, 4, 'B1')
    B2 = Cpmodel.NewIntVar(1, 4, 'B2')
    B3 = Cpmodel.NewIntVar(1, 4, 'B3')
    B4 = Cpmodel.NewIntVar(1, 4, 'B4')

    C1 = Cpmodel.NewIntVar(1, 4, 'C1')
    C2 = Cpmodel.NewIntVar(1, 4, 'C2')
    C3 = Cpmodel.NewIntVar(1, 4, 'C3')
    C4 = Cpmodel.NewIntVar(1, 4, 'C4')

    D1 = Cpmodel.NewIntVar(1, 4, 'D1')
    D2 = Cpmodel.NewIntVar(1, 4, 'D2')
    D3 = Cpmodel.NewIntVar(1, 4, 'D3')
    D4 = Cpmodel.NewIntVar(1, 4, 'D4')

    firstRow = [A1, A2, A3, A4]
    secondRow = [B1, B2, B3, B4]
    thirdRow = [C1, C2, C3, C4]
    fourthRow = [D1, D2, D3, D4]

    firstColumn = [A1, B1, C1, D1]
    secondColumn = [A2, B2, C2, D2]
    thirdColumn = [A3, B3, C3, D3]
    fourthColumn = [A4, B4, C4, D4]

    Cpmodel.AddAllDifferent(firstRow)
    Cpmodel.AddAllDifferent(secondRow)
    Cpmodel.AddAllDifferent(thirdRow)
    Cpmodel.AddAllDifferent(fourthRow)

    Cpmodel.AddAllDifferent(firstColumn)
    Cpmodel.AddAllDifferent(secondColumn)
    Cpmodel.AddAllDifferent(thirdColumn)
    Cpmodel.AddAllDifferent(fourthColumn)

    inputFile = open(input, 'r')
    lines = inputFile.readlines()

    linesplit = []
    for i in lines:

        linesplit.append(i.strip().split(","))

    for x in linesplit:
        try:
            if (int(x[1]) > 0):

                Cpmodel.Add(eval(x[0]) == eval(x[1]))
        except:

            Cpmodel.Add(eval(x[0]) > eval(x[1]))

    inputFile.close()

    outputFile = open(output, 'w')

    status = CpSolver.Solve(Cpmodel)

    if status == cp_model.FEASIBLE:

        outputFile.writelines(
            str(CpSolver.Value(A1)) + "," + str(CpSolver.Value(A2)) + "," +
            str(CpSolver.Value(A3)) + "," + str(CpSolver.Value(A4)) + "\n")
        outputFile.writelines(
            str(CpSolver.Value(B1)) + "," + str(CpSolver.Value(B2)) + "," +
            str(CpSolver.Value(B3)) + "," + str(CpSolver.Value(B4)) + "\n")
        outputFile.writelines(
            str(CpSolver.Value(C1)) + "," + str(CpSolver.Value(C2)) + "," +
            str(CpSolver.Value(C3)) + "," + str(CpSolver.Value(C4)) + "\n")
        outputFile.writelines(
            str(CpSolver.Value(D1)) + "," + str(CpSolver.Value(D2)) + "," +
            str(CpSolver.Value(D3)) + "," + str(CpSolver.Value(D4)) + "\n")
Пример #14
0
def filtered_neighbors(points):
    node_count = len(points)

    # Neighbor Detection
    xy = np.array(points)
    kdt = KDTree(xy)
    k = get_k_value(node_count) + 1
    dist, neighbors = kdt.query(xy, k)

    # Create CP Model
    model = cp_model.CpModel()

    # Define Variables
    a = []  # whether i and j are connected
    u = []  # order of points
    for i in range(node_count):
        row = [model.NewBoolVar(f"a_{i}_{j}") for j in range(node_count)]
        a.append(row)
    u = [
        model.NewIntVar(0, node_count - 1, f"u_{i}") for i in range(node_count)
    ]

    # Add Constraints
    for i in range(node_count):
        model.AddAbsEquality(0, a[i][i])
        model.Add(sum([a[i][j] for j in range(node_count)]) == 1)
        model.Add(sum([a[j][i] for j in range(node_count)]) == 1)

    for i in range(node_count - 1):
        for j in range(i, node_count):
            model.Add(a[i][j] + a[j][i] <= 1)

    # Connectivity Constraint
    model.AddAllDifferent(u)
    for i in range(1, node_count):
        for j in range(1, node_count):
            if i == j:
                continue
            model.Add(u[i] - u[j] + node_count * a[i][j] <= node_count - 1)
    model.Add(u[0] == 0)

    # Proximity Constraint
    for i in range(node_count):
        neigh = neighbors[i, 1:]
        for j in range(node_count):
            if j not in neigh:
                model.AddAbsEquality(0, a[i][j])
                model.AddAbsEquality(0, a[j][i])

    # Objective
    obj = []
    for i in range(node_count):
        for j in range(node_count):
            d = distance(points[i], points[j]) * 100
            obj.append(int(d) * a[i][j])
    model.Minimize(sum(obj))

    # Solve
    max_time = estimate_time(node_count)
    max_time = 600
    cpsolver = cp_model.CpSolver()
    cpsolver.parameters.max_time_in_seconds = max_time
    status = cpsolver.Solve(model)
    print(cpsolver.StatusName())

    if status == cp_model.MODEL_INVALID or status == cp_model.INFEASIBLE:
        raise RuntimeError("Unable to find a solution.")

    # Extract Solution
    sol_mat = []
    for i in range(node_count):
        row = [cpsolver.Value(a[i][j]) for j in range(node_count)]
        sol_mat.append(row)
    sol_mat = np.array(sol_mat)

    # Convert solution to readable format
    sol = matrix_to_route(sol_mat)

    return status == cp_model.OPTIMAL, sol
Пример #15
0
def main(words, word_len, num_answers=5):

    model = cp.CpModel()

    #
    # data
    #
    num_words = len(words)
    n = word_len
    d, _rev = get_dict()

    #
    # declare variables
    #
    A = {}
    for i in range(num_words):
        for j in range(word_len):
            A[(i, j)] = model.NewIntVar(0, 29, "A(%i,%i)" % (i, j))

    A_flat = [A[(i, j)] for i in range(num_words) for j in range(word_len)]

    E = [model.NewIntVar(0, num_words, "E%i" % i) for i in range(n)]

    #
    # constraints
    #
    model.AddAllDifferent(E)

    # copy the words to a Matrix
    for I in range(num_words):
        for J in range(word_len):
            model.Add(A[(I, J)] == d[words[I][J]])

    for i in range(word_len):
        for j in range(word_len):
            # This is what I would like to do:
            # solver.Add(A[(E[i],j)] == A[(E[j],i)])

            # We must use Element explicitly
            val = model.NewIntVar(0, 29, "t")
            ix1 = model.NewIntVar(0, num_words, "t")
            model.Add(ix1 == E[i] * word_len + j)
            ix2 = model.NewIntVar(0, num_words, "t")
            model.Add(ix2 == E[j] * word_len + i)
            model.AddElement(ix1, A_flat, val)
            model.AddElement(ix2, A_flat, val)
    #
    # solution and search
    #
    solver = cp.CpSolver()
    # solver.parameters.search_branching = cp.PORTFOLIO_SEARCH
    # solver.parameters.cp_model_presolve = False
    solver.parameters.linearization_level = 0
    solver.parameters.cp_model_probing_level = 0

    solution_printer = SolutionPrinter(E, words, num_answers)
    status = solver.SearchForAllSolutions(model, solution_printer)

    if not (status == cp.OPTIMAL or status == cp.FEASIBLE):
        print("No solution!")

    print()
    print("NumSolutions:", solution_printer.SolutionCount())
    print("NumConflicts:", solver.NumConflicts())
    print("NumBranches:", solver.NumBranches())
    print("WallTime:", solver.WallTime())
Пример #16
0
def tasks_and_workers_assignment_sat():
    """Solve the assignment problem."""
    model = cp_model.CpModel()

    # CP-SAT solver is integer only.
    task_cost = [24, 10, 7, 2, 11, 16, 1, 13, 9, 27]
    num_tasks = len(task_cost)
    num_workers = 3
    num_groups = 2
    all_workers = range(num_workers)
    all_groups = range(num_groups)
    all_tasks = range(num_tasks)

    # Variables

    ## x_ij = 1 if worker i is assigned to group j
    x = {}
    for i in all_workers:
        for j in all_groups:
            x[i, j] = model.NewBoolVar('x[%i,%i]' % (i, j))

    ## y_kj is 1 if task k is assigned to group j
    y = {}
    for k in all_tasks:
        for j in all_groups:
            y[k, j] = model.NewBoolVar('x[%i,%i]' % (k, j))

    # Constraints

    # Each task k is assigned to a group and only one.
    for k in all_tasks:
        model.Add(sum(y[k, j] for j in all_groups) == 1)

    # Each worker i is assigned to a group and only one.
    for i in all_workers:
        model.Add(sum(x[i, j] for j in all_groups) == 1)

    # cost per group
    sum_of_costs = sum(task_cost)
    averages = []
    num_workers_in_group = []
    scaled_sum_of_costs_in_group = []
    scaling = 1000  # We introduce scaling to deal with floating point average.
    for j in all_groups:
        n = model.NewIntVar(1, num_workers, 'num_workers_in_group_%i' % j)
        model.Add(n == sum(x[i, j] for i in all_workers))
        c = model.NewIntVar(0, sum_of_costs * scaling,
                            'sum_of_costs_of_group_%i' % j)
        model.Add(c == sum(y[k, j] * task_cost[k] * scaling
                           for k in all_tasks))
        a = model.NewIntVar(0, sum_of_costs * scaling,
                            'average_cost_of_group_%i' % j)
        model.AddDivisionEquality(a, c, n)

        averages.append(a)
        num_workers_in_group.append(n)
        scaled_sum_of_costs_in_group.append(c)

    # All workers are assigned.
    model.Add(sum(num_workers_in_group) == num_workers)

    # Objective.
    obj = model.NewIntVar(0, sum_of_costs * scaling, 'obj')
    model.AddMaxEquality(obj, averages)
    model.Minimize(obj)

    # Solve and print out the solution.
    solver = cp_model.CpSolver()
    solver.parameters.max_time_in_seconds = 60 * 60 * 2
    objective_printer = ObjectivePrinter()
    status = solver.SolveWithSolutionCallback(model, objective_printer)
    print(solver.ResponseStats())

    if status == cp_model.OPTIMAL:
        for j in all_groups:
            print('Group %i' % j)
            for i in all_workers:
                if solver.BooleanValue(x[i, j]):
                    print('  - worker %i' % i)
            for k in all_tasks:
                if solver.BooleanValue(y[k, j]):
                    print('  - task %i with cost %i' % (k, task_cost[k]))
            print('  - sum_of_costs = %i' %
                  (solver.Value(scaled_sum_of_costs_in_group[j]) // scaling))
            print('  - average cost = %f' %
                  (solver.Value(averages[j]) * 1.0 / scaling))
Пример #17
0
def main():

    model = cp.CpModel()

    #
    # data
    #
    num_sets = 7
    num_elements = 12
    belongs = [
        # 1 2 3 4 5 6 7 8 9 0 1 2  elements
        [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],  # Set 1
        [0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0],  # 2
        [0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0],  # 3
        [0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0],  # 4
        [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0],  # 5
        [1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0],  # 6
        [0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1]  # 7
    ]

    #
    # variables
    #
    x = [model.NewIntVar(0, 1, 'x[%i]' % i) for i in range(num_sets)]

    # number of choosen sets
    z = model.NewIntVar(0, num_sets * 2, 'z')

    # total number of elements in the choosen sets
    tot_elements = model.NewIntVar(0, num_sets * num_elements, "tot_elements")

    #
    # constraints
    #
    model.Add(z == sum(x))

    # all sets must be used
    for j in range(num_elements):
        model.Add(sum([belongs[i][j] * x[i] for i in range(num_sets)]) >= 1)

    # number of used elements
    model.Add(tot_elements == sum([
        x[i] * belongs[i][j] for i in range(num_sets)
        for j in range(num_elements)
    ]))

    # objective
    model.Minimize(z)

    #
    # search and result
    #
    solver = cp.CpSolver()
    status = solver.Solve(model)

    if status == cp.OPTIMAL:
        print('z:', solver.Value(z))
        print('tot_elements:', solver.Value(tot_elements))
        print('x:', [solver.Value(x[i]) for i in range(num_sets)])

    print()
    print('NumConflicts:', solver.NumConflicts())
    print('NumBranches:', solver.NumBranches())
    print('WallTime:', solver.WallTime())
Пример #18
0
def main():
    # [START data]
    data = {}
    data['weights'] = [
        48, 30, 42, 36, 36, 48, 42, 42, 36, 24, 30, 30, 42, 36, 36
    ]
    data['values'] = [
        10, 30, 25, 50, 35, 30, 15, 40, 30, 35, 45, 10, 20, 30, 25
    ]
    assert len(data['weights']) == len(data['values'])
    data['num_items'] = len(data['weights'])
    data['all_items'] = range(data['num_items'])

    data['bin_capacities'] = [100, 100, 100, 100, 100]
    data['num_bins'] = len(data['bin_capacities'])
    data['all_bins'] = range(data['num_bins'])
    # [END data]

    # [START model]
    model = cp_model.CpModel()
    # [END model]

    # Variables.
    # [START variables]
    # x[i, b] = 1 if item i is packed in bin b.
    x = {}
    for i in data['all_items']:
        for b in data['all_bins']:
            x[i, b] = model.NewBoolVar(f'x_{i}_{b}')
    # [END variables]

    # Constraints.
    # [START constraints]
    # Each item is assigned to at most one bin.
    for i in data['all_items']:
        model.AddAtMostOne([x[i, b] for b in data['all_bins']])

    # The amount packed in each bin cannot exceed its capacity.
    for b in data['all_bins']:
        model.Add(
            sum(x[i, b] * data['weights'][i]
                for i in data['all_items']) <= data['bin_capacities'][b])
    # [END constraints]

    # Objective.
    # [START objective]
    # Maximize total value of packed items.
    objective = []
    for i in data['all_items']:
        for b in data['all_bins']:
            objective.append(
                cp_model.LinearExpr.Term(x[i, b], data['values'][i]))
    model.Maximize(cp_model.LinearExpr.Sum(objective))
    # [END objective]

    # [START solve]
    solver = cp_model.CpSolver()
    status = solver.Solve(model)
    # [END solve]

    # [START print_solution]
    if status == cp_model.OPTIMAL:
        print(f'Total packed value: {solver.ObjectiveValue()}')
        total_weight = 0
        for b in data['all_bins']:
            print(f'Bin {b}')
            bin_weight = 0
            bin_value = 0
            for i in data['all_items']:
                if solver.Value(x[i, b]) > 0:
                    print(
                        f"Item {i} weight: {data['weights'][i]} value: {data['values'][i]}"
                    )
                    bin_weight += data['weights'][i]
                    bin_value += data['values'][i]
            print(f'Packed bin weight: {bin_weight}')
            print(f'Packed bin value: {bin_value}\n')
            total_weight += bin_weight
        print(f'Total packed weight: {total_weight}')
    else:
        print('The problem does not have an optimal solution.')
Пример #19
0
def main():
  # Data.
  cost = [[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]]

  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

  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

  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

  sizes = [10, 7, 3, 12, 15, 4, 11, 5]
  total_size_max = 15
  num_workers = len(cost)
  num_tasks = len(cost[1])
  all_workers = range(num_workers)
  all_tasks = range(num_tasks)

  # Model.

  model = cp_model.CpModel()
  # Variables
  total_cost = model.NewIntVar(0, 1000, 'total_cost')
  x = [[model.NewBoolVar('x[%i,%i]' % (i, j))
        for j in all_tasks]
       for i in all_workers]
  works = [model.NewBoolVar('works[%i]' % i) for i in all_workers]

  # Constraints

  # Link x and workers.
  for i in range(num_workers):
    model.AddMaxEquality(works[i], x[i])

  # Each task is assigned to at least one worker.
  for j in all_tasks:
    model.Add(sum(x[i][j] for i in all_workers) >= 1)

  # Total task size for each worker is at most total_size_max
  for i in all_workers:
    model.Add(sum(sizes[j] * x[i][j] for j in all_tasks) <= total_size_max)

  # Group constraints.
  model.AddAllowedAssignments([works[0], works[1], works[2], works[3]], group1)
  model.AddAllowedAssignments([works[4], works[5], works[6], works[7]], group2)
  model.AddAllowedAssignments([works[8], works[9], works[10], works[11]],
                              group3)

  # Total cost
  model.Add(total_cost == sum(
      x[i][j] * cost[i][j] for j in all_tasks for i in all_workers))
  model.Minimize(total_cost)

  # Solve and output solution.
  solver = cp_model.CpSolver()
  status = solver.Solve(model)

  if status == cp_model.OPTIMAL:
    print('Total cost = %i' % solver.ObjectiveValue())
    print()
    for i in all_workers:
      for j in all_tasks:
        if solver.Value(x[i][j]) == 1:
          print('Worker ', i, ' assigned to task ', j, '  Cost = ', cost[i][j])

    print()

  print('Statistics')
  print('  - conflicts : %i' % solver.NumConflicts())
  print('  - branches  : %i' % solver.NumBranches())
  print('  - wall time : %f ms' % solver.WallTime())
Пример #20
0
def main():
    # Instantiate a cp model.
    cost = [[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]]

    sizes = [10, 7, 3, 12, 15, 4, 11, 5]
    total_size_max = 15
    num_workers = len(cost)
    num_tasks = len(cost[1])
    all_workers = range(num_workers)
    all_tasks = range(num_tasks)

    model = cp_model.CpModel()
    # Variables
    total_cost = model.NewIntVar(0, 1000, 'total_cost')
    x = []
    for i in all_workers:
        t = []
        for j in all_tasks:
            t.append(model.NewBoolVar('x[%i,%i]' % (i, j)))
        x.append(t)

    # Constraints

    # Each task is assigned to at least one worker.
    [model.Add(sum(x[i][j] for i in all_workers) >= 1) for j in all_tasks]

    # Total task size for each worker is at most total_size_max
    for i in all_workers:
        model.Add(sum(sizes[j] * x[i][j] for j in all_tasks) <= total_size_max)

    # Total cost
    model.Add(total_cost == sum(x[i][j] * cost[i][j] for j in all_tasks
                                for i in all_workers))
    model.Minimize(total_cost)

    solver = cp_model.CpSolver()
    status = solver.Solve(model)

    if status == cp_model.OPTIMAL:
        print('Total cost = %i' % solver.ObjectiveValue())
        print()
        for i in all_workers:
            for j in all_tasks:
                if solver.Value(x[i][j]) == 1:
                    print('Worker ', i, ' assigned to task ', j, '  Cost = ',
                          cost[i][j])

        print()

    print('Statistics')
    print('  - conflicts : %i' % solver.NumConflicts())
    print('  - branches  : %i' % solver.NumBranches())
    print('  - wall time : %f s' % solver.WallTime())
def solve_cutting_stock_with_arc_flow_and_sat(output_proto):
    """Solve the cutting stock with arc-flow and the CP-SAT solver."""
    items = regroup_and_count(DESIRED_LENGTHS)
    print('Items:', items)
    num_items = len(DESIRED_LENGTHS)

    max_capacity = max(POSSIBLE_CAPACITIES)
    states, transitions = create_state_graph(items, max_capacity)

    print('Dynamic programming has generated', len(states), 'states and',
          len(transitions), 'transitions')

    incoming_vars = collections.defaultdict(list)
    outgoing_vars = collections.defaultdict(list)
    incoming_sink_vars = []
    item_vars = collections.defaultdict(list)
    item_coeffs = collections.defaultdict(list)
    transition_vars = []

    model = cp_model.CpModel()

    objective_vars = []
    objective_coeffs = []

    for outgoing, incoming, item_index, card in transitions:
        count = items[item_index][1]
        max_count = count // card
        count_var = model.NewIntVar(
            0, max_count,
            'i%i_f%i_t%i_C%s' % (item_index, incoming, outgoing, card))
        incoming_vars[incoming].append(count_var)
        outgoing_vars[outgoing].append(count_var)
        item_vars[item_index].append(count_var)
        item_coeffs[item_index].append(card)
        transition_vars.append(count_var)

    for state_index, state in enumerate(states):
        if state_index == 0:
            continue
        exit_var = model.NewIntVar(0, num_items, 'e%i' % state_index)
        outgoing_vars[state_index].append(exit_var)
        incoming_sink_vars.append(exit_var)
        price = price_usage(state, POSSIBLE_CAPACITIES)
        objective_vars.append(exit_var)
        objective_coeffs.append(price)

    # Flow conservation
    for state_index in range(1, len(states)):
        model.Add(
            sum(incoming_vars[state_index]) == sum(outgoing_vars[state_index]))

    # Flow going out of the source must go in the sink
    model.Add(sum(outgoing_vars[0]) == sum(incoming_sink_vars))

    # Items must be placed
    for item_index, size_and_count in enumerate(items):
        num_arcs = len(item_vars[item_index])
        model.Add(
            sum(item_vars[item_index][i] * item_coeffs[item_index][i]
                for i in range(num_arcs)) == size_and_count[1])

    # Objective is the sum of waste
    model.Minimize(
        sum(objective_vars[i] * objective_coeffs[i]
            for i in range(len(objective_vars))))

    # Output model proto to file.
    if output_proto:
        output_file = open(output_proto, 'w')
        output_file.write(str(model.Proto()))
        output_file.close()

    # Solve model.
    solver = cp_model.CpSolver()
    solver.parameters.log_search_progress = True
    solver.parameters.num_search_workers = 8
    status = solver.Solve(model)
    print(solver.ResponseStats())
Пример #22
0
def solve_hidato(puzzle, index):
    """Solve the given hidato table."""
    # Create the model.
    model = cp_model.CpModel()

    r = len(puzzle)
    c = len(puzzle[0])
    if not visualization.RunFromIPython():
        print('')
        print('----- Solving problem %i -----' % index)
        print('')
        print(('Initial game (%i x %i)' % (r, c)))
        print_matrix(puzzle)

    #
    # declare variables
    #
    positions = [
        model.NewIntVar(0, r * c - 1, 'p[%i]' % i) for i in range(r * c)
    ]

    #
    # constraints
    #
    model.AddAllDifferent(positions)

    #
    # Fill in the clues
    #
    for i in range(r):
        for j in range(c):
            if puzzle[i][j] > 0:
                model.Add(positions[puzzle[i][j] - 1] == i * c + j)

    # Consecutive numbers much touch each other in the grid.
    # We use an allowed assignment constraint to model it.
    close_tuples = build_pairs(r, c)
    for k in range(0, r * c - 1):
        model.AddAllowedAssignments([positions[k], positions[k + 1]],
                                    close_tuples)

    #
    # solution and search
    #

    solver = cp_model.CpSolver()
    status = solver.Solve(model)

    if status == cp_model.FEASIBLE:
        if visualization.RunFromIPython():
            output = visualization.SvgWrapper(10, r, 40.0)
            for i, var in enumerate(positions):
                val = solver.Value(var)
                x = val % c
                y = val // c
                color = 'white' if puzzle[y][x] == 0 else 'lightgreen'
                output.AddRectangle(x, r - y - 1, 1, 1, color, 'black',
                                    str(i + 1))

            output.AddTitle('Puzzle %i solved in %f s' %
                            (index, solver.WallTime()))
            output.Display()
        else:
            print_solution(
                [solver.Value(x) for x in positions],
                r,
                c,
            )
            print('Statistics')
            print('  - conflicts : %i' % solver.NumConflicts())
            print('  - branches  : %i' % solver.NumBranches())
            print('  - wall time : %f s' % solver.WallTime())
Пример #23
0
def main():

  model = cp.CpModel()

  #
  # data
  #
  n = 7

  #
  # variables
  #
  X = [model.NewIntVar(0, 10, "X(%i)" % i) for i in range(n)]
  X0, X1, X2, X3, X4, X5, X6 = X

  #
  # constraints
  #
  model.Add(-76706 * X0 + 98205 * X1 + 23445 * X2 + 67921 * X3 + 24111 * X4 +
             -48614 * X5 + -41906 * X6 == 821228)
  model.Add(87059 * X0 + -29101 * X1 + -5513 * X2 + -21219 * X3 + 22128 * X4 +
             7276 * X5 + 57308 * X6 == 22167)
  model.Add(-60113 * X0 + 29475 * X1 + 34421 * X2 + -76870 * X3 + 62646 * X4 +
             29278 * X5 + -15212 * X6 == 251591)
  model.Add(49149 * X0 + 52871 * X1 + -7132 * X2 + 56728 * X3 + -33576 * X4 +
             -49530 * X5 + -62089 * X6 == 146074)
  model.Add(-10343 * X0 + 87758 * X1 + -11782 * X2 + 19346 * X3 + 70072 * X4 +
             -36991 * X5 + 44529 * X6 == 740061)
  model.Add(85176 * X0 + -95332 * X1 + -1268 * X2 + 57898 * X3 + 15883 * X4 +
             50547 * X5 + 83287 * X6 == 373854)
  model.Add(-85698 * X0 + 29958 * X1 + 57308 * X2 + 48789 * X3 + -78219 * X4 +
             4657 * X5 + 34539 * X6 == 249912)
  model.Add(-67456 * X0 + 84750 * X1 + -51553 * X2 + 21239 * X3 + 81675 * X4 +
             -99395 * X5 + -4254 * X6 == 277271)
  model.Add(94016 * X0 + -82071 * X1 + 35961 * X2 + 66597 * X3 + -30705 * X4 +
             -44404 * X5 + -38304 * X6 == 25334)
  model.Add(-60301 * X0 + 31227 * X1 + 93951 * X2 + 73889 * X3 + 81526 * X4 +
             -72702 * X5 + 68026 * X6 == 1410723)
  model.Add(-16835 * X0 + 47385 * X1 + 97715 * X2 + -12640 * X3 + 69028 * X4 +
             76212 * X5 + -81102 * X6 == 1244857)
  model.Add(-43277 * X0 + 43525 * X1 + 92298 * X2 + 58630 * X3 + 92590 * X4 +
             -9372 * X5 + -60227 * X6 == 1503588)
  model.Add(-64919 * X0 + 80460 * X1 + 90840 * X2 + -59624 * X3 + -75542 * X4 +
             25145 * X5 + -47935 * X6 == 18465)
  model.Add(-45086 * X0 + 51830 * X1 + -4578 * X2 + 96120 * X3 + 21231 * X4 +
             97919 * X5 + 65651 * X6 == 1198280)
  model.Add(85268 * X0 + 54180 * X1 + -18810 * X2 + -48219 * X3 + 6013 * X4 +
             78169 * X5 + -79785 * X6 == 90614)
  model.Add(8874 * X0 + -58412 * X1 + 73947 * X2 + 17147 * X3 + 62335 * X4 +
             16005 * X5 + 8632 * X6 == 752447)
  model.Add(71202 * X0 + -11119 * X1 + 73017 * X2 + -38875 * X3 + -14413 * X4 +
             -29234 * X5 + 72370 * X6 == 129768)
  model.Add(1671 * X0 + -34121 * X1 + 10763 * X2 + 80609 * X3 + 42532 * X4 +
             93520 * X5 + -33488 * X6 == 915683)
  model.Add(51637 * X0 + 67761 * X1 + 95951 * X2 + 3834 * X3 + -96722 * X4 +
             59190 * X5 + 15280 * X6 == 533909)
  model.Add(-16105 * X0 + 62397 * X1 + -6704 * X2 + 43340 * X3 + 95100 * X4 +
             -68610 * X5 + 58301 * X6 == 876370)

  #
  # search and result
  #
  solver = cp.CpSolver()
  status = solver.Solve(model)

  if status == cp.OPTIMAL:
    print("X:", [solver.Value(X[i]) for i in range(n)])
    print()

  print()
  print("NumConflicts:", solver.NumConflicts())
  print("NumBranches:", solver.NumBranches())
  print("WallTime:", solver.WallTime())
Пример #24
0
    def dispatch_jobs_to_slots(self, worker_slots={}, jobs=[]):
        """Assign jobs to worker_slots."""
        num_slots = len(worker_slots)
        num_jobs = len(jobs)

        # All durations are in minutes.
        # max_onsite_time = 10*60 #  660 # 108  # 8 hours. / 5 *num_slots This is per worker.
        # max_shift_time = 4*60  # 60*10
        min_lunch_break_minutes = 30
        min_delay_between_jobs = 2  # 2
        # extra_time = 5
        # min_working_time = 390  # 6.5 hours

        # worker_start_time = 1+ 0*60 # 8:00
        # worker_end_time = 24*60
        # total_worker_minutes = ( worker_end_time - worker_start_time ) * num_slots

        MAX_TRAVEL_MINUTE = 600  # 2 * 24 * 60  # 24 hours in one day.

        # MIN_START_MINUTE = min([slot.start_minutes for slot in worker_slots])
        # MAX_START_MINUTE = max([slot.end_minutes for slot in worker_slots])

        # START_TIME_BASE = MIN_START_MINUTE
        MIN_START_MINUTE = 0
        MAX_START_MINUTE = 400  # MAX_START_MINUTE - START_TIME_BASE

        # Computed statistics.
        all_jobs_total_working_time = sum(
            [jobs[j].requested_duration_minutes for j in range(1, num_jobs)])

        random_total_travel_time = sum([
            self._get_travel_time_2locations(jobs[shift - 1].location,
                                             jobs[shift].location)
            for shift in range(1, num_jobs)
        ])

        print("num worker_slots: ", num_slots, ", num_jobs: ", num_jobs)
        # print('worker_start_time: ', worker_start_time ,'worker_end_time: ', worker_end_time  )
        print("all_jobs_total_working_time: ", all_jobs_total_working_time)
        print("random_total_travel_time: ", random_total_travel_time)
        # print("total worker_slots time:", sum([1]))
        # We are going to build a flow from a the start of the day to the end
        # of the day.
        #
        # Along the path, we will accumulate travel time

        model = cp_model.CpModel()

        # Per node info

        incoming_literals = collections.defaultdict(list)
        outgoing_literals = collections.defaultdict(list)
        outgoing_other_job_index = []

        # emp_job_literals [job] = [worker_n_lit, ....]
        workers_assigned2_job_literals = collections.defaultdict(list)
        travel_time_per_emp_sum_dict = {}  # TODO

        # incoming_sink_literals = []
        # outgoing_source_literals = []

        # new_start_time = []
        # Create all the shift variables before iterating on the transitions
        # between these shifts.
        total_travel_until_emp = {}

        shift_start_time_dict = {}
        travel_time_until_job = {}
        source_lit_dict = {}
        sink_lit_dict = {}
        total_travel_until_emp[-1] = model.NewIntVar(
            0, 0, "total_travel until emp {}".format("init"))

        for ei in range(num_slots):
            source_lit_dict[ei] = {}
            sink_lit_dict[ei] = {}
            travel_time_per_emp_sum_dict[ei] = model.NewIntVar(
                0, MAX_TRAVEL_MINUTE,
                "total_travel time for emp {}".format(ei))
            total_travel_until_emp[ei] = model.NewIntVar(
                0, MAX_TRAVEL_MINUTE * (ei + 1),
                "total_travel for emp {}".format(ei))

            # To chain and  accumulate all travel times for each employee
            model.Add(
                total_travel_until_emp[ei] == total_travel_until_emp[ei - 1] +
                travel_time_per_emp_sum_dict[ei])
        # total traval (travel_time_final_total) is the last one
        travel_time_final_total = model.NewIntVar(
            0, num_slots * int(MAX_TRAVEL_MINUTE * 1),
            "total_travel for  - {}".format("all"))
        model.Add(travel_time_final_total == total_travel_until_emp[num_slots -
                                                                    1])

        # Not sure why sum() does not work!!! sum(travel_time_per_emp_sum_dict)
        """
        model.Add(travel_time_final_total == travel_time_per_emp_sum_dict[0] + travel_time_per_emp_sum_dict[1] \
                + travel_time_per_emp_sum_dict[2] + travel_time_per_emp_sum_dict[3]     \
                + travel_time_per_emp_sum_dict[4] + travel_time_per_emp_sum_dict[5]     \
                )
        """

        # other_start_time_dict = {}

        for shift in range(num_jobs):
            #
            if jobs[shift].job_schedule_type != JobScheduleType.NORMAL:
                shift_start_time_dict[shift] = model.NewIntVar(
                    jobs[shift].requested_start_min_minutes,
                    jobs[shift].requested_start_max_minutes,
                    "start_time_shift_%i" % shift,
                )
            else:
                shift_start_time_dict[shift] = model.NewIntVar(
                    MIN_START_MINUTE, MAX_START_MINUTE,
                    "start_time_shift_%i" % shift)

            # if jobs[shift]['job_schedule_type'] == 'FS':
            #    model.Add( shift_start_time_dict[shift] ==  jobs[shift]['requested_start_minutes'] )

            travel_time_until_job[shift] = model.NewIntVar(
                1, MAX_TRAVEL_MINUTE, "travel_time_until_shift_%i" % shift)
            outgoing_other_job_index.append([])
            for ei in range(num_slots):

                source_lit_dict[ei][shift] = model.NewBoolVar(
                    "from emp {} source to job {}".format(ei, shift))
                # Arc from source worker to this job
                incoming_literals[shift].append(source_lit_dict[ei][shift])

                # If this job[shift] is first job for worker[ei], travel time on this job is from home to job.
                model.Add(travel_time_until_job[shift] ==
                          self._get_travel_time_2locations(
                              worker_slots[ei].start_location,
                              jobs[shift].location)).OnlyEnforceIf(
                                  source_lit_dict[ei][shift])

                sink_lit_dict[ei][shift] = model.NewBoolVar(
                    "from  job {} sink to emp {} ".format(shift, ei))
                # Arc from job to sinking_worker.
                outgoing_literals[shift].append(sink_lit_dict[ei][shift])
                outgoing_other_job_index[shift].append("worker_{}".format(ei))

                # If this job[shift] is the last job for worker[ei], travel_time_per_emp_sum_dict (total) is the travel time on this job is from job to home.
                model.Add(
                    travel_time_per_emp_sum_dict[ei] ==
                    travel_time_until_job[shift] +
                    self._get_travel_time_2locations(
                        worker_slots[ei].end_location, jobs[shift].location)
                ).OnlyEnforceIf(sink_lit_dict[ei][shift])

                model.Add(shift_start_time_dict[shift] <= int(
                    worker_slots[ei].end_minutes -
                    worker_slots[ei].start_minutes -  # Monday
                    jobs[shift].requested_duration_minutes +
                    self._get_travel_time_2locations(
                        worker_slots[ei].end_location, jobs[shift].location))
                          ).OnlyEnforceIf(sink_lit_dict[ei][shift])

                emp_on_job_lit = model.NewBoolVar(
                    "path Emp {} on job {}".format(ei, shift))
                # # ordered by worker_index
                workers_assigned2_job_literals[shift].append(emp_on_job_lit)

                # # job must obey Start time for worker, if assigned to this worker
                # # TODO, only 1 day for now, [0]
                # model.Add(
                #     shift_start_time_dict[shift] >= worker_slots[ei].start_minutes
                # ).OnlyEnforceIf(emp_on_job_lit)
                # #
                # # job must obey end time for worker, if assigned to this worker
                # model.Add(
                #     shift_start_time_dict[shift]
                #     <= int(
                #         worker_slots[ei].end_minutes  # Monday
                #         - jobs[shift].requested_duration_minutes
                #     )
                # ).OnlyEnforceIf(emp_on_job_lit)

                # If source or sink, it is on this emp.
                model.Add(emp_on_job_lit == 1).OnlyEnforceIf(
                    sink_lit_dict[ei][shift])
                model.Add(emp_on_job_lit == 1).OnlyEnforceIf(
                    source_lit_dict[ei][shift])

                if (jobs[shift].job_code in config.DEBUGGING_JOB_CODE_SET
                    ) and (worker_slots[ei].worker_id == "Tom"):
                    log.debug(f"debug {jobs[shift].job_code}")
                if (worker_slots[ei].worker_id,
                    ) not in jobs[shift].searching_worker_candidates:
                    model.Add(source_lit_dict[ei][shift] == 0)
                    model.Add(sink_lit_dict[ei][shift] == 0)
                    model.Add(emp_on_job_lit == 0)

        for shift in range(num_jobs):

            duration = jobs[shift].requested_duration_minutes

            for ei in range(num_slots):
                pass
                # outgoing_source_literals.append(source_lit_dict[ei][shift])

                # Arc from source to shift.
                # incoming_sink_literals.append(sink_lit_dict[ei][shift])

            for other in range(num_jobs):
                if shift == other:
                    continue
                other_duration = jobs[other].requested_duration_minutes
                lit = model.NewBoolVar("job path from %i to %i" %
                                       (shift, other))

                # constraint for start time by duan 2019-10-09 16:58:42  #### + jobs[shift]['requested_duration_minutes'] + min_delay_between_shifts
                # fmt: off
                model.Add(
                    shift_start_time_dict[shift] +
                    int(jobs[shift].requested_duration_minutes) +
                    min_delay_between_jobs + self._get_travel_time_2locations(
                        jobs[shift].location, jobs[other].location) <
                    shift_start_time_dict[other]).OnlyEnforceIf(lit)
                # fmt: on

                # Increase travel time
                model.Add(travel_time_until_job[other] ==
                          travel_time_until_job[shift] +
                          self._get_travel_time_2locations(
                              jobs[shift].location, jobs[other].location)
                          ).OnlyEnforceIf(lit)

                # Make sure that for one flow path, all jobs belong to one worker 2020-01-07 12:59:21
                for ei in range(num_slots):
                    model.Add(workers_assigned2_job_literals[other][ei] ==
                              workers_assigned2_job_literals[shift]
                              [ei]).OnlyEnforceIf(lit)

                # Add arc
                outgoing_literals[shift].append(lit)
                outgoing_other_job_index[shift].append("job_{}".format(other))
                incoming_literals[other].append(lit)

        # Create dag constraint.
        for shift in range(num_jobs):
            model.Add(sum(outgoing_literals[shift]) == 1)
            model.Add(sum(incoming_literals[shift]) == 1)

        # <= 1 makes it possible to leave some worker_slots idle.
        for ei in range(num_slots):
            emp_lits = []
            for ii in range(num_jobs):
                emp_lits.append(source_lit_dict[ei][ii])
            model.Add(sum(emp_lits) == 1)

        for ei in range(num_slots):
            emp_lits = []
            for ii in range(num_jobs):
                emp_lits.append(sink_lit_dict[ei][ii])
            model.Add(sum(emp_lits) == 1)

        model.Minimize(travel_time_final_total)

        # Solve model.
        solver = cp_model.CpSolver()
        solver.parameters.log_search_progress = self.config[
            "log_search_progress"]
        # solver.parameters.num_search_workers = 4
        # https://developers.google.com/optimization/cp/cp_tasks
        solver.parameters.max_time_in_seconds = self.config[
            "max_exec_time"]  # two minutes
        status = solver.Solve(model)

        if status == cp_model.INFEASIBLE:
            print("SufficientAssumptionsForInfeasibility = "
                  f"{solver.SufficientAssumptionsForInfeasibility()}")
            return []

        if status != cp_model.OPTIMAL and status != cp_model.FEASIBLE:  #
            print("Status = %s, failed." % solver.StatusName(status))
            return []

        optimal_travel_time = int(solver.ObjectiveValue())
        print("optimal_travel_time =", optimal_travel_time)

        all_following_tasks = {}
        emp_following_tasks = {}
        """
        for ei in range(num_slots):
            print("w_{}_{}: {}, hasta {}".format(
                ei,
                worker_slots[ei]['worker_code'],
                solver.Value( travel_time_per_emp_sum_dict[ei]),
                solver.Value( total_travel_until_emp[ei])
                )
            )
        for ei in range(num_jobs):
            print("j_{} : {},  travel {}, start: {}".format(
                ei,
                jobs[ei]['requested_duration_minutes'],
                solver.Value(travel_time_until_job[ei] ) ,
                solver.Value( shift_start_time_dict [ei])
                )
            )
        """
        for shift in range(num_jobs):
            if shift == 7:
                pass
                # print("pause")
            for ii in range(len(outgoing_literals[shift])):
                if solver.Value(outgoing_literals[shift][ii]) == 1:
                    # print(
                    #     "job_",
                    #     shift,
                    #     f"({jobs[shift].job_code})--> ",
                    #     outgoing_other_job_index[shift][ii],
                    # )
                    # TODO make it a list for multiple worker_slots on same job
                    # 0 means this is a job, 1 is ending at worker
                    all_following_tasks[shift] = outgoing_other_job_index[
                        shift][ii].split("_")
            for ei in range(num_slots):
                if solver.Value(source_lit_dict[ei][shift]) == 1:
                    # print("worker:", ei, f"({worker_slots[ei].worker_id})--> job_", shift)
                    emp_following_tasks[ei] = ["job", shift]

        # j_file.write('')
        to_print_json_list = []
        for _ in range(num_slots):
            to_print_json_list.append([])
        for ei in emp_following_tasks.keys():
            my_next_node = emp_following_tasks[ei]
            prev_node = my_next_node
            while my_next_node[0] == "job":
                shift = int(my_next_node[1])
                to_print_json_list[ei].append([
                    shift,
                    solver.Value(shift_start_time_dict[shift]),
                    self._get_travel_time_2locations(
                        jobs[int(prev_node[1])].location,
                        jobs[shift].location),
                    jobs[shift].requested_duration_minutes,
                ])
                prev_node = my_next_node
                my_next_node = all_following_tasks[shift]
            to_print_json_list[ei].append([
                -1,
                -2,
                self._get_travel_time_2locations(
                    worker_slots[ei].start_location, jobs[shift].location),
                -4,
            ])
        """
        print(to_print_json_list)

        """
        for ei in range(num_slots):
            print(
                "worker:",
                ei,
                f"({worker_slots[ei].worker_id}) --> ",
                [(
                    to_print_json_list[ei][si][0],
                    f"({jobs[ to_print_json_list[ei][si][0] ].job_code})",
                    to_print_json_list[ei][si][1],
                ) for si in range(len(to_print_json_list[ei]) - 1)],
            )

        return to_print_json_list
Пример #25
0
from ortools.sat.python import cp_model

budget = 10000
numb_worker = 1200
area = 110

model = cp_model.CpModel()

# Define variables
corn = model.NewIntVar(0, area + 1, 'X')
barley = model.NewIntVar(0, area + 1, 'Y')

# Define constraints
model.Add(100 * corn + 200 * barley <= budget)
model.Add(10 * corn + 30 * barley <= numb_worker)
model.Add(corn + barley <= area)

# objective function
model.Maximize(50 * corn + 120 * barley)

# Solve
solver = cp_model.CpSolver()
status = solver.Solve(model)

if status == cp_model.OPTIMAL:
    print('Maximum of objective function: %i' % solver.ObjectiveValue())
    print()
    print('corn value : ', solver.Value(corn))
    print('barley value: ', solver.Value(barley))
Пример #26
0
 def __init__(self):
     self.model = cp_model.CpModel()
     self.solver = cp_model.CpSolver()
     self.grid_size = 9
     self.cell_size = 3
Пример #27
0
def solve_zebra():
    """Solves the zebra problem."""

    # Create the model.
    model = cp_model.CpModel()

    red = model.NewIntVar(1, 5, 'red')
    green = model.NewIntVar(1, 5, 'green')
    yellow = model.NewIntVar(1, 5, 'yellow')
    blue = model.NewIntVar(1, 5, 'blue')
    ivory = model.NewIntVar(1, 5, 'ivory')

    englishman = model.NewIntVar(1, 5, 'englishman')
    spaniard = model.NewIntVar(1, 5, 'spaniard')
    japanese = model.NewIntVar(1, 5, 'japanese')
    ukrainian = model.NewIntVar(1, 5, 'ukrainian')
    norwegian = model.NewIntVar(1, 5, 'norwegian')

    dog = model.NewIntVar(1, 5, 'dog')
    snails = model.NewIntVar(1, 5, 'snails')
    fox = model.NewIntVar(1, 5, 'fox')
    zebra = model.NewIntVar(1, 5, 'zebra')
    horse = model.NewIntVar(1, 5, 'horse')

    tea = model.NewIntVar(1, 5, 'tea')
    coffee = model.NewIntVar(1, 5, 'coffee')
    water = model.NewIntVar(1, 5, 'water')
    milk = model.NewIntVar(1, 5, 'milk')
    fruit_juice = model.NewIntVar(1, 5, 'fruit juice')

    old_gold = model.NewIntVar(1, 5, 'old gold')
    kools = model.NewIntVar(1, 5, 'kools')
    chesterfields = model.NewIntVar(1, 5, 'chesterfields')
    lucky_strike = model.NewIntVar(1, 5, 'lucky strike')
    parliaments = model.NewIntVar(1, 5, 'parliaments')

    model.AddAllDifferent([red, green, yellow, blue, ivory])
    model.AddAllDifferent(
        [englishman, spaniard, japanese, ukrainian, norwegian])
    model.AddAllDifferent([dog, snails, fox, zebra, horse])
    model.AddAllDifferent([tea, coffee, water, milk, fruit_juice])
    model.AddAllDifferent(
        [parliaments, kools, chesterfields, lucky_strike, old_gold])

    model.Add(englishman == red)
    model.Add(spaniard == dog)
    model.Add(coffee == green)
    model.Add(ukrainian == tea)
    model.Add(green == ivory + 1)
    model.Add(old_gold == snails)
    model.Add(kools == yellow)
    model.Add(milk == 3)
    model.Add(norwegian == 1)

    diff_fox_chesterfields = model.NewIntVar(-4, 4, 'diff_fox_chesterfields')
    model.Add(diff_fox_chesterfields == fox - chesterfields)
    model.AddAbsEquality(1, diff_fox_chesterfields)

    diff_horse_kools = model.NewIntVar(-4, 4, 'diff_horse_kools')
    model.Add(diff_horse_kools == horse - kools)
    model.AddAbsEquality(1, diff_horse_kools)

    model.Add(lucky_strike == fruit_juice)
    model.Add(japanese == parliaments)

    diff_norwegian_blue = model.NewIntVar(-4, 4, 'diff_norwegian_blue')
    model.Add(diff_norwegian_blue == norwegian - blue)
    model.AddAbsEquality(1, diff_norwegian_blue)

    # Solve and print out the solution.
    solver = cp_model.CpSolver()
    status = solver.Solve(model)

    if status == cp_model.OPTIMAL:
        people = [englishman, spaniard, japanese, ukrainian, norwegian]
        water_drinker = [
            p for p in people if solver.Value(p) == solver.Value(water)
        ][0]
        zebra_owner = [
            p for p in people if solver.Value(p) == solver.Value(zebra)
        ][0]
        print('The', water_drinker.Name(), 'drinks water.')
        print('The', zebra_owner.Name(), 'owns the zebra.')
    else:
        print('No solutions to the zebra problem, this is unusual!')
Пример #28
0
def solve_shift_scheduling(params, output_proto, num_employees, num_weeks, shifts, fixed_assignments, requests,
    weekly_cover_demands):
    """Solves the shift scheduling problem."""
    # Data
    #num_employees = 8
    #num_weeks = 3
    #shifts = ['O', 'M', 'A', 'N']

    # Fixed assignment: (employee, shift, day).
    # This fixes the first 2 days of the schedule.
    '''fixed_assignments = [
        (0, 0, 0),
        (1, 0, 0),
        (2, 1, 0),
        (3, 1, 0),
        (4, 2, 0),
        (5, 2, 0),
        (6, 2, 3),
        (7, 3, 0),
        (0, 1, 1),
        (1, 1, 1),
        (2, 2, 1),
        (3, 2, 1),
        (4, 2, 1),
        (5, 0, 1),
        (6, 0, 1),
        (7, 3, 1),
    ]'''

    # Request: (employee, shift, day, weight)
    # A negative weight indicates that the employee desire this assignment.
    '''requests = [
        # Employee 3 wants the first Saturday off.
        (3, 0, 5, -2),
        # Employee 5 wants a night shift on the second Thursday.
        (5, 3, 10, -2),
        # Employee 2 does not want a night shift on the first Friday.
        (2, 3, 4, 4)
    ]'''

    # Shift constraints on continuous sequence :
    #     (shift, hard_min, soft_min, min_penalty,
    #             soft_max, hard_max, max_penalty)
    shift_constraints = [
        # One or two consecutive days of rest, this is a hard constraint.
        (0, 1, 1, 0, 7, 7, 0),
        # betweem 2 and 3 consecutive days of night shifts, 1 and 4 are
        # possible but penalized.
        #(2, 1, 2, 20, 2, 4, 5),
    ]

    # Weekly sum constraints on shifts days:
    #     (shift, hard_min, soft_min, min_penalty,
    #             soft_max, hard_max, max_penalty)
    weekly_sum_constraints = [
        # Constraints on rests per week.
        (0, 1, 2, 7, 7, 7, 0),
        # At least 1 night shift per week (penalized). At most 4 (hard).
        #(2, 0, 0, 2, 4, 4, 0),
    ]

    # Penalized transitions:
    #     (previous_shift, next_shift, penalty (0 means forbidden))
    penalized_transitions = [
        # Afternoon to night has a penalty of 4.
        #(1, 2, 4),
        # Night to morning is forbidden.
        #(2, 1, 0),
    ]

    # daily demands for work shifts (morning, afternon, night) for each day
    # of the week starting on Monday.
    '''weekly_cover_demands = [
        [0],[1],[0],[0],[0],[0],[0]
    ]'''

    # Penalty for exceeding the cover constraint per shift type.
    excess_cover_penalties = tuple([1000]*(len(shifts)-1))

    num_days = num_weeks * 7
    num_shifts = len(shifts)

    model = cp_model.CpModel()

    work = {}
    for e in range(num_employees):
        for s in range(num_shifts):
            for d in range(num_days):
                work[e, s, d] = model.NewBoolVar('work%i_%i_%i' % (e, s, d))

    # Linear terms of the objective in a minimization context.
    obj_int_vars = []
    obj_int_coeffs = []
    obj_bool_vars = []
    obj_bool_coeffs = []

    # Exactly one shift per day.
    for e in range(num_employees):
        for d in range(num_days):
            model.Add(sum(work[e, s, d] for s in range(num_shifts)) == 1)

    # Fixed assignments.
    for e, s, d in fixed_assignments:
        model.Add(work[e, s, d] == 1)

    # Employee requests
    for e, s, d, w in requests:
        obj_bool_vars.append(work[e, s, d])
        obj_bool_coeffs.append(w)

    # Shift constraints
    for ct in shift_constraints:
        shift, hard_min, soft_min, min_cost, soft_max, hard_max, max_cost = ct
        for e in range(num_employees):
            works = [work[e, shift, d] for d in range(num_days)]
            variables, coeffs = add_soft_sequence_constraint(
                model, works, hard_min, soft_min, min_cost, soft_max, hard_max,
                max_cost, 'shift_constraint(employee %i, shift %i)' % (e,
                                                                       shift))
            obj_bool_vars.extend(variables)
            obj_bool_coeffs.extend(coeffs)

    # Weekly sum constraints
    for ct in weekly_sum_constraints:
        shift, hard_min, soft_min, min_cost, soft_max, hard_max, max_cost = ct
        for e in range(num_employees):
            for w in range(num_weeks):
                works = [work[e, shift, d + w * 7] for d in range(7)]
                variables, coeffs = add_soft_sum_constraint(
                    model, works, hard_min, soft_min, min_cost, soft_max,
                    hard_max, max_cost,
                    'weekly_sum_constraint(employee %i, shift %i, week %i)' %
                    (e, shift, w))
                obj_int_vars.extend(variables)
                obj_int_coeffs.extend(coeffs)

    # Penalized transitions
    for previous_shift, next_shift, cost in penalized_transitions:
        for e in range(num_employees):
            for d in range(num_days - 1):
                transition = [
                    work[e, previous_shift, d].Not(),
                    work[e, next_shift, d + 1].Not()
                ]
                if cost == 0:
                    model.AddBoolOr(transition)
                else:
                    trans_var = model.NewBoolVar(
                        'transition (employee=%i, day=%i)' % (e, d))
                    transition.append(trans_var)
                    model.AddBoolOr(transition)
                    obj_bool_vars.append(trans_var)
                    obj_bool_coeffs.append(cost)

    # Cover constraints
    for s in range(1, num_shifts):
        for w in range(num_weeks):
            for d in range(7):
                works = [work[e, s, w * 7 + d] for e in range(num_employees)]
                # Ignore Off shift.
                min_demand = weekly_cover_demands[d][s - 1]
                worked = model.NewIntVar(min_demand, num_employees, '')
                model.Add(worked == sum(works))
                over_penalty = excess_cover_penalties[s - 1]
                if over_penalty > 0:
                    name = 'excess_demand(shift=%i, week=%i, day=%i)' % (s, w,
                                                                         d)
                    excess = model.NewIntVar(0, num_employees - min_demand,
                                             name)
                    model.Add(excess == worked - min_demand)
                    obj_int_vars.append(excess)
                    obj_int_coeffs.append(over_penalty)

    # Objective
    model.Minimize(
        sum(obj_bool_vars[i] * obj_bool_coeffs[i]
            for i in range(len(obj_bool_vars)))
        + sum(obj_int_vars[i] * obj_int_coeffs[i]
              for i in range(len(obj_int_vars))))

    if output_proto:
        print('Writing proto to %s' % output_proto)
        with open(output_proto, 'w') as text_file:
            text_file.write(str(model))

    # Solve the model.
    solver = cp_model.CpSolver()
    solver.parameters.num_search_workers = 8
    if params:
        text_format.Merge(params, solver.parameters)
    solution_printer = cp_model.ObjectiveSolutionPrinter()
    status = solver.SolveWithSolutionCallback(model, solution_printer)

    # Print solution.
    employee_dict = {}
    if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE:
        print()
        header = '          '
        for w in range(num_weeks):
            header += 'M T W T F S S '
        print(header)
        for e in range(num_employees):
            schedule = ''
            schedulelist=[]
            for d in range(num_days):
                for s in range(num_shifts):
                    if solver.BooleanValue(work[e, s, d]):
                        schedule += shifts[s] + ' '
                        schedulelist.append(shifts[s])
            print('worker %i: %s' % (e, schedule))
            employee_dict[e] = schedulelist
        print()
        print('Penalties:')
        for i, var in enumerate(obj_bool_vars):
            if solver.BooleanValue(var):
                penalty = obj_bool_coeffs[i]
                if penalty > 0:
                    print('  %s violated, penalty=%i' % (var.Name(), penalty))
                else:
                    print('  %s fulfilled, gain=%i' % (var.Name(), -penalty))

        for i, var in enumerate(obj_int_vars):
            if solver.Value(var) > 0:
                print('  %s violated by %i, linear penalty=%i' %
                      (var.Name(), solver.Value(var), obj_int_coeffs[i]))

    #print()
    print(solver.ResponseStats())
    return(employee_dict)
Пример #29
0
def channeling_example():

    # Create the model.
    # the_model is an object created by cp_model method from  CpModel class
    the_model = cp_model.CpModel()  # 'Channeling Example')

    #
    # data
    #
    n = 3  # a constant ... not var

    #
    # Creating CP variables
    #
    vetor_BOOL = [the_model.NewBoolVar('vetor_BOOL[%i]' % i) for i in range(n)]
    # bool_var_array

    # Other vars in the_model created by the method NewIntVar
    x = the_model.NewIntVar(0, 10, 'x')
    y = the_model.NewIntVar(0, 10, 'y')
    z = the_model.NewIntVar(0, 10, 'z')
    # NewIntVar(self, lb, ub, name)
    #
    # constraints
    #
    ###
    # x >= 5 and x < 10 then write as:
    the_model.Add(x >= 5) 
    the_model.Add(x < 10)
    ###the_model.Add(y >= 8 and y <= 10)  .... NOT WORKS
    the_model.Add(y > 8) . OnlyEnforceIf ( vetor_BOOL[1] ) 
    the_model.Add( y <= 10 ) . OnlyEnforceIf (vetor_BOOL[1].Not()  ) 
    the_model.Add(z > 7)
    the_model.Add((vetor_BOOL[0] and vetor_BOOL[1] and vetor_BOOL[2]) == True) #### NOT WORKS
    the_model.Add(sum(vetor_BOOL) > 1)
    
    #
    # search and result
    # Search for x values in increasing order.
    the_model.AddDecisionStrategy(vetor_BOOL, cp_model.CHOOSE_FIRST,
                              cp_model.SELECT_MIN_VALUE)
    ## Very interesting Decision Strategy 
    #
    # Create a solver and solve with a fixed search.
    solver = cp_model.CpSolver()
    #solver.parameters.max_time_in_seconds = 10.0
    status = solver.Solve(the_model)
    ### 
    #values_vetor_BOOL = [solver.Value(vetor_BOOL[i]) for i in range(n)]    
    ### VERY BIZARRE
    if (status == cp_model.FEASIBLE):
      print_output_VARS(solver.Value(x), solver.Value(y), solver.Value(z), 
                        [solver.Value(vetor_BOOL[i]) for i in range(n)])
    else:
      print ("NOT OK: ", solver.StatusName(status))
      return

    #print('vetor_BOOL:', [solver.Value(vetor_BOOL[i]) for i in range(n)])

    print('\n\n** Final Statistics **')
    print('  - conflicts : %i' % solver.NumConflicts())
    print('  - branches  : %i' % solver.NumBranches())
    print('  - wall time : %f s' % solver.WallTime())
    print("\n END SOLVER ===================================")
Пример #30
0
def main():

    model = cp.CpModel()

    n = 4

    perms = ["+2", "/8", "-3", "*7"]

    # ages 16..120
    age_low = 16
    age_high = 120

    # variables
    m = model.NewIntVar(age_low, age_high, "m")  # my age
    h = model.NewIntVar(age_low, age_high, "h")  # my age

    perm1 = [model.NewIntVar(0, n - 1, "perm1") for i in range(n)]
    perm2 = [model.NewIntVar(0, n - 1, "perm2") for i in range(n)]

    # for calculating my age
    mlist = [model.NewIntVar(0, 1000, "perm2") for i in range(n + 1)]
    # for calculating husbands age
    hlist = [model.NewIntVar(0, 1000, "perm2") for i in range(n + 1)]

    # constraints
    model.AddAllDifferent(perm1)
    model.AddAllDifferent(perm2)

    # same operations in different order
    pb = [model.NewBoolVar("pb") for i in range(n)]
    for i in range(n):
        model.Add(perm1[i] != perm2[i]).OnlyEnforceIf(pb[i])
        model.Add(perm1[i] == perm2[i]).OnlyEnforceIf(pb[i].Not())
    model.Add(sum(pb) > 0)

    # find husbands age, start with my age
    model.Add(hlist[0] == m)

    # husband's age is last in hlist
    model.Add(h == hlist[n])

    # checking my age, start with husband's age
    model.Add(mlist[0] == h)

    # my age is last in mlist
    model.Add(m == mlist[n])

    # check the operations
    for i in range(n):
        check(model, perm1[i], hlist[i], hlist[i + 1])
        check(model, perm2[i], mlist[i], mlist[i + 1])

    # Symmetry breaking: I'm younger than husband
    # model.Add(m < h)

    solver = cp.CpSolver()

    solution_printer = SolutionPrinter(n, perms, m, h, hlist, mlist, perm1,
                                       perm2)
    status = solver.SearchForAllSolutions(model, solution_printer)
    if not status in [cp.OPTIMAL, cp.FEASIBLE]:
        print("No solution!")

    print()
    print("NumSolutions:", solution_printer.SolutionCount())
    print("NumConflicts:", solver.NumConflicts())
    print("NumBranches:", solver.NumBranches())
    print("WallTime:", solver.WallTime())
    print()