Skip to content

Commit

Permalink
Optimizer solution for 2022-21
Browse files Browse the repository at this point in the history
  • Loading branch information
jurisk committed Dec 16, 2023
1 parent 153ca0b commit 8cd9c9b
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ object Advent23 {
val ctx = new Context
import ctx._

val o = mkOptimize
val o = mkOptimize()

val List(x, y, z) = List("x", "y", "z").map(mkIntConst)

Expand Down
124 changes: 108 additions & 16 deletions scala2/src/main/scala/jurisk/adventofcode/y2022/Advent21.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package jurisk.adventofcode.y2022

import cats.implicits._
import com.microsoft.z3.{Context, IntNum}
import jurisk.adventofcode.y2022.Advent21.Expression._
import jurisk.adventofcode.y2022.Advent21.Operation._
import jurisk.utils.FileInput._
Expand Down Expand Up @@ -144,29 +145,100 @@ object Advent21 {
translate(target)
}

def part1(data: Parsed): Value = {
val commands = data.toMap
val root = convertCommandsToExpression(Root, commands, none)
root.rearrange match {
case Literal(value) => value
case other => s"Expected Literal here but got $other".fail
private def solveOptimizer(
commands: Map[Name, Monkey],
calculate: Name,
extraEquality: Option[(Name, Name)],
): Value = {
val ctx = new Context
import ctx._

val o = mkOptimize()

extraEquality foreach { case (a, b) =>
o.Add(mkEq(mkIntConst(a), mkIntConst(b)))
}

commands foreach { case (name, monkey) =>
val n = mkIntConst(name)
monkey match {
case Monkey.BinaryMonkey(aName, operation, bName) =>
val a = mkIntConst(aName)
val b = mkIntConst(bName)

val clauses = operation match {
case Operation.Plus => mkEq(n, mkAdd(a, b)) :: Nil
case Operation.Minus => mkEq(n, mkSub(a, b)) :: Nil
case Operation.Multiply => mkEq(n, mkMul(a, b)) :: Nil
case Operation.Divide =>
mkEq(n, mkDiv(a, b)) ::
mkEq(mkRem(a, b), mkInt(0)) ::
Nil
}

clauses foreach { clause =>
o.Add(clause)
}
case Monkey.Literal(value) => o.Add(mkEq(n, mkInt(value)))
}
}

println(o.Check())

val model = o.getModel

val result = model.evaluate(mkIntConst(calculate), true)

result match {
case intNum: IntNum => intNum.getInt64
case _ => s"Expected IntNum: $result".fail
}
}

def part2(data: Parsed): Value = {
val Human = "humn"
private def solvePart1Optimizer(
commands: Map[Name, Monkey],
calculate: Name,
): Value = solveOptimizer(commands, calculate, none)

val allCommands = data.toMap - Human
val rootCommand = allCommands(Root)
val (rootA, rootB) = rootCommand match {
case c: Monkey.BinaryMonkey => (c.a, c.b)
case _ => s"Unexpectedly $rootCommand is not a binary command".fail
private def solvePart2Optimizer(
commands: Map[Name, Monkey],
leftSideName: Name,
rightSideName: Name,
calculate: Name,
): Value =
solveOptimizer(commands, calculate, (leftSideName, rightSideName).some)

private def solvePart1Algebraic(
commands: Map[Name, Monkey],
calculate: Name,
): Value = {
val expression = convertCommandsToExpression(calculate, commands, none)
println(s"Part 1 expression for $calculate: $expression")

expression.rearrange match {
case Literal(value) => value
case other => s"Expected Literal here but got $other".fail
}
}

val commands: Map[Name, Monkey] = allCommands - Root
def part1(data: Parsed): Value = {
val commands = data.toMap
val (a, b) =
(solvePart1Algebraic(commands, Root), solvePart1Optimizer(commands, Root))
assert(a == b, s"Got different results: $a and $b")
a
}

val leftSide = convertCommandsToExpression(rootA, commands, Human.some)
val rightSide = convertCommandsToExpression(rootB, commands, Human.some)
private def solvePart2Algebraic(
commands: Map[Name, Monkey],
leftSideName: Name,
rightSideName: Name,
calculate: Name,
): Value = {
val leftSide =
convertCommandsToExpression(leftSideName, commands, calculate.some)
val rightSide =
convertCommandsToExpression(rightSideName, commands, calculate.some)

println(s"${leftSide.display} = ${leftSide.display}")

Expand Down Expand Up @@ -211,6 +283,26 @@ object Advent21 {
result
}

def part2(data: Parsed): Value = {
val Human = "humn"

val allCommands = data.toMap - Human
val rootCommand = allCommands(Root)
val (rootA, rootB) = rootCommand match {
case c: Monkey.BinaryMonkey => (c.a, c.b)
case _ => s"Unexpectedly $rootCommand is not a binary command".fail
}

val commands: Map[Name, Monkey] = allCommands - Root

val (s1, s2) = (
solvePart2Algebraic(commands, rootA, rootB, Human),
solvePart2Optimizer(commands, rootA, rootB, Human),
)
assert(s1 == s1, s"Got different results: $s1 and $s2")
s1
}

def main(args: Array[String]): Unit = {
val testData = readFileText("2022/21-test.txt")
val realData = readFileText("2022/21.txt")
Expand Down

0 comments on commit 8cd9c9b

Please sign in to comment.