From 665235e23fd6f0b3d5202f4e49835aae5688012a Mon Sep 17 00:00:00 2001 From: lbressler13 Date: Fri, 1 Mar 2024 03:20:02 -0500 Subject: [PATCH] feat: replace toTerm with getSimplified --- .../exactnumbers/expressions/Expression.kt | 2 +- .../expressions/ExpressionImpl.kt | 4 +- .../expression/AdditiveExpression.kt | 19 +------ .../expression/MultiplicativeExpression.kt | 46 +++++++++++++-- .../expression/SimpleExpression.kt | 8 +-- .../expression/AdditiveExpressionTest.kt | 2 +- .../MultiplicativeExpressionTest.kt | 2 +- .../expression/SimpleExpressionTest.kt | 2 +- .../expression/multiplicative/castingTests.kt | 57 +++++++++---------- .../expression/multiplicative/unaryTests.kt | 4 ++ .../expression/simple/castingTests.kt | 36 ++++++------ signatures/v1.1.0/v1.1.0.md | 3 +- 12 files changed, 102 insertions(+), 83 deletions(-) diff --git a/exact-numbers/src/main/kotlin/xyz/lbres/exactnumbers/expressions/Expression.kt b/exact-numbers/src/main/kotlin/xyz/lbres/exactnumbers/expressions/Expression.kt index 726e1a6..c06d35d 100644 --- a/exact-numbers/src/main/kotlin/xyz/lbres/exactnumbers/expressions/Expression.kt +++ b/exact-numbers/src/main/kotlin/xyz/lbres/exactnumbers/expressions/Expression.kt @@ -20,7 +20,7 @@ sealed class Expression : Number() { // abstract operator fun times(other: Expression): Expression // abstract operator fun div(other: Expression): Expression - abstract fun toTerm(): Term + // abstract fun toTerm(): Term abstract fun getSimplified(): Expression companion object { diff --git a/exact-numbers/src/main/kotlin/xyz/lbres/exactnumbers/expressions/ExpressionImpl.kt b/exact-numbers/src/main/kotlin/xyz/lbres/exactnumbers/expressions/ExpressionImpl.kt index 1c520c3..9255759 100644 --- a/exact-numbers/src/main/kotlin/xyz/lbres/exactnumbers/expressions/ExpressionImpl.kt +++ b/exact-numbers/src/main/kotlin/xyz/lbres/exactnumbers/expressions/ExpressionImpl.kt @@ -11,7 +11,9 @@ import xyz.lbres.exactnumbers.utils.castToShort // internal implementation of expression @Suppress("EqualsOrHashCode") internal abstract class ExpressionImpl : Expression() { - override fun equals(other: Any?): Boolean = other is Expression && getValue() == other.getValue() + override fun equals(other: Any?): Boolean { + return other is Expression && getSimplified().getValue() == other.getSimplified().getValue() + } override fun toByte(): Byte = castToByte(getValue(), this, "Expression") override fun toChar(): Char = castToChar(getValue(), this, "Expression") diff --git a/exact-numbers/src/main/kotlin/xyz/lbres/exactnumbers/expressions/expression/AdditiveExpression.kt b/exact-numbers/src/main/kotlin/xyz/lbres/exactnumbers/expressions/expression/AdditiveExpression.kt index 46389c1..a55b530 100644 --- a/exact-numbers/src/main/kotlin/xyz/lbres/exactnumbers/expressions/expression/AdditiveExpression.kt +++ b/exact-numbers/src/main/kotlin/xyz/lbres/exactnumbers/expressions/expression/AdditiveExpression.kt @@ -1,11 +1,8 @@ package xyz.lbres.exactnumbers.expressions.expression -import xyz.lbres.exactnumbers.exactfraction.ExactFraction import xyz.lbres.exactnumbers.expressions.Expression import xyz.lbres.exactnumbers.expressions.ExpressionImpl -import xyz.lbres.exactnumbers.expressions.term.Term import xyz.lbres.exactnumbers.utils.createHashCode -import xyz.lbres.exactnumbers.utils.getOrSet import xyz.lbres.kotlinutils.collection.ext.toConstMultiSet import xyz.lbres.kotlinutils.set.multiset.const.ConstMultiSet import xyz.lbres.kotlinutils.set.multiset.const.constMultiSetOf @@ -17,8 +14,7 @@ import java.math.BigDecimal * Can also represent 1/sum */ @Suppress("EqualsOrHashCode") -internal class AdditiveExpression private constructor(private val expressions: ConstMultiSet, private val isInverted: Boolean) : ExpressionImpl() { - private var term: Term? = null +internal class AdditiveExpression private constructor(val expressions: ConstMultiSet, private val isInverted: Boolean) : ExpressionImpl() { init { if (expressions.isEmpty()) { @@ -27,6 +23,7 @@ internal class AdditiveExpression private constructor(private val expressions: C } constructor(expr1: Expression, expr2: Expression) : this(constMultiSetOf(expr1, expr2), false) + constructor(expressions: ConstMultiSet) : this(expressions, false) override fun unaryPlus(): Expression = this override fun unaryMinus(): Expression { @@ -36,18 +33,6 @@ internal class AdditiveExpression private constructor(private val expressions: C override fun inverse(): Expression = AdditiveExpression(expressions, !isInverted) - override fun toTerm(): Term { - return getOrSet({ term }, { term = it }) { - val terms = expressions.map { it.toTerm() } - .groupBy { it.factors }.map { - val coefficient = it.value.fold(ExactFraction.ZERO) { acc, t -> acc + t.coefficient } // value is list of terms - Term.fromValues(coefficient, it.key) // key is list of factors - } - Term.ZERO - // TODO - } - } - override fun getValue(): BigDecimal = BigDecimal.ZERO // TODO override fun getSimplified(): Expression = this // TODO override fun isZero(): Boolean = false // TODO diff --git a/exact-numbers/src/main/kotlin/xyz/lbres/exactnumbers/expressions/expression/MultiplicativeExpression.kt b/exact-numbers/src/main/kotlin/xyz/lbres/exactnumbers/expressions/expression/MultiplicativeExpression.kt index b1e1911..95bde40 100644 --- a/exact-numbers/src/main/kotlin/xyz/lbres/exactnumbers/expressions/expression/MultiplicativeExpression.kt +++ b/exact-numbers/src/main/kotlin/xyz/lbres/exactnumbers/expressions/expression/MultiplicativeExpression.kt @@ -4,12 +4,14 @@ import xyz.lbres.exactnumbers.expressions.Expression import xyz.lbres.exactnumbers.expressions.ExpressionImpl import xyz.lbres.exactnumbers.expressions.term.Term import xyz.lbres.exactnumbers.utils.createHashCode -import xyz.lbres.exactnumbers.utils.getOrSet import xyz.lbres.kotlinutils.bigdecimal.ext.isZero import xyz.lbres.kotlinutils.collection.ext.toConstMultiSet +import xyz.lbres.kotlinutils.iterable.ext.forEachWith import xyz.lbres.kotlinutils.set.multiset.anyConsistent import xyz.lbres.kotlinutils.set.multiset.const.ConstMultiSet +import xyz.lbres.kotlinutils.set.multiset.const.ConstMutableMultiSet import xyz.lbres.kotlinutils.set.multiset.const.constMultiSetOf +import xyz.lbres.kotlinutils.set.multiset.const.constMutableMultiSetOf import xyz.lbres.kotlinutils.set.multiset.mapToSetConsistent import java.math.BigDecimal @@ -19,7 +21,6 @@ import java.math.BigDecimal @Suppress("EqualsOrHashCode") internal class MultiplicativeExpression private constructor(expressions: ConstMultiSet) : ExpressionImpl() { private val expressions: ConstMultiSet - private var term: Term? = null init { this.expressions = when { @@ -44,13 +45,46 @@ internal class MultiplicativeExpression private constructor(expressions: ConstMu override fun isZero(): Boolean = expressions.any { it.isZero() } - override fun toTerm(): Term { - return getOrSet({ term }, { term = it }) { - expressions.fold(Term.ONE) { acc, expr -> acc * expr.toTerm() }.getSimplified() + private fun getSplitExpressions(): Pair, ConstMultiSet> { + val simple: ConstMutableMultiSet = constMutableMultiSetOf() + val additive: ConstMutableMultiSet = constMutableMultiSetOf() + + expressions.forEach { + when (it) { + is SimpleExpression -> simple.add(it) + is AdditiveExpression -> additive.add(it) + is MultiplicativeExpression -> { + val split = it.getSplitExpressions() + simple.addAll(split.first) + additive.addAll(split.second) + } + } + } + + return Pair(simple, additive) + } + + override fun getSimplified(): Expression { + val split = getSplitExpressions() + val simpleTerm = split.first.fold(Term.ONE) { acc, expr -> acc * expr.term } + val simple: Expression = SimpleExpression(simpleTerm.getSimplified()) + + if (split.second.isEmpty()) { + return simple + } + + // TODO extract coefficient for each additive expr + + val exprs = split.second.fold(constMultiSetOf(simple)) { acc, additiveExpr -> + val distributed: ConstMutableMultiSet = constMutableMultiSetOf() + acc.forEachWith(additiveExpr.expressions) { expr1, expr2 -> + distributed.add(MultiplicativeExpression(expr1, expr2)) // TODO use times + } + distributed } + return AdditiveExpression(exprs.toConstMultiSet()).getSimplified() } - override fun getSimplified(): Expression = SimpleExpression(toTerm()) override fun getValue(): BigDecimal = getSimplified().getValue() override fun hashCode(): Int = createHashCode(listOf(expressions, "MultiplicativeExpression")) diff --git a/exact-numbers/src/main/kotlin/xyz/lbres/exactnumbers/expressions/expression/SimpleExpression.kt b/exact-numbers/src/main/kotlin/xyz/lbres/exactnumbers/expressions/expression/SimpleExpression.kt index c1b98ca..5ddf6ef 100644 --- a/exact-numbers/src/main/kotlin/xyz/lbres/exactnumbers/expressions/expression/SimpleExpression.kt +++ b/exact-numbers/src/main/kotlin/xyz/lbres/exactnumbers/expressions/expression/SimpleExpression.kt @@ -4,23 +4,19 @@ import xyz.lbres.exactnumbers.expressions.Expression import xyz.lbres.exactnumbers.expressions.ExpressionImpl import xyz.lbres.exactnumbers.expressions.term.Term import xyz.lbres.exactnumbers.utils.createHashCode -import xyz.lbres.exactnumbers.utils.getOrSet import java.math.BigDecimal /** * Expression consisting of a single term */ @Suppress("EqualsOrHashCode") -internal class SimpleExpression(private val term: Term) : ExpressionImpl() { - private var simplified: Expression? = null - +internal class SimpleExpression(val term: Term) : ExpressionImpl() { override fun unaryPlus(): Expression = this override fun unaryMinus(): Expression = SimpleExpression(-term) override fun inverse(): Expression = SimpleExpression(term.inverse()) override fun isZero(): Boolean = term.isZero() - override fun toTerm(): Term = term - override fun getSimplified(): Expression = getOrSet({ simplified }, { simplified = it }) { SimpleExpression(term.getSimplified()) } + override fun getSimplified(): SimpleExpression = SimpleExpression(term.getSimplified()) override fun getValue(): BigDecimal = term.getValue() override fun hashCode(): Int = createHashCode(listOf(term, "Expression")) diff --git a/exact-numbers/src/test/kotlin/xyz/lbres/exactnumbers/expressions/expression/AdditiveExpressionTest.kt b/exact-numbers/src/test/kotlin/xyz/lbres/exactnumbers/expressions/expression/AdditiveExpressionTest.kt index 31a0096..478eb24 100644 --- a/exact-numbers/src/test/kotlin/xyz/lbres/exactnumbers/expressions/expression/AdditiveExpressionTest.kt +++ b/exact-numbers/src/test/kotlin/xyz/lbres/exactnumbers/expressions/expression/AdditiveExpressionTest.kt @@ -12,7 +12,7 @@ class AdditiveExpressionTest { // @Test fun testInverse() = runInverseTests() // TODO // @Test fun testGetValue() = runGetValueTests() // TODO - // @Test fun testToTerm() = runToTermTests() // TODO + // @Test fun testToTerm() = runToTermTests() // @Test fun testToByte() = runToByteTests() // TODO // @Test fun testToChar() = runToCharTests() // TODO // @Test fun testToShort() = runToShortTests() // TODO diff --git a/exact-numbers/src/test/kotlin/xyz/lbres/exactnumbers/expressions/expression/MultiplicativeExpressionTest.kt b/exact-numbers/src/test/kotlin/xyz/lbres/exactnumbers/expressions/expression/MultiplicativeExpressionTest.kt index 39f7d2c..23b69da 100644 --- a/exact-numbers/src/test/kotlin/xyz/lbres/exactnumbers/expressions/expression/MultiplicativeExpressionTest.kt +++ b/exact-numbers/src/test/kotlin/xyz/lbres/exactnumbers/expressions/expression/MultiplicativeExpressionTest.kt @@ -14,7 +14,7 @@ class MultiplicativeExpressionTest { @Test fun testGetSimplified() = runGetSimplifiedTests() @Test fun testIsZero() = runIsZeroTests() - @Test fun testToTerm() = runToTermTests() + // @Test fun testToTerm() = runToTermTests() @Test fun testToByte() = runToByteTests() @Test fun testToChar() = runToCharTests() @Test fun testToShort() = runToShortTests() diff --git a/exact-numbers/src/test/kotlin/xyz/lbres/exactnumbers/expressions/expression/SimpleExpressionTest.kt b/exact-numbers/src/test/kotlin/xyz/lbres/exactnumbers/expressions/expression/SimpleExpressionTest.kt index 7a97f9a..714d0ee 100644 --- a/exact-numbers/src/test/kotlin/xyz/lbres/exactnumbers/expressions/expression/SimpleExpressionTest.kt +++ b/exact-numbers/src/test/kotlin/xyz/lbres/exactnumbers/expressions/expression/SimpleExpressionTest.kt @@ -14,7 +14,7 @@ class SimpleExpressionTest { @Test fun testGetSimplified() = runGetSimplifiedTests() @Test fun isZero() = runIsZeroTests() - @Test fun testToTerm() = runToTermTests() + // @Test fun testToTerm() = runToTermTests() @Test fun testToByte() = runToByteTests() @Test fun testToChar() = runToCharTests() @Test fun testToShort() = runToShortTests() diff --git a/exact-numbers/src/test/kotlin/xyz/lbres/exactnumbers/expressions/expression/multiplicative/castingTests.kt b/exact-numbers/src/test/kotlin/xyz/lbres/exactnumbers/expressions/expression/multiplicative/castingTests.kt index a079512..f53ccde 100644 --- a/exact-numbers/src/test/kotlin/xyz/lbres/exactnumbers/expressions/expression/multiplicative/castingTests.kt +++ b/exact-numbers/src/test/kotlin/xyz/lbres/exactnumbers/expressions/expression/multiplicative/castingTests.kt @@ -5,41 +5,40 @@ import xyz.lbres.exactnumbers.expressions.Expression import xyz.lbres.exactnumbers.expressions.expression.* // ktlint-disable no-wildcard-imports no-unused-imports import xyz.lbres.exactnumbers.expressions.term.Term import xyz.lbres.exactnumbers.irrationals.log.Log -import xyz.lbres.exactnumbers.irrationals.sqrt.Sqrt import xyz.lbres.exactnumbers.testutils.assertSucceeds import xyz.lbres.exactnumbers.testutils.getCastingOverflowAssertion import kotlin.test.assertEquals private val assertCastingOverflow = getCastingOverflowAssertion("Expression") -fun runToTermTests() { - var expr = MultiplicativeExpression(Expression.ONE, Expression.ZERO) - assertEquals(Term.ZERO, expr.toTerm()) - - expr = MultiplicativeExpression(partialMultExpr, partialMultExpr.inverse()) - assertEquals(Term.ONE, expr.toTerm()) - assertEquals(Term.ONE, expr.toTerm()) - - expr = MultiplicativeExpression(simpleExpr1, Expression.ONE) - var expected = Term.fromValues(ExactFraction.EIGHT, listOf(pi)) - assertEquals(expected, expr.toTerm()) - - expr = MultiplicativeExpression(simpleExpr1, partialMultExpr.inverse()) - expected = Term.fromValues(one, listOf(sqrt1.inverse())) - assertEquals(expected, expr.toTerm()) - assertEquals(expected, expr.toTerm()) - - expr = MultiplicativeExpression(simpleExpr2, simpleExpr1) - expected = Term.fromValues(ExactFraction(512, 187), listOf(pi, log4)) - assertEquals(expected, expr.toTerm()) - - val expr1 = MultiplicativeExpression(-simpleExpr2, partialMultExpr.inverse()) - val expr2 = MultiplicativeExpression(simpleExpr1.inverse(), MultiplicativeExpression(simpleExpr3, simpleExpr3)) - expr = MultiplicativeExpression(expr1, expr2) - expected = Term.fromValues(ExactFraction(-3, 187), listOf(log4, Sqrt(11), piInverse, piInverse)) - assertEquals(expected, expr.toTerm()) - assertEquals(expected, expr.toTerm()) -} +// fun runToTermTests() { +// var expr = MultiplicativeExpression(Expression.ONE, Expression.ZERO) +// assertEquals(Term.ZERO, expr.toTerm()) +// +// expr = MultiplicativeExpression(partialMultExpr, partialMultExpr.inverse()) +// assertEquals(Term.ONE, expr.toTerm()) +// assertEquals(Term.ONE, expr.toTerm()) +// +// expr = MultiplicativeExpression(simpleExpr1, Expression.ONE) +// var expected = Term.fromValues(ExactFraction.EIGHT, listOf(pi)) +// assertEquals(expected, expr.toTerm()) +// +// expr = MultiplicativeExpression(simpleExpr1, partialMultExpr.inverse()) +// expected = Term.fromValues(one, listOf(sqrt1.inverse())) +// assertEquals(expected, expr.toTerm()) +// assertEquals(expected, expr.toTerm()) +// +// expr = MultiplicativeExpression(simpleExpr2, simpleExpr1) +// expected = Term.fromValues(ExactFraction(512, 187), listOf(pi, log4)) +// assertEquals(expected, expr.toTerm()) +// +// val expr1 = MultiplicativeExpression(-simpleExpr2, partialMultExpr.inverse()) +// val expr2 = MultiplicativeExpression(simpleExpr1.inverse(), MultiplicativeExpression(simpleExpr3, simpleExpr3)) +// expr = MultiplicativeExpression(expr1, expr2) +// expected = Term.fromValues(ExactFraction(-3, 187), listOf(log4, Sqrt(11), piInverse, piInverse)) +// assertEquals(expected, expr.toTerm()) +// assertEquals(expected, expr.toTerm()) +// } fun runToByteTests() { runWholeNumberCastingTests(Long::toByte, MultiplicativeExpression::toByte, Byte.MIN_VALUE, Byte.MAX_VALUE, "Byte") diff --git a/exact-numbers/src/test/kotlin/xyz/lbres/exactnumbers/expressions/expression/multiplicative/unaryTests.kt b/exact-numbers/src/test/kotlin/xyz/lbres/exactnumbers/expressions/expression/multiplicative/unaryTests.kt index 9f652ca..382e32f 100644 --- a/exact-numbers/src/test/kotlin/xyz/lbres/exactnumbers/expressions/expression/multiplicative/unaryTests.kt +++ b/exact-numbers/src/test/kotlin/xyz/lbres/exactnumbers/expressions/expression/multiplicative/unaryTests.kt @@ -94,6 +94,7 @@ fun runGetValueTests() { expr = MultiplicativeExpression(partialMultExpr.inverse(), -simpleExpr2.inverse()) expected = BigDecimal("0.017061281824748112795308108019747092438130381820126559258080078125") + // expected = BigDecimal("0.0170612818247481127955653165209070906353536211925663773027158203125") assertEquals(expected, expr.getValue()) } @@ -103,6 +104,7 @@ fun runGetSimplifiedTests() { expr = MultiplicativeExpression(partialMultExpr, partialMultExpr.inverse()) assertEquals(Expression.ONE, expr.getSimplified()) + assertEquals(Expression.ONE, expr.getSimplified()) expr = MultiplicativeExpression(simpleExpr1, Expression.ONE) var term = Term.fromValues(ExactFraction.EIGHT, listOf(pi)) @@ -111,10 +113,12 @@ fun runGetSimplifiedTests() { expr = MultiplicativeExpression(simpleExpr1, partialMultExpr.inverse()) term = Term.fromValues(one, listOf(sqrt1.inverse())) assertEquals(SimpleExpression(term), expr.getSimplified()) + assertEquals(SimpleExpression(term), expr.getSimplified()) expr = MultiplicativeExpression(simpleExpr2, simpleExpr1) term = Term.fromValues(ExactFraction(512, 187), listOf(pi, log4)) assertEquals(SimpleExpression(term), expr.getSimplified()) + assertEquals(SimpleExpression(term), expr.getSimplified()) val expr1 = MultiplicativeExpression(-simpleExpr2, partialMultExpr.inverse()) val expr2 = MultiplicativeExpression(simpleExpr1.inverse(), MultiplicativeExpression(simpleExpr3, simpleExpr3)) diff --git a/exact-numbers/src/test/kotlin/xyz/lbres/exactnumbers/expressions/expression/simple/castingTests.kt b/exact-numbers/src/test/kotlin/xyz/lbres/exactnumbers/expressions/expression/simple/castingTests.kt index 5d6615e..a6f4746 100644 --- a/exact-numbers/src/test/kotlin/xyz/lbres/exactnumbers/expressions/expression/simple/castingTests.kt +++ b/exact-numbers/src/test/kotlin/xyz/lbres/exactnumbers/expressions/expression/simple/castingTests.kt @@ -13,24 +13,24 @@ import kotlin.test.assertEquals private val assertCastingOverflow = getCastingOverflowAssertion("Expression") -fun runToTermTests() { - var expr = SimpleExpression(Term.ZERO) - var expected = Term.ZERO - assertEquals(expected, expr.toTerm()) - - expr = SimpleExpression(Term.fromValues(ExactFraction(44, 7), emptyList())) - expected = Term.fromValues(ExactFraction(44, 7), emptyList()) - assertEquals(expected, expr.toTerm()) - - expr = SimpleExpression(Term.fromValues(one, listOf(log2, log4, log1))) - expected = Term.fromValues(one, listOf(log4, log1, log2)) - assertEquals(expected, expr.toTerm()) - - val factors = listOf(log2, log2, log4, testNumber1, log1, sqrt1, sqrt2, piInverse, pi) - expr = SimpleExpression(Term.fromValues(ExactFraction(-100, 333), factors)) - expected = Term.fromValues(ExactFraction(-100, 333), factors) - assertEquals(expected, expr.toTerm()) -} +// fun runToTermTests() { +// var expr = SimpleExpression(Term.ZERO) +// var expected = Term.ZERO +// assertEquals(expected, expr.toTerm()) +// +// expr = SimpleExpression(Term.fromValues(ExactFraction(44, 7), emptyList())) +// expected = Term.fromValues(ExactFraction(44, 7), emptyList()) +// assertEquals(expected, expr.toTerm()) +// +// expr = SimpleExpression(Term.fromValues(one, listOf(log2, log4, log1))) +// expected = Term.fromValues(one, listOf(log4, log1, log2)) +// assertEquals(expected, expr.toTerm()) +// +// val factors = listOf(log2, log2, log4, testNumber1, log1, sqrt1, sqrt2, piInverse, pi) +// expr = SimpleExpression(Term.fromValues(ExactFraction(-100, 333), factors)) +// expected = Term.fromValues(ExactFraction(-100, 333), factors) +// assertEquals(expected, expr.toTerm()) +// } fun runToByteTests() { runWholeNumberCastingTests(Long::toByte, SimpleExpression::toByte, Byte.MIN_VALUE, Byte.MAX_VALUE, "Byte") diff --git a/signatures/v1.1.0/v1.1.0.md b/signatures/v1.1.0/v1.1.0.md index 7f3dc6f..426b7d5 100644 --- a/signatures/v1.1.0/v1.1.0.md +++ b/signatures/v1.1.0/v1.1.0.md @@ -125,12 +125,11 @@ val overflowValue: Any? ```kotlin class Expression: Number() +fun getSimplified(): Expression fun getValue(): BigDecimal fun inverse(): Expression fun isZero(): Boolean -fun toTerm(): Term - operator fun unaryMinus(): Expression operator fun unaryPlus(): Expression ```