#python #optimization #job-scheduling #or-tools
#python #оптимизация #планирование заданий #или-инструменты
Вопрос:
Я работаю с вариантом задачи job shop, где я хочу изменить продолжительность задачи на основе их назначения / ранга в расписании станка.
например, простым случаем было бы то, что выполнение первой задачи, назначенной на компьютере, займет на 50% больше времени.
Более общим случаем было бы то, что для каждой n-й задачи на компьютере потребовалось бы на X% больше времени.
Я читал об ограничениях канала, но я не уверен, как реализовать их в этом сценарии или есть ли другие лучшие альтернативы. Любое направление было бы высоко оценено.
Ниже приведен код, который я использую из документации or tools для решения проблемы job shop.
from __future__ import print_function
import collections
# Import Python wrapper for or-tools CP-SAT solver.
from ortools.sat.python import cp_model
def MinimalJobshopSat():
"""Minimal jobshop problem."""
# Create the model.
model = cp_model.CpModel()
jobs_data = [ # task = (machine_id, processing_time).
[(2, 1), (0, 1), (1, 1)], # Job0
[(0, 1), (1, 1)], # Job1
[(1, 1), (2, 1)] # 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_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.
# Change constraint to only respect the project start date i.e. the first dummy task
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)
Измененный результат, который мы ожидали бы для этого случая, был бы следующим, где продолжительность первой задачи на каждой машине увеличивается на 50%
Optimal Schedule Length: 4
Machine 0: job_1_0 job_0_1
[0,2] [2,3]
Machine 1: job_2_0 job_0_2 job_1_1
[0,2] [2,3] [3,4]
Machine 2: job_0_0 job_2_1
[0,2] [2,3]
Ответ №1:
Посмотрите на это ограничение, оно создает ограничение схемы, которое выполняет переходное преобразование прецедентов в последовательность задач.
Теперь вы можете использовать начальный литерал каждой задачи для указания правильной продолжительности
model.Add(duration[i] == int(nominal_duration * 1.5)).OnlyEnforceIf(start_lit)
model.Add(duration[i] == nominal_duration).OnlyEnforceIf(start_lit.Not())