diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt index a60ca563a..3f0d073b3 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt @@ -447,7 +447,7 @@ public open class PolynomialSpace>( callsInPlace(block, InvocationKind.EXACTLY_ONCE) } block() - while (elementAt(lastIndex).isZero()) removeAt(lastIndex) + while (isNotEmpty() && elementAt(lastIndex).isZero()) removeAt(lastIndex) return this } internal inline fun List.applyAndRemoveZeros(block: MutableList.() -> Unit) : List = @@ -456,7 +456,7 @@ public open class PolynomialSpace>( internal inline fun MutableCoefficients(size: Int, init: (index: Int) -> C): MutableList { val list = ArrayList(size) repeat(size) { index -> list.add(init(index)) } - with(list) { while (elementAt(lastIndex).isZero()) removeAt(lastIndex) } + with(list) { while (isNotEmpty() && elementAt(lastIndex).isZero()) removeAt(lastIndex) } return list } @Suppress("FunctionName") @@ -466,7 +466,7 @@ public open class PolynomialSpace>( contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) } return buildList { builderAction() - while (elementAt(lastIndex).isZero()) removeAt(lastIndex) + while (isNotEmpty() && elementAt(lastIndex).isZero()) removeAt(lastIndex) } } @OptIn(ExperimentalTypeInference::class) @@ -474,7 +474,7 @@ public open class PolynomialSpace>( contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) } return buildList(capacity) { builderAction() - while (elementAt(lastIndex).isZero()) removeAt(lastIndex) + while (isNotEmpty() && elementAt(lastIndex).isZero()) removeAt(lastIndex) } } } diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt index a11242b2a..9e3dea615 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt @@ -5,11 +5,78 @@ package space.kscience.kmath.functions +import space.kscience.kmath.operations.BigInt import space.kscience.kmath.operations.algebra +import space.kscience.kmath.operations.toBigInt +import space.kscience.kmath.test.misc.Rational +import space.kscience.kmath.test.misc.RationalField +import space.kscience.kmath.test.misc.gcd import kotlin.test.Test import kotlin.test.assertEquals class PolynomialTest { + @Test + fun test_Polynomial_Polynomial_plus() { + RationalField.polynomial { + // (5/9 - 8/9 x - 8/7 x^2) + (-5/7 + 5/1 x + 5/8 x^2) ?= -10/63 + 37/9 x - 29/56 x^2 + assertEquals( + Polynomial(Rational(-10, 63), Rational(37, 9), Rational(-29, 56)), + Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + + Polynomial(Rational(-5, 7), Rational(5, 1), Rational(5, 8)), + "test 1" + ) + // (-2/9 - 8/3 x) + (0 + 9/4 x + 2/4 x^2) ?= -2/9 - 5/12 x + 2/4 x^2 + assertEquals( + Polynomial(Rational(-2, 9), Rational(-5, 12), Rational(2, 4)), + Polynomial(Rational(-2, 9), Rational(-8, 3)) + + Polynomial(Rational(0), Rational(9, 4), Rational(2, 4)), + "test 2" + ) + // (-4/7 - 2/6 x + 0 x^2 + 0 x^3) + (-6/3 - 7/2 x + 2/3 x^2) ?= -18/7 - 23/6 x + 2/3 x^2 + assertEquals( + Polynomial(Rational(-18, 7), Rational(-23, 6), Rational(2, 3)), + Polynomial(Rational(-4, 7), Rational(-2, 6), Rational(0), Rational(0)) + + Polynomial(Rational(-6, 3), Rational(-7, 2), Rational(2, 3)), + "test 3" + ) + // (-2/4 - 6/9 x - 4/9 x^2) + (2/4 + 6/9 x + 4/9 x^2) ?= 0 + assertEquals( + Polynomial(), + Polynomial(Rational(-2, 4), Rational(-6, 9), Rational(-4, 9)) + + Polynomial(Rational(2, 4), Rational(6, 9), Rational(4, 9)), + "test 4" + ) + } + } +// @Test +// fun test_Polynomial_Polynomial_minus() { +// RationalField.polynomial { +// assertEquals( +// Polynomial(Rational(1, 2), Rational(3, 5), Rational(-2)) + +// Polynomial(Rational(3), Rational(7, 8), Rational(1, 9)), +// Polynomial(Rational(7, 2), Rational(59, 40), Rational(-17, 9)), +// "test 1" +// ) +// assertEquals( +// Polynomial(Rational(1, 2), Rational(3, 5)) + +// Polynomial(Rational(3), Rational(7, 8), Rational(1, 9)), +// Polynomial(Rational(7, 2), Rational(59, 40), Rational(1, 9)), +// "test 2" +// ) +// assertEquals( +// Polynomial(Rational(1, 2), Rational(3, 5), Rational(0), Rational(0)) + +// Polynomial(Rational(3), Rational(7, 8), Rational(1, 9)), +// Polynomial(Rational(7, 2), Rational(59, 40), Rational(1, 9)), +// "test 3" +// ) +// assertEquals( +// Polynomial(Rational(1, 2), Rational(-3, 5), Rational(7, 3)) + +// Polynomial(Rational(3), Rational(3, 5), Rational(-7, 3)), +// Polynomial(Rational(7, 2)), +// "test 4" +// ) +// } +// } @Test fun simple_polynomial_test() { val polynomial : Polynomial diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt new file mode 100644 index 000000000..fad13f88a --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt @@ -0,0 +1,387 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.test.misc + +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.BigInt +import space.kscience.kmath.operations.Field +import space.kscience.kmath.operations.NumbersAddOps +import space.kscience.kmath.operations.toBigInt +import space.kscience.kmath.operations.BigInt.Companion.ZERO as I0 +import space.kscience.kmath.operations.BigInt.Companion.ONE as I1 + +/** + * The class represents rational numbers. + * + * Instances contain [numerator] and [denominator] represented as [Long]. + * + * Also [numerator] and [denominator] are coprime and [denominator] is positive. + * + * @author [Gleb Minaev](https://github.com/lounres) + */ +public class Rational: Comparable { + public companion object { + /** + * Constant containing the zero (the additive identity) of the [Rational] field. + */ + public val ZERO: Rational = Rational(I0) + /** + * Constant containing the one (the multiplicative identity) of the [Rational] field. + */ + public val ONE: Rational = Rational(I1) + } + + /** + * Numerator of the fraction. It's stored as non-negative coprime with [denominator] integer. + */ + public val numerator: BigInt + /** + * Denominator of the fraction. It's stored as non-zero coprime with [numerator] integer. + */ + public val denominator: BigInt + + /** + * If [toCheckInput] is `true` before assigning values to [Rational.numerator] and [Rational.denominator] makes them coprime and makes + * denominator positive. Otherwise, just assigns the values. + * + * @throws ArithmeticException If denominator is zero. + */ + internal constructor(numerator: BigInt, denominator: BigInt, toCheckInput: Boolean = true) { + if (toCheckInput) { + if (denominator == I0) throw ArithmeticException("/ by zero") + + val greatestCommonDivider = gcd(numerator, denominator).let { if (denominator < I0) -it else it } + + this.numerator = numerator / greatestCommonDivider + this.denominator = denominator / greatestCommonDivider + } else { + this.numerator = numerator + this.denominator = denominator + } + } + + /** + * Before assigning values to [Rational.numerator] and [Rational.denominator] makes them coprime and makes + * denominator positive. + * + * @throws ArithmeticException If denominator is zero. + */ + public constructor(numerator: BigInt, denominator: BigInt) : this(numerator, denominator, true) + public constructor(numerator: Int, denominator: BigInt) : this(numerator.toBigInt(), denominator, true) + public constructor(numerator: Long, denominator: BigInt) : this(numerator.toBigInt(), denominator, true) + public constructor(numerator: BigInt, denominator: Int) : this(numerator, denominator.toBigInt(), true) + public constructor(numerator: BigInt, denominator: Long) : this(numerator, denominator.toBigInt(), true) + public constructor(numerator: Int, denominator: Int) : this(numerator.toBigInt(), denominator.toBigInt(), true) + public constructor(numerator: Int, denominator: Long) : this(numerator.toBigInt(), denominator.toBigInt(), true) + public constructor(numerator: Long, denominator: Int) : this(numerator.toBigInt(), denominator.toBigInt(), true) + public constructor(numerator: Long, denominator: Long) : this(numerator.toBigInt(), denominator.toBigInt(), true) + public constructor(numerator: BigInt) : this(numerator, I1, false) + public constructor(numerator: Int) : this(numerator.toBigInt(), I1, false) + public constructor(numerator: Long) : this(numerator.toBigInt(), I1, false) + + /** + * Returns the same instant. + */ + public operator fun unaryPlus(): Rational = this + + /** + * Returns negation of the instant of [Rational] field. + */ + public operator fun unaryMinus(): Rational = Rational(-this.numerator, this.denominator) + + /** + * Returns sum of the instants of [Rational] field. + */ + public operator fun plus(other: Rational): Rational = + Rational( + numerator * other.denominator + denominator * other.numerator, + denominator * other.denominator + ) + + /** + * Returns sum of the instants of [Rational] field. [other] is represented as [Rational]. + */ + public operator fun plus(other: BigInt): Rational = + Rational( + numerator + denominator * other, + denominator + ) + + /** + * Returns sum of the instants of [Rational] field. [other] is represented as [Rational]. + */ + public operator fun plus(other: Int): Rational = + Rational( + numerator + denominator * other.toBigInt(), + denominator + ) + + /** + * Returns sum of the instants of [Rational] field. [other] is represented as [Rational]. + */ + public operator fun plus(other: Long): Rational = + Rational( + numerator + denominator * other.toBigInt(), + denominator + ) + + /** + * Returns difference of the instants of [Rational] field. + */ + public operator fun minus(other: Rational): Rational = + Rational( + numerator * other.denominator - denominator * other.numerator, + denominator * other.denominator + ) + + /** + * Returns difference of the instants of [Rational] field. [other] is represented as [Rational]. + */ + public operator fun minus(other: BigInt): Rational = + Rational( + numerator - denominator * other, + denominator + ) + + /** + * Returns difference of the instants of [Rational] field. [other] is represented as [Rational]. + */ + public operator fun minus(other: Int): Rational = + Rational( + numerator - denominator * other.toBigInt(), + denominator + ) + + /** + * Returns difference of the instants of [Rational] field. [other] is represented as [Rational]. + */ + public operator fun minus(other: Long): Rational = + Rational( + numerator - denominator * other.toBigInt(), + denominator + ) + + /** + * Returns product of the instants of [Rational] field. + */ + public operator fun times(other: Rational): Rational = + Rational( + numerator * other.numerator, + denominator * other.denominator + ) + + /** + * Returns product of the instants of [Rational] field. [other] is represented as [Rational]. + */ + public operator fun times(other: BigInt): Rational = + Rational( + numerator * other, + denominator + ) + + /** + * Returns product of the instants of [Rational] field. [other] is represented as [Rational]. + */ + public operator fun times(other: Int): Rational = + Rational( + numerator * other.toBigInt(), + denominator + ) + + /** + * Returns product of the instants of [Rational] field. [other] is represented as [Rational]. + */ + public operator fun times(other: Long): Rational = + Rational( + numerator * other.toBigInt(), + denominator + ) + + /** + * Returns quotient of the instants of [Rational] field. + * + * @throws ArithmeticException if [other] is the zero of the field it can't be a divisor. + */ + public operator fun div(other: Rational): Rational = + Rational( + numerator * other.denominator, + denominator * other.numerator + ) + + /** + * Returns quotient of the instants of [Rational] field. [other] is represented as [Rational]. + * + * @throws ArithmeticException if [other] is the zero of the field it can't be a divisor. + */ + public operator fun div(other: BigInt): Rational = + Rational( + numerator, + denominator * other + ) + + /** + * Returns quotient of the instants of [Rational] field. [other] is represented as [Rational]. + * + * @throws ArithmeticException if [other] is the zero of the field it can't be a divisor. + */ + public operator fun div(other: Int): Rational = + Rational( + numerator, + denominator * other.toBigInt() + ) + + /** + * Returns quotient of the instants of [Rational] field. [other] is represented as [Rational]. + * + * @throws ArithmeticException if [other] is the zero of the field it can't be a divisor. + */ + public operator fun div(other: Long): Rational = + Rational( + numerator, + denominator * other.toBigInt() + ) + + /** + * Returns reminder from integral division. + * + * @throws ArithmeticException if [other] is the zero of the field it can't be a divisor. + */ + public operator fun rem(other: Rational): Rational = + Rational( + (numerator * other.denominator) % (denominator * other.numerator), + denominator * other.denominator + ) + + /** + * Returns reminder from integral division. + * + * @throws ArithmeticException if [other] is the zero of the field it can't be a divisor. + */ + public operator fun rem(other: BigInt): Rational = + Rational( + numerator % denominator * other, + denominator * other + ) + + /** + * Returns reminder from integral division. + * + * @throws ArithmeticException if [other] is the zero of the field it can't be a divisor. + */ + public operator fun rem(other: Int): Rational = + Rational( + numerator % denominator * other.toBigInt(), + denominator * other.toBigInt() + ) + + /** + * Returns reminder from integral division. + * + * @throws ArithmeticException if [other] is the zero of the field it can't be a divisor. + */ + public operator fun rem(other: Long): Rational = + Rational( + numerator % denominator * other.toBigInt(), + denominator * other.toBigInt() + ) + + /** + * Checks equality of the instance to [other]. + * + * [BigInt], [Int] and [Long] values are also checked as Rational ones. + */ + override fun equals(other: Any?): Boolean = + when (other) { + is Rational -> numerator == other.numerator && denominator == other.denominator + is BigInt -> numerator == other && denominator == I1 + is Int -> numerator == other && denominator == I1 + is Long -> numerator == other && denominator == I1 + else -> false + } + + /** + * Compares the instance to [other] as [Comparable.compareTo]. + * + * @see Comparable.compareTo + */ + override operator fun compareTo(other: Rational): Int = (numerator * other.denominator).compareTo(other.numerator * denominator) + + /** + * Compares the instance to [other] as [Comparable.compareTo]. + * + * [Integer] values are also checked as Rational ones. + * + * @see Comparable.compareTo + */ + public operator fun compareTo(other: BigInt): Int = (numerator).compareTo(denominator * other) + + /** + * Compares the instance to [other] as [Comparable.compareTo]. + * + * [Int] values are also checked as Rational ones. + * + * @see Comparable.compareTo + */ + public operator fun compareTo(other: Int): Int = (numerator).compareTo(denominator * other.toBigInt()) + + /** + * Compares the instance to [other] as [Comparable.compareTo]. + * + * [Long] values are also checked as Rational ones. + * + * @see Comparable.compareTo + */ + public operator fun compareTo(other: Long): Int = (numerator).compareTo(denominator * other.toBigInt()) + + public override fun hashCode(): Int = 31 * numerator.hashCode() + denominator.hashCode() + +// /** Creates a range from this value to the specified [other] value. */ +// operator fun rangeTo(other: JBInt) = ClosedRationalRange(this, other.toRational()) +// /** Creates a range from this value to the specified [other] value. */ +// operator fun rangeTo(other: Rational) = ClosedRationalRange(this, other) +// /** Creates a range from this value to the specified [other] value. */ +// operator fun rangeTo(other: Int) = ClosedRationalRange(this, other.toRational()) +// /** Creates a range from this value to the specified [other] value. */ +// operator fun rangeTo(other: Long) = ClosedRationalRange(this, other.toRational()) + + public fun toRational(): Rational = this + + public fun toBigInt(): BigInt = numerator / denominator + +// public fun toInt(): Int = (numerator / denominator).toInt() +// +// public fun toLong(): Long = (numerator / denominator).toLong() +// +// public fun toDouble(): Double = (numerator.toDouble() / denominator.toDouble()) +// +// public fun toFloat(): Float = (numerator.toFloat() / denominator.toFloat()) + + public override fun toString(): String = if (denominator == I1) "$numerator" else "$numerator/$denominator" +} + + +/** + * Algebraic structure for rational numbers. + */ +@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") +@OptIn(UnstableKMathAPI::class) +public object RationalField : Field, NumbersAddOps { + override inline val zero: Rational get() = Rational.ZERO + override inline val one: Rational get() = Rational.ONE + + override inline fun number(value: Number): Rational = Rational(value.toLong()) + + override inline fun add(left: Rational, right: Rational): Rational = left + right + override inline fun multiply(left: Rational, right: Rational): Rational = left * right + override inline fun divide(left: Rational, right: Rational): Rational = left / right + override inline fun scale(a: Rational, value: Double): Rational = a * number(value) + + override inline fun Rational.unaryMinus(): Rational = -this + override inline fun Rational.plus(arg: Rational): Rational = this + arg + override inline fun Rational.minus(arg: Rational): Rational = this - arg + override inline fun Rational.times(arg: Rational): Rational = this * arg + override inline fun Rational.div(arg: Rational): Rational = this / arg +} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/RationalWithMemorization.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/RationalWithMemorization.kt new file mode 100644 index 000000000..6aa5ecc09 --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/RationalWithMemorization.kt @@ -0,0 +1,113 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.test.misc + +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.* + +class RationalWithMemorization private constructor( + val value: Rational, + override val memory : OperationsMemory +): WithMemorization { + public companion object { + /** + * Constant containing the zero (the additive identity) of the [Rational] field. + */ + public val ZERO: RationalWithMemorization = RationalWithMemorization(Rational.ZERO, object : Endpoint {}) + /** + * Constant containing the one (the multiplicative identity) of the [Rational] field. + */ + public val ONE: RationalWithMemorization = RationalWithMemorization(Rational.ONE, object : Endpoint {}) + } + public constructor(numerator: BigInt, denominator: BigInt) : this(Rational(numerator, denominator), object : Endpoint {}) + public constructor(numerator: Int, denominator: BigInt) : this(Rational(numerator, denominator), object : Endpoint {}) + public constructor(numerator: Long, denominator: BigInt) : this(Rational(numerator, denominator), object : Endpoint {}) + public constructor(numerator: BigInt, denominator: Int) : this(Rational(numerator, denominator), object : Endpoint {}) + public constructor(numerator: BigInt, denominator: Long) : this(Rational(numerator, denominator), object : Endpoint {}) + public constructor(numerator: Int, denominator: Int) : this(Rational(numerator, denominator), object : Endpoint {}) + public constructor(numerator: Int, denominator: Long) : this(Rational(numerator, denominator), object : Endpoint {}) + public constructor(numerator: Long, denominator: Int) : this(Rational(numerator, denominator), object : Endpoint {}) + public constructor(numerator: Long, denominator: Long) : this(Rational(numerator, denominator), object : Endpoint {}) + public constructor(numerator: BigInt) : this(Rational(numerator), object : Endpoint {}) + public constructor(numerator: Int) : this(Rational(numerator), object : Endpoint {}) + public constructor(numerator: Long) : this(Rational(numerator), object : Endpoint {}) + + public operator fun unaryPlus(): RationalWithMemorization = this + public operator fun unaryMinus(): RationalWithMemorization = RationalWithMemorization( + -value, + object : Negation { + override val negated: OperationsMemory = memory + } + ) + public operator fun plus(other: RationalWithMemorization): RationalWithMemorization = RationalWithMemorization( + value + other.value, + object : Sum { + override val augend: OperationsMemory = memory + override val addend: OperationsMemory = other.memory + } + ) + public operator fun minus(other: RationalWithMemorization): RationalWithMemorization = RationalWithMemorization( + value - other.value, + object : Difference { + override val minuend: OperationsMemory = memory + override val subtrahend: OperationsMemory = other.memory + } + ) + public operator fun times(other: RationalWithMemorization): RationalWithMemorization = RationalWithMemorization( + value * other.value, + object : Product { + override val multiplicand: OperationsMemory = memory + override val multiplier: OperationsMemory = other.memory + } + ) + public operator fun div(other: RationalWithMemorization): RationalWithMemorization = RationalWithMemorization( + value / other.value, + object : Quotient { + override val dividend: OperationsMemory = memory + override val divisor: OperationsMemory = other.memory + } + ) + + public override fun equals(other: Any?): Boolean = + other is RationalWithMemorization && value == other.value + + public override fun hashCode(): Int = value.hashCode() + + public override fun toString(): String = value.toString() +} + +@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") +public object RationalWithMemorizationRing : Ring { + override inline val zero: RationalWithMemorization get() = RationalWithMemorization.ZERO + override inline val one: RationalWithMemorization get() = RationalWithMemorization.ONE + + override inline fun add(left: RationalWithMemorization, right: RationalWithMemorization): RationalWithMemorization = left + right + override inline fun multiply(left: RationalWithMemorization, right: RationalWithMemorization): RationalWithMemorization = left * right + + override inline fun RationalWithMemorization.unaryMinus(): RationalWithMemorization = -this + override inline fun RationalWithMemorization.plus(arg: RationalWithMemorization): RationalWithMemorization = this + arg + override inline fun RationalWithMemorization.minus(arg: RationalWithMemorization): RationalWithMemorization = this - arg + override inline fun RationalWithMemorization.times(arg: RationalWithMemorization): RationalWithMemorization = this * arg +} + +@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") +public object RationalWithMemorizationField : Field { + override inline val zero: RationalWithMemorization get() = RationalWithMemorization.ZERO + override inline val one: RationalWithMemorization get() = RationalWithMemorization.ONE + + override inline fun number(value: Number): RationalWithMemorization = RationalWithMemorization(value.toLong()) + + override inline fun add(left: RationalWithMemorization, right: RationalWithMemorization): RationalWithMemorization = left + right + override inline fun multiply(left: RationalWithMemorization, right: RationalWithMemorization): RationalWithMemorization = left * right + override inline fun divide(left: RationalWithMemorization, right: RationalWithMemorization): RationalWithMemorization = left / right + override inline fun scale(a: RationalWithMemorization, value: Double): RationalWithMemorization = a * number(value) + + override inline fun RationalWithMemorization.unaryMinus(): RationalWithMemorization = -this + override inline fun RationalWithMemorization.plus(arg: RationalWithMemorization): RationalWithMemorization = this + arg + override inline fun RationalWithMemorization.minus(arg: RationalWithMemorization): RationalWithMemorization = this - arg + override inline fun RationalWithMemorization.times(arg: RationalWithMemorization): RationalWithMemorization = this * arg + override inline fun RationalWithMemorization.div(arg: RationalWithMemorization): RationalWithMemorization = this / arg +} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/memorization.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/memorization.kt new file mode 100644 index 000000000..a4fb81274 --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/memorization.kt @@ -0,0 +1,51 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.test.misc + +sealed interface OperationsMemory + +interface Endpoint: OperationsMemory + +interface Negation: OperationsMemory { + val negated: OperationsMemory +} + +interface Sum: OperationsMemory { + val augend: OperationsMemory + val addend: OperationsMemory +} + +interface Difference: OperationsMemory { + val minuend: OperationsMemory + val subtrahend: OperationsMemory +} + +interface Product: OperationsMemory { + val multiplicand: OperationsMemory + val multiplier: OperationsMemory +} + +interface Quotient: OperationsMemory { + val dividend: OperationsMemory + val divisor: OperationsMemory +} + + +fun equalMemories(one: OperationsMemory, other: OperationsMemory) : Boolean = + when(one) { + is Negation -> other is Negation && equalMemories(one.negated, other.negated) + is Sum -> other is Sum && equalMemories(one.augend, other.augend) && equalMemories(one.addend, other.addend) + is Difference -> other is Difference && equalMemories(one.minuend, other.minuend) && equalMemories(one.subtrahend, other.subtrahend) + is Product -> other is Product && equalMemories(one.multiplicand, other.multiplicand) && equalMemories(one.multiplier, other.multiplier) + is Quotient -> other is Quotient && equalMemories(one.dividend, other.dividend) && equalMemories(one.divisor, other.divisor) + is Endpoint -> one === other + } + +interface WithMemorization { + val memory: OperationsMemory +} + +fun equalMemories(one: WithMemorization, other: WithMemorization) : Boolean = equalMemories(one.memory, other.memory) \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt new file mode 100644 index 000000000..eab29842c --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt @@ -0,0 +1,25 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.test.misc + +import space.kscience.kmath.operations.* +import space.kscience.kmath.operations.BigInt.Companion.ZERO as I0 + +// TODO: Move to corresponding module "kmath-number-theory" + +/** + * Computes [Greatest Common Divisor](https://en.wikipedia.org/wiki/Greatest_common_divisor) of [a] and [b]. + * + * It's computed by [Euclidean algorithm](https://en.wikipedia.org/wiki/Greatest_common_divisor#Euclidean_algorithm). + * Hence, its time complexity is $$O(\log(a+b))$$ (see [Wolfram MathWorld](https://mathworld.wolfram.com/EuclideanAlgorithm.html)). + */ +public tailrec fun gcd(a: BigInt, b: BigInt): BigInt = if (a == I0) abs(b) else gcd(b % a, a) + +/** + * Computes [Greatest Common Divisor](https://en.wikipedia.org/wiki/Greatest_common_divisor) of the [values]. + */ +public fun gcd(vararg values: BigInt): BigInt = values.reduce(::gcd) +public fun gcd(values: Iterable): BigInt = values.reduce(::gcd) \ No newline at end of file