{OR-TOOLS CPSAT Job Shop Scheduling} Как добавить ограничение в модель (ограничение Worker)? - PullRequest
0 голосов
/ 01 июня 2019

Я использую гибкую модель CPSAT от Google or-tools для своего производственного графика. Я добавил нужное ограничение (машина уже работает, пытаясь заставить работника работать), но я все еще не уверен, как изменить переменную основного интервала :( Пожалуйста, помогите. Major n00b, и я собираюсь закончить это Это последнее препятствие для графика производства!

Ниже мой код.

def flexible_jobshop():
    # Data part (duration of task, machine) with corresponding alternative machines per task.
    jobs = [[[(11, 1), (11, 5)], [(8, 3)]], [[(11, 1), (11, 5)], [(8, 3)]], [[(11, 1), (11, 5)], [(8, 3)]], [[(13, 1), (13, 5)], [(10, 3)]], [[(17, 1), (17, 5)], [(12, 3)]], [[(22, 1), (22, 5)], [(17, 3)]], [[(26, 1), (26, 5)], [(20, 3)], [(33, 2)], [(20, 4)]], [[(12, 1), (12, 5)], [(9, 3)]], [[(28, 1), (28, 5)], [(21, 3)], [(35, 2)]], [[(28, 1), (28, 5)], [(21, 3)]], [[(11, 1), (11, 5)], [(8, 3)]], [[(28, 1), (28, 5)], [(21, 3)], [(35, 2)]], [[(26, 1), (26, 5)], [(19, 3)], [(33, 2)]]]

    num_jobs = len(jobs)
    all_jobs = range(num_jobs)

    num_machines = 5
    all_machines = range(num_machines)

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

    horizon = 0
    for job in jobs:
        for task in job:
            max_task_duration = 0
            for alternative in task:
                max_task_duration = max(max_task_duration, alternative[0])
            horizon += max_task_duration

    print('Horizon = %i' % horizon)

    # Global storage of variables.
    intervals_per_resources = 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:
        job = jobs[job_id]
        num_tasks = len(job)
        previous_end = None
        for task_id in range(num_tasks):
            task = job[task_id]

            min_duration = task[0][0]
            max_duration = task[0][0]

            num_alternatives = len(task)
            all_alternatives = range(num_alternatives)

            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:
                    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.NewIntVar(1, 1, '')

        job_ends.append(previous_end)

    # Create machines constraints.
    for machine_id in intervals in intervals_per_resources.items():
        intervals = intervals_per_resources[machine_id]

        if len(intervals) > 1:
            model.AddNoOverlap(intervals)

    # Create workers constraints.
    for worker_id, intervals in intervals_per_resources.items():
        intervals = intervals_per_resources[worker_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()
    status = solver.Solve(model)

    # 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, worker_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))
...