Skip to content

Commit e7b6aa1

Browse files
simplified bruteforce
1 parent 6be9d5a commit e7b6aa1

File tree

1 file changed

+13
-24
lines changed

1 file changed

+13
-24
lines changed

app/solver/solver.py

+13-24
Original file line numberDiff line numberDiff line change
@@ -32,48 +32,37 @@ def solve(job: Job) -> Result:
3232

3333
# slowest, but perfect solver; originally O(n!), now much faster (see Job.n_combinations())
3434
def _solve_bruteforce(job: Job) -> tuple[ResultEntry, ...]:
35-
mutable_job = job.model_copy(deep=True)
35+
minimal_trimmings = float('inf')
36+
best_results = []
3637

37-
# find every possible ordering (`factorial(sum(sizes))` elements) and reduce to unique
38-
# equal to set(permutations(...)), but much more efficient
39-
all_orderings = distinct_permutations(mutable_job.iterate_required())
40-
all_stocks = distinct_permutations(mutable_job.iterate_stocks())
41-
42-
# would be int max if we had an upper boundary
43-
minimal_trimmings: int | None = None
44-
best_results: list[tuple[ResultEntry, ...]] = []
45-
46-
# could distribute to multiprocessing, but web worker is parallel anyway
47-
for stock_ordering in all_stocks:
48-
for required_ordering in all_orderings:
49-
result = _group_into_lengths(stock_ordering, required_ordering, mutable_job.cut_width)
38+
required_orderings = distinct_permutations(job.iterate_required())
39+
for stock_ordering in distinct_permutations(job.iterate_stocks()):
40+
for required_ordering in required_orderings:
41+
result = _group_into_lengths(stock_ordering, required_ordering, job.cut_width)
5042
if result is None:
51-
# seems like we were able to short-circuit
43+
# Short-circuit if bad solution
5244
continue
5345
trimmings = sum(lt.trimming for lt in result)
54-
if minimal_trimmings is None or trimmings < minimal_trimmings:
46+
if trimmings < minimal_trimmings:
5547
minimal_trimmings = trimmings
56-
best_results.clear()
57-
best_results.append(result)
48+
best_results = [result]
5849
elif trimmings == minimal_trimmings:
5950
best_results.append(result)
6051

61-
assert len(best_results) > 0
62-
ideal_result = find_best_solution(best_results)
63-
return sort_entries([r for r in ideal_result])
52+
assert best_results, "No valid solution found"
53+
return sort_entries(find_best_solution(best_results))
6454

6555

6656
def _group_into_lengths(stocks: tuple[NS, ...], sizes: tuple[NS, ...], cut_width: int) \
6757
-> tuple[ResultEntry, ...] | None:
6858
"""
6959
Collects sizes until length is reached, then starts another stock
70-
Returns none for orderings that exceed ideal conditions
60+
Returns None for orderings that exceed ideal conditions
7161
"""
7262
available = list(reversed(stocks))
7363
required = list(reversed(sizes))
7464

7565
result: list[ResultEntry] = []
76-
7766
current_cuts: list[NS] = []
7867
cut_sum = 0 # could be calculated, but I think this is faster
7968

@@ -150,7 +139,7 @@ def _solve_FFD(job: Job) -> tuple[ResultEntry, ...]:
150139
return sort_entries([create_result_entry(job.stocks[0].as_base(), r, job.cut_width) for r in layout])
151140

152141

153-
# even faster than FFD, seems like equal results; selfmade and less proven!
142+
# even faster than FFD, seems like equal results; self-made and less proven!
154143
def _solve_gapfill(job: Job) -> tuple[ResultEntry, ...]:
155144
"""
156145
1. Sort by magnitude (largest first)

0 commit comments

Comments
 (0)