Feature: Polynomials and rational functions #469

Merged
lounres merged 132 commits from feature/polynomials into dev 2022-07-28 18:04:06 +03:00
6 changed files with 647 additions and 4 deletions
Showing only changes of commit a965f5683f - Show all commits

View File

@ -447,7 +447,7 @@ public open class PolynomialSpace<C, A : Ring<C>>(
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<C>.applyAndRemoveZeros(block: MutableList<C>.() -> Unit) : List<C> =
@ -456,7 +456,7 @@ public open class PolynomialSpace<C, A : Ring<C>>(
internal inline fun MutableCoefficients(size: Int, init: (index: Int) -> C): MutableList<C> {
val list = ArrayList<C>(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<C, A : Ring<C>>(
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<C, A : Ring<C>>(
contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) }
return buildList(capacity) {
builderAction()
while (elementAt(lastIndex).isZero()) removeAt(lastIndex)
while (isNotEmpty() && elementAt(lastIndex).isZero()) removeAt(lastIndex)
}
}
}

View File

@ -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<Double>

View File

@ -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<Rational> {
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<Rational>, NumbersAddOps<Rational> {
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
}

View File

@ -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<RationalWithMemorization> {
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<RationalWithMemorization> {
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
}

View File

@ -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)

View File

@ -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>): BigInt = values.reduce(::gcd)