使用OR-Tools CP-SAT求解器对唯一性的限制分配优化问题
我试图解决的问题与Or-Tools文档中描述的问题非常相似: https://developers.google.com/optimization/assignment/assignment_example#cp_sat_solution 。 我有15名工人需要分配给5个任务。目标功能是最大程度地降低成本。但是,选定的工人需要完全属于3个州。我在表达这一约束时遇到问题。下面的代码
- 用解决方案编辑
start_time = time.perf_counter()
costs = [500, 75, 80, 25, 95, 100, 10, 30, 400, 50, 80, 110, 150, 20, 60]
# states_label = ["AZ","CT","FL","CA","NY","CA","NY","CT","AZ","CA","CT","CT","AZ","FL","NY"]
states = [0,2,3,1,4,1,4,2,0,1,2,2,0,3,4]
num_workers = len(costs)
num_tasks = 5
num_states = 5
# Model
model = cp_model.CpModel()
# Variables
x = {}
for worker in range(num_workers):
for task in range(num_tasks):
x[worker, task] = model.NewBoolVar(f'x[{worker},{task}]')
# Create
states_is_selected = []
for state in range(num_states):
state_is_selected = model.NewBoolVar('')
# workers_from_that_states are all x that corresponds to this state
workers_from_that_state = []
for worker in range(num_workers):
for task in range(num_tasks):
if (state == states[worker]):
workers_from_that_state.append( x[worker,task])
# print(f"state {state}")
# print(workers_from_that_state)
literals = [c for c in workers_from_that_state]
model.AddBoolOr(literals).OnlyEnforceIf(state_is_selected)
for literal in literals:
model.AddImplication(literal, state_is_selected)
states_is_selected.append(state_is_selected)
# Constraints
# Each worker is assigned to at most 1 task.
for worker in range(num_workers):
model.AddAtMostOne(x[worker,task] for task in range(num_tasks))
# Each task is assigned to exactly one worker.
for task in range(num_tasks):
model.AddExactlyOne(x[worker,task] for worker in range(num_workers))
# The workers belong to exactly 3 states
model.Add(sum(states_is_selected) == 3)
# Objective
objective_terms = []
for worker in range(num_workers):
for task in range(num_tasks):
objective_terms.append(costs[worker] * x[worker,task])
model.Minimize(sum(objective_terms))
# Solve
solver = cp_model.CpSolver()
status = solver.Solve(model)
print(f'Status = {solver.StatusName(status)}')
if status == cp_model.INFEASIBLE:
print('SufficientAssumptionsForInfeasibility = 'f'{solver.SufficientAssumptionsForInfeasibility()}')
# Print solution.
if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE:
print(f"Solution found")
print(f'Total cost = {solver.ObjectiveValue()}')
print()
for worker in range(num_workers):
for task in range(num_tasks):
if solver.BooleanValue(x[worker,task]):
print(f"Worker {worker}, Cost: {costs[worker]}, State: {states[worker]}")
for state in range(num_states):
print(f"State {state}: ", solver.BooleanValue(states_is_selected[state]))
# Number of States for assigned workers
states_selected = [states[worker] for worker in range(num_workers) for task in range(num_tasks) if solver.BooleanValue(x[worker,task])]
print(f"The workers selected are coming from {len(list(set(states_selected)))} states:", set(states_selected))
else:
print(f"No solution found")
end_time = time.perf_counter()
print("Program executed in {:,.2f} s".format(end_time - start_time))
The problem I am trying to solve is pretty similar to the one described in the OR-tools documentation: https://developers.google.com/optimization/assignment/assignment_example#cp_sat_solution.
I have 15 workers that I need to assign to 5 tasks. The objective function is to minimize the cost. However, the selected workers need to belong to exactly 3 states. I am having an issue expressing this constraint. Code below
-- Edited with solution
start_time = time.perf_counter()
costs = [500, 75, 80, 25, 95, 100, 10, 30, 400, 50, 80, 110, 150, 20, 60]
# states_label = ["AZ","CT","FL","CA","NY","CA","NY","CT","AZ","CA","CT","CT","AZ","FL","NY"]
states = [0,2,3,1,4,1,4,2,0,1,2,2,0,3,4]
num_workers = len(costs)
num_tasks = 5
num_states = 5
# Model
model = cp_model.CpModel()
# Variables
x = {}
for worker in range(num_workers):
for task in range(num_tasks):
x[worker, task] = model.NewBoolVar(f'x[{worker},{task}]')
# Create
states_is_selected = []
for state in range(num_states):
state_is_selected = model.NewBoolVar('')
# workers_from_that_states are all x that corresponds to this state
workers_from_that_state = []
for worker in range(num_workers):
for task in range(num_tasks):
if (state == states[worker]):
workers_from_that_state.append( x[worker,task])
# print(f"state {state}")
# print(workers_from_that_state)
literals = [c for c in workers_from_that_state]
model.AddBoolOr(literals).OnlyEnforceIf(state_is_selected)
for literal in literals:
model.AddImplication(literal, state_is_selected)
states_is_selected.append(state_is_selected)
# Constraints
# Each worker is assigned to at most 1 task.
for worker in range(num_workers):
model.AddAtMostOne(x[worker,task] for task in range(num_tasks))
# Each task is assigned to exactly one worker.
for task in range(num_tasks):
model.AddExactlyOne(x[worker,task] for worker in range(num_workers))
# The workers belong to exactly 3 states
model.Add(sum(states_is_selected) == 3)
# Objective
objective_terms = []
for worker in range(num_workers):
for task in range(num_tasks):
objective_terms.append(costs[worker] * x[worker,task])
model.Minimize(sum(objective_terms))
# Solve
solver = cp_model.CpSolver()
status = solver.Solve(model)
print(f'Status = {solver.StatusName(status)}')
if status == cp_model.INFEASIBLE:
print('SufficientAssumptionsForInfeasibility = 'f'{solver.SufficientAssumptionsForInfeasibility()}')
# Print solution.
if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE:
print(f"Solution found")
print(f'Total cost = {solver.ObjectiveValue()}')
print()
for worker in range(num_workers):
for task in range(num_tasks):
if solver.BooleanValue(x[worker,task]):
print(f"Worker {worker}, Cost: {costs[worker]}, State: {states[worker]}")
for state in range(num_states):
print(f"State {state}: ", solver.BooleanValue(states_is_selected[state]))
# Number of States for assigned workers
states_selected = [states[worker] for worker in range(num_workers) for task in range(num_tasks) if solver.BooleanValue(x[worker,task])]
print(f"The workers selected are coming from {len(list(set(states_selected)))} states:", set(states_selected))
else:
print(f"No solution found")
end_time = time.perf_counter()
print("Program executed in {:,.2f} s".format(end_time - start_time))
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您需要每个州有1个布尔变量。
然后实现
这是一个简单的概括: https://github.com/google/OR-tools/blob/stable/stable/ortools/sat/docs/docs/boolean_logic.md#product-of-two-two-boolean-variables
然后
sum(states)== 3
You need to have 1 Boolean variable per state.
Then implement
This is a simple generalization of: https://github.com/google/or-tools/blob/stable/ortools/sat/docs/boolean_logic.md#product-of-two-boolean-variables
then
sum(states) == 3