-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathknapsack_optimizer.py
More file actions
156 lines (126 loc) · 4.46 KB
/
knapsack_optimizer.py
File metadata and controls
156 lines (126 loc) · 4.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
"""Example: 0/1 Knapsack problem.
Demonstrates binary variables and classic optimization.
"""
import asyncio
from chuk_mcp_solver.models import SolveConstraintModelRequest
from chuk_mcp_solver.solver import get_solver
def build_knapsack_model(items: list[dict], capacity: int) -> dict:
"""Build a 0/1 knapsack model.
Args:
items: List of items with id, weight, and value.
capacity: Maximum weight capacity.
Returns:
Model dictionary.
"""
variables = []
constraints = []
# Binary variable for each item (take it or not)
for item in items:
variables.append(
{
"id": f"take_{item['id']}",
"domain": {"type": "bool"},
"metadata": {
"item_id": item["id"],
"weight": item["weight"],
"value": item["value"],
},
}
)
# Capacity constraint: total weight <= capacity
constraints.append(
{
"id": "capacity",
"kind": "linear",
"params": {
"terms": [{"var": f"take_{item['id']}", "coef": item["weight"]} for item in items],
"sense": "<=",
"rhs": capacity,
},
"metadata": {"description": f"Total weight cannot exceed {capacity}"},
}
)
# Objective: maximize total value
objective = {
"sense": "max",
"terms": [{"var": f"take_{item['id']}", "coef": item["value"]} for item in items],
"metadata": {"description": "Maximize total value"},
}
return {
"mode": "optimize",
"variables": variables,
"constraints": constraints,
"objective": objective,
}
def display_solution(solution_vars: list, items: list[dict], capacity: int) -> None:
"""Display the knapsack solution.
Args:
solution_vars: List of SolutionVariable objects.
items: Original item definitions.
capacity: Capacity limit.
"""
# Extract selected items
selected = []
total_weight = 0
total_value = 0
for var in solution_vars:
if var.value == 1: # Item is selected
item_id = var.metadata["item_id"]
weight = var.metadata["weight"]
value = var.metadata["value"]
selected.append({"id": item_id, "weight": weight, "value": value})
total_weight += weight
total_value += value
print("\nOptimal Selection:")
print(f"Capacity: {capacity}")
print(f"Used Weight: {total_weight}/{capacity}")
print(f"Total Value: {total_value}\n")
if selected:
print("Selected Items:")
print("Item | Weight | Value")
print("-----|--------|-------")
for item in selected:
print(f"{item['id']:4} | {item['weight']:6} | {item['value']:5}")
else:
print("No items selected.")
async def main() -> None:
"""Run the knapsack optimizer example."""
print("=== 0/1 Knapsack Optimizer Example ===\n")
# Define items
items = [
{"id": "A", "weight": 3, "value": 10},
{"id": "B", "weight": 5, "value": 15},
{"id": "C", "weight": 2, "value": 8},
{"id": "D", "weight": 4, "value": 12},
{"id": "E", "weight": 1, "value": 5},
]
capacity = 7
print("Items:")
print("Item | Weight | Value")
print("-----|--------|-------")
for item in items:
print(f"{item['id']:4} | {item['weight']:6} | {item['value']:5}")
print(f"\nKnapsack Capacity: {capacity}")
# Build model
model_dict = build_knapsack_model(items, capacity)
request = SolveConstraintModelRequest(**model_dict)
# Solve
print("\nOptimizing...")
solver = get_solver("ortools")
response = await solver.solve_constraint_model(request)
# Display results
print(f"\nStatus: {response.status}")
if response.objective_value is not None:
print(f"Objective Value: {response.objective_value:.0f}")
if response.solutions:
display_solution(response.solutions[0].variables, items, capacity)
if response.explanation:
print(f"\n{response.explanation.summary}")
if response.explanation.binding_constraints:
print("\nBinding Constraint:")
bc = response.explanation.binding_constraints[0]
print(
f" {bc.metadata.get('description', bc.id)} (used: {bc.lhs_value:.0f}/{bc.rhs:.0f})"
)
if __name__ == "__main__":
asyncio.run(main())