Optimise 2024.07

This commit is contained in:
akp 2024-12-07 12:50:06 +00:00
parent b2fa4b72b6
commit 82ffa429d7
No known key found for this signature in database
GPG key ID: CF8D58F3DEB20755
5 changed files with 50 additions and 46 deletions

View file

@ -3,7 +3,7 @@
Part 1 is:
* greater than 450054910499
Before optimisation (pregenerating then testing operator combiantions using `itertools.product("*+|", length=n)`), runtime looks something like this:
Before optimisation (pregenerating then testing operator combiantions using `itertools.product("*+|", length=n)`), run time looks something like this:
```
Part 1: min 0.2671 seconds, max 0.2818 seconds, avg 0.2755
@ -12,3 +12,11 @@ Part 2: min 23.2387 seconds, max 24.8753 seconds, avg 23.8805
It also appeared that using string concatenation as opposed to pure mathematical functions for the concatenation operator was marginally faster in Python.
After optimisation (recursive solves working backwards through the numbers), the run time looks something like this:
```
Part 1: min 0.0214 seconds, max 0.041 seconds, avg 0.0233
Part 2: min 0.0215 seconds, max 0.0273 seconds, avg 0.0229
```
The intial version of this solve is in commit `b2fa4b7`.

View file

@ -14,58 +14,51 @@ def parse(instr: str) -> list[tuple[int, list[int]]]:
return res
def evaluate(ns: list[int], ops: Iterable[str]):
acc = ns[0]
for i, (v, op) in enumerate(zip(ns[1:], ops)):
if op == "*":
acc *= v
elif op == "+":
acc += v
elif op == "|":
acc = (acc * (10 ** int(math.log10(v) + 1))) + v
else:
raise ValueError(f"unknown operation {op}")
return acc
def ends_with(x: int, y: int) -> bool:
ycard = int(math.log10(y)) + 1
return (x - y) * (10**-ycard) == int(x * (10**-ycard))
def trim_int(x: int, y: int) -> int:
ycard = int(math.log10(y)) + 1
return int((x - y) * (10**-ycard))
def solve(target: int, ns: list[int], use_concat: bool = False) -> bool:
v = ns[-1]
rest = ns[:-1]
if len(rest) == 0:
return target == v
if target % v == 0:
# this represents a possible multiplication
if solve(int(target / v), rest, use_concat):
return True
if use_concat and ends_with(target, v):
# this is a possible concatenation
if solve(trim_int(target, v), rest, use_concat):
return True
# last resort, addition
return solve(target - v, rest, use_concat)
def one(instr: str):
cases = parse(instr)
cached_ops = {}
n = 0
for (target, numbers) in cases:
num_ops = len(numbers) - 1
if num_ops not in cached_ops:
cached_ops[num_ops] = tuple(itertools.product("+*", repeat=num_ops))
for ops in cached_ops[num_ops]:
v = evaluate(numbers, ops)
if v == target:
n += v
break
return n
return itertools.accumulate(
target if solve(target, numbers, use_concat=False) else 0
for (target, numbers) in cases
)
def two(instr: str):
cases = parse(instr)
cached_ops = {}
n = 0
for (target, numbers) in cases:
num_ops = len(numbers) - 1
if num_ops not in cached_ops:
cached_ops[num_ops] = tuple(itertools.product("+*|", repeat=num_ops))
for ops in cached_ops[num_ops]:
v = evaluate(numbers, ops)
if v == target:
n += v
break
return n
return itertools.accumulate(
target if solve(target, numbers, use_concat=True) else 0
for (target, numbers) in cases
)
def _debug(*args, **kwargs):

View file

@ -19,4 +19,5 @@ A day denoted with an asterisk means it has a visualisation.
| 03 - Mull It Over | ★ ★ | Python | The first instance of Advent of Parsing this year! |
| 04* - Ceres Search | ★ ★ | Python | When it says a cross, it does not mean a plus. |
| 05 - Print Queue | ★ ★ | Python | Before you dismiss and idea as being "too simple", make sure you check that it doesn't work. |
| 06 - Guard Gallivant | ★ ★ | Python | oh dear runtime (also I knew what I wanted to do for so long it just took me 3 hours to implement it properly) |
| 06 - Guard Gallivant | ★ ★ | Python | oh dear runtime (also I knew what I wanted to do for so long it just took me 3 hours to implement it properly) |
| 07 - Bridge Repair | ★ ★ | Python | Maths? Backwards?? |

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Before After
Before After

View file

@ -12,3 +12,5 @@
{"day": 6, "part": 2, "runner": "py", "min": 15.881408452987671, "max": 17.086341857910156, "avg": 16.64130985736847, "n": 6}
{"day": 7, "part": 1, "runner": "py", "min": 0.26709485054016113, "max": 0.28178858757019043, "avg": 0.2754525661468506, "n": 5}
{"day": 7, "part": 2, "runner": "py", "min": 23.23872661590576, "max": 24.87530255317688, "avg": 23.880544805526732, "n": 5}
{"day": 7, "part": 1, "runner": "py", "min": 0.02138209342956543, "max": 0.04097461700439453, "avg": 0.023260540962219238, "n": 100}
{"day": 7, "part": 2, "runner": "py", "min": 0.021509647369384766, "max": 0.027263402938842773, "avg": 0.022869422435760497, "n": 100}