Advent of Code 2023 day 12
12/12/2023, 5:00 AMNeil Banman
12/12/2023, 5:16 AMKroppeb
12/12/2023, 5:31 AM@lru_cache
Jonathan Kolberg
12/12/2023, 6:07 AMJonathan Kolberg
12/12/2023, 6:08 AMNorbert Kiesel
12/12/2023, 6:15 AMbj0
12/12/2023, 6:20 AMbj0
12/12/2023, 6:21 AMDave Leeds
12/12/2023, 6:36 AM?
spots in a string. Brute force is manageable for 2^18 possibilities, but 2^94 is going to take a while... 😅Marcin Wisniowski
12/12/2023, 6:41 AMLukas Lebovitz
12/12/2023, 6:51 AMJonathan Kolberg
12/12/2023, 6:51 AMJonathan Kolberg
12/12/2023, 6:52 AMdaugian
12/12/2023, 7:14 AM.
and then just return a possibleArrangements^5
for that group… something like that.Dave Leeds
12/12/2023, 7:22 AMMichael de Kaste
12/12/2023, 7:28 AMNorbert Kiesel
12/12/2023, 7:28 AMelizarov
12/12/2023, 7:57 AMdaugian
12/12/2023, 7:59 AM.
and cache the number of those arrangement possibilities?elizarov
12/12/2023, 8:02 AMdaugian
12/12/2023, 8:03 AMMichael de Kaste
12/12/2023, 8:10 AMbj0
12/12/2023, 8:10 AMbj0
12/12/2023, 8:10 AMMichael de Kaste
12/12/2023, 8:13 AMfun functionToMemoize(arg1: String, arg2: List<Int>): Long {
buildMap {
fun recursion(arg1: String, arg2: List<Int>): Long = getOrPut(arg1 to arg2){
// your algorithm here
0L
}
return recursion(arg1, arg2)
}
}
elizarov
12/12/2023, 8:17 AMWerner Altewischer
12/12/2023, 8:41 AMJaap Beetstra
12/12/2023, 8:52 AMJaap Beetstra
12/12/2023, 9:48 AMdaugian
12/12/2023, 9:51 AMdaugian
12/12/2023, 9:52 AMdaugian
12/12/2023, 9:54 AMWerner Altewischer
12/12/2023, 9:55 AMdaugian
12/12/2023, 9:56 AMJakub Gwóźdź
12/12/2023, 11:17 AMDeepRecursiveFunction
? I tried to add extension function DeepRecursiveFunction.cached()
but the val block
inside the DRF
is internal
so it’s not really possible.
Best I can do is
inline fun <T, R> cachedDRF(
cache: MutableMap<T, R> = mutableMapOf(),
crossinline block: suspend DeepRecursiveScope<T, R>.(T) -> R
): DeepRecursiveFunction<T, R> =
DeepRecursiveFunction { value ->
if (value in cache) cache[value]!! else block(value).also { cache[value] = it }
}
Michael de Kaste
12/12/2023, 11:26 AMelizarov
12/12/2023, 11:28 AMephemient
12/12/2023, 11:43 AMephemient
12/12/2023, 11:43 AMephemient
12/12/2023, 11:45 AMJakub Gwóźdź
12/12/2023, 11:54 AMephemient
12/12/2023, 12:13 PMbenchmarking Day 12/part 1
time 5.637 ms (5.620 ms .. 5.649 ms)
1.000 R² (1.000 R² .. 1.000 R²)
mean 5.675 ms (5.662 ms .. 5.688 ms)
std dev 39.45 μs (33.44 μs .. 48.07 μs)
benchmarking Day 12/part 2
time 14.59 s (14.49 s .. 14.70 s)
1.000 R² (1.000 R² .. 1.000 R²)
mean 14.57 s (14.55 s .. 14.59 s)
std dev 22.63 ms (7.623 ms .. 29.77 ms)
variance introduced by outliers: 19% (moderately inflated)
and with parallelization (on a 2-core GItHub Actions runner, so I'm not sure why the speedup could be >2x, but whatever):
benchmarking Day 12/part 1
time 3.160 ms (3.142 ms .. 3.177 ms)
1.000 R² (0.999 R² .. 1.000 R²)
mean 3.157 ms (3.142 ms .. 3.170 ms)
std dev 44.06 μs (35.75 μs .. 60.47 μs)
benchmarking Day 10/part 2
time 6.614 s (6.484 s .. 6.716 s)
1.000 R² (1.000 R² .. 1.000 R²)
mean 6.693 s (6.648 s .. 6.778 s)
std dev 81.98 ms (2.349 ms .. 98.57 ms)
variance introduced by outliers: 19% (moderately inflated)
ephemient
12/12/2023, 12:13 PMWerner Altewischer
12/12/2023, 1:20 PMobject CacheSupport {
private var _cache: MutableMap<*, *>? = null
private inline fun <T, R>withCache(arg: T, crossinline perform: (T) -> R): R {
@Suppress("UNCHECKED_CAST")
val existingCache: MutableMap<T, R>? = _cache as? MutableMap<T, R>
val cache: MutableMap<T, R> = existingCache ?: hashMapOf<T, R>().also { _cache = it }
try {
return cache.getOrPut(arg) {
perform(arg)
}
} finally {
if (existingCache == null) {
_cache = null
}
}
}
}
Then call your recursive function like this:
fun process(state: State) = withCache(state) {
// Do your magic here
}
ephemient
12/12/2023, 1:22 PMEl Anthony
12/12/2023, 2:34 PMkingsley
12/12/2023, 2:37 PMarrangement
function took way too long for me to get right. It still seems to be doing unnecessary things, but it works, so I don't mind too much 😅
Memoization was the easiest part, it turns out
https://github.com/kingsleyadio/adventofcode/blob/main/src/com/kingsleyadio/adventofcode/y2023/Day12.ktMichael Böiers
12/12/2023, 3:37 PMbj0
12/12/2023, 4:11 PMDeepRecursiveFunction
, that's neat, although i didn't need it for this casephldavies
12/12/2023, 4:17 PM@Suppress("FunctionName")
fun <T, R> CachedDeepRecursiveFunction(block: suspend DeepRecursiveScope<T, R>.(T) -> R) =
mutableMapOf<T, R>().let { cache -> DeepRecursiveFunction { cache.getOrPut(it) { block(it) } } }
This came in useful 😄bj0
12/12/2023, 4:38 PM100
phldavies
12/12/2023, 4:39 PMJakub Gwóźdź
12/12/2023, 4:57 PMbj0
12/12/2023, 5:34 PMMemoizedDeepRecursiveFunction
, and it didn't work at all. runtime went from 400ms to > 5m (i stopped it)phldavies
12/12/2023, 5:50 PMBenchmark Mode Cnt Score Error Units
BenchDay12.deepRecursivePart1 avgt 3 0.816 ± 0.037 ms/op
BenchDay12.deepRecursivePart2 avgt 3 26.353 ± 0.818 ms/op
BenchDay12.normalRecursionPart1 avgt 3 1.097 ± 0.098 ms/op
BenchDay12.normalRecursionPart2 avgt 3 33.699 ± 0.246 ms/op
I get a slight performance increase using my Cached DRF vs caching over a normal recursive functionbj0
12/12/2023, 5:50 PMphldavies
12/12/2023, 5:54 PMbj0
12/12/2023, 6:18 PMbj0
12/12/2023, 6:20 PMDRF took 400.858433ms (1.00x): 18093821750095
MDRF took 17m 23.347227919s (1.00x): 18093821750095
bj0
12/12/2023, 6:22 PMphldavies
12/12/2023, 6:34 PMbj0
12/12/2023, 6:38 PMphldavies
12/12/2023, 6:46 PMBenchmark Mode Cnt Score Error Units
BenchDay12.deepRecursivePart1 avgt 3 0.602 ± 0.032 ms/op
BenchDay12.deepRecursivePart2 avgt 3 12.180 ± 4.004 ms/op
BenchDay12.normalRecursionPart1 avgt 3 0.744 ± 0.047 ms/op
BenchDay12.normalRecursionPart2 avgt 3 16.028 ± 2.507 ms/op
optimized it slightly - and I've pushed now: https://github.com/tKe/aoc/blob/main/kt/src/main/kotlin/year2023/Day12.ktTomasz Linkowski
12/12/2023, 8:17 PMephemient
12/12/2023, 9:19 PMbj0
12/12/2023, 9:45 PMbj0
12/12/2023, 9:46 PMphldavies
12/12/2023, 9:46 PMphldavies
12/12/2023, 9:47 PMbj0
12/12/2023, 9:57 PMPaul Woitaschek
12/12/2023, 11:03 PMif (recognized.size > damages.size) return@getOrPut 0
recognized.forEachIndexed { index, i ->
if (damages[index] != i) return@getOrPut 0
}
evgenim
12/12/2023, 11:45 PMephemient
12/13/2023, 6:22 AMephemient
12/13/2023, 6:23 AMritesh
12/13/2023, 3:52 PMNeil Banman
12/14/2023, 8:35 AMjonas.app
12/16/2023, 8:44 AM