'How to get consistent ortools assignment results?
The problem is to assign items into a few regions. Each item pairs have a crossing number, and the objective is to minimize the crossing of items across the regions. Each item also has a size and there is a limitation for the size of each region.
I am able to solve the problem with the following code, but I am getting different results every time. I would like to consistently get the same results.
I have tried to set "solver.parameters.random_seed = 1" but it does not work.
import numpy as np
from ortools.sat.python import cp_model
import random
num_items = 15
num_regions = 3
max_size = 600
random.seed(1)
matrix = [[random.randint(0,99) for _ in range(num_items)] for _ in range(num_items)]
size_array = [random.randint(0,99) for _ in range(num_items)]
# Model
model = cp_model.CpModel()
# Variables
# x[a, b] is a matrix of 0-1 variables, which will be 1
# if item a is assigned to region b.
x = []
for a in range(num_items):
t = []
for b in range(num_regions):
t.append(model.NewBoolVar(f'x[{a},{b}]'))
x.append(t)
# y[a_i, a_j, b_i, b_j] is a matrix of 0-1 variables, which will be 1
# if x[a_i, b_i] = 1 AND x[a_j, b_j] = 1
y = []
for a_i in range(num_items):
t1 = []
for a_j in range(num_items):
t2 = []
for b_i in range(num_regions):
t3 = []
for b_j in range(num_regions):
p = model.NewBoolVar(f'y[{a_i},{a_j},{b_i},{b_j}]')
t3.append(p)
x1 = x[a_i][b_i]
x2 = x[a_j][b_j]
model.AddBoolOr([x1.Not(), x2.Not(), p])
model.AddImplication(p, x1)
model.AddImplication(p, x2)
t2.append(t3)
t1.append(t2)
y.append(t1)
# Constraints
# Each item is assigned to 1 region.
for a in range(num_items):
model.Add(sum([x[a][b] for b in range(num_regions)]) == 1)
# Each region total item's size less than max_size.
for b in range(num_regions):
model.Add(sum([x[a][b]*int(np.ceil(size_array[a])) for a in range(num_items)]) <= max_size)
def crossing(b_i, b_j):
objective_terms = []
for a_i in range(num_items):
for a_j in range(num_items):
objective_terms.append(y[a_i][a_j][b_i][b_j] * int(np.ceil((matrix[a_i][a_j]+matrix[a_j][a_i]))))
return objective_terms
# Objective
# Each item pairs has a crossing value
# Minimize the crossing across regions
objective_terms = []
objective_terms.extend(crossing(0, 1))
objective_terms.extend(crossing(1, 2))
objective_terms.extend(2*crossing(0, 2))
model.Minimize(sum(objective_terms))
# Solve
solver = cp_model.CpSolver()
solver.parameters.num_search_workers = 8
solver.parameters.random_seed = 1
status = solver.Solve(model)
print("Status = {}".format(solver.StatusName(status)), flush=True)
# Print solution
if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE:
print(f'Total cost = {solver.ObjectiveValue()}', flush=True)
for b in range(num_regions):
print("Region {} :".format(b), end='', flush=True)
total_size = 0
for a in range(num_items):
# Test if x[a, b] is 1 (with tolerance for floating point arithmetic).
if solver.BooleanValue(x[a][b]):
total_size += size_array[a]
print(" Total size of items are {} ".format(str(total_size)), flush=True)
Result 1:
Status = OPTIMAL
Total cost = 1274.0
Region 0 : Total size of items are 581
Region 1 : Total size of items are 90
Region 2 : Total size of items are 0
Result 2:
Status = OPTIMAL
Total cost = 1274.0
Region 0 : Total size of items are 0
Region 1 : Total size of items are 90
Region 2 : Total size of items are 581
Solution 1:[1]
Setting num_search_workers = 1 works, thanks!
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | yuansy |