# [START program]
# [START import]
from ortools.sat.python import cp_model
# [END import]
# [START program_part1]
# [START data_model]
def create_data_model():
"""Create the data for the example."""
data = {}
heights = [20, 30, 20, 80, 100, 120, 60]
values = [20, 30, 20, 80, 100, 120, 60]
data['heights'] = heights
data['values'] = values
data['height_list'] = sorted(set(data['heights']))
data['items'] = list(range(len(data['heights'])))
data['num_items'] = len(data['items'])
num_bins = 3
data['bins'] = list(range(num_bins))
data['bin_capacities'] = [200, 200, 200]
return data
# [END data_model]
def main():
# [START data]
data = create_data_model()
# [END data]
# [END program_part1]
# [START solver]
model = cp_model.CpModel()
# [END solver]
# [START program_part2]
# [START variables]
# Variables
# x[i, j] = 1 if item i is packed in bin j.
x = {}
for i in data['items']:
for j in data['bins']:
x[i, j] = model.NewBoolVar(f'x_{i}_{j}')
# y[i, j] = 1 if an item of size i is packed in bin j.
y = {}
for i in data['height_list']:
for j in data['bins']:
y[i, j] = model.NewBoolVar(f'y_{i}_{j}')
# [END variables]
# [START constraints]
# Constraints
# Each item can be in at most one bin.
for i in data['items']:
model.Add(sum(x[i, j] for j in data['bins']) <= 1)
# The amount packed in each bin cannot exceed its capacity.
for j in data['bins']:
model.Add(
sum(x[i, j] * data['heights'][i]
for i in data['items']) <= data['bin_capacities'][j])
# Implement y[i, j] == (items of size i >= 1).
for i in data['height_list']:
for j in data['bins']:
cst = sum(x[k, j] for k in data['items'] if i == data['heights'][k])
model.Add(cst >= 1).OnlyEnforceIf(y[i, j])
model.Add(cst < 1).OnlyEnforceIf(y[i, j].Not())
# limit diff to 60
for j in data['bins']:
model.Add(
sum([y[20, j], y[100, j]]) <= 1)
model.Add(
sum([y[20, j], y[120, j]]) <= 1)
model.Add(
sum([y[30, j], y[120, j]]) <= 1)
# [END constraints]
# [START objective]
# Objective
objective_terms = []
for i in data['items']:
for j in data['bins']:
objective_terms.append(x[i, j] * data['values'][i])
model.Maximize(sum(objective_terms))
# [END objective]
# Creates a solver and solves the model.
# [START solve]
solver = cp_model.CpSolver()
status = solver.Solve(model)
# [END solve]
# [START print_solution]
if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE:
print('Items total value (upper bound):', sum(data['values']))
print('Total packed value:', solver.ObjectiveValue())
total_height = 0
for j in data['bins']:
bin_height = 0
bin_value = 0
print('Bin ', j, '\n')
for i in data['height_list']:
print(f"Has items of size {i}:", bool(solver.Value(y[i,j])))
for i in data['items']:
if solver.Value(x[i, j]) > 0:
print('Item', i, '- height:', data['heights'][i], ' value:', data['values'][i])
bin_height += data['heights'][i]
bin_value += data['values'][i]
print('Packed bin weight:', bin_height)
print('Packed bin value:', bin_value)
print()
total_height += bin_height
print('Total packed weight:', total_height)
else:
print('The problem does not have an optimal solution.')
# [END print_solution]
if __name__ == '__main__':
main()
# [END program_part2]
# [END program]
possible output:
%./plop.py
Items total value (upper bound): 430
Total packed value: 430.0
Bin 0
Has items of size 20: True
Has items of size 30: True
Has items of size 60: False
Has items of size 80: False
Has items of size 100: False
Has items of size 120: False
Item 0 - height: 20 value: 20
Item 1 - height: 30 value: 30
Item 2 - height: 20 value: 20
Packed bin weight: 70
Packed bin value: 70
Bin 1
Has items of size 20: False
Has items of size 30: False
Has items of size 60: False
Has items of size 80: True
Has items of size 100: True
Has items of size 120: False
Item 3 - height: 80 value: 80
Item 4 - height: 100 value: 100
Packed bin weight: 180
Packed bin value: 180
Bin 2
Has items of size 20: False
Has items of size 30: False
Has items of size 60: True
Has items of size 80: False
Has items of size 100: False
Has items of size 120: True
Item 5 - height: 120 value: 120
Item 6 - height: 60 value: 60
Packed bin weight: 180
Packed bin value: 180
Total packed weight: 430