Optimize Day14 + benchmarks
This commit is contained in:
parent
c1f0b7be70
commit
2aa4226083
@ -20,5 +20,5 @@ dependencies {
|
|||||||
}
|
}
|
||||||
|
|
||||||
testImplementation(Libs.Jmh.core)
|
testImplementation(Libs.Jmh.core)
|
||||||
testImplementation(Libs.Jmh.processor)
|
kaptTest(Libs.Jmh.processor)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import be.vandewalleh.aoc.utils.input.Lines
|
|||||||
import be.vandewalleh.aoc.utils.input.createDay
|
import be.vandewalleh.aoc.utils.input.createDay
|
||||||
import kotlin.math.pow
|
import kotlin.math.pow
|
||||||
import org.eclipse.collections.impl.factory.primitive.IntObjectMaps
|
import org.eclipse.collections.impl.factory.primitive.IntObjectMaps
|
||||||
import org.eclipse.collections.impl.factory.primitive.ObjectIntMaps
|
import org.eclipse.collections.impl.factory.primitive.LongIntMaps
|
||||||
|
|
||||||
@Day(14)
|
@Day(14)
|
||||||
class Day14(@Lines val input: Input<List<String>>) {
|
class Day14(@Lines val input: Input<List<String>>) {
|
||||||
@ -42,7 +42,7 @@ class Day14(@Lines val input: Input<List<String>>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun part2(): Long {
|
fun part2(): Long {
|
||||||
val mem = ObjectIntMaps.mutable.empty<String>()
|
val mem = LongIntMaps.mutable.empty()
|
||||||
|
|
||||||
var currentMask = ""
|
var currentMask = ""
|
||||||
|
|
||||||
@ -55,10 +55,10 @@ class Day14(@Lines val input: Input<List<String>>) {
|
|||||||
add.toLong().toBin36() to value.toInt()
|
add.toLong().toBin36() to value.toInt()
|
||||||
}
|
}
|
||||||
|
|
||||||
val builders = generateMutations(currentMask, address)
|
val mutations = generateMutations(currentMask, address)
|
||||||
|
|
||||||
for (builder in builders) {
|
for (mutation in mutations) {
|
||||||
mem.put(builder.toString(), value)
|
mem.put(String(mutation).toLong(2), value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -66,9 +66,9 @@ class Day14(@Lines val input: Input<List<String>>) {
|
|||||||
return mem.values().sum()
|
return mem.values().sum()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun generateMutations(mask: String, address: String): Array<StringBuilder> {
|
private fun generateMutations(mask: String, address: String): Array<CharArray> {
|
||||||
val mutations = mask.count { it == 'X' }.let { 2.0.pow(it.toDouble()).toInt() }
|
val mutationCount = mask.count { it == 'X' }.let { 2.0.pow(it.toDouble()).toInt() }
|
||||||
val builders = Array(mutations) { StringBuilder(36) }
|
val mutations = Array(mutationCount) { CharArray(36) }
|
||||||
|
|
||||||
var groups = 1
|
var groups = 1
|
||||||
|
|
||||||
@ -76,24 +76,20 @@ class Day14(@Lines val input: Input<List<String>>) {
|
|||||||
when (mask[i]) {
|
when (mask[i]) {
|
||||||
'X' -> {
|
'X' -> {
|
||||||
groups *= 2
|
groups *= 2
|
||||||
val groupSize = mutations / groups
|
val groupSize = mutationCount / groups
|
||||||
var j = 1
|
var currentChar = '1'
|
||||||
for (b in builders.indices) {
|
for (b in mutations.indices) {
|
||||||
val builder = builders[b]
|
val builder = mutations[b]
|
||||||
val flip = b % groupSize == 0
|
val flip = b % groupSize == 0
|
||||||
if (flip) j = if (j == 0) 1 else 0
|
if (flip) currentChar = if (currentChar == '0') '1' else '0'
|
||||||
builder.append(j)
|
builder[i] = currentChar
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
'1' -> {
|
'1' -> mutations.forEach { it[i] = '1' }
|
||||||
builders.forEach { it.append('1') }
|
else -> mutations.forEach { it[i] = address[i] }
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
builders.forEach { it.append(address[i]) }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
return mutations
|
||||||
return builders
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
112
days/src/test/kotlin/Day14Benchmark.kt
Normal file
112
days/src/test/kotlin/Day14Benchmark.kt
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
package be.vandewalleh.aoc.days
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
import kotlin.math.pow
|
||||||
|
import org.openjdk.jmh.annotations.*
|
||||||
|
import org.openjdk.jmh.infra.Blackhole
|
||||||
|
import org.openjdk.jmh.runner.Runner
|
||||||
|
import org.openjdk.jmh.runner.options.Options
|
||||||
|
import org.openjdk.jmh.runner.options.OptionsBuilder
|
||||||
|
|
||||||
|
/*
|
||||||
|
Benchmark Mode Cnt Score Error Units
|
||||||
|
Day14Benchmark.charArrays avgt 5 0.038 ± 0.001 ms/op
|
||||||
|
Day14Benchmark.countReplacePad avgt 5 0.044 ± 0.002 ms/op
|
||||||
|
Day14Benchmark.stringBuilders avgt 5 0.082 ± 0.005 ms/op
|
||||||
|
*/
|
||||||
|
|
||||||
|
@BenchmarkMode(Mode.AverageTime)
|
||||||
|
@OutputTimeUnit(TimeUnit.MILLISECONDS)
|
||||||
|
@State(Scope.Benchmark)
|
||||||
|
@Warmup(iterations = 3)
|
||||||
|
@Measurement(iterations = 5)
|
||||||
|
open class Day14Benchmark {
|
||||||
|
|
||||||
|
private val mask = "1XX10X10100X1010X1000100X0X10X001X00"
|
||||||
|
private val address = 43398.toString(2).padStart(36, '0')
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
fun stringBuilders(blackhole: Blackhole) {
|
||||||
|
val mutationCount = mask.count { it == 'X' }.let { 2.0.pow(it.toDouble()).toInt() }
|
||||||
|
val mutations = Array(mutationCount) { StringBuilder(36) }
|
||||||
|
|
||||||
|
var groups = 1
|
||||||
|
|
||||||
|
for (i in mask.indices) {
|
||||||
|
when (mask[i]) {
|
||||||
|
'X' -> {
|
||||||
|
groups *= 2
|
||||||
|
val groupSize = mutationCount / groups
|
||||||
|
var currentChar = '1'
|
||||||
|
for (b in mutations.indices) {
|
||||||
|
val builder = mutations[b]
|
||||||
|
val flip = b % groupSize == 0
|
||||||
|
if (flip) currentChar = if (currentChar == '0') '1' else '0'
|
||||||
|
builder.append(currentChar)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'1' -> mutations.forEach { it.append('1') }
|
||||||
|
else -> mutations.forEach { it.append(address[i]) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
blackhole.consume(mutations)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
fun charArrays(blackhole: Blackhole) {
|
||||||
|
val mutationCount = mask.count { it == 'X' }.let { 2.0.pow(it.toDouble()).toInt() }
|
||||||
|
val mutations = Array(mutationCount) { CharArray(36) }
|
||||||
|
|
||||||
|
var groups = 1
|
||||||
|
|
||||||
|
for (i in mask.indices) {
|
||||||
|
when (mask[i]) {
|
||||||
|
'X' -> {
|
||||||
|
groups *= 2
|
||||||
|
val groupSize = mutationCount / groups
|
||||||
|
var currentChar = '1'
|
||||||
|
for (b in mutations.indices) {
|
||||||
|
val builder = mutations[b]
|
||||||
|
val flip = b % groupSize == 0
|
||||||
|
if (flip) currentChar = if (currentChar == '0') '1' else '0'
|
||||||
|
builder[i] = currentChar
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'1' -> mutations.forEach { it[i] = '1' }
|
||||||
|
else -> mutations.forEach { it[i] = address[i] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
blackhole.consume(mutations)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
fun countReplacePad(blackhole: Blackhole) {
|
||||||
|
val bitCount = mask.count { it == 'X' }
|
||||||
|
val mutationCount = bitCount.let { 2.0.pow(it.toDouble()).toInt() }
|
||||||
|
|
||||||
|
val results = Array(mutationCount) { CharArray(36) }
|
||||||
|
|
||||||
|
repeat(mutationCount) { i ->
|
||||||
|
var count = 0
|
||||||
|
val result = results[i]
|
||||||
|
val currentMask = i.toString(2).padStart(bitCount, '0')
|
||||||
|
for (j in address.indices) {
|
||||||
|
result[j] = when (mask[j]) {
|
||||||
|
'X' -> currentMask[count++]
|
||||||
|
'1' -> '1'
|
||||||
|
else -> address[j]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
blackhole.consume(results)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
val opt: Options = OptionsBuilder()
|
||||||
|
.include(Day14Benchmark::class.java.simpleName)
|
||||||
|
.forks(1)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
Runner(opt).run()
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user