-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.py
129 lines (110 loc) · 4.4 KB
/
main.py
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
import pulp
import re
import string
from collections import Counter
# -------------------------------
# 1. Define Data & Cost Factors
# -------------------------------
# Available stock: (quantity, length)
stock_list = [(9, 28), (11, 32), (9, 42), (15, 48)]
# Required pieces: (name, quantity, length)
piece_list = [('small', 64, 7.5), ('large', 32, 23.25)]
# Define cost factors (favoring smaller boards by assigning them a lower cost)
cost_factors = {28: 1.0, 32: 1.1, 42: 1.5, 48: 2.5}
# -------------------------------
# 2. Create a List of Boards
# -------------------------------
# Each board is represented as a dict with a length and cost factor.
boards = []
for qty, length in stock_list:
boards.extend([{'length': length, 'cost': cost_factors[length]} for _ in range(qty)])
num_boards = len(boards)
# -------------------------------
# 3. Set Up the PuLP Model
# -------------------------------
model = pulp.LpProblem("CuttingStock", pulp.LpMinimize)
# Decision variables:
# y[i] is 1 if board i is used, 0 otherwise.
y = [pulp.LpVariable(f'y_{i}', cat='Binary') for i in range(num_boards)]
# n[(i, piece)] is the number of pieces of a given type cut from board i.
n = {}
for i in range(num_boards):
for name, req, length in piece_list:
n[(i, name)] = pulp.LpVariable(f'n_{i}_{name}', lowBound=0, cat='Integer')
# -------------------------------
# 4. Add Constraints
# -------------------------------
# (a) Board capacity: The total length of pieces assigned to board i must not exceed its length if used.
for i in range(num_boards):
model += (
sum(n[(i, name)] * length for name, req, length in piece_list)
<= boards[i]['length'] * y[i],
f"capacity_{i}"
)
# (b) Demand: The total pieces cut must equal the required quantity for each piece type.
for name, req, length in piece_list:
model += (
sum(n[(i, name)] for i in range(num_boards)) == req,
f"demand_{name}"
)
# -------------------------------
# 5. Define the Objective
# -------------------------------
# Only count the board's length if it is used.
model += pulp.lpSum(
boards[i]['cost'] * (boards[i]['length'] * y[i] - sum(n[(i, name)] * length for name, req, length in piece_list))
for i in range(num_boards)
)
# -------------------------------
# 6. Solve the Model
# -------------------------------
model.solve()
print("Status:", pulp.LpStatus[model.status])
# -------------------------------
# 7. Gather and Display Board-Level Results
# -------------------------------
result_details = {}
for i in range(num_boards):
# Only include boards that are used
if y[i].varValue > 0.5:
used_length = sum(n[(i, name)].varValue * length for name, req, length in piece_list)
waste = boards[i]['length'] - used_length
board_label = f"Board {i+1} ({boards[i]['length']}\")"
cuts = []
for name, req, length in piece_list:
qty = int(n[(i, name)].varValue)
if qty > 0:
cuts.extend([length] * qty)
result_details[board_label] = {"cuts": cuts, "waste": waste}
print("\nDetailed Board Assignments:")
for board, details in result_details.items():
print(f"{board}: Cuts -> {details['cuts']} | Waste -> {details['waste']}\"")
# -------------------------------
# 8. Summarize and Label Patterns
# -------------------------------
def summarize_patterns(result_details):
# Group boards by (stock length, sorted cuts, waste)
pattern_counter = Counter()
for board, details in result_details.items():
# Extract numeric stock length from label (e.g., 'Board 1 (28")' -> 28)
stock_length = int(re.search(r'\((\d+)"\)', board).group(1))
cuts = tuple(sorted(details['cuts']))
waste = details['waste']
pattern_counter[(stock_length, cuts, waste)] += 1
# Label patterns A, B, C, etc.
labeled_patterns = {}
for label, ((stock_length, cuts, waste), count) in zip(string.ascii_uppercase, pattern_counter.items()):
labeled_patterns[label] = {
'stock_length': stock_length,
'cuts': list(cuts),
'waste': waste,
'count': count
}
return labeled_patterns
summary = summarize_patterns(result_details)
print("\nSummary of Patterns:")
for label, info in summary.items():
print(
f"Pattern {label}: Stock Length -> {info['stock_length']}\" | "
f"Cuts -> {info['cuts']} | Waste -> {info['waste']}\" | Count -> {info['count']}"
)