96 lines
4.8 KiB
Python
96 lines
4.8 KiB
Python
#!/usr/bin/env python3
|
|
|
|
# This script calculates the optimal cut distribution to reduce waste while matching the desired 2:2:4 segment count
|
|
# It applies brute force since the problem space is very small.
|
|
|
|
import numpy as np
|
|
import itertools
|
|
|
|
l_tot = 500
|
|
|
|
a, b, c = 94, 124, 80
|
|
n, m, l = 2, 2, 4
|
|
arr = np.array([a, b, c], dtype=int)
|
|
arr_count = np.array([n, m, l], dtype=int)
|
|
|
|
# Find all possible splits of a [l_tot] m led tape into segments of lengths [a], [b] and [c] that leave a remainder
|
|
# that's smaller than any of [a], [b] and [c].
|
|
candidates = []
|
|
for i in range(l_tot//a + 1):
|
|
l_rem_i = l_tot - i*a
|
|
if l_rem_i < 0:
|
|
continue
|
|
|
|
for j in range(l_rem_i//b + 1):
|
|
l_rem_j = l_rem_i - j*b
|
|
if l_rem_j < 0:
|
|
continue
|
|
|
|
k = l_rem_j // c
|
|
l_rem_k = l_rem_j - k*c
|
|
|
|
print(f'Candidate: ({i} {j} {k}) {i=}*{a} {j=}*{b=} {k=}*{c=} => remainder {l_rem_k}')
|
|
candidates.append((i, j, k))
|
|
candidates = np.array(candidates, dtype=int)
|
|
print()
|
|
|
|
# Find all ways to combine the cuts found above to cut [num_rolls] into segments, where the amount of segments of length
|
|
# [a], [b], and [c] that we get in total best matches the proportions we need ([n] times [a], [m] times [b], [l] times
|
|
# [c], so 2:2:4 times for 94:124:80 cm)
|
|
num_rolls = 3
|
|
indices_seen = set()
|
|
out = []
|
|
for indices in itertools.product(candidates, repeat=num_rolls):
|
|
indices = np.array(indices)
|
|
index_tup = tuple(sorted(map(tuple, indices)))
|
|
if index_tup in indices_seen:
|
|
continue
|
|
indices_seen.add(index_tup)
|
|
rem = l_tot - (indices * arr).sum(axis=1)
|
|
rem_total = rem.sum()
|
|
count_total = indices.sum(axis=0).astype(float)
|
|
count_total /= arr_count
|
|
spread = count_total.max() - count_total.min()
|
|
|
|
if spread > 2 or (rem < 2).any():
|
|
continue
|
|
print(indices.tolist(), f'{rem_total=} {spread=}')
|
|
out.append((spread, rem_total, indices.tolist(), rem.tolist(), indices.sum(axis=0).tolist()))
|
|
print()
|
|
|
|
# Print out the n best matches found. Sort first by how close we match our target 2:2:4 ratio, then by how much waste
|
|
# we leave.
|
|
print('Best matches:')
|
|
for spread, rem_total, indices, rem, index_sum in sorted(out, key=lambda x: (x[0], x[1]))[:25]:
|
|
print(indices, f'{spread=} {rem_total=} {rem=} {index_sum=}')
|
|
|
|
# Here's the output for future reference. There are a number of combinations that produce 68 cm of waste split across
|
|
# three 5m rolls of tape. We selected # 1 since it leaves leftovers of useful lengths.
|
|
#
|
|
# Best matches:
|
|
# [[0, 0, 6], [0, 4, 0], [4, 0, 1]] spread=0.25 rem_total=68 rem=[20, 4, 44] index_sum=[4, 4, 7]
|
|
# [[0, 0, 6], [1, 3, 0], [3, 1, 1]] spread=0.25 rem_total=68 rem=[20, 34, 14] index_sum=[4, 4, 7]
|
|
# [[0, 2, 3], [0, 2, 3], [4, 0, 1]] spread=0.25 rem_total=68 rem=[12, 12, 44] index_sum=[4, 4, 7]
|
|
# [[0, 2, 3], [1, 1, 3], [3, 1, 1]] spread=0.25 rem_total=68 rem=[12, 42, 14] index_sum=[4, 4, 7]
|
|
# [[0, 2, 3], [2, 1, 2], [2, 1, 2]] spread=0.25 rem_total=68 rem=[12, 28, 28] index_sum=[4, 4, 7]
|
|
# [[0, 3, 1], [1, 0, 5], [3, 1, 1]] spread=0.25 rem_total=68 rem=[48, 6, 14] index_sum=[4, 4, 7]
|
|
# [[0, 4, 0], [1, 0, 5], [3, 0, 2]] spread=0.25 rem_total=68 rem=[4, 6, 58] index_sum=[4, 4, 7]
|
|
# [[1, 0, 5], [1, 3, 0], [2, 1, 2]] spread=0.25 rem_total=68 rem=[6, 34, 28] index_sum=[4, 4, 7]
|
|
# [[0, 0, 6], [0, 3, 1], [3, 1, 1]] spread=0.5 rem_total=82 rem=[20, 48, 14] index_sum=[3, 4, 8]
|
|
# [[0, 0, 6], [0, 4, 0], [3, 0, 2]] spread=0.5 rem_total=82 rem=[20, 4, 58] index_sum=[3, 4, 8]
|
|
# [[0, 0, 6], [1, 3, 0], [2, 1, 2]] spread=0.5 rem_total=82 rem=[20, 34, 28] index_sum=[3, 4, 8]
|
|
# [[0, 1, 4], [0, 2, 3], [3, 1, 1]] spread=0.5 rem_total=82 rem=[56, 12, 14] index_sum=[3, 4, 8]
|
|
# [[0, 2, 3], [0, 2, 3], [3, 0, 2]] spread=0.5 rem_total=82 rem=[12, 12, 58] index_sum=[3, 4, 8]
|
|
# [[0, 2, 3], [1, 0, 5], [2, 2, 0]] spread=0.5 rem_total=82 rem=[12, 6, 64] index_sum=[3, 4, 8]
|
|
# [[0, 2, 3], [1, 1, 3], [2, 1, 2]] spread=0.5 rem_total=82 rem=[12, 42, 28] index_sum=[3, 4, 8]
|
|
# [[0, 3, 1], [1, 0, 5], [2, 1, 2]] spread=0.5 rem_total=82 rem=[48, 6, 28] index_sum=[3, 4, 8]
|
|
# [[0, 4, 0], [1, 0, 5], [2, 0, 3]] spread=0.5 rem_total=82 rem=[4, 6, 72] index_sum=[3, 4, 8]
|
|
# [[1, 0, 5], [1, 1, 3], [1, 3, 0]] spread=0.5 rem_total=82 rem=[6, 42, 34] index_sum=[3, 4, 8]
|
|
# [[0, 0, 6], [0, 3, 1], [4, 0, 1]] spread=0.5 rem_total=112 rem=[20, 48, 44] index_sum=[4, 3, 8]
|
|
# [[0, 0, 6], [1, 2, 1], [3, 1, 1]] spread=0.5 rem_total=112 rem=[20, 78, 14] index_sum=[4, 3, 8]
|
|
# [[0, 0, 6], [1, 3, 0], [3, 0, 2]] spread=0.5 rem_total=112 rem=[20, 34, 58] index_sum=[4, 3, 8]
|
|
# [[0, 0, 6], [2, 1, 2], [2, 2, 0]] spread=0.5 rem_total=112 rem=[20, 28, 64] index_sum=[4, 3, 8]
|
|
# [[0, 1, 4], [0, 2, 3], [4, 0, 1]] spread=0.5 rem_total=112 rem=[56, 12, 44] index_sum=[4, 3, 8]
|
|
# [[0, 1, 4], [1, 1, 3], [3, 1, 1]] spread=0.5 rem_total=112 rem=[56, 42, 14] index_sum=[4, 3, 8]
|
|
# [[0, 1, 4], [2, 1, 2], [2, 1, 2]] spread=0.5 rem_total=112 rem=[56, 28, 28] index_sum=[4, 3, 8]
|
|
|