Skip to content

Commit

Permalink
feat: replace toTerm with getSimplified
Browse files Browse the repository at this point in the history
  • Loading branch information
lbressler13 committed Mar 1, 2024
1 parent 4af6ae5 commit 665235e
Show file tree
Hide file tree
Showing 12 changed files with 102 additions and 83 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -17,8 +14,7 @@ import java.math.BigDecimal
* Can also represent 1/sum
*/
@Suppress("EqualsOrHashCode")
internal class AdditiveExpression private constructor(private val expressions: ConstMultiSet<Expression>, private val isInverted: Boolean) : ExpressionImpl() {
private var term: Term? = null
internal class AdditiveExpression private constructor(val expressions: ConstMultiSet<Expression>, private val isInverted: Boolean) : ExpressionImpl() {

init {
if (expressions.isEmpty()) {
Expand All @@ -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<Expression>) : this(expressions, false)

override fun unaryPlus(): Expression = this
override fun unaryMinus(): Expression {
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -19,7 +21,6 @@ import java.math.BigDecimal
@Suppress("EqualsOrHashCode")
internal class MultiplicativeExpression private constructor(expressions: ConstMultiSet<Expression>) : ExpressionImpl() {
private val expressions: ConstMultiSet<Expression>
private var term: Term? = null

init {
this.expressions = when {
Expand All @@ -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<SimpleExpression>, ConstMultiSet<AdditiveExpression>> {
val simple: ConstMutableMultiSet<SimpleExpression> = constMutableMultiSetOf()
val additive: ConstMutableMultiSet<AdditiveExpression> = 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<Expression> = 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"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<MultiplicativeExpression>("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")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ fun runGetValueTests() {

expr = MultiplicativeExpression(partialMultExpr.inverse(), -simpleExpr2.inverse())
expected = BigDecimal("0.017061281824748112795308108019747092438130381820126559258080078125")
// expected = BigDecimal("0.0170612818247481127955653165209070906353536211925663773027158203125")
assertEquals(expected, expr.getValue())
}

Expand All @@ -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))
Expand All @@ -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))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,24 @@ import kotlin.test.assertEquals

private val assertCastingOverflow = getCastingOverflowAssertion<SimpleExpression>("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")
Expand Down
3 changes: 1 addition & 2 deletions signatures/v1.1.0/v1.1.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
```
Expand Down

0 comments on commit 665235e

Please sign in to comment.