From 2483c56f1c95180e168bd564be6131122a6c8cfe Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Thu, 3 Mar 2022 20:45:35 +0300 Subject: [PATCH 001/123] Restructured Polynomial --- .../kmath/functions/AbstractPolynomial.kt | 354 +++++++++++++++ .../kscience/kmath/functions/Piecewise.kt | 8 +- .../kscience/kmath/functions/Polynomial.kt | 425 ++++++++++++++---- .../kmath/functions/polynomialUtil.kt | 139 ++++++ .../kmath/integration/SplineIntegrator.kt | 3 +- .../kmath/interpolation/Interpolator.kt | 4 +- .../kmath/functions/PolynomialTest.kt | 11 +- kotlin-js-store/yarn.lock | 56 +-- 8 files changed, 846 insertions(+), 154 deletions(-) create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt new file mode 100644 index 000000000..f6a617656 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt @@ -0,0 +1,354 @@ +/* + * 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.functions + +import space.kscience.kmath.operations.* +import kotlin.js.JsName +import kotlin.jvm.JvmName + + +/** + * Abstraction of polynomials. + */ +public interface AbstractPolynomial + +/** + * Abstraction of ring of polynomials of type [P] over ring of constants of type [C]. + */ +@Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") +public interface AbstractPolynomialSpace> : Ring

{ + // region Constant-integer relation + /** + * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * + * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. + */ + @JvmName("constantIntPlus") + public operator fun C.plus(other: Int): C + /** + * Returns difference between the constant and the integer represented as constant (member of underlying ring). + * + * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. + */ + @JvmName("constantIntMinus") + public operator fun C.minus(other: Int): C + /** + * Returns product of the constant and the integer represented as constant (member of underlying ring). + * + * The operation is equivalent to sum of [other] copies of [this]. + */ + @JvmName("constantIntTimes") + public operator fun C.times(other: Int): C + // endregion + + // region Integer-constant relation + /** + * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * + * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. + */ + @JvmName("intConstantPlus") + public operator fun Int.plus(other: C): C + /** + * Returns difference between the integer represented as constant (member of underlying ring) and the constant. + * + * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. + */ + @JvmName("intConstantMinus") + public operator fun Int.minus(other: C): C + /** + * Returns product of the integer represented as constant (member of underlying ring) and the constant. + * + * The operation is equivalent to sum of [this] copies of [other]. + */ + @JvmName("intConstantTimes") + public operator fun Int.times(other: C): C + // endregion + + // region Polynomial-integer relation + /** + * Returns sum of the constant and the integer represented as polynomial. + * + * The operation is equivalent to adding [other] copies of unit polynomial to [this]. + */ + public operator fun P.plus(other: Int): P = optimizedAddMultiplied(this, one, other) + /** + * Returns difference between the constant and the integer represented as polynomial. + * + * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. + */ + public operator fun P.minus(other: Int): P = optimizedAddMultiplied(this, one, -other) + /** + * Returns product of the constant and the integer represented as polynomial. + * + * The operation is equivalent to sum of [other] copies of [this]. + */ + public operator fun P.times(other: Int): P = optimizedMultiply(this, other) + // endregion + + // region Integer-polynomial relation + /** + * Returns sum of the integer represented as polynomial and the constant. + * + * The operation is equivalent to adding [this] copies of unit polynomial to [other]. + */ + public operator fun Int.plus(other: P): P = optimizedAddMultiplied(other, one, this) + /** + * Returns difference between the integer represented as polynomial and the constant. + * + * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. + */ + public operator fun Int.minus(other: P): P = optimizedAddMultiplied(-other, one, this) + /** + * Returns product of the integer represented as polynomial and the constant. + * + * The operation is equivalent to sum of [this] copies of [other]. + */ + public operator fun Int.times(other: P): P = optimizedMultiply(other, this) + // endregion + + // region Constant-constant relation + /** + * Returns the same constant. + */ + @JvmName("constantUnaryPlus") + @JsName("constantUnaryPlus") + public operator fun C.unaryPlus(): C = this + /** + * Returns negation of the constant. + */ + @JvmName("constantUnaryMinus") + @JsName("constantUnaryMinus") + public operator fun C.unaryMinus(): C + /** + * Returns sum of the constants. + */ + @JvmName("constantPlus") + @JsName("constantPlus") + public operator fun C.plus(other: C): C + /** + * Returns difference of the constants. + */ + @JvmName("constantMinus") + @JsName("constantMinus") + public operator fun C.minus(other: C): C + /** + * Returns product of the constants. + */ + @JvmName("constantTimes") + @JsName("constantTimes") + public operator fun C.times(other: C): C + + /** + * Check if the instant is zero constant. + */ + @JvmName("constantIsZero") + public fun C.isZero(): Boolean + /** + * Check if the instant is NOT zero constant. + */ + @JvmName("constantIsNotZero") + public fun C.isNotZero(): Boolean + /** + * Check if the instant is unit constant. + */ + @JvmName("constantIsOne") + public fun C.isOne(): Boolean + /** + * Check if the instant is NOT unit constant. + */ + @JvmName("constantIsNotOne") + public fun C.isNotOne(): Boolean + /** + * Check if the instant is minus unit constant. + */ + @JvmName("constantIsMinusOne") + public fun C.isMinusOne(): Boolean + /** + * Check if the instant is NOT minus unit constant. + */ + @JvmName("constantIsNotMinusOne") + public fun C.isNotMinusOne(): Boolean + // endregion + + // region Constant-polynomial relation + /** + * Returns sum of the constant represented as polynomial and the polynomial. + */ + public operator fun C.plus(other: P): P + /** + * Returns difference between the constant represented as polynomial and the polynomial. + */ + public operator fun C.minus(other: P): P + /** + * Returns product of the constant represented as polynomial and the polynomial. + */ + public operator fun C.times(other: P): P + // endregion + + // region Polynomial-constant relation + /** + * Returns sum of the constant represented as polynomial and the polynomial. + */ + public operator fun P.plus(other: C): P + /** + * Returns difference between the constant represented as polynomial and the polynomial. + */ + public operator fun P.minus(other: C): P + /** + * Returns product of the constant represented as polynomial and the polynomial. + */ + public operator fun P.times(other: C): P + // endregion + + // region Polynomial-polynomial relation + /** + * Returns the same polynomial. + */ + public override operator fun P.unaryPlus(): P = this + /** + * Returns negation of the polynomial. + */ + public override operator fun P.unaryMinus(): P + /** + * Returns sum of the polynomials. + */ + public override operator fun P.plus(other: P): P + /** + * Returns difference of the polynomials. + */ + public override operator fun P.minus(other: P): P + /** + * Returns product of the polynomials. + */ + public override operator fun P.times(other: P): P + + /** + * Check if the instant is zero polynomial. + */ + public fun P.isZero(): Boolean = this == zero + /** + * Check if the instant is NOT zero polynomial. + */ + public fun P.isNotZero(): Boolean = this != zero + /** + * Check if the instant is unit polynomial. + */ + public fun P.isOne(): Boolean = this == one + /** + * Check if the instant is NOT unit polynomial. + */ + public fun P.isNotOne(): Boolean = this != one + /** + * Check if the instant is minus unit polynomial. + */ + public fun P.isMinusOne(): Boolean = this == -one + /** + * Check if the instant is NOT minus unit polynomial. + */ + public fun P.isNotMinusOne(): Boolean = this != -one + + /** + * Instance of zero polynomial (zero of the polynomial ring). + */ + override val zero: P + /** + * Instance of unit polynomial (unit of the polynomial ring). + */ + override val one: P + + /** + * Checks equality of the polynomials. + */ + @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") + public fun P.equals(other: P): Boolean + // endregion + + // Not sure is it necessary... + // region Polynomial properties + /** + * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is + * zero, degree is -1. + */ + public val P.degree: Int + + /** + * Checks if the instant is constant polynomial (of degree no more than 0) over considered ring. + */ + public fun P.isConstant(): Boolean = degree <= 0 + /** + * Checks if the instant is **not** constant polynomial (of degree no more than 0) over considered ring. + */ + public fun P.isNotConstant(): Boolean = !isConstant() + /** + * Checks if the instant is constant non-zero polynomial (of degree no more than 0) over considered ring. + */ + public fun P.isNonZeroConstant(): Boolean = degree == 0 + /** + * Checks if the instant is **not** constant non-zero polynomial (of degree no more than 0) over considered ring. + */ + public fun P.isNotNonZeroConstant(): Boolean = !isNonZeroConstant() + /** + * If polynomial is a constant polynomial represents and returns it as constant. + * Otherwise, (when the polynomial is not constant polynomial) returns `null`. + */ + public fun P.asConstantOrNull(): C? + /** + * If polynomial is a constant polynomial represents and returns it as constant. + * Otherwise, (when the polynomial is not constant polynomial) raises corresponding exception. + */ + public fun P.asConstant(): C = asConstantOrNull() ?: error("Can not represent non-constant polynomial as a constant") + // endregion + + // region Legacy of Ring interface + override fun add(left: P, right: P): P = left + right + override fun multiply(left: P, right: P): P = left * right + // endregion + + public companion object { + // TODO: All of this should be moved to algebraic structures' place for utilities + // TODO: Move receiver to context receiver + /** + * Multiplication of element and integer. + * + * @receiver the multiplicand. + * @param other the multiplier. + * @return the difference. + */ + internal tailrec fun Group.optimizedMultiply(arg: C, other: Int): C = + when { + other == 0 -> zero + other == 1 -> arg + other == -1 -> -arg + other % 2 == 0 -> optimizedMultiply(arg + arg, other / 2) + other % 2 == 1 -> optimizedAddMultiplied(arg, arg + arg, other / 2) + other % 2 == -1 -> optimizedAddMultiplied(-arg, arg + arg, other / 2) + else -> error("Error in multiplication group instant by integer: got reminder by division by 2 different from 0, 1 and -1") + } + + // TODO: Move receiver to context receiver + /** + * Adds product of [arg] and [multiplier] to [base]. + * + * @receiver the algebra to provide multiplication. + * @param base the augend. + * @param arg the multiplicand. + * @param multiplier the multiplier. + * @return sum of the augend [base] and product of the multiplicand [arg] and the multiplier [multiplier]. + * @author Gleb Minaev + */ + internal tailrec fun Group.optimizedAddMultiplied(base: C, arg: C, multiplier: Int): C = + when { + multiplier == 0 -> base + multiplier == 1 -> base + arg + multiplier == -1 -> base - arg + multiplier % 2 == 0 -> optimizedAddMultiplied(base, arg + arg, multiplier / 2) + multiplier % 2 == 1 -> optimizedAddMultiplied(base + arg, arg + arg, multiplier / 2) + multiplier % 2 == -1 -> optimizedAddMultiplied(base + arg, arg + arg, multiplier / 2) + else -> error("Error in multiplication group instant by integer: got reminder by division by 2 different from 0, 1 and -1") + } + } +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt index 16af7f555..cfd21d552 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt @@ -117,16 +117,16 @@ public fun > PiecewisePolynomial( * Return a value of polynomial function with given [ring] a given [arg] or null if argument is outside piecewise * definition. */ -public fun , C : Ring> PiecewisePolynomial.value(ring: C, arg: T): T? = - findPiece(arg)?.value(ring, arg) +public fun , C : Ring> PiecewisePolynomial.substitute(ring: C, arg: T): T? = + findPiece(arg)?.substitute(ring, arg) /** * Convert this polynomial to a function returning nullable value (null if argument is outside piecewise range). */ -public fun , C : Ring> PiecewisePolynomial.asFunction(ring: C): (T) -> T? = { value(ring, it) } +public fun , C : Ring> PiecewisePolynomial.asFunction(ring: C): (T) -> T? = { substitute(ring, it) } /** * Convert this polynomial to a function using [defaultValue] for arguments outside the piecewise range. */ public fun , C : Ring> PiecewisePolynomial.asFunction(ring: C, defaultValue: T): (T) -> T = - { value(ring, it) ?: defaultValue } + { substitute(ring, it) ?: defaultValue } 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 a36d36f52..30280a396 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 @@ -5,128 +5,371 @@ package space.kscience.kmath.functions -import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.functions.AbstractPolynomialSpace.Companion.optimizedAddMultiplied +import space.kscience.kmath.functions.AbstractPolynomialSpace.Companion.optimizedMultiply import space.kscience.kmath.operations.* -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract +import kotlin.jvm.JvmName import kotlin.math.max -import kotlin.math.pow +import kotlin.math.min /** * Polynomial coefficients model without fixation on specific context they are applied to. * * @param coefficients constant is the leftmost coefficient. */ -public class Polynomial(public val coefficients: List) { +public class Polynomial(public val coefficients: List) : AbstractPolynomial { override fun toString(): String = "Polynomial$coefficients" + +// public companion object { +// /** +// * Default name of variables used in string representations. +// * +// * @see Polynomial.toString +// */ +// public var defaultVariableName: String = "x" +// +// /** +// * Represents result of division with remainder. +// */ +// public data class DividingResult( +// val quotient: Polynomial, +// val reminder: Polynomial +// ) +// } } /** - * Returns a [Polynomial] instance with given [coefficients]. + * Represents internal [Polynomial] errors. + */ +internal class PolynomialError(message: String): Error(message) + +// region Constructors and converters + +/** + * Returns a [Polynomial] instance with given [coefficients]. The collection of coefficients will be reversed if + * [reverse] parameter is true. */ @Suppress("FunctionName") -public fun Polynomial(vararg coefficients: T): Polynomial = Polynomial(coefficients.toList()) +public fun Polynomial(coefficients: List, reverse: Boolean = false): Polynomial = + Polynomial(with(coefficients) { if (reverse) reversed() else this }) /** - * Evaluates the value of the given double polynomial for given double argument. + * Returns a [Polynomial] instance with given [coefficients]. The collection of coefficients will be reversed if + * [reverse] parameter is true. */ -public fun Polynomial.value(arg: Double): Double = coefficients.reduceIndexed { index, acc, c -> - acc + c * arg.pow(index) -} +@Suppress("FunctionName") +public fun Polynomial(vararg coefficients: T, reverse: Boolean = false): Polynomial = + Polynomial(with(coefficients) { if (reverse) reversed() else toList() }) + +public fun T.asPolynomial() : Polynomial = Polynomial(listOf(this)) + +// endregion /** - * Evaluates the value of the given polynomial for given argument. - * https://en.wikipedia.org/wiki/Horner%27s_method - */ -public fun > Polynomial.value(ring: C, arg: T): T = ring { - if (coefficients.isEmpty()) return@ring zero - var result: T = coefficients.last() - for (j in coefficients.size - 2 downTo 0) { - result = (arg * result) + coefficients[j] - } - return result -} - -/** - * Represent the polynomial as a regular context-less function. - */ -public fun > Polynomial.asFunction(ring: C): (T) -> T = { value(ring, it) } - -/** - * Create a polynomial witch represents differentiated version of this polynomial - */ -@UnstableKMathAPI -public fun Polynomial.differentiate( - algebra: A, -): Polynomial where A : Ring, A : NumericAlgebra = algebra { - Polynomial(coefficients.drop(1).mapIndexed { index, t -> number(index) * t }) -} - -/** - * Create a polynomial witch represents indefinite integral version of this polynomial - */ -@UnstableKMathAPI -public fun Polynomial.integrate( - algebra: A, -): Polynomial where A : Field, A : NumericAlgebra = algebra { - val integratedCoefficients = buildList(coefficients.size + 1) { - add(zero) - coefficients.forEachIndexed{ index, t -> add(t / (number(index) + one)) } - } - Polynomial(integratedCoefficients) -} - -/** - * Compute a definite integral of a given polynomial in a [range] - */ -@UnstableKMathAPI -public fun > Polynomial.integrate( - algebra: Field, - range: ClosedRange, -): T = algebra { - val integral = integrate(algebra) - integral.value(algebra, range.endInclusive) - integral.value(algebra, range.start) -} - -/** - * Space of polynomials. + * Space of polynomials constructed over ring. * - * @param T the type of operated polynomials. - * @param C the intersection of [Ring] of [T] and [ScaleOperations] of [T]. - * @param ring the [C] instance. + * @param C the type of constants. Polynomials have them as a coefficients in their terms. + * @param A type of underlying ring of constants. It's [Ring] of [C]. + * @param ring underlying ring of constants of type [A]. */ -public class PolynomialSpace( - private val ring: C, -) : Group>, ScaleOperations> where C : Ring, C : ScaleOperations { - override val zero: Polynomial = Polynomial(emptyList()) +@Suppress("INAPPLICABLE_JVM_NAME") // KT-31420 +public open class PolynomialSpace>( + public val ring: A, +) : AbstractPolynomialSpace>{ + // region Constant-integer relation + @JvmName("constantIntPlus") + public override operator fun C.plus(other: Int): C = ring { optimizedAddMultiplied(this@plus, one, other) } + @JvmName("constantIntMinus") + public override operator fun C.minus(other: Int): C = ring { optimizedAddMultiplied(this@minus, one, -other) } + @JvmName("constantIntTimes") + public override operator fun C.times(other: Int): C = ring { optimizedMultiply(this@times, other) } + // endregion - override fun Polynomial.unaryMinus(): Polynomial = ring { + // region Integer-constant relation + @JvmName("intConstantPlus") + public override operator fun Int.plus(other: C): C = ring { optimizedAddMultiplied(other, one, this@plus) } + @JvmName("intConstantMinus") + public override operator fun Int.minus(other: C): C = ring { optimizedAddMultiplied(-other, one, this@minus) } + @JvmName("intConstantTimes") + public override operator fun Int.times(other: C): C = ring { optimizedMultiply(other, this@times) } + // endregion + + // region Polynomial-integer relation + public override operator fun Polynomial.plus(other: Int): Polynomial = + if (other == 0) this + else + Polynomial( + coefficients + .toMutableList() + .apply { + if (isEmpty()) this[0] = ring.zero + other + else this[0] = this[0]!! + other + } + ) + public override operator fun Polynomial.minus(other: Int): Polynomial = + if (other == 0) this + else + Polynomial( + coefficients + .toMutableList() + .apply { + if (isEmpty()) this[0] = ring.zero - other + else this[0] = this[0]!! - other + } + ) + public override operator fun Polynomial.times(other: Int): Polynomial = + if (other == 0) zero + else Polynomial( + coefficients + .subList(0, degree + 1) + .map { it * other } + ) + // endregion + + // region Integer-polynomial relation + public override operator fun Int.plus(other: Polynomial): Polynomial = + if (this == 0) other + else + Polynomial( + other.coefficients + .toMutableList() + .apply { + if (isEmpty()) this[0] = ring.zero + this@plus + else this[0] = this[0]!! + this@plus + } + ) + public override operator fun Int.minus(other: Polynomial): Polynomial = + if (this == 0) other + else + Polynomial( + other.coefficients + .toMutableList() + .apply { + if (isEmpty()) this[0] = ring.zero - this@minus + else this[0] = this[0]!! - this@minus + } + ) + public override operator fun Int.times(other: Polynomial): Polynomial = + if (this == 0) zero + else Polynomial( + other.coefficients + .subList(0, other.degree + 1) + .map { it * this } + ) + // endregion + + // region Constant-constant relation + @JvmName("constantUnaryMinus") + public override operator fun C.unaryMinus(): C = ring { -this@unaryMinus } + @JvmName("constantPlus") + public override operator fun C.plus(other: C): C = ring { this@plus + other } + @JvmName("constantMinus") + public override operator fun C.minus(other: C): C = ring { this@minus - other } + @JvmName("constantTimes") + public override operator fun C.times(other: C): C = ring { this@times * other } + @JvmName("constantIsZero") + public override fun C.isZero(): Boolean = ring { this == zero } + @JvmName("constantIsNotZero") + public override fun C.isNotZero(): Boolean = ring { this != zero } + @JvmName("constantIsOne") + public override fun C.isOne(): Boolean = ring { this == one } + @JvmName("constantIsNotOne") + public override fun C.isNotOne(): Boolean = ring { this != one } + @JvmName("constantIsMinusOne") + public override fun C.isMinusOne(): Boolean = ring { this == -one } + @JvmName("constantIsNotMinusOne") + public override fun C.isNotMinusOne(): Boolean = ring { this != -one } + // endregion + + // region Constant-polynomial relation + public override operator fun C.plus(other: Polynomial): Polynomial = + with(other.coefficients) { + if (isEmpty()) Polynomial(listOf(this@plus)) + else Polynomial( + toMutableList() + .apply { + this[0] += this@plus + } + ) + } +// if (degree == -1) UnivariatePolynomial(other) else UnivariatePolynomial( +// listOf(coefficients[0] + other) + coefficients.subList(1, degree + 1) +// ) + public override operator fun C.minus(other: Polynomial): Polynomial = + with(other.coefficients) { + if (isEmpty()) Polynomial(listOf(-this@minus)) + else Polynomial( + toMutableList() + .apply { + this[0] -= this@minus + } + ) + } +// if (degree == -1) UnivariatePolynomial(other) else UnivariatePolynomial( +// listOf(coefficients[0] + other) + coefficients.subList(1, degree + 1) +// ) + public override operator fun C.times(other: Polynomial): Polynomial = + Polynomial( + other.coefficients +// .subList(0, other.degree + 1) + .map { it * this } + ) + // endregion + + // region Polynomial-constant relation + public override operator fun Polynomial.plus(other: C): Polynomial = + if (other.isZero()) this + else with(coefficients) { + if (isEmpty()) Polynomial(listOf(other)) + else Polynomial( + toMutableList() + .apply { + this[0] += other + } + ) + } +// if (degree == -1) UnivariatePolynomial(other) else UnivariatePolynomial( +// listOf(coefficients[0] + other) + coefficients.subList(1, degree + 1) +// ) + public override operator fun Polynomial.minus(other: C): Polynomial = + with(coefficients) { + if (isEmpty()) Polynomial(listOf(other)) + else Polynomial( + toMutableList() + .apply { + this[0] -= other + } + ) + } +// if (degree == -1) UnivariatePolynomial(-other) else UnivariatePolynomial( +// listOf(coefficients[0] - other) + coefficients.subList(1, degree + 1) +// ) + public override operator fun Polynomial.times(other: C): Polynomial = + Polynomial( + coefficients +// .subList(0, degree + 1) + .map { it * other } + ) + // endregion + + // region Polynomial-polynomial relation + public override operator fun Polynomial.unaryMinus(): Polynomial = Polynomial(coefficients.map { -it }) - } - - override fun add(left: Polynomial, right: Polynomial): Polynomial { - val dim = max(left.coefficients.size, right.coefficients.size) - - return ring { - Polynomial(List(dim) { index -> - left.coefficients.getOrElse(index) { zero } + right.coefficients.getOrElse(index) { zero } - }) + public override operator fun Polynomial.plus(other: Polynomial): Polynomial = + Polynomial( + (0..max(degree, other.degree)) + .map { + when { + it > degree -> other.coefficients[it] + it > other.degree -> coefficients[it] + else -> coefficients[it] + other.coefficients[it] + } + } + .ifEmpty { listOf(ring.zero) } + ) + public override operator fun Polynomial.minus(other: Polynomial): Polynomial = + Polynomial( + (0..max(degree, other.degree)) + .map { + when { + it > degree -> -other.coefficients[it] + it > other.degree -> coefficients[it] + else -> coefficients[it] - other.coefficients[it] + } + } + .ifEmpty { listOf(ring.zero) } + ) + public override operator fun Polynomial.times(other: Polynomial): Polynomial { + val thisDegree = degree + val otherDegree = other.degree + return when { + thisDegree == -1 -> this + otherDegree == -1 -> other + else -> + Polynomial( + (0..(thisDegree + otherDegree)) + .map { d -> + (max(0, d - otherDegree)..(min(thisDegree, d))) + .map { coefficients[it] * other.coefficients[d - it] } + .reduce { acc, rational -> acc + rational } + } + ) } } - override fun scale(a: Polynomial, value: Double): Polynomial = - ring { Polynomial(List(a.coefficients.size) { index -> a.coefficients[index] * value }) } + public override fun Polynomial.isZero(): Boolean = coefficients.all { it.isZero() } + public override fun Polynomial.isNotZero(): Boolean = coefficients.any { it.isNotZero() } + public override fun Polynomial.isOne(): Boolean = + with(coefficients) { isNotEmpty() && asSequence().withIndex().any { (index, c) -> if (index == 0) c.isOne() else c.isZero() } } // TODO: It's better to write new methods like `anyIndexed`. But what's better way to do it? + public override fun Polynomial.isNotOne(): Boolean = !isOne() + public override fun Polynomial.isMinusOne(): Boolean = + with(coefficients) { isNotEmpty() && asSequence().withIndex().any { (index, c) -> if (index == 0) c.isMinusOne() else c.isZero() } } // TODO: It's better to write new methods like `anyIndexed`. But what's better way to do it? + public override fun Polynomial.isNotMinusOne(): Boolean = !isMinusOne() + + override val zero: Polynomial = Polynomial(emptyList()) + override val one: Polynomial = Polynomial(listOf(ring.one)) + + @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") + public override fun Polynomial.equals(other: Polynomial): Boolean = + when { + this === other -> true + else -> { + if (this.degree == other.degree) + (0..degree).all { coefficients[it] == other.coefficients[it] } + else false + } + } + // endregion + + // Not sure is it necessary... + // region Polynomial properties + public override val Polynomial.degree: Int get() = coefficients.indexOfLast { it != ring.zero } + + public override fun Polynomial.asConstantOrNull(): C? = + with(coefficients) { + when { + isEmpty() -> ring.zero + degree > 0 -> null + else -> first() + } + } + public override fun Polynomial.asConstant(): C = asConstantOrNull() ?: error("Can not represent non-constant polynomial as a constant") + + @Suppress("NOTHING_TO_INLINE") + public inline fun Polynomial.substitute(argument: C): C = this.substitute(ring, argument) + @Suppress("NOTHING_TO_INLINE") + public inline fun Polynomial.substitute(argument: Polynomial): Polynomial = this.substitute(ring, argument) + + @Suppress("NOTHING_TO_INLINE") + public inline fun Polynomial.asFunction(): (C) -> C = { this.substitute(ring, it) } + @Suppress("NOTHING_TO_INLINE") + public inline fun Polynomial.asFunctionOnConstants(): (C) -> C = { this.substitute(ring, it) } + @Suppress("NOTHING_TO_INLINE") + public inline fun Polynomial.asFunctionOnPolynomials(): (Polynomial) -> Polynomial = { this.substitute(ring, it) } /** * Evaluates the polynomial for the given value [arg]. */ - public operator fun Polynomial.invoke(arg: T): T = value(ring, arg) - - public fun Polynomial.asFunction(): (T) -> T = asFunction(ring) + @Suppress("NOTHING_TO_INLINE") + public inline operator fun Polynomial.invoke(argument: C): C = this.substitute(ring, argument) + @Suppress("NOTHING_TO_INLINE") + public inline operator fun Polynomial.invoke(argument: Polynomial): Polynomial = this.substitute(ring, argument) + // endregion } -public inline fun C.polynomial(block: PolynomialSpace.() -> R): R where C : Ring, C : ScaleOperations { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return PolynomialSpace(this).block() +/** + * Space of polynomials constructed over ring. + * + * @param C the type of constants. Polynomials have them as a coefficients in their terms. + * @param A type of underlying ring of constants. It's [Ring] of [C]. + * @param ring underlying ring of constants of type [A]. + */ +public class ScalablePolynomialSpace( + ring: A, +) : PolynomialSpace(ring), ScaleOperations> where A : Ring, A : ScaleOperations { + + override fun scale(a: Polynomial, value: Double): Polynomial = + ring { Polynomial(List(a.coefficients.size) { index -> a.coefficients[index] * value }) } + } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt new file mode 100644 index 000000000..1a3eb7874 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt @@ -0,0 +1,139 @@ +/* + * 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.functions + +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.* +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract +import kotlin.jvm.JvmName +import kotlin.math.pow + + +// region Utilities + +/** + * Removes zeros on the end of the coefficient list of polynomial. + */ +//context(PolynomialSpace) +//fun > Polynomial.removeZeros() : Polynomial = +// if (degree > -1) Polynomial(coefficients.subList(0, degree + 1)) else zero + +/** + * Crates a [PolynomialSpace] over received ring. + */ +public fun > A.polynomial(): PolynomialSpace = + PolynomialSpace(this) + +/** + * Crates a [PolynomialSpace]'s scope over received ring. + */ +public inline fun , R> A.polynomial(block: PolynomialSpace.() -> R): R { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return PolynomialSpace(this).block() +} + +/** + * Crates a [ScalablePolynomialSpace] over received scalable ring. + */ +public fun A.scalablePolynomial(): ScalablePolynomialSpace where A : Ring, A : ScaleOperations = + ScalablePolynomialSpace(this) + +/** + * Crates a [ScalablePolynomialSpace]'s scope over received scalable ring. + */ +public inline fun A.scalablePolynomial(block: ScalablePolynomialSpace.() -> R): R where A : Ring, A : ScaleOperations { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return ScalablePolynomialSpace(this).block() +} + +// endregion + +// region Polynomial substitution and functional representation + +// TODO: May be apply Horner's method too? +/** + * Evaluates the value of the given double polynomial for given double argument. + */ +public fun Polynomial.substitute(arg: Double): Double = + coefficients.reduceIndexedOrNull { index, acc, c -> + acc + c * arg.pow(index) + } ?: .0 + +/** + * Evaluates the value of the given polynomial for given argument. + * + * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). + */ +public fun Polynomial.substitute(ring: Ring, arg: C): C = ring { + if (coefficients.isEmpty()) return@ring zero + var result: C = coefficients.last() + for (j in coefficients.size - 2 downTo 0) { + result = (arg * result) + coefficients[j] + } + return result +} + +// TODO: (Waiting for hero) Replace with optimisation: the [result] may be unboxed, and all operations may be performed +// as soon as possible on it +public fun Polynomial.substitute(ring: Ring, arg: Polynomial) : Polynomial = ring.polynomial { + if (coefficients.isEmpty()) return zero + var result: Polynomial = coefficients.last().asPolynomial() + for (j in coefficients.size - 2 downTo 0) { + result = (arg * result) + coefficients[j] + } + return result +} + +/** + * Represent the polynomial as a regular context-less function. + */ +public fun > Polynomial.asFunction(ring: A): (C) -> C = { substitute(ring, it) } + +/** + * Represent the polynomial as a regular context-less function. + */ +public fun > Polynomial.asPolynomialFunctionOver(ring: A): (Polynomial) -> Polynomial = { substitute(ring, it) } + +// endregion + +// region Algebraic derivative and antiderivative + +/** + * Returns algebraic derivative of received polynomial. + */ +@UnstableKMathAPI +public fun Polynomial.derivative( + algebra: A, +): Polynomial where A : Ring, A : NumericAlgebra = algebra { + Polynomial(coefficients.drop(1).mapIndexed { index, t -> number(index) * t }) +} + +/** + * Create a polynomial witch represents indefinite integral version of this polynomial + */ +@UnstableKMathAPI +public fun Polynomial.antiderivative( + algebra: A, +): Polynomial where A : Field, A : NumericAlgebra = algebra { + val integratedCoefficients = buildList(coefficients.size + 1) { + add(zero) + coefficients.forEachIndexed{ index, t -> add(t / (number(index) + one)) } + } + Polynomial(integratedCoefficients) +} + +/** + * Compute a definite integral of a given polynomial in a [range] + */ +@UnstableKMathAPI +public fun > Polynomial.integrate( + algebra: Field, + range: ClosedRange, +): C = algebra { + val integral = antiderivative(algebra) + integral.substitute(algebra, range.endInclusive) - integral.substitute(algebra, range.start) +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt index 15d548641..2e6873ece 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt @@ -7,6 +7,7 @@ package space.kscience.kmath.integration import space.kscience.kmath.functions.PiecewisePolynomial import space.kscience.kmath.functions.integrate +import space.kscience.kmath.functions.antiderivative import space.kscience.kmath.interpolation.PolynomialInterpolator import space.kscience.kmath.interpolation.SplineInterpolator import space.kscience.kmath.interpolation.interpolatePolynomials @@ -23,7 +24,7 @@ import space.kscience.kmath.structures.MutableBufferFactory @OptIn(PerformancePitfall::class) @UnstableKMathAPI public fun > PiecewisePolynomial.integrate(algebra: Field): PiecewisePolynomial = - PiecewisePolynomial(pieces.map { it.first to it.second.integrate(algebra) }) + PiecewisePolynomial(pieces.map { it.first to it.second.antiderivative(algebra) }) /** * Compute definite integral of given [PiecewisePolynomial] piece by piece in a given [range] diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt index b13adefa5..bbd76c87e 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt @@ -9,7 +9,7 @@ package space.kscience.kmath.interpolation import space.kscience.kmath.data.XYColumnarData import space.kscience.kmath.functions.PiecewisePolynomial -import space.kscience.kmath.functions.value +import space.kscience.kmath.functions.substitute import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.Ring import space.kscience.kmath.structures.Buffer @@ -33,7 +33,7 @@ public interface PolynomialInterpolator> : Interpolator): PiecewisePolynomial override fun interpolate(points: XYColumnarData): (T) -> T = { x -> - interpolatePolynomials(points).value(algebra, x) ?: getDefaultValue() + interpolatePolynomials(points).substitute(algebra, x) ?: getDefaultValue() } } 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 05c16d17e..e0f0e32a4 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,13 +5,22 @@ package space.kscience.kmath.functions +import space.kscience.kmath.operations.algebra import kotlin.test.Test import kotlin.test.assertEquals class PolynomialTest { + @Test + fun simple_polynomial_test() { + Double.algebra.scalablePolynomial { + val x = Polynomial(listOf(0.0, 1.0)) + val polynomial = x * x - 2 * x + 1 + assertEquals(0.0, polynomial.substitute(1.0), 0.001) + } + } @Test fun testIntegration() { val polynomial = Polynomial(1.0, -2.0, 1.0) - assertEquals(0.0, polynomial.value(1.0), 0.001) + assertEquals(0.0, polynomial.substitute(1.0), 0.001) } } \ No newline at end of file diff --git a/kotlin-js-store/yarn.lock b/kotlin-js-store/yarn.lock index e21abe604..9fc75720e 100644 --- a/kotlin-js-store/yarn.lock +++ b/kotlin-js-store/yarn.lock @@ -274,11 +274,6 @@ argparse@^2.0.1: resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== -astring@1.7.5: - version "1.7.5" - resolved "https://registry.yarnpkg.com/astring/-/astring-1.7.5.tgz#a7d47fceaf32b052d33a3d07c511efeec67447ca" - integrity sha512-lobf6RWXb8c4uZ7Mdq0U12efYmpD1UFnyOWVJPTa3ukqZrMopav+2hdNu0hgBF0JIBFK9QgrBDfwYvh3DFJDAA== - balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" @@ -294,24 +289,11 @@ base64id@2.0.0, base64id@~2.0.0: resolved "https://registry.yarnpkg.com/base64id/-/base64id-2.0.0.tgz#2770ac6bc47d312af97a8bf9a634342e0cd25cb6" integrity sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog== -benchmark@*: - version "2.1.4" - resolved "https://registry.yarnpkg.com/benchmark/-/benchmark-2.1.4.tgz#09f3de31c916425d498cc2ee565a0ebf3c2a5629" - integrity sha1-CfPeMckWQl1JjMLuVloOvzwqVik= - dependencies: - lodash "^4.17.4" - platform "^1.3.3" - binary-extensions@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== -binaryen@101.0.0: - version "101.0.0" - resolved "https://registry.yarnpkg.com/binaryen/-/binaryen-101.0.0.tgz#42a9e4cc7a22e2c1d75a31d28005a9b518b2c555" - integrity sha512-FRmVxvrR8jtcf0qcukNAPZDM3dZ2sc9GmA/hKxBI7k3fFzREKh1cAs+ruQi+ITTKz7u/AuFMuVnbJwTh0ef/HQ== - body-parser@^1.19.0: version "1.19.1" resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.1.tgz#1499abbaa9274af3ecc9f6f10396c995943e31d4" @@ -599,14 +581,6 @@ dom-serialize@^2.2.1: extend "^3.0.0" void-elements "^2.0.0" -dukat@0.5.8-rc.4: - version "0.5.8-rc.4" - resolved "https://registry.yarnpkg.com/dukat/-/dukat-0.5.8-rc.4.tgz#90384dcb50b14c26f0e99dae92b2dea44f5fce21" - integrity sha512-ZnMt6DGBjlVgK2uQamXfd7uP/AxH7RqI0BL9GLrrJb2gKdDxvJChWy+M9AQEaL+7/6TmxzJxFOsRiInY9oGWTA== - dependencies: - google-protobuf "3.12.2" - typescript "3.9.5" - ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" @@ -881,11 +855,6 @@ glob@^7.1.3, glob@^7.1.7: once "^1.3.0" path-is-absolute "^1.0.0" -google-protobuf@3.12.2: - version "3.12.2" - resolved "https://registry.yarnpkg.com/google-protobuf/-/google-protobuf-3.12.2.tgz#50ce9f9b6281235724eb243d6a83e969a2176e53" - integrity sha512-4CZhpuRr1d6HjlyrxoXoocoGFnRYgKULgMtikMddA9ztRyYR59Aondv2FioyxWVamRo0rF2XpYawkTCBEQOSkA== - graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.6: version "4.2.9" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.9.tgz#041b05df45755e587a24942279b9d113146e1c96" @@ -1065,11 +1034,6 @@ jest-worker@^27.4.1: merge-stream "^2.0.0" supports-color "^8.0.0" -js-base64@3.6.1: - version "3.6.1" - resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-3.6.1.tgz#555aae398b74694b4037af1f8a5a6209d170efbe" - integrity sha512-Frdq2+tRRGLQUIQOgsIGSCd1VePCS2fsddTG5dTCqR0JHgltXWfsxnY0gIXPoMeRmdom6Oyq+UMOFg5suduOjQ== - js-yaml@4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" @@ -1179,7 +1143,7 @@ locate-path@^6.0.0: dependencies: p-locate "^5.0.0" -lodash@^4.17.15, lodash@^4.17.21, lodash@^4.17.4: +lodash@^4.17.15, lodash@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -1437,11 +1401,6 @@ pkg-dir@^4.2.0: dependencies: find-up "^4.0.0" -platform@^1.3.3: - version "1.3.6" - resolved "https://registry.yarnpkg.com/platform/-/platform-1.3.6.tgz#48b4ce983164b209c2d45a107adb31f473a6e7a7" - integrity sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg== - postcss-modules-extract-imports@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz#cda1f047c0ae80c97dbe28c3e76a43b88025741d" @@ -1696,14 +1655,6 @@ source-map-loader@3.0.0: iconv-lite "^0.6.2" source-map-js "^0.6.2" -source-map-support@0.5.20: - version "0.5.20" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.20.tgz#12166089f8f5e5e8c56926b377633392dd2cb6c9" - integrity sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - source-map-support@~0.5.20: version "0.5.21" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" @@ -1838,11 +1789,6 @@ type-is@~1.6.18: media-typer "0.3.0" mime-types "~2.1.24" -typescript@3.9.5: - version "3.9.5" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.5.tgz#586f0dba300cde8be52dd1ac4f7e1009c1b13f36" - integrity sha512-hSAifV3k+i6lEoCJ2k6R2Z/rp/H3+8sdmcn5NrS3/3kE7+RyZXm9aqvxWqjEXHAd8b0pShatpcdMTvEdvAJltQ== - ua-parser-js@^0.7.28: version "0.7.31" resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.31.tgz#649a656b191dffab4f21d5e053e27ca17cbff5c6" -- 2.34.1 From ab9dcd83b90a468a325948a1c32257ae0a5d5875 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Thu, 10 Mar 2022 01:44:14 +0300 Subject: [PATCH 002/123] Added abstract rational functions --- .../kmath/functions/AbstractPolynomial.kt | 16 +- .../functions/AbstractRationalFunction.kt | 507 ++++++++++++++++++ 2 files changed, 515 insertions(+), 8 deletions(-) create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt index f6a617656..237a72bcc 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt @@ -70,19 +70,19 @@ public interface AbstractPolynomialSpace> : Ring

// region Polynomial-integer relation /** - * Returns sum of the constant and the integer represented as polynomial. + * Returns sum of the polynomial and the integer represented as polynomial. * * The operation is equivalent to adding [other] copies of unit polynomial to [this]. */ public operator fun P.plus(other: Int): P = optimizedAddMultiplied(this, one, other) /** - * Returns difference between the constant and the integer represented as polynomial. + * Returns difference between the polynomial and the integer represented as polynomial. * * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. */ public operator fun P.minus(other: Int): P = optimizedAddMultiplied(this, one, -other) /** - * Returns product of the constant and the integer represented as polynomial. + * Returns product of the polynomial and the integer represented as polynomial. * * The operation is equivalent to sum of [other] copies of [this]. */ @@ -91,19 +91,19 @@ public interface AbstractPolynomialSpace> : Ring

// region Integer-polynomial relation /** - * Returns sum of the integer represented as polynomial and the constant. + * Returns sum of the integer represented as polynomial and the polynomial. * * The operation is equivalent to adding [this] copies of unit polynomial to [other]. */ public operator fun Int.plus(other: P): P = optimizedAddMultiplied(other, one, this) /** - * Returns difference between the integer represented as polynomial and the constant. + * Returns difference between the integer represented as polynomial and the polynomial. * * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. */ public operator fun Int.minus(other: P): P = optimizedAddMultiplied(-other, one, this) /** - * Returns product of the integer represented as polynomial and the constant. + * Returns product of the integer represented as polynomial and the polynomial. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -254,11 +254,11 @@ public interface AbstractPolynomialSpace> : Ring

/** * Instance of zero polynomial (zero of the polynomial ring). */ - override val zero: P + public override val zero: P /** * Instance of unit polynomial (unit of the polynomial ring). */ - override val one: P + public override val one: P /** * Checks equality of the polynomials. diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt new file mode 100644 index 000000000..5cb570c9f --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt @@ -0,0 +1,507 @@ +/* + * 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.functions + +import space.kscience.kmath.functions.AbstractPolynomialSpace.Companion.optimizedAddMultiplied +import space.kscience.kmath.functions.AbstractPolynomialSpace.Companion.optimizedMultiply +import space.kscience.kmath.operations.* +import kotlin.js.JsName +import kotlin.jvm.JvmName + + +/** + * Abstraction of rational function. + */ +public interface AbstractRationalFunction> + +@Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") +public interface AbstractRationalFunctionalSpace, R: AbstractRationalFunction> : Ring { + // region Constant-integer relation + /** + * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * + * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. + */ + @JvmName("constantIntPlus") + public operator fun C.plus(other: Int): C + /** + * Returns difference between the constant and the integer represented as constant (member of underlying ring). + * + * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. + */ + @JvmName("constantIntMinus") + public operator fun C.minus(other: Int): C + /** + * Returns product of the constant and the integer represented as constant (member of underlying ring). + * + * The operation is equivalent to sum of [other] copies of [this]. + */ + @JvmName("constantIntTimes") + public operator fun C.times(other: Int): C + // endregion + + // region Integer-constant relation + /** + * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * + * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. + */ + @JvmName("intConstantPlus") + public operator fun Int.plus(other: C): C + /** + * Returns difference between the integer represented as constant (member of underlying ring) and the constant. + * + * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. + */ + @JvmName("intConstantMinus") + public operator fun Int.minus(other: C): C + /** + * Returns product of the integer represented as constant (member of underlying ring) and the constant. + * + * The operation is equivalent to sum of [this] copies of [other]. + */ + @JvmName("intConstantTimes") + public operator fun Int.times(other: C): C + // endregion + + // region Polynomial-integer relation + /** + * Returns sum of the constant and the integer represented as polynomial. + * + * The operation is equivalent to adding [other] copies of unit polynomial to [this]. + */ + public operator fun P.plus(other: Int): P + /** + * Returns difference between the constant and the integer represented as polynomial. + * + * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. + */ + public operator fun P.minus(other: Int): P + /** + * Returns product of the constant and the integer represented as polynomial. + * + * The operation is equivalent to sum of [other] copies of [this]. + */ + public operator fun P.times(other: Int): P + // endregion + + // region Integer-polynomial relation + /** + * Returns sum of the integer represented as polynomial and the constant. + * + * The operation is equivalent to adding [this] copies of unit polynomial to [other]. + */ + public operator fun Int.plus(other: P): P + /** + * Returns difference between the integer represented as polynomial and the constant. + * + * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. + */ + public operator fun Int.minus(other: P): P + /** + * Returns product of the integer represented as polynomial and the constant. + * + * The operation is equivalent to sum of [this] copies of [other]. + */ + public operator fun Int.times(other: P): P + // endregion + + // region Rational-integer relation + /** + * Returns sum of the rational function and the integer represented as rational function. + * + * The operation is equivalent to adding [other] copies of unit polynomial to [this]. + */ + public operator fun R.plus(other: Int): R = optimizedAddMultiplied(this, one, other) + /** + * Returns difference between the rational function and the integer represented as rational function. + * + * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. + */ + public operator fun R.minus(other: Int): R = optimizedAddMultiplied(this, one, -other) + /** + * Returns product of the rational function and the integer represented as rational function. + * + * The operation is equivalent to sum of [other] copies of [this]. + */ + public operator fun R.times(other: Int): R = optimizedMultiply(this, other) + // endregion + + // region Integer-Rational relation + /** + * Returns sum of the integer represented as rational function and the rational function. + * + * The operation is equivalent to adding [this] copies of unit polynomial to [other]. + */ + public operator fun Int.plus(other: R): R = optimizedAddMultiplied(other, one, this) + /** + * Returns difference between the integer represented as rational function and the rational function. + * + * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. + */ + public operator fun Int.minus(other: R): R = optimizedAddMultiplied(-other, one, this) + /** + * Returns product of the integer represented as rational function and the rational function. + * + * The operation is equivalent to sum of [this] copies of [other]. + */ + public operator fun Int.times(other: R): R = optimizedMultiply(other, this) + // endregion + + // region Constant-constant relation + /** + * Returns the same constant. + */ + @JvmName("constantUnaryPlus") + @JsName("constantUnaryPlus") + public operator fun C.unaryPlus(): C = this + /** + * Returns negation of the constant. + */ + @JvmName("constantUnaryMinus") + @JsName("constantUnaryMinus") + public operator fun C.unaryMinus(): C + /** + * Returns sum of the constants. + */ + @JvmName("constantPlus") + @JsName("constantPlus") + public operator fun C.plus(other: C): C + /** + * Returns difference of the constants. + */ + @JvmName("constantMinus") + @JsName("constantMinus") + public operator fun C.minus(other: C): C + /** + * Returns product of the constants. + */ + @JvmName("constantTimes") + @JsName("constantTimes") + public operator fun C.times(other: C): C + + /** + * Check if the instant is zero constant. + */ + @JvmName("constantIsZero") + public fun C.isZero(): Boolean + /** + * Check if the instant is NOT zero constant. + */ + @JvmName("constantIsNotZero") + public fun C.isNotZero(): Boolean + /** + * Check if the instant is unit constant. + */ + @JvmName("constantIsOne") + public fun C.isOne(): Boolean + /** + * Check if the instant is NOT unit constant. + */ + @JvmName("constantIsNotOne") + public fun C.isNotOne(): Boolean + /** + * Check if the instant is minus unit constant. + */ + @JvmName("constantIsMinusOne") + public fun C.isMinusOne(): Boolean + /** + * Check if the instant is NOT minus unit constant. + */ + @JvmName("constantIsNotMinusOne") + public fun C.isNotMinusOne(): Boolean + // endregion + + // region Constant-polynomial relation + /** + * Returns sum of the constant represented as polynomial and the polynomial. + */ + public operator fun C.plus(other: P): P + /** + * Returns difference between the constant represented as polynomial and the polynomial. + */ + public operator fun C.minus(other: P): P + /** + * Returns product of the constant represented as polynomial and the polynomial. + */ + public operator fun C.times(other: P): P + // endregion + + // region Polynomial-constant relation + /** + * Returns sum of the constant represented as polynomial and the polynomial. + */ + public operator fun P.plus(other: C): P + /** + * Returns difference between the constant represented as polynomial and the polynomial. + */ + public operator fun P.minus(other: C): P + /** + * Returns product of the constant represented as polynomial and the polynomial. + */ + public operator fun P.times(other: C): P + // endregion + + // region Polynomial-polynomial relation + /** + * Returns the same polynomial. + */ + public operator fun P.unaryPlus(): P = this + /** + * Returns negation of the polynomial. + */ + public operator fun P.unaryMinus(): P + /** + * Returns sum of the polynomials. + */ + public operator fun P.plus(other: P): P + /** + * Returns difference of the polynomials. + */ + public operator fun P.minus(other: P): P + /** + * Returns product of the polynomials. + */ + public operator fun P.times(other: P): P + + /** + * Check if the instant is zero polynomial. + */ + public fun P.isZero(): Boolean = this == zeroPolynomial + /** + * Check if the instant is NOT zero polynomial. + */ + public fun P.isNotZero(): Boolean = this != zeroPolynomial + /** + * Check if the instant is unit polynomial. + */ + public fun P.isOne(): Boolean = this == onePolynomial + /** + * Check if the instant is NOT unit polynomial. + */ + public fun P.isNotOne(): Boolean = this != onePolynomial + /** + * Check if the instant is minus unit polynomial. + */ + public fun P.isMinusOne(): Boolean = this == -onePolynomial + /** + * Check if the instant is NOT minus unit polynomial. + */ + public fun P.isNotMinusOne(): Boolean = this != -onePolynomial + + /** + * Instance of zero polynomial (zero of the polynomial ring). + */ + public val zeroPolynomial: P + /** + * Instance of unit polynomial (unit of the polynomial ring). + */ + public val onePolynomial: P + + /** + * Checks equality of the polynomials. + */ + @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") + public fun P.equals(other: P): Boolean + // endregion + + // region Constant-rational relation + /** + * Returns sum of the constant represented as rational function and the rational function. + */ + public operator fun C.plus(other: R): R + /** + * Returns difference between the constant represented as polynomial and the rational function. + */ + public operator fun C.minus(other: R): R + /** + * Returns product of the constant represented as polynomial and the rational function. + */ + public operator fun C.times(other: R): R + // endregion + + // region Rational-constant relation + /** + * Returns sum of the constant represented as rational function and the rational function. + */ + public operator fun R.plus(other: C): R + /** + * Returns difference between the constant represented as rational function and the rational function. + */ + public operator fun R.minus(other: C): R + /** + * Returns product of the constant represented as rational function and the rational function. + */ + public operator fun R.times(other: C): R + // endregion + + // region Polynomial-rational relation + /** + * Returns sum of the polynomial represented as rational function and the rational function. + */ + public operator fun P.plus(other: R): R + /** + * Returns difference between the polynomial represented as polynomial and the rational function. + */ + public operator fun P.minus(other: R): R + /** + * Returns product of the polynomial represented as polynomial and the rational function. + */ + public operator fun P.times(other: R): R + // endregion + + // region Rational-polynomial relation + /** + * Returns sum of the polynomial represented as rational function and the rational function. + */ + public operator fun R.plus(other: P): R + /** + * Returns difference between the polynomial represented as rational function and the rational function. + */ + public operator fun R.minus(other: P): R + /** + * Returns product of the polynomial represented as rational function and the rational function. + */ + public operator fun R.times(other: P): R + // endregion + + // region Rational-rational relation + /** + * Returns the same rational function. + */ + public override operator fun R.unaryPlus(): R = this + /** + * Returns negation of the rational function. + */ + public override operator fun R.unaryMinus(): R + /** + * Returns sum of the rational functions. + */ + public override operator fun R.plus(other: R): R + /** + * Returns difference of the rational functions. + */ + public override operator fun R.minus(other: R): R + /** + * Returns product of the rational functions. + */ + public override operator fun R.times(other: R): R + + /** + * Check if the instant is zero rational function. + */ + public fun R.isZero(): Boolean = this == zero + /** + * Check if the instant is NOT zero rational function. + */ + public fun R.isNotZero(): Boolean = this != zero + /** + * Check if the instant is unit rational function. + */ + public fun R.isOne(): Boolean = this == one + /** + * Check if the instant is NOT unit rational function. + */ + public fun R.isNotOne(): Boolean = this != one + /** + * Check if the instant is minus unit rational function. + */ + public fun R.isMinusOne(): Boolean = this == -one + /** + * Check if the instant is NOT minus unit rational function. + */ + public fun R.isNotMinusOne(): Boolean = this != -one + + /** + * Instance of zero rational function (zero of the rational functions ring). + */ + public override val zero: R + /** + * Instance of unit polynomial (unit of the rational functions ring). + */ + public override val one: R + + /** + * Checks equality of the rational functions. + */ + @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") + public fun R.equals(other: R): Boolean + // endregion + + // Not sure is it necessary... + // region Polynomial properties + /** + * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is + * zero, degree is -1. + */ + public val P.degree: Int + + /** + * Checks if the instant is constant polynomial (of degree no more than 0) over considered ring. + */ + public fun P.isConstant(): Boolean = degree <= 0 + /** + * Checks if the instant is **not** constant polynomial (of degree no more than 0) over considered ring. + */ + public fun P.isNotConstant(): Boolean = !isConstant() + /** + * Checks if the instant is constant non-zero polynomial (of degree no more than 0) over considered ring. + */ + public fun P.isNonZeroConstant(): Boolean = degree == 0 + /** + * Checks if the instant is **not** constant non-zero polynomial (of degree no more than 0) over considered ring. + */ + public fun P.isNotNonZeroConstant(): Boolean = !isNonZeroConstant() + + public fun P.asConstantOrNull(): C? + + public fun P.asConstant(): C = asConstantOrNull() ?: error("Can not represent non-constant polynomial as a constant") + + // endregion + + // Not sure is it necessary... + // region Polynomial properties + /** + * Checks if the instant is constant polynomial (of degree no more than 0) over considered ring. + */ + public fun R.isConstant(): Boolean + /** + * Checks if the instant is **not** constant polynomial (of degree no more than 0) over considered ring. + */ + public fun R.isNotConstant(): Boolean = !isConstant() + /** + * Checks if the instant is constant non-zero polynomial (of degree no more than 0) over considered ring. + */ + public fun R.isNonZeroConstant(): Boolean + /** + * Checks if the instant is **not** constant non-zero polynomial (of degree no more than 0) over considered ring. + */ + public fun R.isNotNonZeroConstant(): Boolean = !isNonZeroConstant() + + public fun R.asConstantOrNull(): C? + + public fun R.asConstant(): C = asConstantOrNull() ?: error("Can not represent non-constant polynomial as a constant") + + // TODO: Перенести в реализацию +// fun R.substitute(argument: C): C +// fun R.substitute(argument: P): R +// fun R.substitute(argument: R): R +// +// fun R.asFunction(): (C) -> C = /*this::substitute*/ { this.substitute(it) } +// fun R.asFunctionOnConstants(): (C) -> C = /*this::substitute*/ { this.substitute(it) } +// fun P.asFunctionOnPolynomials(): (P) -> R = /*this::substitute*/ { this.substitute(it) } +// fun R.asFunctionOnRationalFunctions(): (R) -> R = /*this::substitute*/ { this.substitute(it) } +// +// operator fun R.invoke(argument: C): C = this.substitute(argument) +// operator fun R.invoke(argument: P): R = this.substitute(argument) +// operator fun R.invoke(argument: R): R = this.substitute(argument) + // endregion + + // region Legacy + override fun add(left: R, right: R): R = left + right + override fun multiply(left: R, right: R): R = left * right + // endregion +} \ No newline at end of file -- 2.34.1 From ffea8cc2234d869745fb0b99a8baedbf9cb51118 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sun, 13 Mar 2022 03:25:25 +0300 Subject: [PATCH 003/123] Regenerated READMEs --- README.md | 4 ++-- kmath-ast/README.md | 47 +++++++++++++++++++++++++++++--------- kmath-complex/README.md | 6 ++--- kmath-core/README.md | 6 ++--- kmath-ejml/README.md | 6 ++--- kmath-for-real/README.md | 6 ++--- kmath-functions/README.md | 6 ++--- kmath-jafama/README.md | 6 ++--- kmath-kotlingrad/README.md | 6 ++--- kmath-nd4j/README.md | 6 ++--- kmath-tensors/README.md | 6 ++--- 11 files changed, 65 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index 99dd6d00f..76b8ce2f7 100644 --- a/README.md +++ b/README.md @@ -308,8 +308,8 @@ repositories { } dependencies { - api("space.kscience:kmath-core:0.3.0-dev-17") - // api("space.kscience:kmath-core-jvm:0.3.0-dev-17") for jvm-specific version + api("space.kscience:kmath-core:0.3.0-dev-19") + // api("space.kscience:kmath-core-jvm:0.3.0-dev-19") for jvm-specific version } ``` diff --git a/kmath-ast/README.md b/kmath-ast/README.md index bedf17486..9411befe3 100644 --- a/kmath-ast/README.md +++ b/kmath-ast/README.md @@ -10,7 +10,7 @@ Extensions to MST API: transformations, dynamic compilation and visualization. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-ast:0.3.0-dev-17`. +The Maven coordinates of this project are `space.kscience:kmath-ast:0.3.0-dev-19`. **Gradle:** ```gradle @@ -20,7 +20,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-ast:0.3.0-dev-17' + implementation 'space.kscience:kmath-ast:0.3.0-dev-19' } ``` **Gradle Kotlin DSL:** @@ -31,7 +31,7 @@ repositories { } dependencies { - implementation("space.kscience:kmath-ast:0.3.0-dev-17") + implementation("space.kscience:kmath-ast:0.3.0-dev-19") } ``` @@ -66,20 +66,19 @@ For example, the following code: ```kotlin import space.kscience.kmath.asm.compileToExpression -import space.kscience.kmath.complex.ComplexField +import space.kscience.kmath.operations.DoubleField -"x+2".parseMath().compileToExpression(ComplexField) +"x^3-x+3".parseMath().compileToExpression(DoubleField) ``` … leads to generation of bytecode, which can be decompiled to the following Java class: ```java -import java.util.Map; -import kotlin.jvm.functions.Function2; -import space.kscience.kmath.asm.internal.MapIntrinsics; -import space.kscience.kmath.complex.Complex; -import space.kscience.kmath.expressions.Expression; -import space.kscience.kmath.expressions.Symbol; +import java.util.*; +import kotlin.jvm.functions.*; +import space.kscience.kmath.asm.internal.*; +import space.kscience.kmath.complex.*; +import space.kscience.kmath.expressions.*; public final class CompiledExpression_45045_0 implements Expression { private final Object[] constants; @@ -91,6 +90,32 @@ public final class CompiledExpression_45045_0 implements Expression { } ``` +For `LongRing`, `IntRing`, and `DoubleField` specialization is supported for better performance: + +```java +import java.util.*; +import space.kscience.kmath.asm.internal.*; +import space.kscience.kmath.expressions.*; + +public final class CompiledExpression_-386104628_0 implements DoubleExpression { + private final SymbolIndexer indexer; + + public SymbolIndexer getIndexer() { + return this.indexer; + } + + public double invoke(double[] arguments) { + double var2 = arguments[0]; + return Math.pow(var2, 3.0D) - var2 + 3.0D; + } + + public final Double invoke(Map arguments) { + double var2 = ((Double)MapIntrinsics.getOrFail(arguments, "x")).doubleValue(); + return Math.pow(var2, 3.0D) - var2 + 3.0D; + } +} +``` + Setting JVM system property `space.kscience.kmath.ast.dump.generated.classes` to `1` makes the translator dump class files to program's working directory, so they can be reviewed manually. #### Limitations diff --git a/kmath-complex/README.md b/kmath-complex/README.md index 92f2435ba..cfaf43aa1 100644 --- a/kmath-complex/README.md +++ b/kmath-complex/README.md @@ -8,7 +8,7 @@ Complex and hypercomplex number systems in KMath. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-complex:0.3.0-dev-17`. +The Maven coordinates of this project are `space.kscience:kmath-complex:0.3.0-dev-19`. **Gradle:** ```gradle @@ -18,7 +18,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-complex:0.3.0-dev-17' + implementation 'space.kscience:kmath-complex:0.3.0-dev-19' } ``` **Gradle Kotlin DSL:** @@ -29,6 +29,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-complex:0.3.0-dev-17") + implementation("space.kscience:kmath-complex:0.3.0-dev-19") } ``` diff --git a/kmath-core/README.md b/kmath-core/README.md index e765ad50c..4e980baf5 100644 --- a/kmath-core/README.md +++ b/kmath-core/README.md @@ -15,7 +15,7 @@ performance calculations to code generation. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-core:0.3.0-dev-17`. +The Maven coordinates of this project are `space.kscience:kmath-core:0.3.0-dev-19`. **Gradle:** ```gradle @@ -25,7 +25,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-core:0.3.0-dev-17' + implementation 'space.kscience:kmath-core:0.3.0-dev-19' } ``` **Gradle Kotlin DSL:** @@ -36,6 +36,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-core:0.3.0-dev-17") + implementation("space.kscience:kmath-core:0.3.0-dev-19") } ``` diff --git a/kmath-ejml/README.md b/kmath-ejml/README.md index fcd092bf1..24b36aa0d 100644 --- a/kmath-ejml/README.md +++ b/kmath-ejml/README.md @@ -9,7 +9,7 @@ EJML based linear algebra implementation. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-ejml:0.3.0-dev-17`. +The Maven coordinates of this project are `space.kscience:kmath-ejml:0.3.0-dev-19`. **Gradle:** ```gradle @@ -19,7 +19,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-ejml:0.3.0-dev-17' + implementation 'space.kscience:kmath-ejml:0.3.0-dev-19' } ``` **Gradle Kotlin DSL:** @@ -30,6 +30,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-ejml:0.3.0-dev-17") + implementation("space.kscience:kmath-ejml:0.3.0-dev-19") } ``` diff --git a/kmath-for-real/README.md b/kmath-for-real/README.md index 938327612..f6b02e6ad 100644 --- a/kmath-for-real/README.md +++ b/kmath-for-real/README.md @@ -9,7 +9,7 @@ Specialization of KMath APIs for Double numbers. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-for-real:0.3.0-dev-17`. +The Maven coordinates of this project are `space.kscience:kmath-for-real:0.3.0-dev-19`. **Gradle:** ```gradle @@ -19,7 +19,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-for-real:0.3.0-dev-17' + implementation 'space.kscience:kmath-for-real:0.3.0-dev-19' } ``` **Gradle Kotlin DSL:** @@ -30,6 +30,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-for-real:0.3.0-dev-17") + implementation("space.kscience:kmath-for-real:0.3.0-dev-19") } ``` diff --git a/kmath-functions/README.md b/kmath-functions/README.md index 3d4beee47..a7f4f9b6f 100644 --- a/kmath-functions/README.md +++ b/kmath-functions/README.md @@ -11,7 +11,7 @@ Functions and interpolations. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-functions:0.3.0-dev-17`. +The Maven coordinates of this project are `space.kscience:kmath-functions:0.3.0-dev-19`. **Gradle:** ```gradle @@ -21,7 +21,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-functions:0.3.0-dev-17' + implementation 'space.kscience:kmath-functions:0.3.0-dev-19' } ``` **Gradle Kotlin DSL:** @@ -32,6 +32,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-functions:0.3.0-dev-17") + implementation("space.kscience:kmath-functions:0.3.0-dev-19") } ``` diff --git a/kmath-jafama/README.md b/kmath-jafama/README.md index 760244751..3e0d9c418 100644 --- a/kmath-jafama/README.md +++ b/kmath-jafama/README.md @@ -7,7 +7,7 @@ Integration with [Jafama](https://github.com/jeffhain/jafama). ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-jafama:0.3.0-dev-17`. +The Maven coordinates of this project are `space.kscience:kmath-jafama:0.3.0-dev-19`. **Gradle:** ```gradle @@ -17,7 +17,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-jafama:0.3.0-dev-17' + implementation 'space.kscience:kmath-jafama:0.3.0-dev-19' } ``` **Gradle Kotlin DSL:** @@ -28,7 +28,7 @@ repositories { } dependencies { - implementation("space.kscience:kmath-jafama:0.3.0-dev-17") + implementation("space.kscience:kmath-jafama:0.3.0-dev-19") } ``` diff --git a/kmath-kotlingrad/README.md b/kmath-kotlingrad/README.md index 588ccb9b4..422ce4fb0 100644 --- a/kmath-kotlingrad/README.md +++ b/kmath-kotlingrad/README.md @@ -8,7 +8,7 @@ ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-kotlingrad:0.3.0-dev-17`. +The Maven coordinates of this project are `space.kscience:kmath-kotlingrad:0.3.0-dev-19`. **Gradle:** ```gradle @@ -18,7 +18,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-kotlingrad:0.3.0-dev-17' + implementation 'space.kscience:kmath-kotlingrad:0.3.0-dev-19' } ``` **Gradle Kotlin DSL:** @@ -29,6 +29,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-kotlingrad:0.3.0-dev-17") + implementation("space.kscience:kmath-kotlingrad:0.3.0-dev-19") } ``` diff --git a/kmath-nd4j/README.md b/kmath-nd4j/README.md index 7ca9cd4fd..23d529e72 100644 --- a/kmath-nd4j/README.md +++ b/kmath-nd4j/README.md @@ -9,7 +9,7 @@ ND4J based implementations of KMath abstractions. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-nd4j:0.3.0-dev-17`. +The Maven coordinates of this project are `space.kscience:kmath-nd4j:0.3.0-dev-19`. **Gradle:** ```gradle @@ -19,7 +19,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-nd4j:0.3.0-dev-17' + implementation 'space.kscience:kmath-nd4j:0.3.0-dev-19' } ``` **Gradle Kotlin DSL:** @@ -30,7 +30,7 @@ repositories { } dependencies { - implementation("space.kscience:kmath-nd4j:0.3.0-dev-17") + implementation("space.kscience:kmath-nd4j:0.3.0-dev-19") } ``` diff --git a/kmath-tensors/README.md b/kmath-tensors/README.md index 42ce91336..93f78e895 100644 --- a/kmath-tensors/README.md +++ b/kmath-tensors/README.md @@ -9,7 +9,7 @@ Common linear algebra operations on tensors. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-tensors:0.3.0-dev-17`. +The Maven coordinates of this project are `space.kscience:kmath-tensors:0.3.0-dev-19`. **Gradle:** ```gradle @@ -19,7 +19,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-tensors:0.3.0-dev-17' + implementation 'space.kscience:kmath-tensors:0.3.0-dev-19' } ``` **Gradle Kotlin DSL:** @@ -30,6 +30,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-tensors:0.3.0-dev-17") + implementation("space.kscience:kmath-tensors:0.3.0-dev-19") } ``` -- 2.34.1 From 843d63c76a46a55c683f4a8276663f5fecc6d6f5 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sun, 13 Mar 2022 03:27:00 +0300 Subject: [PATCH 004/123] Added support for all polynomials. But standard utilities still are not fully implemented. --- .../kmath/functions/AbstractPolynomial.kt | 47 +- .../functions/AbstractRationalFunction.kt | 2 - .../kmath/functions/LabeledPolynomial.kt | 927 ++++++++++++++++++ .../kmath/functions/NumberedPolynomial.kt | 689 +++++++++++++ .../kscience/kmath/functions/Polynomial.kt | 151 ++- .../kscience/kmath/functions/Variable.kt | 38 + .../kscience/kmath/functions/algebraicStub.kt | 51 + .../kmath/functions/labeledPolynomialUtil.kt | 490 +++++++++ .../kmath/functions/numberedPolynomialUtil.kt | 605 ++++++++++++ .../kmath/functions/polynomialUtil.kt | 6 +- 10 files changed, 2911 insertions(+), 95 deletions(-) create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Variable.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt index 237a72bcc..b7b7116f0 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt @@ -17,6 +17,9 @@ public interface AbstractPolynomial /** * Abstraction of ring of polynomials of type [P] over ring of constants of type [C]. + * + * @param C the type of constants. Polynomials have them as a coefficients in their terms. + * @param P the type of polynomials. */ @Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") public interface AbstractPolynomialSpace> : Ring

{ @@ -307,48 +310,4 @@ public interface AbstractPolynomialSpace> : Ring

override fun add(left: P, right: P): P = left + right override fun multiply(left: P, right: P): P = left * right // endregion - - public companion object { - // TODO: All of this should be moved to algebraic structures' place for utilities - // TODO: Move receiver to context receiver - /** - * Multiplication of element and integer. - * - * @receiver the multiplicand. - * @param other the multiplier. - * @return the difference. - */ - internal tailrec fun Group.optimizedMultiply(arg: C, other: Int): C = - when { - other == 0 -> zero - other == 1 -> arg - other == -1 -> -arg - other % 2 == 0 -> optimizedMultiply(arg + arg, other / 2) - other % 2 == 1 -> optimizedAddMultiplied(arg, arg + arg, other / 2) - other % 2 == -1 -> optimizedAddMultiplied(-arg, arg + arg, other / 2) - else -> error("Error in multiplication group instant by integer: got reminder by division by 2 different from 0, 1 and -1") - } - - // TODO: Move receiver to context receiver - /** - * Adds product of [arg] and [multiplier] to [base]. - * - * @receiver the algebra to provide multiplication. - * @param base the augend. - * @param arg the multiplicand. - * @param multiplier the multiplier. - * @return sum of the augend [base] and product of the multiplicand [arg] and the multiplier [multiplier]. - * @author Gleb Minaev - */ - internal tailrec fun Group.optimizedAddMultiplied(base: C, arg: C, multiplier: Int): C = - when { - multiplier == 0 -> base - multiplier == 1 -> base + arg - multiplier == -1 -> base - arg - multiplier % 2 == 0 -> optimizedAddMultiplied(base, arg + arg, multiplier / 2) - multiplier % 2 == 1 -> optimizedAddMultiplied(base + arg, arg + arg, multiplier / 2) - multiplier % 2 == -1 -> optimizedAddMultiplied(base + arg, arg + arg, multiplier / 2) - else -> error("Error in multiplication group instant by integer: got reminder by division by 2 different from 0, 1 and -1") - } - } } \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt index 5cb570c9f..34050aa0f 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt @@ -5,8 +5,6 @@ package space.kscience.kmath.functions -import space.kscience.kmath.functions.AbstractPolynomialSpace.Companion.optimizedAddMultiplied -import space.kscience.kmath.functions.AbstractPolynomialSpace.Companion.optimizedMultiply import space.kscience.kmath.operations.* import kotlin.js.JsName import kotlin.jvm.JvmName diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt new file mode 100644 index 000000000..48f6f57fa --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt @@ -0,0 +1,927 @@ +package space.kscience.kmath.functions + +import space.kscience.kmath.operations.* +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract +import kotlin.experimental.ExperimentalTypeInference +import kotlin.jvm.JvmName +import kotlin.math.max + + +/** + * Represents multivariate polynomials with labeled variables. + * + * @param C Ring in which the polynomial is considered. + */ +public class LabeledPolynomial +internal constructor( + /** + * Map that collects coefficients of the polynomial. Every non-zero monomial + * `a x_1^{d_1} ... x_n^{d_n}` is represented as pair "key-value" in the map, where value is coefficients `a` and + * key is map that associates variables in the monomial with multiplicity of them occurring in the monomial. + * For example polynomial + * ``` + * 5 a^2 c^3 - 6 b + 0 b c + * ``` + * has coefficients represented as + * ``` + * mapOf( + * mapOf( + * a to 2, + * c to 3 + * ) to 5, + * mapOf( + * b to 1 + * ) to (-6) + * ) + * ``` + * where `a`, `b` and `c` are corresponding [Variable] objects. + */ + public val coefficients: Map, C> +) : AbstractPolynomial { + override fun toString(): String = "LabeledPolynomial$coefficients" +} + +// region Internal utilities + +/** + * Represents internal [LabeledPolynomial] errors. + */ +internal class LabeledPolynomialError: Error { + constructor(): super() + constructor(message: String): super(message) + constructor(message: String?, cause: Throwable?): super(message, cause) + constructor(cause: Throwable?): super(cause) +} + +/** + * Throws an [LabeledPolynomialError] with the given [message]. + */ +internal fun labeledPolynomialError(message: Any): Nothing = throw LabeledPolynomialError(message.toString()) + +/** + * Returns the same degrees description of the monomial, but without zero degrees. + */ +internal fun Map.cleanUp() = filterValues { it > 0U } + +// endregion + +// region Constructors and converters + +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received +// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. +// * +// * @param pairs Collection of pairs that represent monomials. +// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. +// * +// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(A) +//internal fun > LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = true): LabeledPolynomial { +// if (!toCheckInput) return LabeledPolynomial(coefs) +// +// // Map for cleaned coefficients. +// val fixedCoefs = mutableMapOf, C>() +// +// // Cleaning the degrees, summing monomials of the same degrees. +// for (entry in coefs) { +// val key = entry.key.cleanUp() +// val value = entry.value +// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value +// } +// +// // Removing zero monomials. +// return LabeledPolynomial( +// fixedCoefs +// .filter { it.value.isNotZero() } +// ) +//} +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received +// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. +// * +// * @param pairs Collection of pairs that represent monomials. +// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. +// * +// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(A) +//internal fun > LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean): LabeledPolynomial { +// if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) +// +// // Map for cleaned coefficients. +// val fixedCoefs = mutableMapOf, C>() +// +// // Cleaning the degrees, summing monomials of the same degrees. +// for (entry in pairs) { +// val key = entry.first.cleanUp() +// val value = entry.second +// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value +// } +// +// // Removing zero monomials. +// return LabeledPolynomial( +// fixedCoefs.filterValues { it.isNotZero() } +// ) +//} +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received +// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. +// * +// * @param pairs Collection of pairs that represents monomials. +// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. +// * +// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(A) +//internal fun > LabeledPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean): LabeledPolynomial { +// if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) +// +// // Map for cleaned coefficients. +// val fixedCoefs = mutableMapOf, C>() +// +// // Cleaning the degrees, summing monomials of the same degrees. +// for (entry in pairs) { +// val key = entry.first.cleanUp() +// val value = entry.second +// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value +// } +// +// // Removing zero monomials. +// return LabeledPolynomial( +// fixedCoefs.filterValues { it.isNotZero() } +// ) +//} +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received +// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. +// * +// * @param coefs Coefficients of the instants. +// * +// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(A) +//fun > LabeledPolynomial(coefs: Map, C>): LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received +// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. +// * +// * @param pairs Collection of pairs that represents monomials. +// * +// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(A) +//fun > LabeledPolynomial(pairs: Collection, C>>): LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received +// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. +// * +// * @param pairs Collection of pairs that represents monomials. +// * +// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(A) +//fun > LabeledPolynomial(vararg pairs: Pair, C>): LabeledPolynomial = LabeledPolynomial(*pairs, toCheckInput = true) +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received +// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. +// * +// * @param pairs Collection of pairs that represent monomials. +// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. +// * +// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(LabeledPolynomialSpace) +//internal fun > LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = true): LabeledPolynomial { +// if (!toCheckInput) return LabeledPolynomial(coefs) +// +// // Map for cleaned coefficients. +// val fixedCoefs = mutableMapOf, C>() +// +// // Cleaning the degrees, summing monomials of the same degrees. +// for (entry in coefs) { +// val key = entry.key.cleanUp() +// val value = entry.value +// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value +// } +// +// // Removing zero monomials. +// return LabeledPolynomial( +// fixedCoefs +// .filter { it.value.isNotZero() } +// ) +//} +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received +// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. +// * +// * @param pairs Collection of pairs that represent monomials. +// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. +// * +// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(LabeledPolynomialSpace) +//internal fun > LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean): LabeledPolynomial { +// if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) +// +// // Map for cleaned coefficients. +// val fixedCoefs = mutableMapOf, C>() +// +// // Cleaning the degrees, summing monomials of the same degrees. +// for (entry in pairs) { +// val key = entry.first.cleanUp() +// val value = entry.second +// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value +// } +// +// // Removing zero monomials. +// return LabeledPolynomial( +// fixedCoefs.filterValues { it.isNotZero() } +// ) +//} +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received +// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. +// * +// * @param pairs Collection of pairs that represents monomials. +// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. +// * +// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(LabeledPolynomialSpace) +//internal fun > LabeledPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean): LabeledPolynomial { +// if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) +// +// // Map for cleaned coefficients. +// val fixedCoefs = mutableMapOf, C>() +// +// // Cleaning the degrees, summing monomials of the same degrees. +// for (entry in pairs) { +// val key = entry.first.cleanUp() +// val value = entry.second +// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value +// } +// +// // Removing zero monomials. +// return LabeledPolynomial( +// fixedCoefs.filterValues { it.isNotZero() } +// ) +//} +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received +// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. +// * +// * @param coefs Coefficients of the instants. +// * +// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(LabeledPolynomialSpace) +//fun > LabeledPolynomial(coefs: Map, C>): LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received +// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. +// * +// * @param pairs Collection of pairs that represents monomials. +// * +// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(LabeledPolynomialSpace) +//fun > LabeledPolynomial(pairs: Collection, C>>): LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received +// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. +// * +// * @param pairs Collection of pairs that represents monomials. +// * +// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(LabeledPolynomialSpace) +//fun > LabeledPolynomial(vararg pairs: Pair, C>): LabeledPolynomial = LabeledPolynomial(*pairs, toCheckInput = true) +// +//fun C.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to this)) +// +//context(A) +//fun > Variable.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1U) to one)) +// +//context(LabeledPolynomialSpace) +//fun > Variable.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1U) to ring.one)) +// +//context(A) +//fun > Variable.asLabeledPolynomial(c: C) : LabeledPolynomial = +// if(c.isZero()) LabeledPolynomial(emptyMap()) +// else LabeledPolynomial(mapOf(mapOf(this to 1U) to c)) +// +//context(LabeledPolynomialSpace) +//fun > Variable.asLabeledPolynomial(c: C) : LabeledPolynomial = +// if(c.isZero()) zero +// else LabeledPolynomial(mapOf(mapOf(this to 1U) to c)) + +// endregion + +/** + * Space of polynomials. + * + * @param C the type of operated polynomials. + * @param A the intersection of [Ring] of [C] and [ScaleOperations] of [C]. + * @param ring the [A] instance. + */ +@Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE", "INAPPLICABLE_JVM_NAME") +public class LabeledPolynomialSpace>( + public val ring: A, +) : AbstractPolynomialSpace> { + // region Constant-integer relation + @JvmName("constantIntPlus") + public override operator fun C.plus(other: Int): C = ring { optimizedAddMultiplied(this@plus, one, other) } + @JvmName("constantIntMinus") + public override operator fun C.minus(other: Int): C = ring { optimizedAddMultiplied(this@minus, one, -other) } + @JvmName("constantIntTimes") + public override operator fun C.times(other: Int): C = ring { optimizedMultiply(this@times, other) } + // endregion + + // region Integer-constant relation + @JvmName("intConstantPlus") + public override operator fun Int.plus(other: C): C = ring { optimizedAddMultiplied(other, one, this@plus) } + @JvmName("intConstantMinus") + public override operator fun Int.minus(other: C): C = ring { optimizedAddMultiplied(-other, one, this@minus) } + @JvmName("intConstantTimes") + public override operator fun Int.times(other: C): C = ring { optimizedMultiply(other, this@times) } + // endregion + + // region Variable-integer relation + public operator fun Variable.plus(other: Int): LabeledPolynomial = + if (other == 0) LabeledPolynomial(mapOf( + mapOf(this@plus to 1U) to ring.one, + )) + else LabeledPolynomial(mapOf( + mapOf(this@plus to 1U) to ring.one, + emptyMap() to ring.one * other, + )) + public operator fun Variable.minus(other: Int): LabeledPolynomial = + if (other == 0) LabeledPolynomial(mapOf( + mapOf(this@minus to 1U) to -ring.one, + )) + else LabeledPolynomial(mapOf( + mapOf(this@minus to 1U) to -ring.one, + emptyMap() to ring.one * other, + )) + public operator fun Variable.times(other: Int): LabeledPolynomial = + if (other == 0) zero + else LabeledPolynomial(mapOf( + mapOf(this to 1U) to ring.one * other, + )) + // endregion + + // region Integer-variable relation + public operator fun Int.plus(other: Variable): LabeledPolynomial = + if (this == 0) LabeledPolynomial(mapOf( + mapOf(other to 1U) to ring.one, + )) + else LabeledPolynomial(mapOf( + mapOf(other to 1U) to ring.one, + emptyMap() to ring.one * this@plus, + )) + public operator fun Int.minus(other: Variable): LabeledPolynomial = + if (this == 0) LabeledPolynomial(mapOf( + mapOf(other to 1U) to -ring.one, + )) + else LabeledPolynomial(mapOf( + mapOf(other to 1U) to -ring.one, + emptyMap() to ring.one * this@minus, + )) + public operator fun Int.times(other: Variable): LabeledPolynomial = + if (this == 0) zero + else LabeledPolynomial(mapOf( + mapOf(other to 1U) to ring.one * this@times, + )) + // endregion + + // region Polynomial-integer relation + public override operator fun LabeledPolynomial.plus(other: Int): LabeledPolynomial = + if (other == 0) this + else + LabeledPolynomial( + coefficients + .toMutableMap() + .apply { + val degs = emptyMap() + + val result = getOrElse(degs) { ring.zero } + other + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + public override operator fun LabeledPolynomial.minus(other: Int): LabeledPolynomial = + if (other == 0) this + else + LabeledPolynomial( + coefficients + .toMutableMap() + .apply { + val degs = emptyMap() + + val result = getOrElse(degs) { ring.zero } - other + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + public override operator fun LabeledPolynomial.times(other: Int): LabeledPolynomial = + if (other == 0) zero + else LabeledPolynomial( + coefficients + .applyAndRemoveZeros { + mapValues { (_, c) -> c * other } + } + ) + // endregion + + // region Integer-polynomial relation + public override operator fun Int.plus(other: LabeledPolynomial): LabeledPolynomial = + if (this == 0) other + else + LabeledPolynomial( + other.coefficients + .toMutableMap() + .apply { + val degs = emptyMap() + + val result = this@plus + getOrElse(degs) { ring.zero } + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + public override operator fun Int.minus(other: LabeledPolynomial): LabeledPolynomial = + if (this == 0) other + else + LabeledPolynomial( + other.coefficients + .toMutableMap() + .apply { + val degs = emptyMap() + + val result = this@minus - getOrElse(degs) { ring.zero } + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + public override operator fun Int.times(other: LabeledPolynomial): LabeledPolynomial = + if (this == 0) zero + else LabeledPolynomial( + other.coefficients + .applyAndRemoveZeros { + mapValues { (_, c) -> this@times * c } + } + ) + // endregion + + // region Constant-constant relation + @JvmName("constantUnaryMinus") + override operator fun C.unaryMinus(): C = ring { -this@unaryMinus } + @JvmName("constantPlus") + override operator fun C.plus(other: C): C = ring { this@plus + other } + @JvmName("constantMinus") + override operator fun C.minus(other: C): C = ring { this@minus - other } + @JvmName("constantTimes") + override operator fun C.times(other: C): C = ring { this@times * other } + @JvmName("constantIsZero") + public override fun C.isZero(): Boolean = ring { this == zero } + @JvmName("constantIsNotZero") + public override fun C.isNotZero(): Boolean = ring { this != zero } + @JvmName("constantIsOne") + public override fun C.isOne(): Boolean = ring { this == one } + @JvmName("constantIsNotOne") + public override fun C.isNotOne(): Boolean = ring { this != one } + @JvmName("constantIsMinusOne") + public override fun C.isMinusOne(): Boolean = ring { this == -one } + @JvmName("constantIsNotMinusOne") + public override fun C.isNotMinusOne(): Boolean = ring { this != -one } + // endregion + + // region Constant-variable relation + public operator fun C.plus(other: Variable): LabeledPolynomial = + if (isZero()) LabeledPolynomial(mapOf( + mapOf(other to 1U) to ring.one, + )) + else LabeledPolynomial(mapOf( + mapOf(other to 1U) to ring.one, + emptyMap() to this@plus, + )) + public operator fun C.minus(other: Variable): LabeledPolynomial = + if (isZero()) LabeledPolynomial(mapOf( + mapOf(other to 1U) to -ring.one, + )) + else LabeledPolynomial(mapOf( + mapOf(other to 1U) to -ring.one, + emptyMap() to this@minus, + )) + public operator fun C.times(other: Variable): LabeledPolynomial = + if (isZero()) zero + else LabeledPolynomial(mapOf( + mapOf(other to 1U) to this@times, + )) + // endregion + + // region Variable-constant relation + public operator fun Variable.plus(other: C): LabeledPolynomial = + if (other.isZero()) LabeledPolynomial(mapOf( + mapOf(this@plus to 1U) to ring.one, + )) + else LabeledPolynomial(mapOf( + mapOf(this@plus to 1U) to ring.one, + emptyMap() to other, + )) + public operator fun Variable.minus(other: C): LabeledPolynomial = + if (other.isZero()) LabeledPolynomial(mapOf( + mapOf(this@minus to 1U) to -ring.one, + )) + else LabeledPolynomial(mapOf( + mapOf(this@minus to 1U) to -ring.one, + emptyMap() to other, + )) + public operator fun Variable.times(other: C): LabeledPolynomial = + if (other.isZero()) zero + else LabeledPolynomial(mapOf( + mapOf(this@times to 1U) to other, + )) + // endregion + + // region Constant-polynomial relation + override operator fun C.plus(other: LabeledPolynomial): LabeledPolynomial = + if (this.isZero()) other + else with(other.coefficients) { + if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to this@plus)) + else LabeledPolynomial( + toMutableMap() + .apply { + val degs = emptyMap() + + val result = this@plus + getOrElse(degs) { ring.zero } + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + } + override operator fun C.minus(other: LabeledPolynomial): LabeledPolynomial = + if (this.isZero()) other + else with(other.coefficients) { + if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to this@minus)) + else LabeledPolynomial( + toMutableMap() + .apply { + forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } + + val degs = emptyMap() + + val result = this@minus - getOrElse(degs) { ring.zero } + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + } + override operator fun C.times(other: LabeledPolynomial): LabeledPolynomial = + if (this.isZero()) zero + else LabeledPolynomial( + other.coefficients + .applyAndRemoveZeros { + mapValues { (_, c) -> this@times * c } + } + ) + // endregion + + // region Polynomial-constant relation + /** + * Returns sum of the polynomials. [other] is interpreted as [UnivariatePolynomial]. + */ + override operator fun LabeledPolynomial.plus(other: C): LabeledPolynomial = + if (other.isZero()) this + else with(coefficients) { + if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to other)) + else LabeledPolynomial( + toMutableMap() + .apply { + val degs = emptyMap() + + val result = getOrElse(degs) { ring.zero } + other + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + } + /** + * Returns difference of the polynomials. [other] is interpreted as [UnivariatePolynomial]. + */ + override operator fun LabeledPolynomial.minus(other: C): LabeledPolynomial = + if (other.isZero()) this + else with(coefficients) { + if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to other)) + else LabeledPolynomial( + toMutableMap() + .apply { + forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } + + val degs = emptyMap() + + val result = getOrElse(degs) { ring.zero } - other + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + } + /** + * Returns product of the polynomials. [other] is interpreted as [UnivariatePolynomial]. + */ + override operator fun LabeledPolynomial.times(other: C): LabeledPolynomial = + if (other.isZero()) zero + else LabeledPolynomial( + coefficients + .applyAndRemoveZeros { + mapValues { (_, c) -> c * other } + } + ) + // endregion + + // region Variable-variable relation + public operator fun Variable.plus(other: Variable): LabeledPolynomial = + if (this == other) LabeledPolynomial(mapOf( + mapOf(this to 1U) to ring.one * 2 + )) + else LabeledPolynomial(mapOf( + mapOf(this to 1U) to ring.one, + mapOf(other to 1U) to ring.one, + )) + public operator fun Variable.minus(other: Variable): LabeledPolynomial = + if (this == other) zero + else LabeledPolynomial(mapOf( + mapOf(this to 1U) to ring.one, + mapOf(other to 1U) to -ring.one, + )) + public operator fun Variable.times(other: Variable): LabeledPolynomial = + if (this == other) LabeledPolynomial(mapOf( + mapOf(this to 2U) to ring.one + )) + else LabeledPolynomial(mapOf( + mapOf(this to 1U, other to 1U) to ring.one, + )) + // endregion + + // region Variable-polynomial relation + public operator fun Variable.plus(other: LabeledPolynomial): LabeledPolynomial = + with(other.coefficients) { + if (isEmpty()) LabeledPolynomial(mapOf(mapOf(this@plus to 1u) to ring.one)) + else LabeledPolynomial( + toMutableMap() + .apply { + val degs = mapOf(this@plus to 1U) + + val result = ring.one + getOrElse(degs) { ring.zero } + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + } + public operator fun Variable.minus(other: LabeledPolynomial): LabeledPolynomial = + with(other.coefficients) { + if (isEmpty()) LabeledPolynomial(mapOf(mapOf(this@minus to 1u) to ring.one)) + else LabeledPolynomial( + toMutableMap() + .apply { + forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } + + val degs = mapOf(this@minus to 1U) + + val result = ring.one - getOrElse(degs) { ring.zero } + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + } + public operator fun Variable.times(other: LabeledPolynomial): LabeledPolynomial = + LabeledPolynomial( + other.coefficients + .mapKeys { (degs, _) -> degs.toMutableMap().also{ it[this] = if (this in it) it[this]!! + 1U else 1U } } + ) + // endregion + + // region Polynomial-variable relation + public operator fun LabeledPolynomial.plus(other: Variable): LabeledPolynomial = + with(coefficients) { + if (isEmpty()) LabeledPolynomial(mapOf(mapOf(other to 1u) to ring.one)) + else LabeledPolynomial( + toMutableMap() + .apply { + val degs = mapOf(other to 1U) + + val result = ring.one + getOrElse(degs) { ring.zero } + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + } + public operator fun LabeledPolynomial.minus(other: Variable): LabeledPolynomial = + with(coefficients) { + if (isEmpty()) LabeledPolynomial(mapOf(mapOf(other to 1u) to ring.one)) + else LabeledPolynomial( + toMutableMap() + .apply { + val degs = mapOf(other to 1U) + + val result = ring.one - getOrElse(degs) { ring.zero } + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + } + public operator fun LabeledPolynomial.times(other: Variable): LabeledPolynomial = + LabeledPolynomial( + coefficients + .mapKeys { (degs, _) -> degs.toMutableMap().also{ it[other] = if (other in it) it[other]!! + 1U else 1U } } + ) + // endregion + + // region Polynomial-polynomial relation + /** + * Returns negation of the polynomial. + */ + override fun LabeledPolynomial.unaryMinus(): LabeledPolynomial = + LabeledPolynomial( + coefficients.mapValues { -it.value } + ) + /** + * Returns sum of the polynomials. + */ + override operator fun LabeledPolynomial.plus(other: LabeledPolynomial): LabeledPolynomial = + LabeledPolynomial( + coefficients + .applyAndRemoveZeros { + other.coefficients + .mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! + value else value } + } + ) + /** + * Returns difference of the polynomials. + */ + override operator fun LabeledPolynomial.minus(other: LabeledPolynomial): LabeledPolynomial = + LabeledPolynomial( + coefficients + .applyAndRemoveZeros { + other.coefficients + .mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! - value else -value } + } + ) + /** + * Returns product of the polynomials. + */ + override operator fun LabeledPolynomial.times(other: LabeledPolynomial): LabeledPolynomial = + when { + isZero() -> zero + other.isZero() -> zero + else -> LabeledPolynomial( + buildCoefficients { + for ((degs1, c1) in coefficients) for ((degs2, c2) in other.coefficients) { + val degs = degs1.toMutableMap() + degs2.mapValuesTo(degs) { (variable, deg) -> degs.getOrElse(variable) { 0u } + deg } + val c = c1 * c2 + this[degs] = if (degs in this) this[degs]!! + c else c + } + } + ) + } + + override val zero: LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to ring.zero)) + override val one: LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to ring.one)) + + // TODO: Docs + @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") + override fun LabeledPolynomial.equals(other: LabeledPolynomial): Boolean = + when { + this === other -> true + else -> coefficients.size == other.coefficients.size && + coefficients.all { (key, value) -> with(other.coefficients) { key in this && this[key] == value } } + } + // endregion + + // Not sure is it necessary... + // region Polynomial properties + /** + * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is + * zero, degree is -1. + */ + override val LabeledPolynomial.degree: Int + get() = coefficients.entries.maxOfOrNull { (degs, c) -> if (c.isZero()) -1 else degs.values.sum().toInt() } ?: -1 + /** + * Map that associates variables (that appear in the polynomial in positive exponents) with their most exponents + * in which they are appeared in the polynomial. + * + * As consequence all values in the map are positive integers. Also, if the polynomial is constant, the map is empty. + * And keys of the map is the same as in [variables]. + */ + public val LabeledPolynomial.degrees: Map + get() = + buildMap { + coefficients.entries.forEach { (degs, c) -> + if (c.isNotZero()) degs.mapValuesTo(this) { (variable, deg) -> + max(getOrElse(variable) { 0u }, deg) + } + } + } + /** + * Set of all variables that appear in the polynomial in positive exponents. + */ + public val LabeledPolynomial.variables: Set + get() = + buildSet { + coefficients.entries.forEach { (degs, c) -> if (c.isNotZero()) addAll(degs.keys) } + } + /** + * Count of all variables that appear in the polynomial in positive exponents. + */ + public val LabeledPolynomial.countOfVariables: Int get() = variables.size + + /** + * Checks if the instant is constant polynomial (of degree no more than 0) over considered ring. + */ + override fun LabeledPolynomial.isConstant(): Boolean = + coefficients.all { (degs, c) -> degs.isEmpty() || c.isZero() } + /** + * Checks if the instant is constant non-zero polynomial (of degree no more than 0) over considered ring. + */ + override fun LabeledPolynomial.isNonZeroConstant(): Boolean = + with(coefficients) { + var foundAbsoluteTermAndItIsNotZero = false + for ((degs, c) in this) { + if (degs.isNotEmpty()) if (c.isNotZero()) return@with false + else { + if (c.isZero()) return@with false + else foundAbsoluteTermAndItIsNotZero = true + } + } + foundAbsoluteTermAndItIsNotZero + } + + override fun LabeledPolynomial.asConstantOrNull(): C? = + with(coefficients) { + if(isConstant()) getOrElse(emptyMap()) { ring.zero } + else null + } + +// @Suppress("NOTHING_TO_INLINE") +// public inline fun LabeledPolynomial.substitute(argument: Map): LabeledPolynomial = this.substitute(ring, argument) +// @Suppress("NOTHING_TO_INLINE") +// @JvmName("substitutePolynomial") +// public inline fun LabeledPolynomial.substitute(argument: Map>): LabeledPolynomial = this.substitute(ring, argument) +// +// @Suppress("NOTHING_TO_INLINE") +// public inline fun LabeledPolynomial.asFunction(): (Map) -> LabeledPolynomial = { this.substitute(ring, it) } +// @Suppress("NOTHING_TO_INLINE") +// public inline fun LabeledPolynomial.asFunctionOnConstants(): (Map) -> LabeledPolynomial = { this.substitute(ring, it) } +// @Suppress("NOTHING_TO_INLINE") +// public inline fun LabeledPolynomial.asFunctionOnPolynomials(): (Map>) -> LabeledPolynomial = { this.substitute(ring, it) } +// +// @Suppress("NOTHING_TO_INLINE") +// public inline operator fun LabeledPolynomial.invoke(argument: Map): LabeledPolynomial = this.substitute(ring, argument) +// @Suppress("NOTHING_TO_INLINE") +// @JvmName("invokePolynomial") +// public inline operator fun LabeledPolynomial.invoke(argument: Map>): LabeledPolynomial = this.substitute(ring, argument) + // endregion + + // region Legacy + @Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") + override inline fun add(left: LabeledPolynomial, right: LabeledPolynomial): LabeledPolynomial = left + right + @Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") + override inline fun multiply(left: LabeledPolynomial, right: LabeledPolynomial): LabeledPolynomial = left * right + // endregion + + // region Utilities + // TODO: Move to region internal utilities with context receiver + internal fun MutableMap, C>.applyAndRemoveZeros(block: MutableMap, C>.() -> Unit) : MutableMap, C> { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + block() + for ((degs, c) in this) if (c.isZero()) this.remove(degs) + return this + } + internal fun Map, C>.applyAndRemoveZeros(block: MutableMap, C>.() -> Unit) : Map, C> = + toMutableMap().applyAndRemoveZeros(block) + @OptIn(ExperimentalTypeInference::class) + internal fun buildCoefficients(@BuilderInference builderAction: MutableMap, C>.() -> Unit): Map, C> { + contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) } + return buildMap { + builderAction() + for ((degs, c) in this) if (c.isZero()) this.remove(degs) + } + } + // endregion +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt new file mode 100644 index 000000000..f1ad9a74f --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -0,0 +1,689 @@ +package space.kscience.kmath.functions + +import space.kscience.kmath.operations.* +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract +import kotlin.experimental.ExperimentalTypeInference +import kotlin.jvm.JvmName +import kotlin.math.max + + +/** + * Polynomial model without fixation on specific context they are applied to. + * + * @param C the type of constants. + */ +public class NumberedPolynomial +internal constructor( + /** + * Map that collects coefficients of the polynomial. Every monomial `a x_1^{d_1} ... x_n^{d_n}` is represented as + * pair "key-value" in the map, where value is coefficients `a` and + * key is list that associates index of every variable in the monomial with multiplicity of the variable occurring + * in the monomial. For example coefficients of polynomial `5 x_1^2 x_3^3 - 6 x_2` can be represented as + * ``` + * mapOf( + * listOf(2, 0, 3) to 5, + * listOf(0, 1) to (-6), + * ) + * ``` + * and also as + * ``` + * mapOf( + * listOf(2, 0, 3) to 5, + * listOf(0, 1) to (-6), + * listOf(0, 1, 1) to 0, + * ) + * ``` + * It is recommended not to put zero monomials into the map, but is not prohibited. Lists of degrees always do not + * contain any zeros on end, but can contain zeros on start or anywhere in middle. + */ + public val coefficients: Map, C> +) : AbstractPolynomial { + override fun toString(): String = "NumberedPolynomial$coefficients" +} + +// region Internal utilities + +/** + * Represents internal [Polynomial] errors. + */ +internal class NumberedPolynomialError : Error { + constructor(): super() + constructor(message: String): super(message) + constructor(message: String?, cause: Throwable?): super(message, cause) + constructor(cause: Throwable?): super(cause) +} + +/** + * Throws an [PolynomialError] with the given [message]. + */ +internal fun numberedPolynomialError(message: Any): Nothing = throw PolynomialError(message.toString()) + +/** + * Returns the same degrees description of the monomial, but without extra zero degrees on the end. + */ +internal fun List.cleanUp() = subList(0, indexOfLast { it != 0U } + 1) + +// endregion + +// region Constructors and converters +// Waiting for context receivers :( TODO: Replace with context receivers when they will be available + +//context(A) +//@Suppress("FunctionName") +//internal fun > NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean): NumberedPolynomial { +// if (!toCheckInput) return NumberedPolynomial(coefs) +// +// val fixedCoefs = mutableMapOf, C>() +// +// for (entry in coefs) { +// val key = entry.key.cleanUp() +// val value = entry.value +// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value +// } +// +// return NumberedPolynomial( +// fixedCoefs +// .filter { it.value.isNotZero() } +// ) +//} +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received +// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. +// * +// * @param pairs Collection of pairs that represent monomials. +// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. +// * +// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(A) +//@Suppress("FunctionName") +//internal fun > NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean): NumberedPolynomial { +// if (!toCheckInput) return NumberedPolynomial(pairs.toMap()) +// +// val fixedCoefs = mutableMapOf, C>() +// +// for (entry in pairs) { +// val key = entry.first.cleanUp() +// val value = entry.second +// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value +// } +// +// return NumberedPolynomial( +// fixedCoefs +// .filter { it.value.isNotZero() } +// ) +//} +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received +// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. +// * +// * @param pairs Collection of pairs that represent monomials. +// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. +// * +// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(A) +//@Suppress("FunctionName") +//internal fun > NumberedPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean): NumberedPolynomial = +// NumberedPolynomial(pairs.toMap(), toCheckInput) +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received +// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. +// * +// * @param coefs Coefficients of the instants. +// * +// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(A) +//public fun > NumberedPolynomial(coefs: Map, C>) = NumberedPolynomial(coefs, toCheckInput = true) +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received +// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. +// * +// * @param pairs Collection of pairs that represent monomials. +// * +// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(A) +//public fun > NumberedPolynomial(pairs: Collection, C>>) = NumberedPolynomial(pairs, toCheckInput = true) +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received +// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. +// * +// * @param pairs Collection of pairs that represent monomials. +// * +// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(A) +//public fun > NumberedPolynomial(vararg pairs: Pair, C>) = NumberedPolynomial(*pairs, toCheckInput = true) +// +//context(NumberedPolynomialSpace) +//@Suppress("FunctionName") +//internal fun > NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean): NumberedPolynomial { +// if (!toCheckInput) return NumberedPolynomial(coefs) +// +// val fixedCoefs = mutableMapOf, C>() +// +// for (entry in coefs) { +// val key = entry.key.cleanUp() +// val value = entry.value +// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value +// } +// +// return NumberedPolynomial( +// fixedCoefs +// .filter { it.value.isNotZero() } +// ) +//} +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received +// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. +// * +// * @param pairs Collection of pairs that represent monomials. +// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. +// * +// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(NumberedPolynomialSpace) +//@Suppress("FunctionName") +//internal fun > NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean): NumberedPolynomial { +// if (!toCheckInput) return NumberedPolynomial(pairs.toMap()) +// +// val fixedCoefs = mutableMapOf, C>() +// +// for (entry in pairs) { +// val key = entry.first.cleanUp() +// val value = entry.second +// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value +// } +// +// return NumberedPolynomial( +// fixedCoefs +// .filter { it.value.isNotZero() } +// ) +//} +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received +// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. +// * +// * @param pairs Collection of pairs that represent monomials. +// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. +// * +// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(NumberedPolynomialSpace) +//@Suppress("FunctionName") +//internal fun > NumberedPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean): NumberedPolynomial = +// NumberedPolynomial(pairs.toList(), toCheckInput) +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received +// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. +// * +// * @param coefs Coefficients of the instants. +// * +// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(NumberedPolynomialSpace) +//public fun > NumberedPolynomial(coefs: Map, C>) = NumberedPolynomial(coefs, toCheckInput = true) +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received +// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. +// * +// * @param pairs Collection of pairs that represent monomials. +// * +// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(NumberedPolynomialSpace) +//public fun > NumberedPolynomial(pairs: Collection, C>>) = NumberedPolynomial(pairs, toCheckInput = true) +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received +// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. +// * +// * @param pairs Collection of pairs that represent monomials. +// * +// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(NumberedPolynomialSpace) +//public fun > NumberedPolynomial(vararg pairs: Pair, C>) = NumberedPolynomial(*pairs, toCheckInput = true) + +public fun > C.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomial(mapOf(emptyList() to this)) + +// endregion + +/** + * Space of polynomials. + * + * @param C the type of operated polynomials. + * @param A the intersection of [Ring] of [C] and [ScaleOperations] of [C]. + * @param ring the [A] instance. + */ +@Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE", "INAPPLICABLE_JVM_NAME") +public class NumberedPolynomialSpace>( + public val ring: A, +) : AbstractPolynomialSpace> { + // region Constant-integer relation + @JvmName("constantIntPlus") + public override operator fun C.plus(other: Int): C = ring { optimizedAddMultiplied(this@plus, one, other) } + @JvmName("constantIntMinus") + public override operator fun C.minus(other: Int): C = ring { optimizedAddMultiplied(this@minus, one, -other) } + @JvmName("constantIntTimes") + public override operator fun C.times(other: Int): C = ring { optimizedMultiply(this@times, other) } + // endregion + + // region Integer-constant relation + @JvmName("intConstantPlus") + public override operator fun Int.plus(other: C): C = ring { optimizedAddMultiplied(other, one, this@plus) } + @JvmName("intConstantMinus") + public override operator fun Int.minus(other: C): C = ring { optimizedAddMultiplied(-other, one, this@minus) } + @JvmName("intConstantTimes") + public override operator fun Int.times(other: C): C = ring { optimizedMultiply(other, this@times) } + // endregion + + // region Polynomial-integer relation + public override operator fun NumberedPolynomial.plus(other: Int): NumberedPolynomial = + if (other == 0) this + else + NumberedPolynomial( + coefficients + .toMutableMap() + .apply { + val degs = emptyList() + + val result = getOrElse(degs) { ring.zero } + other + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + public override operator fun NumberedPolynomial.minus(other: Int): NumberedPolynomial = + if (other == 0) this + else + NumberedPolynomial( + coefficients + .toMutableMap() + .apply { + val degs = emptyList() + + val result = getOrElse(degs) { ring.zero } - other + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + public override operator fun NumberedPolynomial.times(other: Int): NumberedPolynomial = + if (other == 0) zero + else NumberedPolynomial( + coefficients + .applyAndRemoveZeros { + mapValues { (_, c) -> c * other } + } + ) + // endregion + + // region Integer-polynomial relation + public override operator fun Int.plus(other: NumberedPolynomial): NumberedPolynomial = + if (this == 0) other + else + NumberedPolynomial( + other.coefficients + .toMutableMap() + .apply { + val degs = emptyList() + + val result = this@plus + getOrElse(degs) { ring.zero } + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + public override operator fun Int.minus(other: NumberedPolynomial): NumberedPolynomial = + if (this == 0) other + else + NumberedPolynomial( + other.coefficients + .toMutableMap() + .apply { + val degs = emptyList() + + val result = this@minus - getOrElse(degs) { ring.zero } + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + public override operator fun Int.times(other: NumberedPolynomial): NumberedPolynomial = + if (this == 0) zero + else NumberedPolynomial( + other.coefficients + .applyAndRemoveZeros { + mapValues { (_, c) -> this@times * c } + } + ) + // endregion + + // region Constant-constant relation + @JvmName("constantUnaryMinus") + override operator fun C.unaryMinus(): C = ring { -this@unaryMinus } + @JvmName("constantPlus") + override operator fun C.plus(other: C): C = ring { this@plus + other } + @JvmName("constantMinus") + override operator fun C.minus(other: C): C = ring { this@minus - other } + @JvmName("constantTimes") + override operator fun C.times(other: C): C = ring { this@times * other } + @JvmName("constantIsZero") + public override fun C.isZero(): Boolean = ring { this == zero } + @JvmName("constantIsNotZero") + public override fun C.isNotZero(): Boolean = ring { this != zero } + @JvmName("constantIsOne") + public override fun C.isOne(): Boolean = ring { this == one } + @JvmName("constantIsNotOne") + public override fun C.isNotOne(): Boolean = ring { this != one } + @JvmName("constantIsMinusOne") + public override fun C.isMinusOne(): Boolean = ring { this == -one } + @JvmName("constantIsNotMinusOne") + public override fun C.isNotMinusOne(): Boolean = ring { this != -one } + // endregion + + // region Constant-polynomial relation + override operator fun C.plus(other: NumberedPolynomial): NumberedPolynomial = + if (this.isZero()) other + else with(other.coefficients) { + if (isEmpty()) NumberedPolynomial(mapOf(emptyList() to this@plus)) + else NumberedPolynomial( + toMutableMap() + .apply { + val degs = emptyList() + + val result = this@plus + getOrElse(degs) { ring.zero } + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + } + override operator fun C.minus(other: NumberedPolynomial): NumberedPolynomial = + if (this.isZero()) -other + else with(other.coefficients) { + if (isEmpty()) NumberedPolynomial(mapOf(listOf() to this@minus)) + else NumberedPolynomial( + toMutableMap() + .apply { + forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } + + val degs = emptyList() + + val result = this@minus - getOrElse(degs) { ring.zero } + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + } + override operator fun C.times(other: NumberedPolynomial): NumberedPolynomial = + if (this.isZero()) zero + else NumberedPolynomial( + other.coefficients + .applyAndRemoveZeros { + mapValues { (_, c) -> this@times * c } + } + ) + // endregion + + // region Polynomial-constant relation + /** + * Returns sum of the polynomials. [other] is interpreted as [NumberedPolynomial]. + */ + override operator fun NumberedPolynomial.plus(other: C): NumberedPolynomial = + if (other.isZero()) this + else with(coefficients) { + if (isEmpty()) NumberedPolynomial(mapOf(listOf() to other)) + else NumberedPolynomial( + toMutableMap() + .apply { + val degs = emptyList() + + val result = getOrElse(degs) { ring.zero } + other + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + } + /** + * Returns difference of the polynomials. [other] is interpreted as [NumberedPolynomial]. + */ + override operator fun NumberedPolynomial.minus(other: C): NumberedPolynomial = + if (other.isZero()) this + else with(coefficients) { + if (isEmpty()) NumberedPolynomial(mapOf(listOf() to other)) + else NumberedPolynomial( + toMutableMap() + .apply { + val degs = emptyList() + + val result = getOrElse(degs) { ring.zero } - other + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + } + /** + * Returns product of the polynomials. [other] is interpreted as [NumberedPolynomial]. + */ + override operator fun NumberedPolynomial.times(other: C): NumberedPolynomial = + if (other.isZero()) zero + else NumberedPolynomial( + coefficients + .applyAndRemoveZeros { + mapValues { (_, c) -> c * other } + } + ) + // endregion + + // region Polynomial-polynomial relation + /** + * Returns negation of the polynomial. + */ + override fun NumberedPolynomial.unaryMinus(): NumberedPolynomial = + NumberedPolynomial( + coefficients.mapValues { -it.value } + ) + /** + * Returns sum of the polynomials. + */ + override operator fun NumberedPolynomial.plus(other: NumberedPolynomial): NumberedPolynomial = + NumberedPolynomial( + coefficients + .applyAndRemoveZeros { + other.coefficients + .mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! + value else value } + } + ) + /** + * Returns difference of the polynomials. + */ + override operator fun NumberedPolynomial.minus(other: NumberedPolynomial): NumberedPolynomial = + NumberedPolynomial( + coefficients + .applyAndRemoveZeros { + other.coefficients + .mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! - value else -value } + } + ) + /** + * Returns product of the polynomials. + */ + override operator fun NumberedPolynomial.times(other: NumberedPolynomial): NumberedPolynomial = + when { + isZero() -> zero + other.isZero() -> zero + else -> + NumberedPolynomial( + buildCoefficients { + for ((degs1, c1) in coefficients) for ((degs2, c2) in other.coefficients) { + val degs = + (0..max(degs1.lastIndex, degs2.lastIndex)) + .map { degs1.getOrElse(it) { 0U } + degs2.getOrElse(it) { 0U } } + val c = c1 * c2 + this[degs] = if (degs in this) this[degs]!! + c else c + } + } + ) + } + + public override fun NumberedPolynomial.isZero(): Boolean = coefficients.values.all { it.isZero() } + public override fun NumberedPolynomial.isNotZero(): Boolean = coefficients.values.any { it.isNotZero() } + public override fun NumberedPolynomial.isOne(): Boolean = + with(coefficients) { + var foundAbsoluteTermAndItIsOne = false + for ((degs, c) in this) { + if (degs.isNotEmpty()) if (c.isNotZero()) return@with false + else { + if (c.isNotOne()) return@with false + else foundAbsoluteTermAndItIsOne = true + } + } + foundAbsoluteTermAndItIsOne + } + public override fun NumberedPolynomial.isNotOne(): Boolean = !isOne() + public override fun NumberedPolynomial.isMinusOne(): Boolean = + with(coefficients) { + var foundAbsoluteTermAndItIsMinusOne = false + for ((degs, c) in this) { + if (degs.isNotEmpty()) if (c.isNotZero()) return@with false + else { + if (c.isNotMinusOne()) return@with false + else foundAbsoluteTermAndItIsMinusOne = true + } + } + foundAbsoluteTermAndItIsMinusOne + } + public override fun NumberedPolynomial.isNotMinusOne(): Boolean = !isMinusOne() + + override val zero: NumberedPolynomial = NumberedPolynomial(emptyMap()) + override val one: NumberedPolynomial = + NumberedPolynomial( + mapOf( + listOf() to ring.one // 1 * x_1^0 * x_2^0 * ... + ) + ) + + // TODO: Docs + @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") + override fun NumberedPolynomial.equals(other: NumberedPolynomial): Boolean = + when { + this === other -> true + else -> coefficients.size == other.coefficients.size && + coefficients.all { (key, value) -> with(other.coefficients) { key in this && this[key] == value } } + } + // endregion + + // Not sure is it necessary... + // region Polynomial properties + /** + * Count of all variables that appear in the polynomial in positive exponents. + */ + public val NumberedPolynomial.countOfVariables: Int + get() = coefficients.entries.maxOfOrNull { (degs, c) -> if (c.isZero()) 0 else degs.size } ?: 0 + /** + * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is + * zero, degree is -1. + */ + override val NumberedPolynomial.degree: Int + get() = coefficients.entries.maxOfOrNull { (degs, c) -> if (c.isZero()) -1 else degs.sum().toInt() } ?: -1 + /** + * List that associates indices of variables (that appear in the polynomial in positive exponents) with their most + * exponents in which the variables are appeared in the polynomial. + * + * As consequence all values in the list are non-negative integers. Also, if the polynomial is constant, the list is empty. + * And size of the list is [countOfVariables]. + */ + public val NumberedPolynomial.degrees: List + get() = + buildList(countOfVariables) { + repeat(countOfVariables) { add(0U) } + coefficients.entries.forEach { (degs, c) -> + if (c.isNotZero()) degs.forEachIndexed { index, deg -> + this[index] = max(this[index], deg) + } + } + } + + /** + * Checks if the instant is constant polynomial (of degree no more than 0) over considered ring. + */ + override fun NumberedPolynomial.isConstant(): Boolean = + coefficients.all { (degs, c) -> degs.isEmpty() || c.isZero() } + /** + * Checks if the instant is constant non-zero polynomial (of degree no more than 0) over considered ring. + */ + override fun NumberedPolynomial.isNonZeroConstant(): Boolean = + with(coefficients) { + var foundAbsoluteTermAndItIsNotZero = false + for ((degs, c) in this) { + if (degs.isNotEmpty()) if (c.isNotZero()) return@with false + else { + if (c.isZero()) return@with false + else foundAbsoluteTermAndItIsNotZero = true + } + } + foundAbsoluteTermAndItIsNotZero + } + + override fun NumberedPolynomial.asConstantOrNull(): C? = + with(coefficients) { + if(isConstant()) getOrElse(emptyList()) { ring.zero } + else null + } + + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.substitute(argument: Map): NumberedPolynomial = this.substitute(ring, argument) + @Suppress("NOTHING_TO_INLINE") + @JvmName("substitutePolynomial") + public inline fun NumberedPolynomial.substitute(argument: Map>): NumberedPolynomial = this.substitute(ring, argument) + + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.asFunction(): (Map) -> NumberedPolynomial = { this.substitute(ring, it) } + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.asFunctionOnConstants(): (Map) -> NumberedPolynomial = { this.substitute(ring, it) } + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.asFunctionOnPolynomials(): (Map>) -> NumberedPolynomial = { this.substitute(ring, it) } + + @Suppress("NOTHING_TO_INLINE") + public inline operator fun NumberedPolynomial.invoke(argument: Map): NumberedPolynomial = this.substitute(ring, argument) + @Suppress("NOTHING_TO_INLINE") + @JvmName("invokePolynomial") + public inline operator fun NumberedPolynomial.invoke(argument: Map>): NumberedPolynomial = this.substitute(ring, argument) + // endregion + + // region Legacy + @Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") + override inline fun add(left: NumberedPolynomial, right: NumberedPolynomial): NumberedPolynomial = left + right + @Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") + override inline fun multiply(left: NumberedPolynomial, right: NumberedPolynomial): NumberedPolynomial = left * right + // endregion + + // region Utilities + // TODO: Move to region internal utilities with context receiver + internal fun MutableMap, C>.applyAndRemoveZeros(block: MutableMap, C>.() -> Unit) : MutableMap, C> { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + block() + for ((degs, c) in this) if (c.isZero()) this.remove(degs) + return this + } + internal fun Map, C>.applyAndRemoveZeros(block: MutableMap, C>.() -> Unit) : Map, C> = + toMutableMap().applyAndRemoveZeros(block) + @OptIn(ExperimentalTypeInference::class) + internal fun buildCoefficients(@BuilderInference builderAction: MutableMap, C>.() -> Unit): Map, C> { + contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) } + return buildMap { + builderAction() + for ((degs, c) in this) if (c.isZero()) this.remove(degs) + } + } + // endregion +} \ No newline at end of file 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 30280a396..99d6b0659 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 @@ -5,43 +5,38 @@ package space.kscience.kmath.functions -import space.kscience.kmath.functions.AbstractPolynomialSpace.Companion.optimizedAddMultiplied -import space.kscience.kmath.functions.AbstractPolynomialSpace.Companion.optimizedMultiply import space.kscience.kmath.operations.* import kotlin.jvm.JvmName import kotlin.math.max import kotlin.math.min /** - * Polynomial coefficients model without fixation on specific context they are applied to. + * Polynomial model without fixation on specific context they are applied to. * * @param coefficients constant is the leftmost coefficient. */ public class Polynomial(public val coefficients: List) : AbstractPolynomial { override fun toString(): String = "Polynomial$coefficients" - -// public companion object { -// /** -// * Default name of variables used in string representations. -// * -// * @see Polynomial.toString -// */ -// public var defaultVariableName: String = "x" -// -// /** -// * Represents result of division with remainder. -// */ -// public data class DividingResult( -// val quotient: Polynomial, -// val reminder: Polynomial -// ) -// } } +// region Internal utilities + /** * Represents internal [Polynomial] errors. */ -internal class PolynomialError(message: String): Error(message) +internal class PolynomialError : Error { + constructor(): super() + constructor(message: String): super(message) + constructor(message: String?, cause: Throwable?): super(message, cause) + constructor(cause: Throwable?): super(cause) +} + +/** + * Throws an [PolynomialError] with the given [message]. + */ +internal fun polynomialError(message: Any): Nothing = throw PolynomialError(message.toString()) + +// endregion // region Constructors and converters @@ -66,16 +61,16 @@ public fun T.asPolynomial() : Polynomial = Polynomial(listOf(this)) // endregion /** - * Space of polynomials constructed over ring. + * Space of univariate polynomials constructed over ring. * * @param C the type of constants. Polynomials have them as a coefficients in their terms. * @param A type of underlying ring of constants. It's [Ring] of [C]. * @param ring underlying ring of constants of type [A]. */ -@Suppress("INAPPLICABLE_JVM_NAME") // KT-31420 +@Suppress("INAPPLICABLE_JVM_NAME") // TODO: KT-31420 public open class PolynomialSpace>( public val ring: A, -) : AbstractPolynomialSpace>{ +) : AbstractPolynomialSpace> { // region Constant-integer relation @JvmName("constantIntPlus") public override operator fun C.plus(other: Int): C = ring { optimizedAddMultiplied(this@plus, one, other) } @@ -102,8 +97,14 @@ public open class PolynomialSpace>( coefficients .toMutableList() .apply { - if (isEmpty()) this[0] = ring.zero + other - else this[0] = this[0]!! + other + val result = getOrElse(0) { ring.zero } + other + val isResultZero = result.isZero() + + when { + size == 0 && !isResultZero -> add(result) + size > 1 || !isResultZero -> this[0] = result + else -> clear() + } } ) public override operator fun Polynomial.minus(other: Int): Polynomial = @@ -113,8 +114,14 @@ public open class PolynomialSpace>( coefficients .toMutableList() .apply { - if (isEmpty()) this[0] = ring.zero - other - else this[0] = this[0]!! - other + val result = getOrElse(0) { ring.zero } - other + val isResultZero = result.isZero() + + when { + size == 0 && !isResultZero -> add(result) + size > 1 || !isResultZero -> this[0] = result + else -> clear() + } } ) public override operator fun Polynomial.times(other: Int): Polynomial = @@ -134,8 +141,14 @@ public open class PolynomialSpace>( other.coefficients .toMutableList() .apply { - if (isEmpty()) this[0] = ring.zero + this@plus - else this[0] = this[0]!! + this@plus + val result = this@plus + getOrElse(0) { ring.zero } + val isResultZero = result.isZero() + + when { + size == 0 && !isResultZero -> add(result) + size > 1 || !isResultZero -> this[0] = result + else -> clear() + } } ) public override operator fun Int.minus(other: Polynomial): Polynomial = @@ -145,8 +158,16 @@ public open class PolynomialSpace>( other.coefficients .toMutableList() .apply { - if (isEmpty()) this[0] = ring.zero - this@minus - else this[0] = this[0]!! - this@minus + forEachIndexed { index, c -> if (index != 0) this[index] = -c } + + val result = this@minus - getOrElse(0) { ring.zero } + val isResultZero = result.isZero() + + when { + size == 0 && !isResultZero -> add(result) + size > 1 || !isResultZero -> this[0] = result + else -> clear() + } } ) public override operator fun Int.times(other: Polynomial): Polynomial = @@ -183,12 +204,20 @@ public open class PolynomialSpace>( // region Constant-polynomial relation public override operator fun C.plus(other: Polynomial): Polynomial = - with(other.coefficients) { + if (this.isZero()) other + else with(other.coefficients) { if (isEmpty()) Polynomial(listOf(this@plus)) else Polynomial( toMutableList() .apply { - this[0] += this@plus + val result = if (size == 0) this@plus else this@plus + get(0) + val isResultZero = result.isZero() + + when { + size == 0 && !isResultZero -> add(result) + size > 1 || !isResultZero -> this[0] = result + else -> clear() + } } ) } @@ -196,12 +225,22 @@ public open class PolynomialSpace>( // listOf(coefficients[0] + other) + coefficients.subList(1, degree + 1) // ) public override operator fun C.minus(other: Polynomial): Polynomial = - with(other.coefficients) { + if (this.isZero()) other + else with(other.coefficients) { if (isEmpty()) Polynomial(listOf(-this@minus)) else Polynomial( toMutableList() .apply { - this[0] -= this@minus + forEachIndexed { index, c -> if (index != 0) this[index] = -c } + + val result = if (size == 0) this@minus else this@minus - get(0) + val isResultZero = result.isZero() + + when { + size == 0 && !isResultZero -> add(result) + size > 1 || !isResultZero -> this[0] = result + else -> clear() + } } ) } @@ -209,9 +248,10 @@ public open class PolynomialSpace>( // listOf(coefficients[0] + other) + coefficients.subList(1, degree + 1) // ) public override operator fun C.times(other: Polynomial): Polynomial = - Polynomial( + if (this.isZero()) other + else Polynomial( other.coefficients -// .subList(0, other.degree + 1) + .subList(0, other.degree + 1) .map { it * this } ) // endregion @@ -224,7 +264,14 @@ public open class PolynomialSpace>( else Polynomial( toMutableList() .apply { - this[0] += other + val result = if (size == 0) other else get(0) + other + val isResultZero = result.isZero() + + when { + size == 0 && !isResultZero -> add(result) + size > 1 || !isResultZero -> this[0] = result + else -> clear() + } } ) } @@ -232,12 +279,20 @@ public open class PolynomialSpace>( // listOf(coefficients[0] + other) + coefficients.subList(1, degree + 1) // ) public override operator fun Polynomial.minus(other: C): Polynomial = - with(coefficients) { + if (other.isZero()) this + else with(coefficients) { if (isEmpty()) Polynomial(listOf(other)) else Polynomial( toMutableList() .apply { - this[0] -= other + val result = if (size == 0) other else get(0) - other + val isResultZero = result.isZero() + + when { + size == 0 && !isResultZero -> add(result) + size > 1 || !isResultZero -> this[0] = result + else -> clear() + } } ) } @@ -245,9 +300,10 @@ public open class PolynomialSpace>( // listOf(coefficients[0] - other) + coefficients.subList(1, degree + 1) // ) public override operator fun Polynomial.times(other: C): Polynomial = - Polynomial( + if (other.isZero()) this + else Polynomial( coefficients -// .subList(0, degree + 1) + .subList(0, degree + 1) .map { it * other } ) // endregion @@ -283,8 +339,8 @@ public open class PolynomialSpace>( val thisDegree = degree val otherDegree = other.degree return when { - thisDegree == -1 -> this - otherDegree == -1 -> other + thisDegree == -1 -> zero + otherDegree == -1 -> zero else -> Polynomial( (0..(thisDegree + otherDegree)) @@ -293,6 +349,7 @@ public open class PolynomialSpace>( .map { coefficients[it] * other.coefficients[d - it] } .reduce { acc, rational -> acc + rational } } + .run { subList(0, indexOfLast { it.isNotZero() } + 1) } ) } } @@ -321,8 +378,8 @@ public open class PolynomialSpace>( } // endregion - // Not sure is it necessary... // region Polynomial properties + public override val Polynomial.degree: Int get() = coefficients.indexOfLast { it != ring.zero } public override fun Polynomial.asConstantOrNull(): C? = @@ -354,8 +411,8 @@ public open class PolynomialSpace>( public inline operator fun Polynomial.invoke(argument: C): C = this.substitute(ring, argument) @Suppress("NOTHING_TO_INLINE") public inline operator fun Polynomial.invoke(argument: Polynomial): Polynomial = this.substitute(ring, argument) - // endregion + // endregion } /** diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Variable.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Variable.kt new file mode 100644 index 000000000..410604fd3 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Variable.kt @@ -0,0 +1,38 @@ +package space.kscience.kmath.functions + +import kotlin.reflect.KProperty + + +/** + * Represents class of labeled variables like usual + * `x`, `y`, `z`, `a`, `b`, `n`, `m`, etc. + * + * Variables does not contain any information about field (or ring, ets.) they are considered in + * and therefore about coefficient. + * + * @property name Is the label or name of variable. For `x` it is `"x"`, for `n` – `"n"`, etc. + */ +public data class Variable (val name: String) : Comparable { + /** + * Represents the variable as a string. + * + * @return Only name of the variable. + */ + override fun toString(): String = name + /** + * Compares two variables. + * Comparison is realised by comparison of variables' names. + * + * Used in [LabeledPolynomial] and [LabeledRationalFunction] to sort monomials in + * [LabeledPolynomial.toString] and [LabeledRationalFunction.toString] in lexicographic order. + * + * @see Comparable.compareTo + * @sample LabeledPolynomial.monomialComparator + * @return Only name of the variable. + */ + override fun compareTo(other: Variable): Int = name.compareTo(other.name) + + public companion object { + public operator fun getValue(thisRef: Any?, property: KProperty<*>) : Variable = Variable(property.name) + } +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt new file mode 100644 index 000000000..9e5043b8c --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.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.functions + +import space.kscience.kmath.operations.Group + + +// TODO: All of this should be moved to algebraic structures' place for utilities +// TODO: Move receiver to context receiver +/** + * Multiplication of element and integer. + * + * @receiver the multiplicand. + * @param other the multiplier. + * @return the difference. + */ +internal tailrec fun Group.optimizedMultiply(arg: C, other: Int): C = + when { + other == 0 -> zero + other == 1 -> arg + other == -1 -> -arg + other % 2 == 0 -> optimizedMultiply(arg + arg, other / 2) + other % 2 == 1 -> optimizedAddMultiplied(arg, arg + arg, other / 2) + other % 2 == -1 -> optimizedAddMultiplied(-arg, arg + arg, other / 2) + else -> error("Error in multiplication group instant by integer: got reminder by division by 2 different from 0, 1 and -1") + } + +// TODO: Move receiver to context receiver +/** + * Adds product of [arg] and [multiplier] to [base]. + * + * @receiver the algebra to provide multiplication. + * @param base the augend. + * @param arg the multiplicand. + * @param multiplier the multiplier. + * @return sum of the augend [base] and product of the multiplicand [arg] and the multiplier [multiplier]. + * @author Gleb Minaev + */ +internal tailrec fun Group.optimizedAddMultiplied(base: C, arg: C, multiplier: Int): C = + when { + multiplier == 0 -> base + multiplier == 1 -> base + arg + multiplier == -1 -> base - arg + multiplier % 2 == 0 -> optimizedAddMultiplied(base, arg + arg, multiplier / 2) + multiplier % 2 == 1 -> optimizedAddMultiplied(base + arg, arg + arg, multiplier / 2) + multiplier % 2 == -1 -> optimizedAddMultiplied(base + arg, arg + arg, multiplier / 2) + else -> error("Error in multiplication group instant by integer: got reminder by division by 2 different from 0, 1 and -1") + } \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt new file mode 100644 index 000000000..62ac31b64 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt @@ -0,0 +1,490 @@ +package space.kscience.kmath.functions + +import space.kscience.kmath.operations.* +import kotlin.contracts.* + + +// TODO: Docs + +// region Sort of legacy + +//// region Constants +// +//// TODO: Reuse underlying ring extensions +// +//context(LabeledPolynomialSpace) +//@Suppress("NOTHING_TO_INLINE") +//fun > numberConstant(value: Int): C = ring { number(value) } +// +//context(LabeledPolynomialSpace) +//fun > power(arg: C, pow: UInt): C = ring { power(arg, pow) } +// +//context(LabeledPolynomialSpace) +//fun > multiplyWithPower(base: C, arg: C, pow: UInt): C = ring { multiplyWithPower(base, arg, pow) } +// +//// endregion + +//// region Variables +// +//context(LabeledPolynomialSpace) +//fun > power(arg: Variable, pow: UInt): LabeledPolynomial = +// if (pow == 0U) one +// else LabeledPolynomial(mapOf( +// mapOf(arg to pow) to ring.one +// )) +// +//// endregion + +//// region Polynomials +// +//context(LabeledPolynomialSpace) +//fun > number(value: Int): LabeledPolynomial = ring { LabeledPolynomial(mapOf(emptyMap() to number(value))) } +// +//context(LabeledPolynomialSpace) +//fun > multiplyWithPower(base: LabeledPolynomial, arg: LabeledPolynomial, pow: UInt): LabeledPolynomial = +// when { +// arg.isZero() && pow > 0U -> base +// arg.isOne() -> base +// arg.isMinusOne() -> if (pow % 2U == 0U) base else -base +// else -> multiplyWithPowerInternalLogic(base, arg, pow) +// } +// +//// Trivial but slow as duck +//context(LabeledPolynomialSpace) +//internal tailrec fun > multiplyWithPowerInternalLogic(base: LabeledPolynomial, arg: LabeledPolynomial, exponent: UInt): LabeledPolynomial = +// when { +// exponent == 0U -> base +// exponent == 1U -> base * arg +// exponent % 2U == 0U -> multiplyWithPowerInternalLogic(base, arg * arg, exponent / 2U) +// exponent % 2U == 1U -> multiplyWithPowerInternalLogic(base * arg, arg * arg, exponent / 2U) +// else -> error("Error in raising ring instant by unsigned integer: got reminder by division by 2 different from 0 and 1") +// } +// +//// endregion + +// endregion + +// region Utilities + +// TODO: Docs +@OptIn(ExperimentalContracts::class) +public inline fun , R> A.labeledPolynomial(block: LabeledPolynomialSpace.() -> R): R { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return LabeledPolynomialSpace(this).block() +} + +// endregion + +//// region String representations +// +///** +// * Represents the polynomial as a [String] with names of variables substituted with names from [names]. +// * Consider that monomials are sorted in lexicographic order. +// */ +//context(LabeledPolynomialSpace) +//fun > LabeledPolynomial.represent(names: Map = emptyMap()): String = +// coefficients.entries +// .sortedWith { o1, o2 -> LabeledPolynomial.monomialComparator.compare(o1.key, o2.key) } +// .asSequence() +// .map { (degs, t) -> +// if (degs.isEmpty()) "$t" +// else { +// when { +// t.isOne() -> "" +// t.isMinusOne() -> "-" +// else -> "$t " +// } + +// degs +// .toSortedMap() +// .filter { it.value > 0U } +// .map { (variable, deg) -> +// val variableName = names.getOrDefault(variable, variable.toString()) +// when (deg) { +// 1U -> variableName +// else -> "$variableName^$deg" +// } +// } +// .joinToString(separator = " ") { it } +// } +// } +// .joinToString(separator = " + ") { it } +// .ifEmpty { "0" } +// +///** +// * Represents the polynomial as a [String] naming variables by [namer]. +// * Consider that monomials are sorted in lexicographic order. +// */ +//context(LabeledPolynomialSpace) +//fun > LabeledPolynomial.represent(namer: (Variable) -> String): String = +// coefficients.entries +// .sortedWith { o1, o2 -> LabeledPolynomial.monomialComparator.compare(o1.key, o2.key) } +// .asSequence() +// .map { (degs, t) -> +// if (degs.isEmpty()) "$t" +// else { +// when { +// t.isOne() -> "" +// t.isMinusOne() -> "-" +// else -> "$t " +// } + +// degs +// .toSortedMap() +// .filter { it.value > 0U } +// .map { (variable, deg) -> +// when (deg) { +// 1U -> namer(variable) +// else -> "${namer(variable)}^$deg" +// } +// } +// .joinToString(separator = " ") { it } +// } +// } +// .joinToString(separator = " + ") { it } +// .ifEmpty { "0" } +// +///** +// * Represents the polynomial as a [String] with names of variables substituted with names from [names] and with +// * brackets around the string if needed (i.e. when there are at least two addends in the representation). +// * Consider that monomials are sorted in lexicographic order. +// */ +//context(LabeledPolynomialSpace) +//fun > LabeledPolynomial.representWithBrackets(names: Map = emptyMap()): String = +// with(represent(names)) { if (coefficients.count() == 1) this else "($this)" } +// +///** +// * Represents the polynomial as a [String] naming variables by [namer] and with brackets around the string if needed +// * (i.e. when there are at least two addends in the representation). +// * Consider that monomials are sorted in lexicographic order. +// */ +//context(LabeledPolynomialSpace) +//fun > LabeledPolynomial.representWithBrackets(namer: (Variable) -> String): String = +// with(represent(namer)) { if (coefficients.count() == 1) this else "($this)" } +// +///** +// * Represents the polynomial as a [String] with names of variables substituted with names from [names]. +// * Consider that monomials are sorted in **reversed** lexicographic order. +// */ +//context(LabeledPolynomialSpace) +//fun > LabeledPolynomial.representReversed(names: Map = emptyMap()): String = +// coefficients.entries +// .sortedWith { o1, o2 -> -LabeledPolynomial.monomialComparator.compare(o1.key, o2.key) } +// .asSequence() +// .map { (degs, t) -> +// if (degs.isEmpty()) "$t" +// else { +// when { +// t.isOne() -> "" +// t.isMinusOne() -> "-" +// else -> "$t " +// } + +// degs +// .toSortedMap() +// .filter { it.value > 0U } +// .map { (variable, deg) -> +// val variableName = names.getOrDefault(variable, variable.toString()) +// when (deg) { +// 1U -> variableName +// else -> "$variableName^$deg" +// } +// } +// .joinToString(separator = " ") { it } +// } +// } +// .joinToString(separator = " + ") { it } +// .ifEmpty { "0" } +// +///** +// * Represents the polynomial as a [String] naming variables by [namer]. +// * Consider that monomials are sorted in **reversed** lexicographic order. +// */ +//context(LabeledPolynomialSpace) +//fun > LabeledPolynomial.representReversed(namer: (Variable) -> String): String = +// coefficients.entries +// .sortedWith { o1, o2 -> -LabeledPolynomial.monomialComparator.compare(o1.key, o2.key) } +// .asSequence() +// .map { (degs, t) -> +// if (degs.isEmpty()) "$t" +// else { +// when { +// t.isOne() -> "" +// t.isMinusOne() -> "-" +// else -> "$t " +// } + +// degs +// .toSortedMap() +// .filter { it.value > 0U } +// .map { (variable, deg) -> +// when (deg) { +// 1U -> namer(variable) +// else -> "${namer(variable)}^$deg" +// } +// } +// .joinToString(separator = " ") { it } +// } +// } +// .joinToString(separator = " + ") { it } +// .ifEmpty { "0" } +// +///** +// * Represents the polynomial as a [String] with names of variables substituted with names from [names] and with +// * brackets around the string if needed (i.e. when there are at least two addends in the representation). +// * Consider that monomials are sorted in **reversed** lexicographic order. +// */ +//context(LabeledPolynomialSpace) +//fun > LabeledPolynomial.representReversedWithBrackets(names: Map = emptyMap()): String = +// with(representReversed(names)) { if (coefficients.count() == 1) this else "($this)" } +// +///** +// * Represents the polynomial as a [String] naming variables by [namer] and with brackets around the string if needed +// * (i.e. when there are at least two addends in the representation). +// * Consider that monomials are sorted in **reversed** lexicographic order. +// */ +//context(LabeledPolynomialSpace) +//fun > LabeledPolynomial.representReversedWithBrackets(namer: (Variable) -> String): String = +// with(representReversed(namer)) { if (coefficients.count() == 1) this else "($this)" } +// +//// endregion + +// region Operator extensions + +//// region Field case +// +//operator fun > Polynomial.div(other: Polynomial): Polynomial { +// if (other.isZero()) throw ArithmeticException("/ by zero") +// if (isZero()) return this +// +// fun Map, T>.leadingTerm() = +// this +// .asSequence() +// .map { Pair(it.key, it.value) } +// .reduce { (accDegs, accC), (listDegs, listC) -> +// for (i in 0..accDegs.lastIndex) { +// if (accDegs[i] > listDegs.getOrElse(i) { 0 }) return@reduce accDegs to accC +// if (accDegs[i] < listDegs.getOrElse(i) { 0 }) return@reduce listDegs to listC +// } +// if (accDegs.size < listDegs.size) listDegs to listC else accDegs to accC +// } +// +// var thisCoefficients = coefficients.toMutableMap() +// val otherCoefficients = other.coefficients +// val quotientCoefficients = HashMap, T>() +// +// var (thisLeadingTermDegs, thisLeadingTermC) = thisCoefficients.leadingTerm() +// val (otherLeadingTermDegs, otherLeadingTermC) = otherCoefficients.leadingTerm() +// +// while ( +// thisLeadingTermDegs.size >= otherLeadingTermDegs.size && +// (0..otherLeadingTermDegs.lastIndex).all { thisLeadingTermDegs[it] >= otherLeadingTermDegs[it] } +// ) { +// val multiplierDegs = +// thisLeadingTermDegs +// .mapIndexed { index, deg -> deg - otherLeadingTermDegs.getOrElse(index) { 0 } } +// .cleanUp() +// val multiplierC = thisLeadingTermC / otherLeadingTermC +// +// quotientCoefficients[multiplierDegs] = multiplierC +// +// for ((degs, t) in otherCoefficients) { +// val productDegs = +// (0..max(degs.lastIndex, multiplierDegs.lastIndex)) +// .map { degs.getOrElse(it) { 0 } + multiplierDegs.getOrElse(it) { 0 } } +// .cleanUp() +// val productC = t * multiplierC +// thisCoefficients[productDegs] = +// if (productDegs in thisCoefficients) thisCoefficients[productDegs]!! - productC else -productC +// } +// +// thisCoefficients = thisCoefficients.filterValues { it.isNotZero() }.toMutableMap() +// +// if (thisCoefficients.isEmpty()) +// return Polynomial(quotientCoefficients, toCheckInput = false) +// +// val t = thisCoefficients.leadingTerm() +// thisLeadingTermDegs = t.first +// thisLeadingTermC = t.second +// } +// +// return Polynomial(quotientCoefficients, toCheckInput = false) +//} +// +//operator fun > Polynomial.div(other: T): Polynomial = +// if (other.isZero()) throw ArithmeticException("/ by zero") +// else +// Polynomial( +// coefficients +// .mapValues { it.value / other }, +// toCheckInput = false +// ) +// +//operator fun > Polynomial.rem(other: Polynomial): Polynomial { +// if (other.isZero()) throw ArithmeticException("/ by zero") +// if (isZero()) return this +// +// fun Map, T>.leadingTerm() = +// this +// .asSequence() +// .map { Pair(it.key, it.value) } +// .reduce { (accDegs, accC), (listDegs, listC) -> +// for (i in 0..accDegs.lastIndex) { +// if (accDegs[i] > listDegs.getOrElse(i) { 0 }) return@reduce accDegs to accC +// if (accDegs[i] < listDegs.getOrElse(i) { 0 }) return@reduce listDegs to listC +// } +// if (accDegs.size < listDegs.size) listDegs to listC else accDegs to accC +// } +// +// var thisCoefficients = coefficients.toMutableMap() +// val otherCoefficients = other.coefficients +// +// var (thisLeadingTermDegs, thisLeadingTermC) = thisCoefficients.leadingTerm() +// val (otherLeadingTermDegs, otherLeadingTermC) = otherCoefficients.leadingTerm() +// +// while ( +// thisLeadingTermDegs.size >= otherLeadingTermDegs.size && +// (0..otherLeadingTermDegs.lastIndex).all { thisLeadingTermDegs[it] >= otherLeadingTermDegs[it] } +// ) { +// val multiplierDegs = +// thisLeadingTermDegs +// .mapIndexed { index, deg -> deg - otherLeadingTermDegs.getOrElse(index) { 0 } } +// .cleanUp() +// val multiplierC = thisLeadingTermC / otherLeadingTermC +// +// for ((degs, t) in otherCoefficients) { +// val productDegs = +// (0..max(degs.lastIndex, multiplierDegs.lastIndex)) +// .map { degs.getOrElse(it) { 0 } + multiplierDegs.getOrElse(it) { 0 } } +// .cleanUp() +// val productC = t * multiplierC +// thisCoefficients[productDegs] = +// if (productDegs in thisCoefficients) thisCoefficients[productDegs]!! - productC else -productC +// } +// +// thisCoefficients = thisCoefficients.filterValues { it.isNotZero() }.toMutableMap() +// +// if (thisCoefficients.isEmpty()) +// return Polynomial(thisCoefficients, toCheckInput = false) +// +// val t = thisCoefficients.leadingTerm() +// thisLeadingTermDegs = t.first +// thisLeadingTermC = t.second +// } +// +// return Polynomial(thisCoefficients, toCheckInput = false) +//} +// +//infix fun > Polynomial.divrem(other: Polynomial): Polynomial.Companion.DividingResult { +// if (other.isZero()) throw ArithmeticException("/ by zero") +// if (isZero()) return Polynomial.Companion.DividingResult(this, this) +// +// fun Map, T>.leadingTerm() = +// this +// .asSequence() +// .map { Pair(it.key, it.value) } +// .reduce { (accDegs, accC), (listDegs, listC) -> +// for (i in 0..accDegs.lastIndex) { +// if (accDegs[i] > listDegs.getOrElse(i) { 0 }) return@reduce accDegs to accC +// if (accDegs[i] < listDegs.getOrElse(i) { 0 }) return@reduce listDegs to listC +// } +// if (accDegs.size < listDegs.size) listDegs to listC else accDegs to accC +// } +// +// var thisCoefficients = coefficients.toMutableMap() +// val otherCoefficients = other.coefficients +// val quotientCoefficients = HashMap, T>() +// +// var (thisLeadingTermDegs, thisLeadingTermC) = thisCoefficients.leadingTerm() +// val (otherLeadingTermDegs, otherLeadingTermC) = otherCoefficients.leadingTerm() +// +// while ( +// thisLeadingTermDegs.size >= otherLeadingTermDegs.size && +// (0..otherLeadingTermDegs.lastIndex).all { thisLeadingTermDegs[it] >= otherLeadingTermDegs[it] } +// ) { +// val multiplierDegs = +// thisLeadingTermDegs +// .mapIndexed { index, deg -> deg - otherLeadingTermDegs.getOrElse(index) { 0 } } +// .cleanUp() +// val multiplierC = thisLeadingTermC / otherLeadingTermC +// +// quotientCoefficients[multiplierDegs] = multiplierC +// +// for ((degs, t) in otherCoefficients) { +// val productDegs = +// (0..max(degs.lastIndex, multiplierDegs.lastIndex)) +// .map { degs.getOrElse(it) { 0 } + multiplierDegs.getOrElse(it) { 0 } } +// .cleanUp() +// val productC = t * multiplierC +// thisCoefficients[productDegs] = +// if (productDegs in thisCoefficients) thisCoefficients[productDegs]!! - productC else -productC +// } +// +// thisCoefficients = thisCoefficients.filterValues { it.isNotZero() }.toMutableMap() +// +// if (thisCoefficients.isEmpty()) +// return Polynomial.Companion.DividingResult( +// Polynomial(quotientCoefficients, toCheckInput = false), +// Polynomial(thisCoefficients, toCheckInput = false) +// ) +// +// val t = thisCoefficients.leadingTerm() +// thisLeadingTermDegs = t.first +// thisLeadingTermC = t.second +// } +// +// return Polynomial.Companion.DividingResult( +// Polynomial(quotientCoefficients, toCheckInput = false), +// Polynomial(thisCoefficients, toCheckInput = false) +// ) +//} +// +//// endregion + +// endregion + +//// region Polynomial substitution and functional representation +// +//public fun LabeledPolynomial.substitute(ring: Ring, args: Map): LabeledPolynomial = ring { +// if (coefficients.isEmpty()) return this@substitute +// LabeledPolynomial( +// buildMap { +// coefficients.forEach { (degs, c) -> +// val newDegs = degs.filterKeys { it !in args } +// val newC = degs.entries.asSequence().filter { it.key in args }.fold(c) { acc, (variable, deg) -> +// multiplyWithPower(acc, args[variable]!!, deg) +// } +// this[newDegs] = if (newDegs in this) this[newDegs]!! + newC else newC +// } +// } +// ) +//} +// +//// TODO: Replace with optimisation: the [result] may be unboxed, and all operations may be performed as soon as +//// possible on it +//@JvmName("substitutePolynomial") +//fun LabeledPolynomial.substitute(ring: Ring, arg: Map>) : LabeledPolynomial = +// ring.labeledPolynomial { +// if (coefficients.isEmpty()) return zero +// coefficients +// .asSequence() +// .map { (degs, c) -> +// degs.entries +// .asSequence() +// .filter { it.key in arg } +// .fold(LabeledPolynomial(mapOf(degs.filterKeys { it !in arg } to c))) { acc, (index, deg) -> +// multiplyWithPower(acc, arg[index]!!, deg) +// } +// } +// .reduce { acc, polynomial -> acc + polynomial } // TODO: Rewrite. Might be slow. +// } +// +//// TODO: Substitute rational function +// +//fun > LabeledPolynomial.asFunctionOver(ring: A): (Map) -> LabeledPolynomial = +// { substitute(ring, it) } +// +//fun > LabeledPolynomial.asPolynomialFunctionOver(ring: A): (Map>) -> LabeledPolynomial = +// { substitute(ring, it) } +// +//// endregion + +//// region Algebraic derivative and antiderivative +//// TODO +//// endregion \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt new file mode 100644 index 000000000..d4053442d --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt @@ -0,0 +1,605 @@ +package space.kscience.kmath.functions + +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.* +import kotlin.contracts.* +import kotlin.jvm.JvmName + + +// TODO: Docs + +// region Sort of legacy + +//// region Constants +// +//// TODO: Reuse underlying ring extensions +// +//context(NumberedPolynomialSpace) +//@Suppress("NOTHING_TO_INLINE") +//public fun > numberConstant(value: Int): C = ring { number(value) } +// +//context(NumberedPolynomialSpace) +//public fun > multiplyWithPower(base: C, arg: C, pow: UInt): C = ring { multiplyWithPower(base, arg, pow) } +// +//// endregion + +//// region Polynomials +// +//context(NumberedPolynomialSpace) +//public fun > number(value: Int): NumberedPolynomial = ring { NumberedPolynomial(mapOf(emptyList() to number(value))) } +// +//context(NumberedPolynomialSpace) +//public fun > multiplyWithPower(base: NumberedPolynomial, arg: NumberedPolynomial, pow: UInt): NumberedPolynomial = +// when { +// arg.isZero() && pow > 0U -> base +// arg.isOne() -> base +// arg.isMinusOne() -> if (pow % 2U == 0U) base else -base +// else -> multiplyWithPowerInternalLogic(base, arg, pow) +// } +// +//// Trivial but slow as duck +//context(NumberedPolynomialSpace) +//internal tailrec fun > multiplyWithPowerInternalLogic(base: NumberedPolynomial, arg: NumberedPolynomial, exponent: UInt): NumberedPolynomial = +// when { +// exponent == 0U -> base +// exponent == 1U -> base * arg +// exponent % 2U == 0U -> multiplyWithPowerInternalLogic(base, arg * arg, exponent / 2U) +// exponent % 2U == 1U -> multiplyWithPowerInternalLogic(base * arg, arg * arg, exponent / 2U) +// else -> error("Error in raising ring instant by unsigned integer: got reminder by division by 2 different from 0 and 1") +// } +// +//// endregion + +// endregion + +// region Utilities + +// TODO: Docs +@OptIn(ExperimentalContracts::class) +public inline fun , R> A.numberedPolynomial(block: NumberedPolynomialSpace.() -> R): R { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return NumberedPolynomialSpace(this).block() +} + +// endregion + +//// region String representations +// +///** +// * Represents the polynomial as a [String] where name of variable with index `i` is [withVariableName] + `"_${i+1}"`. +// * Consider that monomials are sorted in lexicographic order. +// */ +//context(NumberedPolynomialSpace) +//public fun > NumberedPolynomial.represent(withVariableName: String = NumberedPolynomial.defaultVariableName): String = +// coefficients.entries +// .sortedWith { o1, o2 -> NumberedPolynomial.monomialComparator.compare(o1.key, o2.key) } +// .asSequence() +// .map { (degs, t) -> +// if (degs.isEmpty()) "$t" +// else { +// when { +// t.isOne() -> "" +// t.isMinusOne() -> "-" +// else -> "$t " +// } + +// degs +// .mapIndexed { index, deg -> +// when (deg) { +// 0U -> "" +// 1U -> "${withVariableName}_${index+1}" +// else -> "${withVariableName}_${index+1}^$deg" +// } +// } +// .filter { it.isNotEmpty() } +// .joinToString(separator = " ") { it } +// } +// } +// .joinToString(separator = " + ") { it } +// .ifEmpty { "0" } +// +///** +// * Represents the polynomial as a [String] naming variables by [namer]. +// * Consider that monomials are sorted in lexicographic order. +// */ +//context(NumberedPolynomialSpace) +//public fun > NumberedPolynomial.represent(namer: (Int) -> String): String = +// coefficients.entries +// .sortedWith { o1, o2 -> NumberedPolynomial.monomialComparator.compare(o1.key, o2.key) } +// .asSequence() +// .map { (degs, t) -> +// if (degs.isEmpty()) "$t" +// else { +// when { +// t.isOne() -> "" +// t.isMinusOne() -> "-" +// else -> "$t " +// } + +// degs +// .mapIndexed { index, deg -> +// when (deg) { +// 0U -> "" +// 1U -> namer(index) +// else -> "${namer(index)}^$deg" +// } +// } +// .filter { it.isNotEmpty() } +// .joinToString(separator = " ") { it } +// } +// } +// .joinToString(separator = " + ") { it } +// .ifEmpty { "0" } +// +///** +// * Represents the polynomial as a [String] where name of variable with index `i` is [withVariableName] + `"_${i+1}"` +// * and with brackets around the string if needed (i.e. when there are at least two addends in the representation). +// * Consider that monomials are sorted in lexicographic order. +// */ +//context(NumberedPolynomialSpace) +//public fun > NumberedPolynomial.representWithBrackets(withVariableName: String = NumberedPolynomial.defaultVariableName): String = +// with(represent(withVariableName)) { if (coefficients.count() == 1) this else "($this)" } +// +///** +// * Represents the polynomial as a [String] naming variables by [namer] and with brackets around the string if needed +// * (i.e. when there are at least two addends in the representation). +// * Consider that monomials are sorted in lexicographic order. +// */ +//context(NumberedPolynomialSpace) +//public fun > NumberedPolynomial.representWithBrackets(namer: (Int) -> String): String = +// with(represent(namer)) { if (coefficients.count() == 1) this else "($this)" } +// +///** +// * Represents the polynomial as a [String] where name of variable with index `i` is [withVariableName] + `"_${i+1}"`. +// * Consider that monomials are sorted in **reversed** lexicographic order. +// */ +//context(NumberedPolynomialSpace) +//public fun > NumberedPolynomial.representReversed(withVariableName: String = NumberedPolynomial.defaultVariableName): String = +// coefficients.entries +// .sortedWith { o1, o2 -> -NumberedPolynomial.monomialComparator.compare(o1.key, o2.key) } +// .asSequence() +// .map { (degs, t) -> +// if (degs.isEmpty()) "$t" +// else { +// when { +// t.isOne() -> "" +// t.isMinusOne() -> "-" +// else -> "$t " +// } + +// degs +// .mapIndexed { index, deg -> +// when (deg) { +// 0U -> "" +// 1U -> "${withVariableName}_${index+1}" +// else -> "${withVariableName}_${index+1}^$deg" +// } +// } +// .filter { it.isNotEmpty() } +// .joinToString(separator = " ") { it } +// } +// } +// .joinToString(separator = " + ") { it } +// .ifEmpty { "0" } +// +///** +// * Represents the polynomial as a [String] naming variables by [namer]. +// * Consider that monomials are sorted in **reversed** lexicographic order. +// */ +//context(NumberedPolynomialSpace) +//public fun > NumberedPolynomial.representReversed(namer: (Int) -> String): String = +// coefficients.entries +// .sortedWith { o1, o2 -> -NumberedPolynomial.monomialComparator.compare(o1.key, o2.key) } +// .asSequence() +// .map { (degs, t) -> +// if (degs.isEmpty()) "$t" +// else { +// when { +// t.isOne() -> "" +// t.isMinusOne() -> "-" +// else -> "$t " +// } + +// degs +// .mapIndexed { index, deg -> +// when (deg) { +// 0U -> "" +// 1U -> namer(index) +// else -> "${namer(index)}^$deg" +// } +// } +// .filter { it.isNotEmpty() } +// .joinToString(separator = " ") { it } +// } +// } +// .joinToString(separator = " + ") { it } +// .ifEmpty { "0" } +// +///** +// * Represents the polynomial as a [String] where name of variable with index `i` is [withVariableName] + `"_${i+1}"` +// * and with brackets around the string if needed (i.e. when there are at least two addends in the representation). +// * Consider that monomials are sorted in **reversed** lexicographic order. +// */ +//context(NumberedPolynomialSpace) +//public fun > NumberedPolynomial.representReversedWithBrackets(withVariableName: String = NumberedPolynomial.defaultVariableName): String = +// with(representReversed(withVariableName)) { if (coefficients.count() == 1) this else "($this)" } +// +///** +// * Represents the polynomial as a [String] naming variables by [namer] and with brackets around the string if needed +// * (i.e. when there are at least two addends in the representation). +// * Consider that monomials are sorted in **reversed** lexicographic order. +// */ +//context(NumberedPolynomialSpace) +//public fun > NumberedPolynomial.representReversedWithBrackets(namer: (Int) -> String): String = +// with(representReversed(namer)) { if (coefficients.count() == 1) this else "($this)" } +// +//// endregion + +//// region Polynomial substitution and functional representation +// +//public fun NumberedPolynomial.substitute(ring: Ring, args: Map): NumberedPolynomial = ring { +// if (coefficients.isEmpty()) return this@substitute +// NumberedPolynomial( +// buildMap { +// coefficients.forEach { (degs, c) -> +// val newDegs = degs.mapIndexed { index, deg -> if (index in args) 0U else deg }.cleanUp() +// val newC = degs.foldIndexed(c) { index, acc, deg -> +// if (index in args) multiplyWithPower(acc, args[index]!!, deg) +// else acc +// } +// this[newDegs] = if (newDegs in this) this[newDegs]!! + newC else newC +// } +// } +// ) +//} +// +//// TODO: Replace with optimisation: the [result] may be unboxed, and all operations may be performed as soon as +//// possible on it +//@JvmName("substitutePolynomial") +//public fun NumberedPolynomial.substitute(ring: Ring, arg: Map>) : NumberedPolynomial = +// ring.numberedPolynomialSpace { +// if (coefficients.isEmpty()) return zero +// coefficients +// .asSequence() +// .map { (degs, c) -> +// degs.foldIndexed( +// NumberedPolynomial( +// degs.mapIndexed { index, deg -> if (index in arg) 0U else deg } to c +// ) +// ) { index, acc, deg -> if (index in arg) multiplyWithPower(acc, arg[index]!!, deg) else acc } +// } +// .reduce { acc, polynomial -> acc + polynomial } // TODO: Rewrite. Might be slow. +// } +// +//// TODO: Substitute rational function +// +//public fun > NumberedPolynomial.asFunctionOver(ring: A): (Map) -> NumberedPolynomial = +// { substitute(ring, it) } +// +//public fun > NumberedPolynomial.asPolynomialFunctionOver(ring: A): (Map>) -> NumberedPolynomial = +// { substitute(ring, it) } +// +//// endregion + +// region Operator extensions + +//// region Field case +// +//operator fun > Polynomial.div(other: Polynomial): Polynomial { +// if (other.isZero()) throw ArithmeticException("/ by zero") +// if (isZero()) return this +// +// fun Map, T>.leadingTerm() = +// this +// .asSequence() +// .map { Pair(it.key, it.value) } +// .reduce { (accDegs, accC), (listDegs, listC) -> +// for (i in 0..accDegs.lastIndex) { +// if (accDegs[i] > listDegs.getOrElse(i) { 0 }) return@reduce accDegs to accC +// if (accDegs[i] < listDegs.getOrElse(i) { 0 }) return@reduce listDegs to listC +// } +// if (accDegs.size < listDegs.size) listDegs to listC else accDegs to accC +// } +// +// var thisCoefficients = coefficients.toMutableMap() +// val otherCoefficients = other.coefficients +// val quotientCoefficients = HashMap, T>() +// +// var (thisLeadingTermDegs, thisLeadingTermC) = thisCoefficients.leadingTerm() +// val (otherLeadingTermDegs, otherLeadingTermC) = otherCoefficients.leadingTerm() +// +// while ( +// thisLeadingTermDegs.size >= otherLeadingTermDegs.size && +// (0..otherLeadingTermDegs.lastIndex).all { thisLeadingTermDegs[it] >= otherLeadingTermDegs[it] } +// ) { +// val multiplierDegs = +// thisLeadingTermDegs +// .mapIndexed { index, deg -> deg - otherLeadingTermDegs.getOrElse(index) { 0 } } +// .cleanUp() +// val multiplierC = thisLeadingTermC / otherLeadingTermC +// +// quotientCoefficients[multiplierDegs] = multiplierC +// +// for ((degs, t) in otherCoefficients) { +// val productDegs = +// (0..max(degs.lastIndex, multiplierDegs.lastIndex)) +// .map { degs.getOrElse(it) { 0 } + multiplierDegs.getOrElse(it) { 0 } } +// .cleanUp() +// val productC = t * multiplierC +// thisCoefficients[productDegs] = +// if (productDegs in thisCoefficients) thisCoefficients[productDegs]!! - productC else -productC +// } +// +// thisCoefficients = thisCoefficients.filterValues { it.isNotZero() }.toMutableMap() +// +// if (thisCoefficients.isEmpty()) +// return Polynomial(quotientCoefficients, toCheckInput = false) +// +// val t = thisCoefficients.leadingTerm() +// thisLeadingTermDegs = t.first +// thisLeadingTermC = t.second +// } +// +// return Polynomial(quotientCoefficients, toCheckInput = false) +//} +// +//operator fun > Polynomial.div(other: T): Polynomial = +// if (other.isZero()) throw ArithmeticException("/ by zero") +// else +// Polynomial( +// coefficients +// .mapValues { it.value / other }, +// toCheckInput = false +// ) +// +//operator fun > Polynomial.rem(other: Polynomial): Polynomial { +// if (other.isZero()) throw ArithmeticException("/ by zero") +// if (isZero()) return this +// +// fun Map, T>.leadingTerm() = +// this +// .asSequence() +// .map { Pair(it.key, it.value) } +// .reduce { (accDegs, accC), (listDegs, listC) -> +// for (i in 0..accDegs.lastIndex) { +// if (accDegs[i] > listDegs.getOrElse(i) { 0 }) return@reduce accDegs to accC +// if (accDegs[i] < listDegs.getOrElse(i) { 0 }) return@reduce listDegs to listC +// } +// if (accDegs.size < listDegs.size) listDegs to listC else accDegs to accC +// } +// +// var thisCoefficients = coefficients.toMutableMap() +// val otherCoefficients = other.coefficients +// +// var (thisLeadingTermDegs, thisLeadingTermC) = thisCoefficients.leadingTerm() +// val (otherLeadingTermDegs, otherLeadingTermC) = otherCoefficients.leadingTerm() +// +// while ( +// thisLeadingTermDegs.size >= otherLeadingTermDegs.size && +// (0..otherLeadingTermDegs.lastIndex).all { thisLeadingTermDegs[it] >= otherLeadingTermDegs[it] } +// ) { +// val multiplierDegs = +// thisLeadingTermDegs +// .mapIndexed { index, deg -> deg - otherLeadingTermDegs.getOrElse(index) { 0 } } +// .cleanUp() +// val multiplierC = thisLeadingTermC / otherLeadingTermC +// +// for ((degs, t) in otherCoefficients) { +// val productDegs = +// (0..max(degs.lastIndex, multiplierDegs.lastIndex)) +// .map { degs.getOrElse(it) { 0 } + multiplierDegs.getOrElse(it) { 0 } } +// .cleanUp() +// val productC = t * multiplierC +// thisCoefficients[productDegs] = +// if (productDegs in thisCoefficients) thisCoefficients[productDegs]!! - productC else -productC +// } +// +// thisCoefficients = thisCoefficients.filterValues { it.isNotZero() }.toMutableMap() +// +// if (thisCoefficients.isEmpty()) +// return Polynomial(thisCoefficients, toCheckInput = false) +// +// val t = thisCoefficients.leadingTerm() +// thisLeadingTermDegs = t.first +// thisLeadingTermC = t.second +// } +// +// return Polynomial(thisCoefficients, toCheckInput = false) +//} +// +//infix fun > Polynomial.divrem(other: Polynomial): Polynomial.Companion.DividingResult { +// if (other.isZero()) throw ArithmeticException("/ by zero") +// if (isZero()) return Polynomial.Companion.DividingResult(this, this) +// +// fun Map, T>.leadingTerm() = +// this +// .asSequence() +// .map { Pair(it.key, it.value) } +// .reduce { (accDegs, accC), (listDegs, listC) -> +// for (i in 0..accDegs.lastIndex) { +// if (accDegs[i] > listDegs.getOrElse(i) { 0 }) return@reduce accDegs to accC +// if (accDegs[i] < listDegs.getOrElse(i) { 0 }) return@reduce listDegs to listC +// } +// if (accDegs.size < listDegs.size) listDegs to listC else accDegs to accC +// } +// +// var thisCoefficients = coefficients.toMutableMap() +// val otherCoefficients = other.coefficients +// val quotientCoefficients = HashMap, T>() +// +// var (thisLeadingTermDegs, thisLeadingTermC) = thisCoefficients.leadingTerm() +// val (otherLeadingTermDegs, otherLeadingTermC) = otherCoefficients.leadingTerm() +// +// while ( +// thisLeadingTermDegs.size >= otherLeadingTermDegs.size && +// (0..otherLeadingTermDegs.lastIndex).all { thisLeadingTermDegs[it] >= otherLeadingTermDegs[it] } +// ) { +// val multiplierDegs = +// thisLeadingTermDegs +// .mapIndexed { index, deg -> deg - otherLeadingTermDegs.getOrElse(index) { 0 } } +// .cleanUp() +// val multiplierC = thisLeadingTermC / otherLeadingTermC +// +// quotientCoefficients[multiplierDegs] = multiplierC +// +// for ((degs, t) in otherCoefficients) { +// val productDegs = +// (0..max(degs.lastIndex, multiplierDegs.lastIndex)) +// .map { degs.getOrElse(it) { 0 } + multiplierDegs.getOrElse(it) { 0 } } +// .cleanUp() +// val productC = t * multiplierC +// thisCoefficients[productDegs] = +// if (productDegs in thisCoefficients) thisCoefficients[productDegs]!! - productC else -productC +// } +// +// thisCoefficients = thisCoefficients.filterValues { it.isNotZero() }.toMutableMap() +// +// if (thisCoefficients.isEmpty()) +// return Polynomial.Companion.DividingResult( +// Polynomial(quotientCoefficients, toCheckInput = false), +// Polynomial(thisCoefficients, toCheckInput = false) +// ) +// +// val t = thisCoefficients.leadingTerm() +// thisLeadingTermDegs = t.first +// thisLeadingTermC = t.second +// } +// +// return Polynomial.Companion.DividingResult( +// Polynomial(quotientCoefficients, toCheckInput = false), +// Polynomial(thisCoefficients, toCheckInput = false) +// ) +//} +// +//// endregion + +// endregion + +// region Polynomial substitution and functional representation + +// TODO: May be apply Horner's method too? +/** + * Evaluates the value of the given double polynomial for given double argument. + */ +public fun NumberedPolynomial.substitute(args: Map): NumberedPolynomial = Double.algebra { + val acc = LinkedHashMap, Double>(coefficients.size) + for ((degs, c) in coefficients) { + val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp() + val newC = args.entries.fold(c) { product, (variable, substitutor) -> + val deg = degs.getOrElse(variable) { 0u } + if (deg == 0u) product else product * substitutor.pow(deg.toInt()) + } + if (newDegs !in acc) acc[newDegs] = c + else acc[newDegs] = acc[newDegs]!! + c + } + return NumberedPolynomial(acc) +} + +/** + * Evaluates the value of the given polynomial for given argument. + * + * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). + */ +public fun NumberedPolynomial.substitute(ring: Ring, args: Map): NumberedPolynomial = ring { + val acc = LinkedHashMap, C>(coefficients.size) + for ((degs, c) in coefficients) { + val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp() + val newC = args.entries.fold(c) { product, (variable, substitutor) -> + val deg = degs.getOrElse(variable) { 0u } + if (deg == 0u) product else product * power(substitutor, deg) + } + if (newDegs !in acc) acc[newDegs] = c + else acc[newDegs] = acc[newDegs]!! + c + } + return NumberedPolynomial(acc) +} + +// TODO: (Waiting for hero) Replace with optimisation: the [result] may be unboxed, and all operations may be performed +// as soon as possible on it +@JvmName("substitutePolynomial") +public fun NumberedPolynomial.substitute(ring: Ring, args: Map>) : NumberedPolynomial = TODO() /*ring.numberedPolynomial { + val acc = LinkedHashMap, NumberedPolynomial>(coefficients.size) + for ((degs, c) in coefficients) { + val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp() + val newC = args.entries.fold(c.asNumberedPolynomial()) { product, (variable, substitutor) -> + val deg = degs.getOrElse(variable) { 0u } + if (deg == 0u) product else product * power(substitutor, deg) + } + if (newDegs !in acc) acc[newDegs] = c.asNumberedPolynomial() + else acc[newDegs] = acc[newDegs]!! + c + } +}*/ + +/** + * Represent the polynomial as a regular context-less function. + */ +public fun > NumberedPolynomial.asFunction(ring: A): (Map) -> NumberedPolynomial = { substitute(ring, it) } + +/** + * Represent the polynomial as a regular context-less function. + */ +public fun > NumberedPolynomial.asPolynomialFunctionOver(ring: A): (Map>) -> NumberedPolynomial = { substitute(ring, it) } + +// endregion + +// region Algebraic derivative and antiderivative + +/** + * Returns algebraic derivative of received polynomial. + */ +@UnstableKMathAPI +public fun NumberedPolynomial.derivativeBy( + algebra: A, + variable: Int, +): Polynomial where A : Ring, A : NumericAlgebra = algebra { + TODO() +} + +/** + * Returns algebraic derivative of received polynomial. + */ +@UnstableKMathAPI +public fun NumberedPolynomial.derivativeBy( + algebra: A, + variables: IntArray, +): Polynomial where A : Ring, A : NumericAlgebra = algebra { + TODO() +} + +/** + * Returns algebraic derivative of received polynomial. + */ +@UnstableKMathAPI +public fun NumberedPolynomial.derivativeBy( + algebra: A, + variables: Collection, +): Polynomial where A : Ring, A : NumericAlgebra = derivativeBy(algebra, variables.toIntArray()) + +/** + * Create a polynomial witch represents indefinite integral version of this polynomial + */ +@UnstableKMathAPI +public fun NumberedPolynomial.antiderivativeBy( + algebra: A, + variable: Int, +): Polynomial where A : Field, A : NumericAlgebra = algebra { + TODO() +} + +/** + * Create a polynomial witch represents indefinite integral version of this polynomial + */ +@UnstableKMathAPI +public fun NumberedPolynomial.antiderivativeBy( + algebra: A, + variables: IntArray, +): Polynomial where A : Field, A : NumericAlgebra = algebra { + TODO() +} + +/** + * Create a polynomial witch represents indefinite integral version of this polynomial + */ +@UnstableKMathAPI +public fun NumberedPolynomial.antiderivativeBy( + algebra: A, + variables: Collection, +): Polynomial where A : Field, A : NumericAlgebra = antiderivativeBy(algebra, variables.toIntArray()) + +// endregion \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt index 1a3eb7874..4d99b3a45 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt @@ -121,7 +121,7 @@ public fun Polynomial.antiderivative( ): Polynomial where A : Field, A : NumericAlgebra = algebra { val integratedCoefficients = buildList(coefficients.size + 1) { add(zero) - coefficients.forEachIndexed{ index, t -> add(t / (number(index) + one)) } + coefficients.forEachIndexed{ index, t -> add(t / number(index + 1)) } } Polynomial(integratedCoefficients) } @@ -136,4 +136,6 @@ public fun > Polynomial.integrate( ): C = algebra { val integral = antiderivative(algebra) integral.substitute(algebra, range.endInclusive) - integral.substitute(algebra, range.start) -} \ No newline at end of file +} + +// endregion \ No newline at end of file -- 2.34.1 From 191dd02e478787df7a50efb7b9568701ad243d01 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Thu, 3 Mar 2022 20:45:35 +0300 Subject: [PATCH 005/123] Restructured Polynomial --- .../kmath/functions/AbstractPolynomial.kt | 354 +++++++++++++++ .../kscience/kmath/functions/Piecewise.kt | 8 +- .../kscience/kmath/functions/Polynomial.kt | 425 ++++++++++++++---- .../kmath/functions/polynomialUtil.kt | 139 ++++++ .../kmath/integration/SplineIntegrator.kt | 3 +- .../kmath/interpolation/Interpolator.kt | 4 +- .../kmath/functions/PolynomialTest.kt | 11 +- 7 files changed, 845 insertions(+), 99 deletions(-) create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt new file mode 100644 index 000000000..f6a617656 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt @@ -0,0 +1,354 @@ +/* + * 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.functions + +import space.kscience.kmath.operations.* +import kotlin.js.JsName +import kotlin.jvm.JvmName + + +/** + * Abstraction of polynomials. + */ +public interface AbstractPolynomial + +/** + * Abstraction of ring of polynomials of type [P] over ring of constants of type [C]. + */ +@Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") +public interface AbstractPolynomialSpace> : Ring

{ + // region Constant-integer relation + /** + * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * + * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. + */ + @JvmName("constantIntPlus") + public operator fun C.plus(other: Int): C + /** + * Returns difference between the constant and the integer represented as constant (member of underlying ring). + * + * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. + */ + @JvmName("constantIntMinus") + public operator fun C.minus(other: Int): C + /** + * Returns product of the constant and the integer represented as constant (member of underlying ring). + * + * The operation is equivalent to sum of [other] copies of [this]. + */ + @JvmName("constantIntTimes") + public operator fun C.times(other: Int): C + // endregion + + // region Integer-constant relation + /** + * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * + * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. + */ + @JvmName("intConstantPlus") + public operator fun Int.plus(other: C): C + /** + * Returns difference between the integer represented as constant (member of underlying ring) and the constant. + * + * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. + */ + @JvmName("intConstantMinus") + public operator fun Int.minus(other: C): C + /** + * Returns product of the integer represented as constant (member of underlying ring) and the constant. + * + * The operation is equivalent to sum of [this] copies of [other]. + */ + @JvmName("intConstantTimes") + public operator fun Int.times(other: C): C + // endregion + + // region Polynomial-integer relation + /** + * Returns sum of the constant and the integer represented as polynomial. + * + * The operation is equivalent to adding [other] copies of unit polynomial to [this]. + */ + public operator fun P.plus(other: Int): P = optimizedAddMultiplied(this, one, other) + /** + * Returns difference between the constant and the integer represented as polynomial. + * + * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. + */ + public operator fun P.minus(other: Int): P = optimizedAddMultiplied(this, one, -other) + /** + * Returns product of the constant and the integer represented as polynomial. + * + * The operation is equivalent to sum of [other] copies of [this]. + */ + public operator fun P.times(other: Int): P = optimizedMultiply(this, other) + // endregion + + // region Integer-polynomial relation + /** + * Returns sum of the integer represented as polynomial and the constant. + * + * The operation is equivalent to adding [this] copies of unit polynomial to [other]. + */ + public operator fun Int.plus(other: P): P = optimizedAddMultiplied(other, one, this) + /** + * Returns difference between the integer represented as polynomial and the constant. + * + * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. + */ + public operator fun Int.minus(other: P): P = optimizedAddMultiplied(-other, one, this) + /** + * Returns product of the integer represented as polynomial and the constant. + * + * The operation is equivalent to sum of [this] copies of [other]. + */ + public operator fun Int.times(other: P): P = optimizedMultiply(other, this) + // endregion + + // region Constant-constant relation + /** + * Returns the same constant. + */ + @JvmName("constantUnaryPlus") + @JsName("constantUnaryPlus") + public operator fun C.unaryPlus(): C = this + /** + * Returns negation of the constant. + */ + @JvmName("constantUnaryMinus") + @JsName("constantUnaryMinus") + public operator fun C.unaryMinus(): C + /** + * Returns sum of the constants. + */ + @JvmName("constantPlus") + @JsName("constantPlus") + public operator fun C.plus(other: C): C + /** + * Returns difference of the constants. + */ + @JvmName("constantMinus") + @JsName("constantMinus") + public operator fun C.minus(other: C): C + /** + * Returns product of the constants. + */ + @JvmName("constantTimes") + @JsName("constantTimes") + public operator fun C.times(other: C): C + + /** + * Check if the instant is zero constant. + */ + @JvmName("constantIsZero") + public fun C.isZero(): Boolean + /** + * Check if the instant is NOT zero constant. + */ + @JvmName("constantIsNotZero") + public fun C.isNotZero(): Boolean + /** + * Check if the instant is unit constant. + */ + @JvmName("constantIsOne") + public fun C.isOne(): Boolean + /** + * Check if the instant is NOT unit constant. + */ + @JvmName("constantIsNotOne") + public fun C.isNotOne(): Boolean + /** + * Check if the instant is minus unit constant. + */ + @JvmName("constantIsMinusOne") + public fun C.isMinusOne(): Boolean + /** + * Check if the instant is NOT minus unit constant. + */ + @JvmName("constantIsNotMinusOne") + public fun C.isNotMinusOne(): Boolean + // endregion + + // region Constant-polynomial relation + /** + * Returns sum of the constant represented as polynomial and the polynomial. + */ + public operator fun C.plus(other: P): P + /** + * Returns difference between the constant represented as polynomial and the polynomial. + */ + public operator fun C.minus(other: P): P + /** + * Returns product of the constant represented as polynomial and the polynomial. + */ + public operator fun C.times(other: P): P + // endregion + + // region Polynomial-constant relation + /** + * Returns sum of the constant represented as polynomial and the polynomial. + */ + public operator fun P.plus(other: C): P + /** + * Returns difference between the constant represented as polynomial and the polynomial. + */ + public operator fun P.minus(other: C): P + /** + * Returns product of the constant represented as polynomial and the polynomial. + */ + public operator fun P.times(other: C): P + // endregion + + // region Polynomial-polynomial relation + /** + * Returns the same polynomial. + */ + public override operator fun P.unaryPlus(): P = this + /** + * Returns negation of the polynomial. + */ + public override operator fun P.unaryMinus(): P + /** + * Returns sum of the polynomials. + */ + public override operator fun P.plus(other: P): P + /** + * Returns difference of the polynomials. + */ + public override operator fun P.minus(other: P): P + /** + * Returns product of the polynomials. + */ + public override operator fun P.times(other: P): P + + /** + * Check if the instant is zero polynomial. + */ + public fun P.isZero(): Boolean = this == zero + /** + * Check if the instant is NOT zero polynomial. + */ + public fun P.isNotZero(): Boolean = this != zero + /** + * Check if the instant is unit polynomial. + */ + public fun P.isOne(): Boolean = this == one + /** + * Check if the instant is NOT unit polynomial. + */ + public fun P.isNotOne(): Boolean = this != one + /** + * Check if the instant is minus unit polynomial. + */ + public fun P.isMinusOne(): Boolean = this == -one + /** + * Check if the instant is NOT minus unit polynomial. + */ + public fun P.isNotMinusOne(): Boolean = this != -one + + /** + * Instance of zero polynomial (zero of the polynomial ring). + */ + override val zero: P + /** + * Instance of unit polynomial (unit of the polynomial ring). + */ + override val one: P + + /** + * Checks equality of the polynomials. + */ + @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") + public fun P.equals(other: P): Boolean + // endregion + + // Not sure is it necessary... + // region Polynomial properties + /** + * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is + * zero, degree is -1. + */ + public val P.degree: Int + + /** + * Checks if the instant is constant polynomial (of degree no more than 0) over considered ring. + */ + public fun P.isConstant(): Boolean = degree <= 0 + /** + * Checks if the instant is **not** constant polynomial (of degree no more than 0) over considered ring. + */ + public fun P.isNotConstant(): Boolean = !isConstant() + /** + * Checks if the instant is constant non-zero polynomial (of degree no more than 0) over considered ring. + */ + public fun P.isNonZeroConstant(): Boolean = degree == 0 + /** + * Checks if the instant is **not** constant non-zero polynomial (of degree no more than 0) over considered ring. + */ + public fun P.isNotNonZeroConstant(): Boolean = !isNonZeroConstant() + /** + * If polynomial is a constant polynomial represents and returns it as constant. + * Otherwise, (when the polynomial is not constant polynomial) returns `null`. + */ + public fun P.asConstantOrNull(): C? + /** + * If polynomial is a constant polynomial represents and returns it as constant. + * Otherwise, (when the polynomial is not constant polynomial) raises corresponding exception. + */ + public fun P.asConstant(): C = asConstantOrNull() ?: error("Can not represent non-constant polynomial as a constant") + // endregion + + // region Legacy of Ring interface + override fun add(left: P, right: P): P = left + right + override fun multiply(left: P, right: P): P = left * right + // endregion + + public companion object { + // TODO: All of this should be moved to algebraic structures' place for utilities + // TODO: Move receiver to context receiver + /** + * Multiplication of element and integer. + * + * @receiver the multiplicand. + * @param other the multiplier. + * @return the difference. + */ + internal tailrec fun Group.optimizedMultiply(arg: C, other: Int): C = + when { + other == 0 -> zero + other == 1 -> arg + other == -1 -> -arg + other % 2 == 0 -> optimizedMultiply(arg + arg, other / 2) + other % 2 == 1 -> optimizedAddMultiplied(arg, arg + arg, other / 2) + other % 2 == -1 -> optimizedAddMultiplied(-arg, arg + arg, other / 2) + else -> error("Error in multiplication group instant by integer: got reminder by division by 2 different from 0, 1 and -1") + } + + // TODO: Move receiver to context receiver + /** + * Adds product of [arg] and [multiplier] to [base]. + * + * @receiver the algebra to provide multiplication. + * @param base the augend. + * @param arg the multiplicand. + * @param multiplier the multiplier. + * @return sum of the augend [base] and product of the multiplicand [arg] and the multiplier [multiplier]. + * @author Gleb Minaev + */ + internal tailrec fun Group.optimizedAddMultiplied(base: C, arg: C, multiplier: Int): C = + when { + multiplier == 0 -> base + multiplier == 1 -> base + arg + multiplier == -1 -> base - arg + multiplier % 2 == 0 -> optimizedAddMultiplied(base, arg + arg, multiplier / 2) + multiplier % 2 == 1 -> optimizedAddMultiplied(base + arg, arg + arg, multiplier / 2) + multiplier % 2 == -1 -> optimizedAddMultiplied(base + arg, arg + arg, multiplier / 2) + else -> error("Error in multiplication group instant by integer: got reminder by division by 2 different from 0, 1 and -1") + } + } +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt index 16af7f555..cfd21d552 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt @@ -117,16 +117,16 @@ public fun > PiecewisePolynomial( * Return a value of polynomial function with given [ring] a given [arg] or null if argument is outside piecewise * definition. */ -public fun , C : Ring> PiecewisePolynomial.value(ring: C, arg: T): T? = - findPiece(arg)?.value(ring, arg) +public fun , C : Ring> PiecewisePolynomial.substitute(ring: C, arg: T): T? = + findPiece(arg)?.substitute(ring, arg) /** * Convert this polynomial to a function returning nullable value (null if argument is outside piecewise range). */ -public fun , C : Ring> PiecewisePolynomial.asFunction(ring: C): (T) -> T? = { value(ring, it) } +public fun , C : Ring> PiecewisePolynomial.asFunction(ring: C): (T) -> T? = { substitute(ring, it) } /** * Convert this polynomial to a function using [defaultValue] for arguments outside the piecewise range. */ public fun , C : Ring> PiecewisePolynomial.asFunction(ring: C, defaultValue: T): (T) -> T = - { value(ring, it) ?: defaultValue } + { substitute(ring, it) ?: defaultValue } 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 a36d36f52..30280a396 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 @@ -5,128 +5,371 @@ package space.kscience.kmath.functions -import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.functions.AbstractPolynomialSpace.Companion.optimizedAddMultiplied +import space.kscience.kmath.functions.AbstractPolynomialSpace.Companion.optimizedMultiply import space.kscience.kmath.operations.* -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract +import kotlin.jvm.JvmName import kotlin.math.max -import kotlin.math.pow +import kotlin.math.min /** * Polynomial coefficients model without fixation on specific context they are applied to. * * @param coefficients constant is the leftmost coefficient. */ -public class Polynomial(public val coefficients: List) { +public class Polynomial(public val coefficients: List) : AbstractPolynomial { override fun toString(): String = "Polynomial$coefficients" + +// public companion object { +// /** +// * Default name of variables used in string representations. +// * +// * @see Polynomial.toString +// */ +// public var defaultVariableName: String = "x" +// +// /** +// * Represents result of division with remainder. +// */ +// public data class DividingResult( +// val quotient: Polynomial, +// val reminder: Polynomial +// ) +// } } /** - * Returns a [Polynomial] instance with given [coefficients]. + * Represents internal [Polynomial] errors. + */ +internal class PolynomialError(message: String): Error(message) + +// region Constructors and converters + +/** + * Returns a [Polynomial] instance with given [coefficients]. The collection of coefficients will be reversed if + * [reverse] parameter is true. */ @Suppress("FunctionName") -public fun Polynomial(vararg coefficients: T): Polynomial = Polynomial(coefficients.toList()) +public fun Polynomial(coefficients: List, reverse: Boolean = false): Polynomial = + Polynomial(with(coefficients) { if (reverse) reversed() else this }) /** - * Evaluates the value of the given double polynomial for given double argument. + * Returns a [Polynomial] instance with given [coefficients]. The collection of coefficients will be reversed if + * [reverse] parameter is true. */ -public fun Polynomial.value(arg: Double): Double = coefficients.reduceIndexed { index, acc, c -> - acc + c * arg.pow(index) -} +@Suppress("FunctionName") +public fun Polynomial(vararg coefficients: T, reverse: Boolean = false): Polynomial = + Polynomial(with(coefficients) { if (reverse) reversed() else toList() }) + +public fun T.asPolynomial() : Polynomial = Polynomial(listOf(this)) + +// endregion /** - * Evaluates the value of the given polynomial for given argument. - * https://en.wikipedia.org/wiki/Horner%27s_method - */ -public fun > Polynomial.value(ring: C, arg: T): T = ring { - if (coefficients.isEmpty()) return@ring zero - var result: T = coefficients.last() - for (j in coefficients.size - 2 downTo 0) { - result = (arg * result) + coefficients[j] - } - return result -} - -/** - * Represent the polynomial as a regular context-less function. - */ -public fun > Polynomial.asFunction(ring: C): (T) -> T = { value(ring, it) } - -/** - * Create a polynomial witch represents differentiated version of this polynomial - */ -@UnstableKMathAPI -public fun Polynomial.differentiate( - algebra: A, -): Polynomial where A : Ring, A : NumericAlgebra = algebra { - Polynomial(coefficients.drop(1).mapIndexed { index, t -> number(index) * t }) -} - -/** - * Create a polynomial witch represents indefinite integral version of this polynomial - */ -@UnstableKMathAPI -public fun Polynomial.integrate( - algebra: A, -): Polynomial where A : Field, A : NumericAlgebra = algebra { - val integratedCoefficients = buildList(coefficients.size + 1) { - add(zero) - coefficients.forEachIndexed{ index, t -> add(t / (number(index) + one)) } - } - Polynomial(integratedCoefficients) -} - -/** - * Compute a definite integral of a given polynomial in a [range] - */ -@UnstableKMathAPI -public fun > Polynomial.integrate( - algebra: Field, - range: ClosedRange, -): T = algebra { - val integral = integrate(algebra) - integral.value(algebra, range.endInclusive) - integral.value(algebra, range.start) -} - -/** - * Space of polynomials. + * Space of polynomials constructed over ring. * - * @param T the type of operated polynomials. - * @param C the intersection of [Ring] of [T] and [ScaleOperations] of [T]. - * @param ring the [C] instance. + * @param C the type of constants. Polynomials have them as a coefficients in their terms. + * @param A type of underlying ring of constants. It's [Ring] of [C]. + * @param ring underlying ring of constants of type [A]. */ -public class PolynomialSpace( - private val ring: C, -) : Group>, ScaleOperations> where C : Ring, C : ScaleOperations { - override val zero: Polynomial = Polynomial(emptyList()) +@Suppress("INAPPLICABLE_JVM_NAME") // KT-31420 +public open class PolynomialSpace>( + public val ring: A, +) : AbstractPolynomialSpace>{ + // region Constant-integer relation + @JvmName("constantIntPlus") + public override operator fun C.plus(other: Int): C = ring { optimizedAddMultiplied(this@plus, one, other) } + @JvmName("constantIntMinus") + public override operator fun C.minus(other: Int): C = ring { optimizedAddMultiplied(this@minus, one, -other) } + @JvmName("constantIntTimes") + public override operator fun C.times(other: Int): C = ring { optimizedMultiply(this@times, other) } + // endregion - override fun Polynomial.unaryMinus(): Polynomial = ring { + // region Integer-constant relation + @JvmName("intConstantPlus") + public override operator fun Int.plus(other: C): C = ring { optimizedAddMultiplied(other, one, this@plus) } + @JvmName("intConstantMinus") + public override operator fun Int.minus(other: C): C = ring { optimizedAddMultiplied(-other, one, this@minus) } + @JvmName("intConstantTimes") + public override operator fun Int.times(other: C): C = ring { optimizedMultiply(other, this@times) } + // endregion + + // region Polynomial-integer relation + public override operator fun Polynomial.plus(other: Int): Polynomial = + if (other == 0) this + else + Polynomial( + coefficients + .toMutableList() + .apply { + if (isEmpty()) this[0] = ring.zero + other + else this[0] = this[0]!! + other + } + ) + public override operator fun Polynomial.minus(other: Int): Polynomial = + if (other == 0) this + else + Polynomial( + coefficients + .toMutableList() + .apply { + if (isEmpty()) this[0] = ring.zero - other + else this[0] = this[0]!! - other + } + ) + public override operator fun Polynomial.times(other: Int): Polynomial = + if (other == 0) zero + else Polynomial( + coefficients + .subList(0, degree + 1) + .map { it * other } + ) + // endregion + + // region Integer-polynomial relation + public override operator fun Int.plus(other: Polynomial): Polynomial = + if (this == 0) other + else + Polynomial( + other.coefficients + .toMutableList() + .apply { + if (isEmpty()) this[0] = ring.zero + this@plus + else this[0] = this[0]!! + this@plus + } + ) + public override operator fun Int.minus(other: Polynomial): Polynomial = + if (this == 0) other + else + Polynomial( + other.coefficients + .toMutableList() + .apply { + if (isEmpty()) this[0] = ring.zero - this@minus + else this[0] = this[0]!! - this@minus + } + ) + public override operator fun Int.times(other: Polynomial): Polynomial = + if (this == 0) zero + else Polynomial( + other.coefficients + .subList(0, other.degree + 1) + .map { it * this } + ) + // endregion + + // region Constant-constant relation + @JvmName("constantUnaryMinus") + public override operator fun C.unaryMinus(): C = ring { -this@unaryMinus } + @JvmName("constantPlus") + public override operator fun C.plus(other: C): C = ring { this@plus + other } + @JvmName("constantMinus") + public override operator fun C.minus(other: C): C = ring { this@minus - other } + @JvmName("constantTimes") + public override operator fun C.times(other: C): C = ring { this@times * other } + @JvmName("constantIsZero") + public override fun C.isZero(): Boolean = ring { this == zero } + @JvmName("constantIsNotZero") + public override fun C.isNotZero(): Boolean = ring { this != zero } + @JvmName("constantIsOne") + public override fun C.isOne(): Boolean = ring { this == one } + @JvmName("constantIsNotOne") + public override fun C.isNotOne(): Boolean = ring { this != one } + @JvmName("constantIsMinusOne") + public override fun C.isMinusOne(): Boolean = ring { this == -one } + @JvmName("constantIsNotMinusOne") + public override fun C.isNotMinusOne(): Boolean = ring { this != -one } + // endregion + + // region Constant-polynomial relation + public override operator fun C.plus(other: Polynomial): Polynomial = + with(other.coefficients) { + if (isEmpty()) Polynomial(listOf(this@plus)) + else Polynomial( + toMutableList() + .apply { + this[0] += this@plus + } + ) + } +// if (degree == -1) UnivariatePolynomial(other) else UnivariatePolynomial( +// listOf(coefficients[0] + other) + coefficients.subList(1, degree + 1) +// ) + public override operator fun C.minus(other: Polynomial): Polynomial = + with(other.coefficients) { + if (isEmpty()) Polynomial(listOf(-this@minus)) + else Polynomial( + toMutableList() + .apply { + this[0] -= this@minus + } + ) + } +// if (degree == -1) UnivariatePolynomial(other) else UnivariatePolynomial( +// listOf(coefficients[0] + other) + coefficients.subList(1, degree + 1) +// ) + public override operator fun C.times(other: Polynomial): Polynomial = + Polynomial( + other.coefficients +// .subList(0, other.degree + 1) + .map { it * this } + ) + // endregion + + // region Polynomial-constant relation + public override operator fun Polynomial.plus(other: C): Polynomial = + if (other.isZero()) this + else with(coefficients) { + if (isEmpty()) Polynomial(listOf(other)) + else Polynomial( + toMutableList() + .apply { + this[0] += other + } + ) + } +// if (degree == -1) UnivariatePolynomial(other) else UnivariatePolynomial( +// listOf(coefficients[0] + other) + coefficients.subList(1, degree + 1) +// ) + public override operator fun Polynomial.minus(other: C): Polynomial = + with(coefficients) { + if (isEmpty()) Polynomial(listOf(other)) + else Polynomial( + toMutableList() + .apply { + this[0] -= other + } + ) + } +// if (degree == -1) UnivariatePolynomial(-other) else UnivariatePolynomial( +// listOf(coefficients[0] - other) + coefficients.subList(1, degree + 1) +// ) + public override operator fun Polynomial.times(other: C): Polynomial = + Polynomial( + coefficients +// .subList(0, degree + 1) + .map { it * other } + ) + // endregion + + // region Polynomial-polynomial relation + public override operator fun Polynomial.unaryMinus(): Polynomial = Polynomial(coefficients.map { -it }) - } - - override fun add(left: Polynomial, right: Polynomial): Polynomial { - val dim = max(left.coefficients.size, right.coefficients.size) - - return ring { - Polynomial(List(dim) { index -> - left.coefficients.getOrElse(index) { zero } + right.coefficients.getOrElse(index) { zero } - }) + public override operator fun Polynomial.plus(other: Polynomial): Polynomial = + Polynomial( + (0..max(degree, other.degree)) + .map { + when { + it > degree -> other.coefficients[it] + it > other.degree -> coefficients[it] + else -> coefficients[it] + other.coefficients[it] + } + } + .ifEmpty { listOf(ring.zero) } + ) + public override operator fun Polynomial.minus(other: Polynomial): Polynomial = + Polynomial( + (0..max(degree, other.degree)) + .map { + when { + it > degree -> -other.coefficients[it] + it > other.degree -> coefficients[it] + else -> coefficients[it] - other.coefficients[it] + } + } + .ifEmpty { listOf(ring.zero) } + ) + public override operator fun Polynomial.times(other: Polynomial): Polynomial { + val thisDegree = degree + val otherDegree = other.degree + return when { + thisDegree == -1 -> this + otherDegree == -1 -> other + else -> + Polynomial( + (0..(thisDegree + otherDegree)) + .map { d -> + (max(0, d - otherDegree)..(min(thisDegree, d))) + .map { coefficients[it] * other.coefficients[d - it] } + .reduce { acc, rational -> acc + rational } + } + ) } } - override fun scale(a: Polynomial, value: Double): Polynomial = - ring { Polynomial(List(a.coefficients.size) { index -> a.coefficients[index] * value }) } + public override fun Polynomial.isZero(): Boolean = coefficients.all { it.isZero() } + public override fun Polynomial.isNotZero(): Boolean = coefficients.any { it.isNotZero() } + public override fun Polynomial.isOne(): Boolean = + with(coefficients) { isNotEmpty() && asSequence().withIndex().any { (index, c) -> if (index == 0) c.isOne() else c.isZero() } } // TODO: It's better to write new methods like `anyIndexed`. But what's better way to do it? + public override fun Polynomial.isNotOne(): Boolean = !isOne() + public override fun Polynomial.isMinusOne(): Boolean = + with(coefficients) { isNotEmpty() && asSequence().withIndex().any { (index, c) -> if (index == 0) c.isMinusOne() else c.isZero() } } // TODO: It's better to write new methods like `anyIndexed`. But what's better way to do it? + public override fun Polynomial.isNotMinusOne(): Boolean = !isMinusOne() + + override val zero: Polynomial = Polynomial(emptyList()) + override val one: Polynomial = Polynomial(listOf(ring.one)) + + @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") + public override fun Polynomial.equals(other: Polynomial): Boolean = + when { + this === other -> true + else -> { + if (this.degree == other.degree) + (0..degree).all { coefficients[it] == other.coefficients[it] } + else false + } + } + // endregion + + // Not sure is it necessary... + // region Polynomial properties + public override val Polynomial.degree: Int get() = coefficients.indexOfLast { it != ring.zero } + + public override fun Polynomial.asConstantOrNull(): C? = + with(coefficients) { + when { + isEmpty() -> ring.zero + degree > 0 -> null + else -> first() + } + } + public override fun Polynomial.asConstant(): C = asConstantOrNull() ?: error("Can not represent non-constant polynomial as a constant") + + @Suppress("NOTHING_TO_INLINE") + public inline fun Polynomial.substitute(argument: C): C = this.substitute(ring, argument) + @Suppress("NOTHING_TO_INLINE") + public inline fun Polynomial.substitute(argument: Polynomial): Polynomial = this.substitute(ring, argument) + + @Suppress("NOTHING_TO_INLINE") + public inline fun Polynomial.asFunction(): (C) -> C = { this.substitute(ring, it) } + @Suppress("NOTHING_TO_INLINE") + public inline fun Polynomial.asFunctionOnConstants(): (C) -> C = { this.substitute(ring, it) } + @Suppress("NOTHING_TO_INLINE") + public inline fun Polynomial.asFunctionOnPolynomials(): (Polynomial) -> Polynomial = { this.substitute(ring, it) } /** * Evaluates the polynomial for the given value [arg]. */ - public operator fun Polynomial.invoke(arg: T): T = value(ring, arg) - - public fun Polynomial.asFunction(): (T) -> T = asFunction(ring) + @Suppress("NOTHING_TO_INLINE") + public inline operator fun Polynomial.invoke(argument: C): C = this.substitute(ring, argument) + @Suppress("NOTHING_TO_INLINE") + public inline operator fun Polynomial.invoke(argument: Polynomial): Polynomial = this.substitute(ring, argument) + // endregion } -public inline fun C.polynomial(block: PolynomialSpace.() -> R): R where C : Ring, C : ScaleOperations { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return PolynomialSpace(this).block() +/** + * Space of polynomials constructed over ring. + * + * @param C the type of constants. Polynomials have them as a coefficients in their terms. + * @param A type of underlying ring of constants. It's [Ring] of [C]. + * @param ring underlying ring of constants of type [A]. + */ +public class ScalablePolynomialSpace( + ring: A, +) : PolynomialSpace(ring), ScaleOperations> where A : Ring, A : ScaleOperations { + + override fun scale(a: Polynomial, value: Double): Polynomial = + ring { Polynomial(List(a.coefficients.size) { index -> a.coefficients[index] * value }) } + } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt new file mode 100644 index 000000000..1a3eb7874 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt @@ -0,0 +1,139 @@ +/* + * 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.functions + +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.* +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract +import kotlin.jvm.JvmName +import kotlin.math.pow + + +// region Utilities + +/** + * Removes zeros on the end of the coefficient list of polynomial. + */ +//context(PolynomialSpace) +//fun > Polynomial.removeZeros() : Polynomial = +// if (degree > -1) Polynomial(coefficients.subList(0, degree + 1)) else zero + +/** + * Crates a [PolynomialSpace] over received ring. + */ +public fun > A.polynomial(): PolynomialSpace = + PolynomialSpace(this) + +/** + * Crates a [PolynomialSpace]'s scope over received ring. + */ +public inline fun , R> A.polynomial(block: PolynomialSpace.() -> R): R { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return PolynomialSpace(this).block() +} + +/** + * Crates a [ScalablePolynomialSpace] over received scalable ring. + */ +public fun A.scalablePolynomial(): ScalablePolynomialSpace where A : Ring, A : ScaleOperations = + ScalablePolynomialSpace(this) + +/** + * Crates a [ScalablePolynomialSpace]'s scope over received scalable ring. + */ +public inline fun A.scalablePolynomial(block: ScalablePolynomialSpace.() -> R): R where A : Ring, A : ScaleOperations { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return ScalablePolynomialSpace(this).block() +} + +// endregion + +// region Polynomial substitution and functional representation + +// TODO: May be apply Horner's method too? +/** + * Evaluates the value of the given double polynomial for given double argument. + */ +public fun Polynomial.substitute(arg: Double): Double = + coefficients.reduceIndexedOrNull { index, acc, c -> + acc + c * arg.pow(index) + } ?: .0 + +/** + * Evaluates the value of the given polynomial for given argument. + * + * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). + */ +public fun Polynomial.substitute(ring: Ring, arg: C): C = ring { + if (coefficients.isEmpty()) return@ring zero + var result: C = coefficients.last() + for (j in coefficients.size - 2 downTo 0) { + result = (arg * result) + coefficients[j] + } + return result +} + +// TODO: (Waiting for hero) Replace with optimisation: the [result] may be unboxed, and all operations may be performed +// as soon as possible on it +public fun Polynomial.substitute(ring: Ring, arg: Polynomial) : Polynomial = ring.polynomial { + if (coefficients.isEmpty()) return zero + var result: Polynomial = coefficients.last().asPolynomial() + for (j in coefficients.size - 2 downTo 0) { + result = (arg * result) + coefficients[j] + } + return result +} + +/** + * Represent the polynomial as a regular context-less function. + */ +public fun > Polynomial.asFunction(ring: A): (C) -> C = { substitute(ring, it) } + +/** + * Represent the polynomial as a regular context-less function. + */ +public fun > Polynomial.asPolynomialFunctionOver(ring: A): (Polynomial) -> Polynomial = { substitute(ring, it) } + +// endregion + +// region Algebraic derivative and antiderivative + +/** + * Returns algebraic derivative of received polynomial. + */ +@UnstableKMathAPI +public fun Polynomial.derivative( + algebra: A, +): Polynomial where A : Ring, A : NumericAlgebra = algebra { + Polynomial(coefficients.drop(1).mapIndexed { index, t -> number(index) * t }) +} + +/** + * Create a polynomial witch represents indefinite integral version of this polynomial + */ +@UnstableKMathAPI +public fun Polynomial.antiderivative( + algebra: A, +): Polynomial where A : Field, A : NumericAlgebra = algebra { + val integratedCoefficients = buildList(coefficients.size + 1) { + add(zero) + coefficients.forEachIndexed{ index, t -> add(t / (number(index) + one)) } + } + Polynomial(integratedCoefficients) +} + +/** + * Compute a definite integral of a given polynomial in a [range] + */ +@UnstableKMathAPI +public fun > Polynomial.integrate( + algebra: Field, + range: ClosedRange, +): C = algebra { + val integral = antiderivative(algebra) + integral.substitute(algebra, range.endInclusive) - integral.substitute(algebra, range.start) +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt index eb88d9ae0..0fcd4c6e5 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt @@ -7,6 +7,7 @@ package space.kscience.kmath.integration import space.kscience.kmath.functions.PiecewisePolynomial import space.kscience.kmath.functions.integrate +import space.kscience.kmath.functions.antiderivative import space.kscience.kmath.interpolation.PolynomialInterpolator import space.kscience.kmath.interpolation.SplineInterpolator import space.kscience.kmath.interpolation.interpolatePolynomials @@ -23,7 +24,7 @@ import space.kscience.kmath.structures.MutableBufferFactory @OptIn(PerformancePitfall::class) @UnstableKMathAPI public fun > PiecewisePolynomial.integrate(algebra: Field): PiecewisePolynomial = - PiecewisePolynomial(pieces.map { it.first to it.second.integrate(algebra) }) + PiecewisePolynomial(pieces.map { it.first to it.second.antiderivative(algebra) }) /** * Compute definite integral of given [PiecewisePolynomial] piece by piece in a given [range] diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt index 2266092a3..62819be0c 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt @@ -10,7 +10,7 @@ package space.kscience.kmath.interpolation import space.kscience.kmath.data.XYColumnarData import space.kscience.kmath.functions.PiecewisePolynomial import space.kscience.kmath.functions.asFunction -import space.kscience.kmath.functions.value +import space.kscience.kmath.functions.substitute import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.Ring import space.kscience.kmath.structures.Buffer @@ -34,7 +34,7 @@ public interface PolynomialInterpolator> : Interpolator): PiecewisePolynomial override fun interpolate(points: XYColumnarData): (T) -> T = { x -> - interpolatePolynomials(points).value(algebra, x) ?: getDefaultValue() + interpolatePolynomials(points).substitute(algebra, x) ?: getDefaultValue() } } 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 05c16d17e..e0f0e32a4 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,13 +5,22 @@ package space.kscience.kmath.functions +import space.kscience.kmath.operations.algebra import kotlin.test.Test import kotlin.test.assertEquals class PolynomialTest { + @Test + fun simple_polynomial_test() { + Double.algebra.scalablePolynomial { + val x = Polynomial(listOf(0.0, 1.0)) + val polynomial = x * x - 2 * x + 1 + assertEquals(0.0, polynomial.substitute(1.0), 0.001) + } + } @Test fun testIntegration() { val polynomial = Polynomial(1.0, -2.0, 1.0) - assertEquals(0.0, polynomial.value(1.0), 0.001) + assertEquals(0.0, polynomial.substitute(1.0), 0.001) } } \ No newline at end of file -- 2.34.1 From cab59581071d25e2a569ad3bb13eb799e42e046f Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Thu, 10 Mar 2022 01:44:14 +0300 Subject: [PATCH 006/123] Added abstract rational functions --- .../kmath/functions/AbstractPolynomial.kt | 16 +- .../functions/AbstractRationalFunction.kt | 507 ++++++++++++++++++ 2 files changed, 515 insertions(+), 8 deletions(-) create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt index f6a617656..237a72bcc 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt @@ -70,19 +70,19 @@ public interface AbstractPolynomialSpace> : Ring

// region Polynomial-integer relation /** - * Returns sum of the constant and the integer represented as polynomial. + * Returns sum of the polynomial and the integer represented as polynomial. * * The operation is equivalent to adding [other] copies of unit polynomial to [this]. */ public operator fun P.plus(other: Int): P = optimizedAddMultiplied(this, one, other) /** - * Returns difference between the constant and the integer represented as polynomial. + * Returns difference between the polynomial and the integer represented as polynomial. * * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. */ public operator fun P.minus(other: Int): P = optimizedAddMultiplied(this, one, -other) /** - * Returns product of the constant and the integer represented as polynomial. + * Returns product of the polynomial and the integer represented as polynomial. * * The operation is equivalent to sum of [other] copies of [this]. */ @@ -91,19 +91,19 @@ public interface AbstractPolynomialSpace> : Ring

// region Integer-polynomial relation /** - * Returns sum of the integer represented as polynomial and the constant. + * Returns sum of the integer represented as polynomial and the polynomial. * * The operation is equivalent to adding [this] copies of unit polynomial to [other]. */ public operator fun Int.plus(other: P): P = optimizedAddMultiplied(other, one, this) /** - * Returns difference between the integer represented as polynomial and the constant. + * Returns difference between the integer represented as polynomial and the polynomial. * * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. */ public operator fun Int.minus(other: P): P = optimizedAddMultiplied(-other, one, this) /** - * Returns product of the integer represented as polynomial and the constant. + * Returns product of the integer represented as polynomial and the polynomial. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -254,11 +254,11 @@ public interface AbstractPolynomialSpace> : Ring

/** * Instance of zero polynomial (zero of the polynomial ring). */ - override val zero: P + public override val zero: P /** * Instance of unit polynomial (unit of the polynomial ring). */ - override val one: P + public override val one: P /** * Checks equality of the polynomials. diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt new file mode 100644 index 000000000..5cb570c9f --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt @@ -0,0 +1,507 @@ +/* + * 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.functions + +import space.kscience.kmath.functions.AbstractPolynomialSpace.Companion.optimizedAddMultiplied +import space.kscience.kmath.functions.AbstractPolynomialSpace.Companion.optimizedMultiply +import space.kscience.kmath.operations.* +import kotlin.js.JsName +import kotlin.jvm.JvmName + + +/** + * Abstraction of rational function. + */ +public interface AbstractRationalFunction> + +@Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") +public interface AbstractRationalFunctionalSpace, R: AbstractRationalFunction> : Ring { + // region Constant-integer relation + /** + * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * + * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. + */ + @JvmName("constantIntPlus") + public operator fun C.plus(other: Int): C + /** + * Returns difference between the constant and the integer represented as constant (member of underlying ring). + * + * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. + */ + @JvmName("constantIntMinus") + public operator fun C.minus(other: Int): C + /** + * Returns product of the constant and the integer represented as constant (member of underlying ring). + * + * The operation is equivalent to sum of [other] copies of [this]. + */ + @JvmName("constantIntTimes") + public operator fun C.times(other: Int): C + // endregion + + // region Integer-constant relation + /** + * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * + * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. + */ + @JvmName("intConstantPlus") + public operator fun Int.plus(other: C): C + /** + * Returns difference between the integer represented as constant (member of underlying ring) and the constant. + * + * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. + */ + @JvmName("intConstantMinus") + public operator fun Int.minus(other: C): C + /** + * Returns product of the integer represented as constant (member of underlying ring) and the constant. + * + * The operation is equivalent to sum of [this] copies of [other]. + */ + @JvmName("intConstantTimes") + public operator fun Int.times(other: C): C + // endregion + + // region Polynomial-integer relation + /** + * Returns sum of the constant and the integer represented as polynomial. + * + * The operation is equivalent to adding [other] copies of unit polynomial to [this]. + */ + public operator fun P.plus(other: Int): P + /** + * Returns difference between the constant and the integer represented as polynomial. + * + * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. + */ + public operator fun P.minus(other: Int): P + /** + * Returns product of the constant and the integer represented as polynomial. + * + * The operation is equivalent to sum of [other] copies of [this]. + */ + public operator fun P.times(other: Int): P + // endregion + + // region Integer-polynomial relation + /** + * Returns sum of the integer represented as polynomial and the constant. + * + * The operation is equivalent to adding [this] copies of unit polynomial to [other]. + */ + public operator fun Int.plus(other: P): P + /** + * Returns difference between the integer represented as polynomial and the constant. + * + * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. + */ + public operator fun Int.minus(other: P): P + /** + * Returns product of the integer represented as polynomial and the constant. + * + * The operation is equivalent to sum of [this] copies of [other]. + */ + public operator fun Int.times(other: P): P + // endregion + + // region Rational-integer relation + /** + * Returns sum of the rational function and the integer represented as rational function. + * + * The operation is equivalent to adding [other] copies of unit polynomial to [this]. + */ + public operator fun R.plus(other: Int): R = optimizedAddMultiplied(this, one, other) + /** + * Returns difference between the rational function and the integer represented as rational function. + * + * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. + */ + public operator fun R.minus(other: Int): R = optimizedAddMultiplied(this, one, -other) + /** + * Returns product of the rational function and the integer represented as rational function. + * + * The operation is equivalent to sum of [other] copies of [this]. + */ + public operator fun R.times(other: Int): R = optimizedMultiply(this, other) + // endregion + + // region Integer-Rational relation + /** + * Returns sum of the integer represented as rational function and the rational function. + * + * The operation is equivalent to adding [this] copies of unit polynomial to [other]. + */ + public operator fun Int.plus(other: R): R = optimizedAddMultiplied(other, one, this) + /** + * Returns difference between the integer represented as rational function and the rational function. + * + * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. + */ + public operator fun Int.minus(other: R): R = optimizedAddMultiplied(-other, one, this) + /** + * Returns product of the integer represented as rational function and the rational function. + * + * The operation is equivalent to sum of [this] copies of [other]. + */ + public operator fun Int.times(other: R): R = optimizedMultiply(other, this) + // endregion + + // region Constant-constant relation + /** + * Returns the same constant. + */ + @JvmName("constantUnaryPlus") + @JsName("constantUnaryPlus") + public operator fun C.unaryPlus(): C = this + /** + * Returns negation of the constant. + */ + @JvmName("constantUnaryMinus") + @JsName("constantUnaryMinus") + public operator fun C.unaryMinus(): C + /** + * Returns sum of the constants. + */ + @JvmName("constantPlus") + @JsName("constantPlus") + public operator fun C.plus(other: C): C + /** + * Returns difference of the constants. + */ + @JvmName("constantMinus") + @JsName("constantMinus") + public operator fun C.minus(other: C): C + /** + * Returns product of the constants. + */ + @JvmName("constantTimes") + @JsName("constantTimes") + public operator fun C.times(other: C): C + + /** + * Check if the instant is zero constant. + */ + @JvmName("constantIsZero") + public fun C.isZero(): Boolean + /** + * Check if the instant is NOT zero constant. + */ + @JvmName("constantIsNotZero") + public fun C.isNotZero(): Boolean + /** + * Check if the instant is unit constant. + */ + @JvmName("constantIsOne") + public fun C.isOne(): Boolean + /** + * Check if the instant is NOT unit constant. + */ + @JvmName("constantIsNotOne") + public fun C.isNotOne(): Boolean + /** + * Check if the instant is minus unit constant. + */ + @JvmName("constantIsMinusOne") + public fun C.isMinusOne(): Boolean + /** + * Check if the instant is NOT minus unit constant. + */ + @JvmName("constantIsNotMinusOne") + public fun C.isNotMinusOne(): Boolean + // endregion + + // region Constant-polynomial relation + /** + * Returns sum of the constant represented as polynomial and the polynomial. + */ + public operator fun C.plus(other: P): P + /** + * Returns difference between the constant represented as polynomial and the polynomial. + */ + public operator fun C.minus(other: P): P + /** + * Returns product of the constant represented as polynomial and the polynomial. + */ + public operator fun C.times(other: P): P + // endregion + + // region Polynomial-constant relation + /** + * Returns sum of the constant represented as polynomial and the polynomial. + */ + public operator fun P.plus(other: C): P + /** + * Returns difference between the constant represented as polynomial and the polynomial. + */ + public operator fun P.minus(other: C): P + /** + * Returns product of the constant represented as polynomial and the polynomial. + */ + public operator fun P.times(other: C): P + // endregion + + // region Polynomial-polynomial relation + /** + * Returns the same polynomial. + */ + public operator fun P.unaryPlus(): P = this + /** + * Returns negation of the polynomial. + */ + public operator fun P.unaryMinus(): P + /** + * Returns sum of the polynomials. + */ + public operator fun P.plus(other: P): P + /** + * Returns difference of the polynomials. + */ + public operator fun P.minus(other: P): P + /** + * Returns product of the polynomials. + */ + public operator fun P.times(other: P): P + + /** + * Check if the instant is zero polynomial. + */ + public fun P.isZero(): Boolean = this == zeroPolynomial + /** + * Check if the instant is NOT zero polynomial. + */ + public fun P.isNotZero(): Boolean = this != zeroPolynomial + /** + * Check if the instant is unit polynomial. + */ + public fun P.isOne(): Boolean = this == onePolynomial + /** + * Check if the instant is NOT unit polynomial. + */ + public fun P.isNotOne(): Boolean = this != onePolynomial + /** + * Check if the instant is minus unit polynomial. + */ + public fun P.isMinusOne(): Boolean = this == -onePolynomial + /** + * Check if the instant is NOT minus unit polynomial. + */ + public fun P.isNotMinusOne(): Boolean = this != -onePolynomial + + /** + * Instance of zero polynomial (zero of the polynomial ring). + */ + public val zeroPolynomial: P + /** + * Instance of unit polynomial (unit of the polynomial ring). + */ + public val onePolynomial: P + + /** + * Checks equality of the polynomials. + */ + @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") + public fun P.equals(other: P): Boolean + // endregion + + // region Constant-rational relation + /** + * Returns sum of the constant represented as rational function and the rational function. + */ + public operator fun C.plus(other: R): R + /** + * Returns difference between the constant represented as polynomial and the rational function. + */ + public operator fun C.minus(other: R): R + /** + * Returns product of the constant represented as polynomial and the rational function. + */ + public operator fun C.times(other: R): R + // endregion + + // region Rational-constant relation + /** + * Returns sum of the constant represented as rational function and the rational function. + */ + public operator fun R.plus(other: C): R + /** + * Returns difference between the constant represented as rational function and the rational function. + */ + public operator fun R.minus(other: C): R + /** + * Returns product of the constant represented as rational function and the rational function. + */ + public operator fun R.times(other: C): R + // endregion + + // region Polynomial-rational relation + /** + * Returns sum of the polynomial represented as rational function and the rational function. + */ + public operator fun P.plus(other: R): R + /** + * Returns difference between the polynomial represented as polynomial and the rational function. + */ + public operator fun P.minus(other: R): R + /** + * Returns product of the polynomial represented as polynomial and the rational function. + */ + public operator fun P.times(other: R): R + // endregion + + // region Rational-polynomial relation + /** + * Returns sum of the polynomial represented as rational function and the rational function. + */ + public operator fun R.plus(other: P): R + /** + * Returns difference between the polynomial represented as rational function and the rational function. + */ + public operator fun R.minus(other: P): R + /** + * Returns product of the polynomial represented as rational function and the rational function. + */ + public operator fun R.times(other: P): R + // endregion + + // region Rational-rational relation + /** + * Returns the same rational function. + */ + public override operator fun R.unaryPlus(): R = this + /** + * Returns negation of the rational function. + */ + public override operator fun R.unaryMinus(): R + /** + * Returns sum of the rational functions. + */ + public override operator fun R.plus(other: R): R + /** + * Returns difference of the rational functions. + */ + public override operator fun R.minus(other: R): R + /** + * Returns product of the rational functions. + */ + public override operator fun R.times(other: R): R + + /** + * Check if the instant is zero rational function. + */ + public fun R.isZero(): Boolean = this == zero + /** + * Check if the instant is NOT zero rational function. + */ + public fun R.isNotZero(): Boolean = this != zero + /** + * Check if the instant is unit rational function. + */ + public fun R.isOne(): Boolean = this == one + /** + * Check if the instant is NOT unit rational function. + */ + public fun R.isNotOne(): Boolean = this != one + /** + * Check if the instant is minus unit rational function. + */ + public fun R.isMinusOne(): Boolean = this == -one + /** + * Check if the instant is NOT minus unit rational function. + */ + public fun R.isNotMinusOne(): Boolean = this != -one + + /** + * Instance of zero rational function (zero of the rational functions ring). + */ + public override val zero: R + /** + * Instance of unit polynomial (unit of the rational functions ring). + */ + public override val one: R + + /** + * Checks equality of the rational functions. + */ + @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") + public fun R.equals(other: R): Boolean + // endregion + + // Not sure is it necessary... + // region Polynomial properties + /** + * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is + * zero, degree is -1. + */ + public val P.degree: Int + + /** + * Checks if the instant is constant polynomial (of degree no more than 0) over considered ring. + */ + public fun P.isConstant(): Boolean = degree <= 0 + /** + * Checks if the instant is **not** constant polynomial (of degree no more than 0) over considered ring. + */ + public fun P.isNotConstant(): Boolean = !isConstant() + /** + * Checks if the instant is constant non-zero polynomial (of degree no more than 0) over considered ring. + */ + public fun P.isNonZeroConstant(): Boolean = degree == 0 + /** + * Checks if the instant is **not** constant non-zero polynomial (of degree no more than 0) over considered ring. + */ + public fun P.isNotNonZeroConstant(): Boolean = !isNonZeroConstant() + + public fun P.asConstantOrNull(): C? + + public fun P.asConstant(): C = asConstantOrNull() ?: error("Can not represent non-constant polynomial as a constant") + + // endregion + + // Not sure is it necessary... + // region Polynomial properties + /** + * Checks if the instant is constant polynomial (of degree no more than 0) over considered ring. + */ + public fun R.isConstant(): Boolean + /** + * Checks if the instant is **not** constant polynomial (of degree no more than 0) over considered ring. + */ + public fun R.isNotConstant(): Boolean = !isConstant() + /** + * Checks if the instant is constant non-zero polynomial (of degree no more than 0) over considered ring. + */ + public fun R.isNonZeroConstant(): Boolean + /** + * Checks if the instant is **not** constant non-zero polynomial (of degree no more than 0) over considered ring. + */ + public fun R.isNotNonZeroConstant(): Boolean = !isNonZeroConstant() + + public fun R.asConstantOrNull(): C? + + public fun R.asConstant(): C = asConstantOrNull() ?: error("Can not represent non-constant polynomial as a constant") + + // TODO: Перенести в реализацию +// fun R.substitute(argument: C): C +// fun R.substitute(argument: P): R +// fun R.substitute(argument: R): R +// +// fun R.asFunction(): (C) -> C = /*this::substitute*/ { this.substitute(it) } +// fun R.asFunctionOnConstants(): (C) -> C = /*this::substitute*/ { this.substitute(it) } +// fun P.asFunctionOnPolynomials(): (P) -> R = /*this::substitute*/ { this.substitute(it) } +// fun R.asFunctionOnRationalFunctions(): (R) -> R = /*this::substitute*/ { this.substitute(it) } +// +// operator fun R.invoke(argument: C): C = this.substitute(argument) +// operator fun R.invoke(argument: P): R = this.substitute(argument) +// operator fun R.invoke(argument: R): R = this.substitute(argument) + // endregion + + // region Legacy + override fun add(left: R, right: R): R = left + right + override fun multiply(left: R, right: R): R = left * right + // endregion +} \ No newline at end of file -- 2.34.1 From 571c6342ddcead43bbcd99b1583e86366212f802 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sun, 13 Mar 2022 03:25:25 +0300 Subject: [PATCH 007/123] Regenerated READMEs --- README.md | 4 ++-- kmath-ast/README.md | 47 +++++++++++++++++++++++++++++--------- kmath-complex/README.md | 6 ++--- kmath-core/README.md | 6 ++--- kmath-ejml/README.md | 6 ++--- kmath-for-real/README.md | 6 ++--- kmath-functions/README.md | 6 ++--- kmath-jafama/README.md | 6 ++--- kmath-kotlingrad/README.md | 6 ++--- kmath-nd4j/README.md | 6 ++--- kmath-tensors/README.md | 6 ++--- 11 files changed, 65 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index 99dd6d00f..76b8ce2f7 100644 --- a/README.md +++ b/README.md @@ -308,8 +308,8 @@ repositories { } dependencies { - api("space.kscience:kmath-core:0.3.0-dev-17") - // api("space.kscience:kmath-core-jvm:0.3.0-dev-17") for jvm-specific version + api("space.kscience:kmath-core:0.3.0-dev-19") + // api("space.kscience:kmath-core-jvm:0.3.0-dev-19") for jvm-specific version } ``` diff --git a/kmath-ast/README.md b/kmath-ast/README.md index bedf17486..9411befe3 100644 --- a/kmath-ast/README.md +++ b/kmath-ast/README.md @@ -10,7 +10,7 @@ Extensions to MST API: transformations, dynamic compilation and visualization. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-ast:0.3.0-dev-17`. +The Maven coordinates of this project are `space.kscience:kmath-ast:0.3.0-dev-19`. **Gradle:** ```gradle @@ -20,7 +20,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-ast:0.3.0-dev-17' + implementation 'space.kscience:kmath-ast:0.3.0-dev-19' } ``` **Gradle Kotlin DSL:** @@ -31,7 +31,7 @@ repositories { } dependencies { - implementation("space.kscience:kmath-ast:0.3.0-dev-17") + implementation("space.kscience:kmath-ast:0.3.0-dev-19") } ``` @@ -66,20 +66,19 @@ For example, the following code: ```kotlin import space.kscience.kmath.asm.compileToExpression -import space.kscience.kmath.complex.ComplexField +import space.kscience.kmath.operations.DoubleField -"x+2".parseMath().compileToExpression(ComplexField) +"x^3-x+3".parseMath().compileToExpression(DoubleField) ``` … leads to generation of bytecode, which can be decompiled to the following Java class: ```java -import java.util.Map; -import kotlin.jvm.functions.Function2; -import space.kscience.kmath.asm.internal.MapIntrinsics; -import space.kscience.kmath.complex.Complex; -import space.kscience.kmath.expressions.Expression; -import space.kscience.kmath.expressions.Symbol; +import java.util.*; +import kotlin.jvm.functions.*; +import space.kscience.kmath.asm.internal.*; +import space.kscience.kmath.complex.*; +import space.kscience.kmath.expressions.*; public final class CompiledExpression_45045_0 implements Expression { private final Object[] constants; @@ -91,6 +90,32 @@ public final class CompiledExpression_45045_0 implements Expression { } ``` +For `LongRing`, `IntRing`, and `DoubleField` specialization is supported for better performance: + +```java +import java.util.*; +import space.kscience.kmath.asm.internal.*; +import space.kscience.kmath.expressions.*; + +public final class CompiledExpression_-386104628_0 implements DoubleExpression { + private final SymbolIndexer indexer; + + public SymbolIndexer getIndexer() { + return this.indexer; + } + + public double invoke(double[] arguments) { + double var2 = arguments[0]; + return Math.pow(var2, 3.0D) - var2 + 3.0D; + } + + public final Double invoke(Map arguments) { + double var2 = ((Double)MapIntrinsics.getOrFail(arguments, "x")).doubleValue(); + return Math.pow(var2, 3.0D) - var2 + 3.0D; + } +} +``` + Setting JVM system property `space.kscience.kmath.ast.dump.generated.classes` to `1` makes the translator dump class files to program's working directory, so they can be reviewed manually. #### Limitations diff --git a/kmath-complex/README.md b/kmath-complex/README.md index 92f2435ba..cfaf43aa1 100644 --- a/kmath-complex/README.md +++ b/kmath-complex/README.md @@ -8,7 +8,7 @@ Complex and hypercomplex number systems in KMath. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-complex:0.3.0-dev-17`. +The Maven coordinates of this project are `space.kscience:kmath-complex:0.3.0-dev-19`. **Gradle:** ```gradle @@ -18,7 +18,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-complex:0.3.0-dev-17' + implementation 'space.kscience:kmath-complex:0.3.0-dev-19' } ``` **Gradle Kotlin DSL:** @@ -29,6 +29,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-complex:0.3.0-dev-17") + implementation("space.kscience:kmath-complex:0.3.0-dev-19") } ``` diff --git a/kmath-core/README.md b/kmath-core/README.md index e765ad50c..4e980baf5 100644 --- a/kmath-core/README.md +++ b/kmath-core/README.md @@ -15,7 +15,7 @@ performance calculations to code generation. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-core:0.3.0-dev-17`. +The Maven coordinates of this project are `space.kscience:kmath-core:0.3.0-dev-19`. **Gradle:** ```gradle @@ -25,7 +25,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-core:0.3.0-dev-17' + implementation 'space.kscience:kmath-core:0.3.0-dev-19' } ``` **Gradle Kotlin DSL:** @@ -36,6 +36,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-core:0.3.0-dev-17") + implementation("space.kscience:kmath-core:0.3.0-dev-19") } ``` diff --git a/kmath-ejml/README.md b/kmath-ejml/README.md index fcd092bf1..24b36aa0d 100644 --- a/kmath-ejml/README.md +++ b/kmath-ejml/README.md @@ -9,7 +9,7 @@ EJML based linear algebra implementation. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-ejml:0.3.0-dev-17`. +The Maven coordinates of this project are `space.kscience:kmath-ejml:0.3.0-dev-19`. **Gradle:** ```gradle @@ -19,7 +19,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-ejml:0.3.0-dev-17' + implementation 'space.kscience:kmath-ejml:0.3.0-dev-19' } ``` **Gradle Kotlin DSL:** @@ -30,6 +30,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-ejml:0.3.0-dev-17") + implementation("space.kscience:kmath-ejml:0.3.0-dev-19") } ``` diff --git a/kmath-for-real/README.md b/kmath-for-real/README.md index 938327612..f6b02e6ad 100644 --- a/kmath-for-real/README.md +++ b/kmath-for-real/README.md @@ -9,7 +9,7 @@ Specialization of KMath APIs for Double numbers. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-for-real:0.3.0-dev-17`. +The Maven coordinates of this project are `space.kscience:kmath-for-real:0.3.0-dev-19`. **Gradle:** ```gradle @@ -19,7 +19,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-for-real:0.3.0-dev-17' + implementation 'space.kscience:kmath-for-real:0.3.0-dev-19' } ``` **Gradle Kotlin DSL:** @@ -30,6 +30,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-for-real:0.3.0-dev-17") + implementation("space.kscience:kmath-for-real:0.3.0-dev-19") } ``` diff --git a/kmath-functions/README.md b/kmath-functions/README.md index 3d4beee47..a7f4f9b6f 100644 --- a/kmath-functions/README.md +++ b/kmath-functions/README.md @@ -11,7 +11,7 @@ Functions and interpolations. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-functions:0.3.0-dev-17`. +The Maven coordinates of this project are `space.kscience:kmath-functions:0.3.0-dev-19`. **Gradle:** ```gradle @@ -21,7 +21,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-functions:0.3.0-dev-17' + implementation 'space.kscience:kmath-functions:0.3.0-dev-19' } ``` **Gradle Kotlin DSL:** @@ -32,6 +32,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-functions:0.3.0-dev-17") + implementation("space.kscience:kmath-functions:0.3.0-dev-19") } ``` diff --git a/kmath-jafama/README.md b/kmath-jafama/README.md index 760244751..3e0d9c418 100644 --- a/kmath-jafama/README.md +++ b/kmath-jafama/README.md @@ -7,7 +7,7 @@ Integration with [Jafama](https://github.com/jeffhain/jafama). ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-jafama:0.3.0-dev-17`. +The Maven coordinates of this project are `space.kscience:kmath-jafama:0.3.0-dev-19`. **Gradle:** ```gradle @@ -17,7 +17,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-jafama:0.3.0-dev-17' + implementation 'space.kscience:kmath-jafama:0.3.0-dev-19' } ``` **Gradle Kotlin DSL:** @@ -28,7 +28,7 @@ repositories { } dependencies { - implementation("space.kscience:kmath-jafama:0.3.0-dev-17") + implementation("space.kscience:kmath-jafama:0.3.0-dev-19") } ``` diff --git a/kmath-kotlingrad/README.md b/kmath-kotlingrad/README.md index 588ccb9b4..422ce4fb0 100644 --- a/kmath-kotlingrad/README.md +++ b/kmath-kotlingrad/README.md @@ -8,7 +8,7 @@ ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-kotlingrad:0.3.0-dev-17`. +The Maven coordinates of this project are `space.kscience:kmath-kotlingrad:0.3.0-dev-19`. **Gradle:** ```gradle @@ -18,7 +18,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-kotlingrad:0.3.0-dev-17' + implementation 'space.kscience:kmath-kotlingrad:0.3.0-dev-19' } ``` **Gradle Kotlin DSL:** @@ -29,6 +29,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-kotlingrad:0.3.0-dev-17") + implementation("space.kscience:kmath-kotlingrad:0.3.0-dev-19") } ``` diff --git a/kmath-nd4j/README.md b/kmath-nd4j/README.md index 7ca9cd4fd..23d529e72 100644 --- a/kmath-nd4j/README.md +++ b/kmath-nd4j/README.md @@ -9,7 +9,7 @@ ND4J based implementations of KMath abstractions. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-nd4j:0.3.0-dev-17`. +The Maven coordinates of this project are `space.kscience:kmath-nd4j:0.3.0-dev-19`. **Gradle:** ```gradle @@ -19,7 +19,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-nd4j:0.3.0-dev-17' + implementation 'space.kscience:kmath-nd4j:0.3.0-dev-19' } ``` **Gradle Kotlin DSL:** @@ -30,7 +30,7 @@ repositories { } dependencies { - implementation("space.kscience:kmath-nd4j:0.3.0-dev-17") + implementation("space.kscience:kmath-nd4j:0.3.0-dev-19") } ``` diff --git a/kmath-tensors/README.md b/kmath-tensors/README.md index 42ce91336..93f78e895 100644 --- a/kmath-tensors/README.md +++ b/kmath-tensors/README.md @@ -9,7 +9,7 @@ Common linear algebra operations on tensors. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-tensors:0.3.0-dev-17`. +The Maven coordinates of this project are `space.kscience:kmath-tensors:0.3.0-dev-19`. **Gradle:** ```gradle @@ -19,7 +19,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-tensors:0.3.0-dev-17' + implementation 'space.kscience:kmath-tensors:0.3.0-dev-19' } ``` **Gradle Kotlin DSL:** @@ -30,6 +30,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-tensors:0.3.0-dev-17") + implementation("space.kscience:kmath-tensors:0.3.0-dev-19") } ``` -- 2.34.1 From 93de1d53116b29391797f68972c0f6bf144857d6 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sun, 13 Mar 2022 03:27:00 +0300 Subject: [PATCH 008/123] Added support for all polynomials. But standard utilities still are not fully implemented. --- .../kmath/functions/AbstractPolynomial.kt | 47 +- .../functions/AbstractRationalFunction.kt | 2 - .../kmath/functions/LabeledPolynomial.kt | 927 ++++++++++++++++++ .../kmath/functions/NumberedPolynomial.kt | 689 +++++++++++++ .../kscience/kmath/functions/Polynomial.kt | 151 ++- .../kscience/kmath/functions/Variable.kt | 38 + .../kscience/kmath/functions/algebraicStub.kt | 51 + .../kmath/functions/labeledPolynomialUtil.kt | 490 +++++++++ .../kmath/functions/numberedPolynomialUtil.kt | 605 ++++++++++++ .../kmath/functions/polynomialUtil.kt | 6 +- 10 files changed, 2911 insertions(+), 95 deletions(-) create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Variable.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt index 237a72bcc..b7b7116f0 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt @@ -17,6 +17,9 @@ public interface AbstractPolynomial /** * Abstraction of ring of polynomials of type [P] over ring of constants of type [C]. + * + * @param C the type of constants. Polynomials have them as a coefficients in their terms. + * @param P the type of polynomials. */ @Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") public interface AbstractPolynomialSpace> : Ring

{ @@ -307,48 +310,4 @@ public interface AbstractPolynomialSpace> : Ring

override fun add(left: P, right: P): P = left + right override fun multiply(left: P, right: P): P = left * right // endregion - - public companion object { - // TODO: All of this should be moved to algebraic structures' place for utilities - // TODO: Move receiver to context receiver - /** - * Multiplication of element and integer. - * - * @receiver the multiplicand. - * @param other the multiplier. - * @return the difference. - */ - internal tailrec fun Group.optimizedMultiply(arg: C, other: Int): C = - when { - other == 0 -> zero - other == 1 -> arg - other == -1 -> -arg - other % 2 == 0 -> optimizedMultiply(arg + arg, other / 2) - other % 2 == 1 -> optimizedAddMultiplied(arg, arg + arg, other / 2) - other % 2 == -1 -> optimizedAddMultiplied(-arg, arg + arg, other / 2) - else -> error("Error in multiplication group instant by integer: got reminder by division by 2 different from 0, 1 and -1") - } - - // TODO: Move receiver to context receiver - /** - * Adds product of [arg] and [multiplier] to [base]. - * - * @receiver the algebra to provide multiplication. - * @param base the augend. - * @param arg the multiplicand. - * @param multiplier the multiplier. - * @return sum of the augend [base] and product of the multiplicand [arg] and the multiplier [multiplier]. - * @author Gleb Minaev - */ - internal tailrec fun Group.optimizedAddMultiplied(base: C, arg: C, multiplier: Int): C = - when { - multiplier == 0 -> base - multiplier == 1 -> base + arg - multiplier == -1 -> base - arg - multiplier % 2 == 0 -> optimizedAddMultiplied(base, arg + arg, multiplier / 2) - multiplier % 2 == 1 -> optimizedAddMultiplied(base + arg, arg + arg, multiplier / 2) - multiplier % 2 == -1 -> optimizedAddMultiplied(base + arg, arg + arg, multiplier / 2) - else -> error("Error in multiplication group instant by integer: got reminder by division by 2 different from 0, 1 and -1") - } - } } \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt index 5cb570c9f..34050aa0f 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt @@ -5,8 +5,6 @@ package space.kscience.kmath.functions -import space.kscience.kmath.functions.AbstractPolynomialSpace.Companion.optimizedAddMultiplied -import space.kscience.kmath.functions.AbstractPolynomialSpace.Companion.optimizedMultiply import space.kscience.kmath.operations.* import kotlin.js.JsName import kotlin.jvm.JvmName diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt new file mode 100644 index 000000000..48f6f57fa --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt @@ -0,0 +1,927 @@ +package space.kscience.kmath.functions + +import space.kscience.kmath.operations.* +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract +import kotlin.experimental.ExperimentalTypeInference +import kotlin.jvm.JvmName +import kotlin.math.max + + +/** + * Represents multivariate polynomials with labeled variables. + * + * @param C Ring in which the polynomial is considered. + */ +public class LabeledPolynomial +internal constructor( + /** + * Map that collects coefficients of the polynomial. Every non-zero monomial + * `a x_1^{d_1} ... x_n^{d_n}` is represented as pair "key-value" in the map, where value is coefficients `a` and + * key is map that associates variables in the monomial with multiplicity of them occurring in the monomial. + * For example polynomial + * ``` + * 5 a^2 c^3 - 6 b + 0 b c + * ``` + * has coefficients represented as + * ``` + * mapOf( + * mapOf( + * a to 2, + * c to 3 + * ) to 5, + * mapOf( + * b to 1 + * ) to (-6) + * ) + * ``` + * where `a`, `b` and `c` are corresponding [Variable] objects. + */ + public val coefficients: Map, C> +) : AbstractPolynomial { + override fun toString(): String = "LabeledPolynomial$coefficients" +} + +// region Internal utilities + +/** + * Represents internal [LabeledPolynomial] errors. + */ +internal class LabeledPolynomialError: Error { + constructor(): super() + constructor(message: String): super(message) + constructor(message: String?, cause: Throwable?): super(message, cause) + constructor(cause: Throwable?): super(cause) +} + +/** + * Throws an [LabeledPolynomialError] with the given [message]. + */ +internal fun labeledPolynomialError(message: Any): Nothing = throw LabeledPolynomialError(message.toString()) + +/** + * Returns the same degrees description of the monomial, but without zero degrees. + */ +internal fun Map.cleanUp() = filterValues { it > 0U } + +// endregion + +// region Constructors and converters + +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received +// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. +// * +// * @param pairs Collection of pairs that represent monomials. +// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. +// * +// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(A) +//internal fun > LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = true): LabeledPolynomial { +// if (!toCheckInput) return LabeledPolynomial(coefs) +// +// // Map for cleaned coefficients. +// val fixedCoefs = mutableMapOf, C>() +// +// // Cleaning the degrees, summing monomials of the same degrees. +// for (entry in coefs) { +// val key = entry.key.cleanUp() +// val value = entry.value +// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value +// } +// +// // Removing zero monomials. +// return LabeledPolynomial( +// fixedCoefs +// .filter { it.value.isNotZero() } +// ) +//} +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received +// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. +// * +// * @param pairs Collection of pairs that represent monomials. +// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. +// * +// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(A) +//internal fun > LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean): LabeledPolynomial { +// if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) +// +// // Map for cleaned coefficients. +// val fixedCoefs = mutableMapOf, C>() +// +// // Cleaning the degrees, summing monomials of the same degrees. +// for (entry in pairs) { +// val key = entry.first.cleanUp() +// val value = entry.second +// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value +// } +// +// // Removing zero monomials. +// return LabeledPolynomial( +// fixedCoefs.filterValues { it.isNotZero() } +// ) +//} +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received +// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. +// * +// * @param pairs Collection of pairs that represents monomials. +// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. +// * +// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(A) +//internal fun > LabeledPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean): LabeledPolynomial { +// if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) +// +// // Map for cleaned coefficients. +// val fixedCoefs = mutableMapOf, C>() +// +// // Cleaning the degrees, summing monomials of the same degrees. +// for (entry in pairs) { +// val key = entry.first.cleanUp() +// val value = entry.second +// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value +// } +// +// // Removing zero monomials. +// return LabeledPolynomial( +// fixedCoefs.filterValues { it.isNotZero() } +// ) +//} +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received +// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. +// * +// * @param coefs Coefficients of the instants. +// * +// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(A) +//fun > LabeledPolynomial(coefs: Map, C>): LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received +// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. +// * +// * @param pairs Collection of pairs that represents monomials. +// * +// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(A) +//fun > LabeledPolynomial(pairs: Collection, C>>): LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received +// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. +// * +// * @param pairs Collection of pairs that represents monomials. +// * +// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(A) +//fun > LabeledPolynomial(vararg pairs: Pair, C>): LabeledPolynomial = LabeledPolynomial(*pairs, toCheckInput = true) +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received +// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. +// * +// * @param pairs Collection of pairs that represent monomials. +// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. +// * +// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(LabeledPolynomialSpace) +//internal fun > LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = true): LabeledPolynomial { +// if (!toCheckInput) return LabeledPolynomial(coefs) +// +// // Map for cleaned coefficients. +// val fixedCoefs = mutableMapOf, C>() +// +// // Cleaning the degrees, summing monomials of the same degrees. +// for (entry in coefs) { +// val key = entry.key.cleanUp() +// val value = entry.value +// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value +// } +// +// // Removing zero monomials. +// return LabeledPolynomial( +// fixedCoefs +// .filter { it.value.isNotZero() } +// ) +//} +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received +// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. +// * +// * @param pairs Collection of pairs that represent monomials. +// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. +// * +// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(LabeledPolynomialSpace) +//internal fun > LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean): LabeledPolynomial { +// if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) +// +// // Map for cleaned coefficients. +// val fixedCoefs = mutableMapOf, C>() +// +// // Cleaning the degrees, summing monomials of the same degrees. +// for (entry in pairs) { +// val key = entry.first.cleanUp() +// val value = entry.second +// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value +// } +// +// // Removing zero monomials. +// return LabeledPolynomial( +// fixedCoefs.filterValues { it.isNotZero() } +// ) +//} +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received +// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. +// * +// * @param pairs Collection of pairs that represents monomials. +// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. +// * +// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(LabeledPolynomialSpace) +//internal fun > LabeledPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean): LabeledPolynomial { +// if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) +// +// // Map for cleaned coefficients. +// val fixedCoefs = mutableMapOf, C>() +// +// // Cleaning the degrees, summing monomials of the same degrees. +// for (entry in pairs) { +// val key = entry.first.cleanUp() +// val value = entry.second +// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value +// } +// +// // Removing zero monomials. +// return LabeledPolynomial( +// fixedCoefs.filterValues { it.isNotZero() } +// ) +//} +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received +// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. +// * +// * @param coefs Coefficients of the instants. +// * +// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(LabeledPolynomialSpace) +//fun > LabeledPolynomial(coefs: Map, C>): LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received +// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. +// * +// * @param pairs Collection of pairs that represents monomials. +// * +// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(LabeledPolynomialSpace) +//fun > LabeledPolynomial(pairs: Collection, C>>): LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received +// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. +// * +// * @param pairs Collection of pairs that represents monomials. +// * +// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(LabeledPolynomialSpace) +//fun > LabeledPolynomial(vararg pairs: Pair, C>): LabeledPolynomial = LabeledPolynomial(*pairs, toCheckInput = true) +// +//fun C.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to this)) +// +//context(A) +//fun > Variable.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1U) to one)) +// +//context(LabeledPolynomialSpace) +//fun > Variable.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1U) to ring.one)) +// +//context(A) +//fun > Variable.asLabeledPolynomial(c: C) : LabeledPolynomial = +// if(c.isZero()) LabeledPolynomial(emptyMap()) +// else LabeledPolynomial(mapOf(mapOf(this to 1U) to c)) +// +//context(LabeledPolynomialSpace) +//fun > Variable.asLabeledPolynomial(c: C) : LabeledPolynomial = +// if(c.isZero()) zero +// else LabeledPolynomial(mapOf(mapOf(this to 1U) to c)) + +// endregion + +/** + * Space of polynomials. + * + * @param C the type of operated polynomials. + * @param A the intersection of [Ring] of [C] and [ScaleOperations] of [C]. + * @param ring the [A] instance. + */ +@Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE", "INAPPLICABLE_JVM_NAME") +public class LabeledPolynomialSpace>( + public val ring: A, +) : AbstractPolynomialSpace> { + // region Constant-integer relation + @JvmName("constantIntPlus") + public override operator fun C.plus(other: Int): C = ring { optimizedAddMultiplied(this@plus, one, other) } + @JvmName("constantIntMinus") + public override operator fun C.minus(other: Int): C = ring { optimizedAddMultiplied(this@minus, one, -other) } + @JvmName("constantIntTimes") + public override operator fun C.times(other: Int): C = ring { optimizedMultiply(this@times, other) } + // endregion + + // region Integer-constant relation + @JvmName("intConstantPlus") + public override operator fun Int.plus(other: C): C = ring { optimizedAddMultiplied(other, one, this@plus) } + @JvmName("intConstantMinus") + public override operator fun Int.minus(other: C): C = ring { optimizedAddMultiplied(-other, one, this@minus) } + @JvmName("intConstantTimes") + public override operator fun Int.times(other: C): C = ring { optimizedMultiply(other, this@times) } + // endregion + + // region Variable-integer relation + public operator fun Variable.plus(other: Int): LabeledPolynomial = + if (other == 0) LabeledPolynomial(mapOf( + mapOf(this@plus to 1U) to ring.one, + )) + else LabeledPolynomial(mapOf( + mapOf(this@plus to 1U) to ring.one, + emptyMap() to ring.one * other, + )) + public operator fun Variable.minus(other: Int): LabeledPolynomial = + if (other == 0) LabeledPolynomial(mapOf( + mapOf(this@minus to 1U) to -ring.one, + )) + else LabeledPolynomial(mapOf( + mapOf(this@minus to 1U) to -ring.one, + emptyMap() to ring.one * other, + )) + public operator fun Variable.times(other: Int): LabeledPolynomial = + if (other == 0) zero + else LabeledPolynomial(mapOf( + mapOf(this to 1U) to ring.one * other, + )) + // endregion + + // region Integer-variable relation + public operator fun Int.plus(other: Variable): LabeledPolynomial = + if (this == 0) LabeledPolynomial(mapOf( + mapOf(other to 1U) to ring.one, + )) + else LabeledPolynomial(mapOf( + mapOf(other to 1U) to ring.one, + emptyMap() to ring.one * this@plus, + )) + public operator fun Int.minus(other: Variable): LabeledPolynomial = + if (this == 0) LabeledPolynomial(mapOf( + mapOf(other to 1U) to -ring.one, + )) + else LabeledPolynomial(mapOf( + mapOf(other to 1U) to -ring.one, + emptyMap() to ring.one * this@minus, + )) + public operator fun Int.times(other: Variable): LabeledPolynomial = + if (this == 0) zero + else LabeledPolynomial(mapOf( + mapOf(other to 1U) to ring.one * this@times, + )) + // endregion + + // region Polynomial-integer relation + public override operator fun LabeledPolynomial.plus(other: Int): LabeledPolynomial = + if (other == 0) this + else + LabeledPolynomial( + coefficients + .toMutableMap() + .apply { + val degs = emptyMap() + + val result = getOrElse(degs) { ring.zero } + other + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + public override operator fun LabeledPolynomial.minus(other: Int): LabeledPolynomial = + if (other == 0) this + else + LabeledPolynomial( + coefficients + .toMutableMap() + .apply { + val degs = emptyMap() + + val result = getOrElse(degs) { ring.zero } - other + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + public override operator fun LabeledPolynomial.times(other: Int): LabeledPolynomial = + if (other == 0) zero + else LabeledPolynomial( + coefficients + .applyAndRemoveZeros { + mapValues { (_, c) -> c * other } + } + ) + // endregion + + // region Integer-polynomial relation + public override operator fun Int.plus(other: LabeledPolynomial): LabeledPolynomial = + if (this == 0) other + else + LabeledPolynomial( + other.coefficients + .toMutableMap() + .apply { + val degs = emptyMap() + + val result = this@plus + getOrElse(degs) { ring.zero } + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + public override operator fun Int.minus(other: LabeledPolynomial): LabeledPolynomial = + if (this == 0) other + else + LabeledPolynomial( + other.coefficients + .toMutableMap() + .apply { + val degs = emptyMap() + + val result = this@minus - getOrElse(degs) { ring.zero } + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + public override operator fun Int.times(other: LabeledPolynomial): LabeledPolynomial = + if (this == 0) zero + else LabeledPolynomial( + other.coefficients + .applyAndRemoveZeros { + mapValues { (_, c) -> this@times * c } + } + ) + // endregion + + // region Constant-constant relation + @JvmName("constantUnaryMinus") + override operator fun C.unaryMinus(): C = ring { -this@unaryMinus } + @JvmName("constantPlus") + override operator fun C.plus(other: C): C = ring { this@plus + other } + @JvmName("constantMinus") + override operator fun C.minus(other: C): C = ring { this@minus - other } + @JvmName("constantTimes") + override operator fun C.times(other: C): C = ring { this@times * other } + @JvmName("constantIsZero") + public override fun C.isZero(): Boolean = ring { this == zero } + @JvmName("constantIsNotZero") + public override fun C.isNotZero(): Boolean = ring { this != zero } + @JvmName("constantIsOne") + public override fun C.isOne(): Boolean = ring { this == one } + @JvmName("constantIsNotOne") + public override fun C.isNotOne(): Boolean = ring { this != one } + @JvmName("constantIsMinusOne") + public override fun C.isMinusOne(): Boolean = ring { this == -one } + @JvmName("constantIsNotMinusOne") + public override fun C.isNotMinusOne(): Boolean = ring { this != -one } + // endregion + + // region Constant-variable relation + public operator fun C.plus(other: Variable): LabeledPolynomial = + if (isZero()) LabeledPolynomial(mapOf( + mapOf(other to 1U) to ring.one, + )) + else LabeledPolynomial(mapOf( + mapOf(other to 1U) to ring.one, + emptyMap() to this@plus, + )) + public operator fun C.minus(other: Variable): LabeledPolynomial = + if (isZero()) LabeledPolynomial(mapOf( + mapOf(other to 1U) to -ring.one, + )) + else LabeledPolynomial(mapOf( + mapOf(other to 1U) to -ring.one, + emptyMap() to this@minus, + )) + public operator fun C.times(other: Variable): LabeledPolynomial = + if (isZero()) zero + else LabeledPolynomial(mapOf( + mapOf(other to 1U) to this@times, + )) + // endregion + + // region Variable-constant relation + public operator fun Variable.plus(other: C): LabeledPolynomial = + if (other.isZero()) LabeledPolynomial(mapOf( + mapOf(this@plus to 1U) to ring.one, + )) + else LabeledPolynomial(mapOf( + mapOf(this@plus to 1U) to ring.one, + emptyMap() to other, + )) + public operator fun Variable.minus(other: C): LabeledPolynomial = + if (other.isZero()) LabeledPolynomial(mapOf( + mapOf(this@minus to 1U) to -ring.one, + )) + else LabeledPolynomial(mapOf( + mapOf(this@minus to 1U) to -ring.one, + emptyMap() to other, + )) + public operator fun Variable.times(other: C): LabeledPolynomial = + if (other.isZero()) zero + else LabeledPolynomial(mapOf( + mapOf(this@times to 1U) to other, + )) + // endregion + + // region Constant-polynomial relation + override operator fun C.plus(other: LabeledPolynomial): LabeledPolynomial = + if (this.isZero()) other + else with(other.coefficients) { + if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to this@plus)) + else LabeledPolynomial( + toMutableMap() + .apply { + val degs = emptyMap() + + val result = this@plus + getOrElse(degs) { ring.zero } + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + } + override operator fun C.minus(other: LabeledPolynomial): LabeledPolynomial = + if (this.isZero()) other + else with(other.coefficients) { + if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to this@minus)) + else LabeledPolynomial( + toMutableMap() + .apply { + forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } + + val degs = emptyMap() + + val result = this@minus - getOrElse(degs) { ring.zero } + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + } + override operator fun C.times(other: LabeledPolynomial): LabeledPolynomial = + if (this.isZero()) zero + else LabeledPolynomial( + other.coefficients + .applyAndRemoveZeros { + mapValues { (_, c) -> this@times * c } + } + ) + // endregion + + // region Polynomial-constant relation + /** + * Returns sum of the polynomials. [other] is interpreted as [UnivariatePolynomial]. + */ + override operator fun LabeledPolynomial.plus(other: C): LabeledPolynomial = + if (other.isZero()) this + else with(coefficients) { + if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to other)) + else LabeledPolynomial( + toMutableMap() + .apply { + val degs = emptyMap() + + val result = getOrElse(degs) { ring.zero } + other + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + } + /** + * Returns difference of the polynomials. [other] is interpreted as [UnivariatePolynomial]. + */ + override operator fun LabeledPolynomial.minus(other: C): LabeledPolynomial = + if (other.isZero()) this + else with(coefficients) { + if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to other)) + else LabeledPolynomial( + toMutableMap() + .apply { + forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } + + val degs = emptyMap() + + val result = getOrElse(degs) { ring.zero } - other + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + } + /** + * Returns product of the polynomials. [other] is interpreted as [UnivariatePolynomial]. + */ + override operator fun LabeledPolynomial.times(other: C): LabeledPolynomial = + if (other.isZero()) zero + else LabeledPolynomial( + coefficients + .applyAndRemoveZeros { + mapValues { (_, c) -> c * other } + } + ) + // endregion + + // region Variable-variable relation + public operator fun Variable.plus(other: Variable): LabeledPolynomial = + if (this == other) LabeledPolynomial(mapOf( + mapOf(this to 1U) to ring.one * 2 + )) + else LabeledPolynomial(mapOf( + mapOf(this to 1U) to ring.one, + mapOf(other to 1U) to ring.one, + )) + public operator fun Variable.minus(other: Variable): LabeledPolynomial = + if (this == other) zero + else LabeledPolynomial(mapOf( + mapOf(this to 1U) to ring.one, + mapOf(other to 1U) to -ring.one, + )) + public operator fun Variable.times(other: Variable): LabeledPolynomial = + if (this == other) LabeledPolynomial(mapOf( + mapOf(this to 2U) to ring.one + )) + else LabeledPolynomial(mapOf( + mapOf(this to 1U, other to 1U) to ring.one, + )) + // endregion + + // region Variable-polynomial relation + public operator fun Variable.plus(other: LabeledPolynomial): LabeledPolynomial = + with(other.coefficients) { + if (isEmpty()) LabeledPolynomial(mapOf(mapOf(this@plus to 1u) to ring.one)) + else LabeledPolynomial( + toMutableMap() + .apply { + val degs = mapOf(this@plus to 1U) + + val result = ring.one + getOrElse(degs) { ring.zero } + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + } + public operator fun Variable.minus(other: LabeledPolynomial): LabeledPolynomial = + with(other.coefficients) { + if (isEmpty()) LabeledPolynomial(mapOf(mapOf(this@minus to 1u) to ring.one)) + else LabeledPolynomial( + toMutableMap() + .apply { + forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } + + val degs = mapOf(this@minus to 1U) + + val result = ring.one - getOrElse(degs) { ring.zero } + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + } + public operator fun Variable.times(other: LabeledPolynomial): LabeledPolynomial = + LabeledPolynomial( + other.coefficients + .mapKeys { (degs, _) -> degs.toMutableMap().also{ it[this] = if (this in it) it[this]!! + 1U else 1U } } + ) + // endregion + + // region Polynomial-variable relation + public operator fun LabeledPolynomial.plus(other: Variable): LabeledPolynomial = + with(coefficients) { + if (isEmpty()) LabeledPolynomial(mapOf(mapOf(other to 1u) to ring.one)) + else LabeledPolynomial( + toMutableMap() + .apply { + val degs = mapOf(other to 1U) + + val result = ring.one + getOrElse(degs) { ring.zero } + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + } + public operator fun LabeledPolynomial.minus(other: Variable): LabeledPolynomial = + with(coefficients) { + if (isEmpty()) LabeledPolynomial(mapOf(mapOf(other to 1u) to ring.one)) + else LabeledPolynomial( + toMutableMap() + .apply { + val degs = mapOf(other to 1U) + + val result = ring.one - getOrElse(degs) { ring.zero } + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + } + public operator fun LabeledPolynomial.times(other: Variable): LabeledPolynomial = + LabeledPolynomial( + coefficients + .mapKeys { (degs, _) -> degs.toMutableMap().also{ it[other] = if (other in it) it[other]!! + 1U else 1U } } + ) + // endregion + + // region Polynomial-polynomial relation + /** + * Returns negation of the polynomial. + */ + override fun LabeledPolynomial.unaryMinus(): LabeledPolynomial = + LabeledPolynomial( + coefficients.mapValues { -it.value } + ) + /** + * Returns sum of the polynomials. + */ + override operator fun LabeledPolynomial.plus(other: LabeledPolynomial): LabeledPolynomial = + LabeledPolynomial( + coefficients + .applyAndRemoveZeros { + other.coefficients + .mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! + value else value } + } + ) + /** + * Returns difference of the polynomials. + */ + override operator fun LabeledPolynomial.minus(other: LabeledPolynomial): LabeledPolynomial = + LabeledPolynomial( + coefficients + .applyAndRemoveZeros { + other.coefficients + .mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! - value else -value } + } + ) + /** + * Returns product of the polynomials. + */ + override operator fun LabeledPolynomial.times(other: LabeledPolynomial): LabeledPolynomial = + when { + isZero() -> zero + other.isZero() -> zero + else -> LabeledPolynomial( + buildCoefficients { + for ((degs1, c1) in coefficients) for ((degs2, c2) in other.coefficients) { + val degs = degs1.toMutableMap() + degs2.mapValuesTo(degs) { (variable, deg) -> degs.getOrElse(variable) { 0u } + deg } + val c = c1 * c2 + this[degs] = if (degs in this) this[degs]!! + c else c + } + } + ) + } + + override val zero: LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to ring.zero)) + override val one: LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to ring.one)) + + // TODO: Docs + @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") + override fun LabeledPolynomial.equals(other: LabeledPolynomial): Boolean = + when { + this === other -> true + else -> coefficients.size == other.coefficients.size && + coefficients.all { (key, value) -> with(other.coefficients) { key in this && this[key] == value } } + } + // endregion + + // Not sure is it necessary... + // region Polynomial properties + /** + * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is + * zero, degree is -1. + */ + override val LabeledPolynomial.degree: Int + get() = coefficients.entries.maxOfOrNull { (degs, c) -> if (c.isZero()) -1 else degs.values.sum().toInt() } ?: -1 + /** + * Map that associates variables (that appear in the polynomial in positive exponents) with their most exponents + * in which they are appeared in the polynomial. + * + * As consequence all values in the map are positive integers. Also, if the polynomial is constant, the map is empty. + * And keys of the map is the same as in [variables]. + */ + public val LabeledPolynomial.degrees: Map + get() = + buildMap { + coefficients.entries.forEach { (degs, c) -> + if (c.isNotZero()) degs.mapValuesTo(this) { (variable, deg) -> + max(getOrElse(variable) { 0u }, deg) + } + } + } + /** + * Set of all variables that appear in the polynomial in positive exponents. + */ + public val LabeledPolynomial.variables: Set + get() = + buildSet { + coefficients.entries.forEach { (degs, c) -> if (c.isNotZero()) addAll(degs.keys) } + } + /** + * Count of all variables that appear in the polynomial in positive exponents. + */ + public val LabeledPolynomial.countOfVariables: Int get() = variables.size + + /** + * Checks if the instant is constant polynomial (of degree no more than 0) over considered ring. + */ + override fun LabeledPolynomial.isConstant(): Boolean = + coefficients.all { (degs, c) -> degs.isEmpty() || c.isZero() } + /** + * Checks if the instant is constant non-zero polynomial (of degree no more than 0) over considered ring. + */ + override fun LabeledPolynomial.isNonZeroConstant(): Boolean = + with(coefficients) { + var foundAbsoluteTermAndItIsNotZero = false + for ((degs, c) in this) { + if (degs.isNotEmpty()) if (c.isNotZero()) return@with false + else { + if (c.isZero()) return@with false + else foundAbsoluteTermAndItIsNotZero = true + } + } + foundAbsoluteTermAndItIsNotZero + } + + override fun LabeledPolynomial.asConstantOrNull(): C? = + with(coefficients) { + if(isConstant()) getOrElse(emptyMap()) { ring.zero } + else null + } + +// @Suppress("NOTHING_TO_INLINE") +// public inline fun LabeledPolynomial.substitute(argument: Map): LabeledPolynomial = this.substitute(ring, argument) +// @Suppress("NOTHING_TO_INLINE") +// @JvmName("substitutePolynomial") +// public inline fun LabeledPolynomial.substitute(argument: Map>): LabeledPolynomial = this.substitute(ring, argument) +// +// @Suppress("NOTHING_TO_INLINE") +// public inline fun LabeledPolynomial.asFunction(): (Map) -> LabeledPolynomial = { this.substitute(ring, it) } +// @Suppress("NOTHING_TO_INLINE") +// public inline fun LabeledPolynomial.asFunctionOnConstants(): (Map) -> LabeledPolynomial = { this.substitute(ring, it) } +// @Suppress("NOTHING_TO_INLINE") +// public inline fun LabeledPolynomial.asFunctionOnPolynomials(): (Map>) -> LabeledPolynomial = { this.substitute(ring, it) } +// +// @Suppress("NOTHING_TO_INLINE") +// public inline operator fun LabeledPolynomial.invoke(argument: Map): LabeledPolynomial = this.substitute(ring, argument) +// @Suppress("NOTHING_TO_INLINE") +// @JvmName("invokePolynomial") +// public inline operator fun LabeledPolynomial.invoke(argument: Map>): LabeledPolynomial = this.substitute(ring, argument) + // endregion + + // region Legacy + @Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") + override inline fun add(left: LabeledPolynomial, right: LabeledPolynomial): LabeledPolynomial = left + right + @Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") + override inline fun multiply(left: LabeledPolynomial, right: LabeledPolynomial): LabeledPolynomial = left * right + // endregion + + // region Utilities + // TODO: Move to region internal utilities with context receiver + internal fun MutableMap, C>.applyAndRemoveZeros(block: MutableMap, C>.() -> Unit) : MutableMap, C> { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + block() + for ((degs, c) in this) if (c.isZero()) this.remove(degs) + return this + } + internal fun Map, C>.applyAndRemoveZeros(block: MutableMap, C>.() -> Unit) : Map, C> = + toMutableMap().applyAndRemoveZeros(block) + @OptIn(ExperimentalTypeInference::class) + internal fun buildCoefficients(@BuilderInference builderAction: MutableMap, C>.() -> Unit): Map, C> { + contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) } + return buildMap { + builderAction() + for ((degs, c) in this) if (c.isZero()) this.remove(degs) + } + } + // endregion +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt new file mode 100644 index 000000000..f1ad9a74f --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -0,0 +1,689 @@ +package space.kscience.kmath.functions + +import space.kscience.kmath.operations.* +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract +import kotlin.experimental.ExperimentalTypeInference +import kotlin.jvm.JvmName +import kotlin.math.max + + +/** + * Polynomial model without fixation on specific context they are applied to. + * + * @param C the type of constants. + */ +public class NumberedPolynomial +internal constructor( + /** + * Map that collects coefficients of the polynomial. Every monomial `a x_1^{d_1} ... x_n^{d_n}` is represented as + * pair "key-value" in the map, where value is coefficients `a` and + * key is list that associates index of every variable in the monomial with multiplicity of the variable occurring + * in the monomial. For example coefficients of polynomial `5 x_1^2 x_3^3 - 6 x_2` can be represented as + * ``` + * mapOf( + * listOf(2, 0, 3) to 5, + * listOf(0, 1) to (-6), + * ) + * ``` + * and also as + * ``` + * mapOf( + * listOf(2, 0, 3) to 5, + * listOf(0, 1) to (-6), + * listOf(0, 1, 1) to 0, + * ) + * ``` + * It is recommended not to put zero monomials into the map, but is not prohibited. Lists of degrees always do not + * contain any zeros on end, but can contain zeros on start or anywhere in middle. + */ + public val coefficients: Map, C> +) : AbstractPolynomial { + override fun toString(): String = "NumberedPolynomial$coefficients" +} + +// region Internal utilities + +/** + * Represents internal [Polynomial] errors. + */ +internal class NumberedPolynomialError : Error { + constructor(): super() + constructor(message: String): super(message) + constructor(message: String?, cause: Throwable?): super(message, cause) + constructor(cause: Throwable?): super(cause) +} + +/** + * Throws an [PolynomialError] with the given [message]. + */ +internal fun numberedPolynomialError(message: Any): Nothing = throw PolynomialError(message.toString()) + +/** + * Returns the same degrees description of the monomial, but without extra zero degrees on the end. + */ +internal fun List.cleanUp() = subList(0, indexOfLast { it != 0U } + 1) + +// endregion + +// region Constructors and converters +// Waiting for context receivers :( TODO: Replace with context receivers when they will be available + +//context(A) +//@Suppress("FunctionName") +//internal fun > NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean): NumberedPolynomial { +// if (!toCheckInput) return NumberedPolynomial(coefs) +// +// val fixedCoefs = mutableMapOf, C>() +// +// for (entry in coefs) { +// val key = entry.key.cleanUp() +// val value = entry.value +// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value +// } +// +// return NumberedPolynomial( +// fixedCoefs +// .filter { it.value.isNotZero() } +// ) +//} +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received +// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. +// * +// * @param pairs Collection of pairs that represent monomials. +// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. +// * +// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(A) +//@Suppress("FunctionName") +//internal fun > NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean): NumberedPolynomial { +// if (!toCheckInput) return NumberedPolynomial(pairs.toMap()) +// +// val fixedCoefs = mutableMapOf, C>() +// +// for (entry in pairs) { +// val key = entry.first.cleanUp() +// val value = entry.second +// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value +// } +// +// return NumberedPolynomial( +// fixedCoefs +// .filter { it.value.isNotZero() } +// ) +//} +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received +// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. +// * +// * @param pairs Collection of pairs that represent monomials. +// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. +// * +// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(A) +//@Suppress("FunctionName") +//internal fun > NumberedPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean): NumberedPolynomial = +// NumberedPolynomial(pairs.toMap(), toCheckInput) +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received +// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. +// * +// * @param coefs Coefficients of the instants. +// * +// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(A) +//public fun > NumberedPolynomial(coefs: Map, C>) = NumberedPolynomial(coefs, toCheckInput = true) +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received +// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. +// * +// * @param pairs Collection of pairs that represent monomials. +// * +// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(A) +//public fun > NumberedPolynomial(pairs: Collection, C>>) = NumberedPolynomial(pairs, toCheckInput = true) +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received +// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. +// * +// * @param pairs Collection of pairs that represent monomials. +// * +// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(A) +//public fun > NumberedPolynomial(vararg pairs: Pair, C>) = NumberedPolynomial(*pairs, toCheckInput = true) +// +//context(NumberedPolynomialSpace) +//@Suppress("FunctionName") +//internal fun > NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean): NumberedPolynomial { +// if (!toCheckInput) return NumberedPolynomial(coefs) +// +// val fixedCoefs = mutableMapOf, C>() +// +// for (entry in coefs) { +// val key = entry.key.cleanUp() +// val value = entry.value +// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value +// } +// +// return NumberedPolynomial( +// fixedCoefs +// .filter { it.value.isNotZero() } +// ) +//} +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received +// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. +// * +// * @param pairs Collection of pairs that represent monomials. +// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. +// * +// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(NumberedPolynomialSpace) +//@Suppress("FunctionName") +//internal fun > NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean): NumberedPolynomial { +// if (!toCheckInput) return NumberedPolynomial(pairs.toMap()) +// +// val fixedCoefs = mutableMapOf, C>() +// +// for (entry in pairs) { +// val key = entry.first.cleanUp() +// val value = entry.second +// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value +// } +// +// return NumberedPolynomial( +// fixedCoefs +// .filter { it.value.isNotZero() } +// ) +//} +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received +// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. +// * +// * @param pairs Collection of pairs that represent monomials. +// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. +// * +// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(NumberedPolynomialSpace) +//@Suppress("FunctionName") +//internal fun > NumberedPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean): NumberedPolynomial = +// NumberedPolynomial(pairs.toList(), toCheckInput) +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received +// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. +// * +// * @param coefs Coefficients of the instants. +// * +// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(NumberedPolynomialSpace) +//public fun > NumberedPolynomial(coefs: Map, C>) = NumberedPolynomial(coefs, toCheckInput = true) +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received +// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. +// * +// * @param pairs Collection of pairs that represent monomials. +// * +// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(NumberedPolynomialSpace) +//public fun > NumberedPolynomial(pairs: Collection, C>>) = NumberedPolynomial(pairs, toCheckInput = true) +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received +// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. +// * +// * @param pairs Collection of pairs that represent monomials. +// * +// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(NumberedPolynomialSpace) +//public fun > NumberedPolynomial(vararg pairs: Pair, C>) = NumberedPolynomial(*pairs, toCheckInput = true) + +public fun > C.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomial(mapOf(emptyList() to this)) + +// endregion + +/** + * Space of polynomials. + * + * @param C the type of operated polynomials. + * @param A the intersection of [Ring] of [C] and [ScaleOperations] of [C]. + * @param ring the [A] instance. + */ +@Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE", "INAPPLICABLE_JVM_NAME") +public class NumberedPolynomialSpace>( + public val ring: A, +) : AbstractPolynomialSpace> { + // region Constant-integer relation + @JvmName("constantIntPlus") + public override operator fun C.plus(other: Int): C = ring { optimizedAddMultiplied(this@plus, one, other) } + @JvmName("constantIntMinus") + public override operator fun C.minus(other: Int): C = ring { optimizedAddMultiplied(this@minus, one, -other) } + @JvmName("constantIntTimes") + public override operator fun C.times(other: Int): C = ring { optimizedMultiply(this@times, other) } + // endregion + + // region Integer-constant relation + @JvmName("intConstantPlus") + public override operator fun Int.plus(other: C): C = ring { optimizedAddMultiplied(other, one, this@plus) } + @JvmName("intConstantMinus") + public override operator fun Int.minus(other: C): C = ring { optimizedAddMultiplied(-other, one, this@minus) } + @JvmName("intConstantTimes") + public override operator fun Int.times(other: C): C = ring { optimizedMultiply(other, this@times) } + // endregion + + // region Polynomial-integer relation + public override operator fun NumberedPolynomial.plus(other: Int): NumberedPolynomial = + if (other == 0) this + else + NumberedPolynomial( + coefficients + .toMutableMap() + .apply { + val degs = emptyList() + + val result = getOrElse(degs) { ring.zero } + other + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + public override operator fun NumberedPolynomial.minus(other: Int): NumberedPolynomial = + if (other == 0) this + else + NumberedPolynomial( + coefficients + .toMutableMap() + .apply { + val degs = emptyList() + + val result = getOrElse(degs) { ring.zero } - other + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + public override operator fun NumberedPolynomial.times(other: Int): NumberedPolynomial = + if (other == 0) zero + else NumberedPolynomial( + coefficients + .applyAndRemoveZeros { + mapValues { (_, c) -> c * other } + } + ) + // endregion + + // region Integer-polynomial relation + public override operator fun Int.plus(other: NumberedPolynomial): NumberedPolynomial = + if (this == 0) other + else + NumberedPolynomial( + other.coefficients + .toMutableMap() + .apply { + val degs = emptyList() + + val result = this@plus + getOrElse(degs) { ring.zero } + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + public override operator fun Int.minus(other: NumberedPolynomial): NumberedPolynomial = + if (this == 0) other + else + NumberedPolynomial( + other.coefficients + .toMutableMap() + .apply { + val degs = emptyList() + + val result = this@minus - getOrElse(degs) { ring.zero } + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + public override operator fun Int.times(other: NumberedPolynomial): NumberedPolynomial = + if (this == 0) zero + else NumberedPolynomial( + other.coefficients + .applyAndRemoveZeros { + mapValues { (_, c) -> this@times * c } + } + ) + // endregion + + // region Constant-constant relation + @JvmName("constantUnaryMinus") + override operator fun C.unaryMinus(): C = ring { -this@unaryMinus } + @JvmName("constantPlus") + override operator fun C.plus(other: C): C = ring { this@plus + other } + @JvmName("constantMinus") + override operator fun C.minus(other: C): C = ring { this@minus - other } + @JvmName("constantTimes") + override operator fun C.times(other: C): C = ring { this@times * other } + @JvmName("constantIsZero") + public override fun C.isZero(): Boolean = ring { this == zero } + @JvmName("constantIsNotZero") + public override fun C.isNotZero(): Boolean = ring { this != zero } + @JvmName("constantIsOne") + public override fun C.isOne(): Boolean = ring { this == one } + @JvmName("constantIsNotOne") + public override fun C.isNotOne(): Boolean = ring { this != one } + @JvmName("constantIsMinusOne") + public override fun C.isMinusOne(): Boolean = ring { this == -one } + @JvmName("constantIsNotMinusOne") + public override fun C.isNotMinusOne(): Boolean = ring { this != -one } + // endregion + + // region Constant-polynomial relation + override operator fun C.plus(other: NumberedPolynomial): NumberedPolynomial = + if (this.isZero()) other + else with(other.coefficients) { + if (isEmpty()) NumberedPolynomial(mapOf(emptyList() to this@plus)) + else NumberedPolynomial( + toMutableMap() + .apply { + val degs = emptyList() + + val result = this@plus + getOrElse(degs) { ring.zero } + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + } + override operator fun C.minus(other: NumberedPolynomial): NumberedPolynomial = + if (this.isZero()) -other + else with(other.coefficients) { + if (isEmpty()) NumberedPolynomial(mapOf(listOf() to this@minus)) + else NumberedPolynomial( + toMutableMap() + .apply { + forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } + + val degs = emptyList() + + val result = this@minus - getOrElse(degs) { ring.zero } + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + } + override operator fun C.times(other: NumberedPolynomial): NumberedPolynomial = + if (this.isZero()) zero + else NumberedPolynomial( + other.coefficients + .applyAndRemoveZeros { + mapValues { (_, c) -> this@times * c } + } + ) + // endregion + + // region Polynomial-constant relation + /** + * Returns sum of the polynomials. [other] is interpreted as [NumberedPolynomial]. + */ + override operator fun NumberedPolynomial.plus(other: C): NumberedPolynomial = + if (other.isZero()) this + else with(coefficients) { + if (isEmpty()) NumberedPolynomial(mapOf(listOf() to other)) + else NumberedPolynomial( + toMutableMap() + .apply { + val degs = emptyList() + + val result = getOrElse(degs) { ring.zero } + other + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + } + /** + * Returns difference of the polynomials. [other] is interpreted as [NumberedPolynomial]. + */ + override operator fun NumberedPolynomial.minus(other: C): NumberedPolynomial = + if (other.isZero()) this + else with(coefficients) { + if (isEmpty()) NumberedPolynomial(mapOf(listOf() to other)) + else NumberedPolynomial( + toMutableMap() + .apply { + val degs = emptyList() + + val result = getOrElse(degs) { ring.zero } - other + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + } + /** + * Returns product of the polynomials. [other] is interpreted as [NumberedPolynomial]. + */ + override operator fun NumberedPolynomial.times(other: C): NumberedPolynomial = + if (other.isZero()) zero + else NumberedPolynomial( + coefficients + .applyAndRemoveZeros { + mapValues { (_, c) -> c * other } + } + ) + // endregion + + // region Polynomial-polynomial relation + /** + * Returns negation of the polynomial. + */ + override fun NumberedPolynomial.unaryMinus(): NumberedPolynomial = + NumberedPolynomial( + coefficients.mapValues { -it.value } + ) + /** + * Returns sum of the polynomials. + */ + override operator fun NumberedPolynomial.plus(other: NumberedPolynomial): NumberedPolynomial = + NumberedPolynomial( + coefficients + .applyAndRemoveZeros { + other.coefficients + .mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! + value else value } + } + ) + /** + * Returns difference of the polynomials. + */ + override operator fun NumberedPolynomial.minus(other: NumberedPolynomial): NumberedPolynomial = + NumberedPolynomial( + coefficients + .applyAndRemoveZeros { + other.coefficients + .mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! - value else -value } + } + ) + /** + * Returns product of the polynomials. + */ + override operator fun NumberedPolynomial.times(other: NumberedPolynomial): NumberedPolynomial = + when { + isZero() -> zero + other.isZero() -> zero + else -> + NumberedPolynomial( + buildCoefficients { + for ((degs1, c1) in coefficients) for ((degs2, c2) in other.coefficients) { + val degs = + (0..max(degs1.lastIndex, degs2.lastIndex)) + .map { degs1.getOrElse(it) { 0U } + degs2.getOrElse(it) { 0U } } + val c = c1 * c2 + this[degs] = if (degs in this) this[degs]!! + c else c + } + } + ) + } + + public override fun NumberedPolynomial.isZero(): Boolean = coefficients.values.all { it.isZero() } + public override fun NumberedPolynomial.isNotZero(): Boolean = coefficients.values.any { it.isNotZero() } + public override fun NumberedPolynomial.isOne(): Boolean = + with(coefficients) { + var foundAbsoluteTermAndItIsOne = false + for ((degs, c) in this) { + if (degs.isNotEmpty()) if (c.isNotZero()) return@with false + else { + if (c.isNotOne()) return@with false + else foundAbsoluteTermAndItIsOne = true + } + } + foundAbsoluteTermAndItIsOne + } + public override fun NumberedPolynomial.isNotOne(): Boolean = !isOne() + public override fun NumberedPolynomial.isMinusOne(): Boolean = + with(coefficients) { + var foundAbsoluteTermAndItIsMinusOne = false + for ((degs, c) in this) { + if (degs.isNotEmpty()) if (c.isNotZero()) return@with false + else { + if (c.isNotMinusOne()) return@with false + else foundAbsoluteTermAndItIsMinusOne = true + } + } + foundAbsoluteTermAndItIsMinusOne + } + public override fun NumberedPolynomial.isNotMinusOne(): Boolean = !isMinusOne() + + override val zero: NumberedPolynomial = NumberedPolynomial(emptyMap()) + override val one: NumberedPolynomial = + NumberedPolynomial( + mapOf( + listOf() to ring.one // 1 * x_1^0 * x_2^0 * ... + ) + ) + + // TODO: Docs + @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") + override fun NumberedPolynomial.equals(other: NumberedPolynomial): Boolean = + when { + this === other -> true + else -> coefficients.size == other.coefficients.size && + coefficients.all { (key, value) -> with(other.coefficients) { key in this && this[key] == value } } + } + // endregion + + // Not sure is it necessary... + // region Polynomial properties + /** + * Count of all variables that appear in the polynomial in positive exponents. + */ + public val NumberedPolynomial.countOfVariables: Int + get() = coefficients.entries.maxOfOrNull { (degs, c) -> if (c.isZero()) 0 else degs.size } ?: 0 + /** + * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is + * zero, degree is -1. + */ + override val NumberedPolynomial.degree: Int + get() = coefficients.entries.maxOfOrNull { (degs, c) -> if (c.isZero()) -1 else degs.sum().toInt() } ?: -1 + /** + * List that associates indices of variables (that appear in the polynomial in positive exponents) with their most + * exponents in which the variables are appeared in the polynomial. + * + * As consequence all values in the list are non-negative integers. Also, if the polynomial is constant, the list is empty. + * And size of the list is [countOfVariables]. + */ + public val NumberedPolynomial.degrees: List + get() = + buildList(countOfVariables) { + repeat(countOfVariables) { add(0U) } + coefficients.entries.forEach { (degs, c) -> + if (c.isNotZero()) degs.forEachIndexed { index, deg -> + this[index] = max(this[index], deg) + } + } + } + + /** + * Checks if the instant is constant polynomial (of degree no more than 0) over considered ring. + */ + override fun NumberedPolynomial.isConstant(): Boolean = + coefficients.all { (degs, c) -> degs.isEmpty() || c.isZero() } + /** + * Checks if the instant is constant non-zero polynomial (of degree no more than 0) over considered ring. + */ + override fun NumberedPolynomial.isNonZeroConstant(): Boolean = + with(coefficients) { + var foundAbsoluteTermAndItIsNotZero = false + for ((degs, c) in this) { + if (degs.isNotEmpty()) if (c.isNotZero()) return@with false + else { + if (c.isZero()) return@with false + else foundAbsoluteTermAndItIsNotZero = true + } + } + foundAbsoluteTermAndItIsNotZero + } + + override fun NumberedPolynomial.asConstantOrNull(): C? = + with(coefficients) { + if(isConstant()) getOrElse(emptyList()) { ring.zero } + else null + } + + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.substitute(argument: Map): NumberedPolynomial = this.substitute(ring, argument) + @Suppress("NOTHING_TO_INLINE") + @JvmName("substitutePolynomial") + public inline fun NumberedPolynomial.substitute(argument: Map>): NumberedPolynomial = this.substitute(ring, argument) + + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.asFunction(): (Map) -> NumberedPolynomial = { this.substitute(ring, it) } + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.asFunctionOnConstants(): (Map) -> NumberedPolynomial = { this.substitute(ring, it) } + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.asFunctionOnPolynomials(): (Map>) -> NumberedPolynomial = { this.substitute(ring, it) } + + @Suppress("NOTHING_TO_INLINE") + public inline operator fun NumberedPolynomial.invoke(argument: Map): NumberedPolynomial = this.substitute(ring, argument) + @Suppress("NOTHING_TO_INLINE") + @JvmName("invokePolynomial") + public inline operator fun NumberedPolynomial.invoke(argument: Map>): NumberedPolynomial = this.substitute(ring, argument) + // endregion + + // region Legacy + @Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") + override inline fun add(left: NumberedPolynomial, right: NumberedPolynomial): NumberedPolynomial = left + right + @Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") + override inline fun multiply(left: NumberedPolynomial, right: NumberedPolynomial): NumberedPolynomial = left * right + // endregion + + // region Utilities + // TODO: Move to region internal utilities with context receiver + internal fun MutableMap, C>.applyAndRemoveZeros(block: MutableMap, C>.() -> Unit) : MutableMap, C> { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + block() + for ((degs, c) in this) if (c.isZero()) this.remove(degs) + return this + } + internal fun Map, C>.applyAndRemoveZeros(block: MutableMap, C>.() -> Unit) : Map, C> = + toMutableMap().applyAndRemoveZeros(block) + @OptIn(ExperimentalTypeInference::class) + internal fun buildCoefficients(@BuilderInference builderAction: MutableMap, C>.() -> Unit): Map, C> { + contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) } + return buildMap { + builderAction() + for ((degs, c) in this) if (c.isZero()) this.remove(degs) + } + } + // endregion +} \ No newline at end of file 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 30280a396..99d6b0659 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 @@ -5,43 +5,38 @@ package space.kscience.kmath.functions -import space.kscience.kmath.functions.AbstractPolynomialSpace.Companion.optimizedAddMultiplied -import space.kscience.kmath.functions.AbstractPolynomialSpace.Companion.optimizedMultiply import space.kscience.kmath.operations.* import kotlin.jvm.JvmName import kotlin.math.max import kotlin.math.min /** - * Polynomial coefficients model without fixation on specific context they are applied to. + * Polynomial model without fixation on specific context they are applied to. * * @param coefficients constant is the leftmost coefficient. */ public class Polynomial(public val coefficients: List) : AbstractPolynomial { override fun toString(): String = "Polynomial$coefficients" - -// public companion object { -// /** -// * Default name of variables used in string representations. -// * -// * @see Polynomial.toString -// */ -// public var defaultVariableName: String = "x" -// -// /** -// * Represents result of division with remainder. -// */ -// public data class DividingResult( -// val quotient: Polynomial, -// val reminder: Polynomial -// ) -// } } +// region Internal utilities + /** * Represents internal [Polynomial] errors. */ -internal class PolynomialError(message: String): Error(message) +internal class PolynomialError : Error { + constructor(): super() + constructor(message: String): super(message) + constructor(message: String?, cause: Throwable?): super(message, cause) + constructor(cause: Throwable?): super(cause) +} + +/** + * Throws an [PolynomialError] with the given [message]. + */ +internal fun polynomialError(message: Any): Nothing = throw PolynomialError(message.toString()) + +// endregion // region Constructors and converters @@ -66,16 +61,16 @@ public fun T.asPolynomial() : Polynomial = Polynomial(listOf(this)) // endregion /** - * Space of polynomials constructed over ring. + * Space of univariate polynomials constructed over ring. * * @param C the type of constants. Polynomials have them as a coefficients in their terms. * @param A type of underlying ring of constants. It's [Ring] of [C]. * @param ring underlying ring of constants of type [A]. */ -@Suppress("INAPPLICABLE_JVM_NAME") // KT-31420 +@Suppress("INAPPLICABLE_JVM_NAME") // TODO: KT-31420 public open class PolynomialSpace>( public val ring: A, -) : AbstractPolynomialSpace>{ +) : AbstractPolynomialSpace> { // region Constant-integer relation @JvmName("constantIntPlus") public override operator fun C.plus(other: Int): C = ring { optimizedAddMultiplied(this@plus, one, other) } @@ -102,8 +97,14 @@ public open class PolynomialSpace>( coefficients .toMutableList() .apply { - if (isEmpty()) this[0] = ring.zero + other - else this[0] = this[0]!! + other + val result = getOrElse(0) { ring.zero } + other + val isResultZero = result.isZero() + + when { + size == 0 && !isResultZero -> add(result) + size > 1 || !isResultZero -> this[0] = result + else -> clear() + } } ) public override operator fun Polynomial.minus(other: Int): Polynomial = @@ -113,8 +114,14 @@ public open class PolynomialSpace>( coefficients .toMutableList() .apply { - if (isEmpty()) this[0] = ring.zero - other - else this[0] = this[0]!! - other + val result = getOrElse(0) { ring.zero } - other + val isResultZero = result.isZero() + + when { + size == 0 && !isResultZero -> add(result) + size > 1 || !isResultZero -> this[0] = result + else -> clear() + } } ) public override operator fun Polynomial.times(other: Int): Polynomial = @@ -134,8 +141,14 @@ public open class PolynomialSpace>( other.coefficients .toMutableList() .apply { - if (isEmpty()) this[0] = ring.zero + this@plus - else this[0] = this[0]!! + this@plus + val result = this@plus + getOrElse(0) { ring.zero } + val isResultZero = result.isZero() + + when { + size == 0 && !isResultZero -> add(result) + size > 1 || !isResultZero -> this[0] = result + else -> clear() + } } ) public override operator fun Int.minus(other: Polynomial): Polynomial = @@ -145,8 +158,16 @@ public open class PolynomialSpace>( other.coefficients .toMutableList() .apply { - if (isEmpty()) this[0] = ring.zero - this@minus - else this[0] = this[0]!! - this@minus + forEachIndexed { index, c -> if (index != 0) this[index] = -c } + + val result = this@minus - getOrElse(0) { ring.zero } + val isResultZero = result.isZero() + + when { + size == 0 && !isResultZero -> add(result) + size > 1 || !isResultZero -> this[0] = result + else -> clear() + } } ) public override operator fun Int.times(other: Polynomial): Polynomial = @@ -183,12 +204,20 @@ public open class PolynomialSpace>( // region Constant-polynomial relation public override operator fun C.plus(other: Polynomial): Polynomial = - with(other.coefficients) { + if (this.isZero()) other + else with(other.coefficients) { if (isEmpty()) Polynomial(listOf(this@plus)) else Polynomial( toMutableList() .apply { - this[0] += this@plus + val result = if (size == 0) this@plus else this@plus + get(0) + val isResultZero = result.isZero() + + when { + size == 0 && !isResultZero -> add(result) + size > 1 || !isResultZero -> this[0] = result + else -> clear() + } } ) } @@ -196,12 +225,22 @@ public open class PolynomialSpace>( // listOf(coefficients[0] + other) + coefficients.subList(1, degree + 1) // ) public override operator fun C.minus(other: Polynomial): Polynomial = - with(other.coefficients) { + if (this.isZero()) other + else with(other.coefficients) { if (isEmpty()) Polynomial(listOf(-this@minus)) else Polynomial( toMutableList() .apply { - this[0] -= this@minus + forEachIndexed { index, c -> if (index != 0) this[index] = -c } + + val result = if (size == 0) this@minus else this@minus - get(0) + val isResultZero = result.isZero() + + when { + size == 0 && !isResultZero -> add(result) + size > 1 || !isResultZero -> this[0] = result + else -> clear() + } } ) } @@ -209,9 +248,10 @@ public open class PolynomialSpace>( // listOf(coefficients[0] + other) + coefficients.subList(1, degree + 1) // ) public override operator fun C.times(other: Polynomial): Polynomial = - Polynomial( + if (this.isZero()) other + else Polynomial( other.coefficients -// .subList(0, other.degree + 1) + .subList(0, other.degree + 1) .map { it * this } ) // endregion @@ -224,7 +264,14 @@ public open class PolynomialSpace>( else Polynomial( toMutableList() .apply { - this[0] += other + val result = if (size == 0) other else get(0) + other + val isResultZero = result.isZero() + + when { + size == 0 && !isResultZero -> add(result) + size > 1 || !isResultZero -> this[0] = result + else -> clear() + } } ) } @@ -232,12 +279,20 @@ public open class PolynomialSpace>( // listOf(coefficients[0] + other) + coefficients.subList(1, degree + 1) // ) public override operator fun Polynomial.minus(other: C): Polynomial = - with(coefficients) { + if (other.isZero()) this + else with(coefficients) { if (isEmpty()) Polynomial(listOf(other)) else Polynomial( toMutableList() .apply { - this[0] -= other + val result = if (size == 0) other else get(0) - other + val isResultZero = result.isZero() + + when { + size == 0 && !isResultZero -> add(result) + size > 1 || !isResultZero -> this[0] = result + else -> clear() + } } ) } @@ -245,9 +300,10 @@ public open class PolynomialSpace>( // listOf(coefficients[0] - other) + coefficients.subList(1, degree + 1) // ) public override operator fun Polynomial.times(other: C): Polynomial = - Polynomial( + if (other.isZero()) this + else Polynomial( coefficients -// .subList(0, degree + 1) + .subList(0, degree + 1) .map { it * other } ) // endregion @@ -283,8 +339,8 @@ public open class PolynomialSpace>( val thisDegree = degree val otherDegree = other.degree return when { - thisDegree == -1 -> this - otherDegree == -1 -> other + thisDegree == -1 -> zero + otherDegree == -1 -> zero else -> Polynomial( (0..(thisDegree + otherDegree)) @@ -293,6 +349,7 @@ public open class PolynomialSpace>( .map { coefficients[it] * other.coefficients[d - it] } .reduce { acc, rational -> acc + rational } } + .run { subList(0, indexOfLast { it.isNotZero() } + 1) } ) } } @@ -321,8 +378,8 @@ public open class PolynomialSpace>( } // endregion - // Not sure is it necessary... // region Polynomial properties + public override val Polynomial.degree: Int get() = coefficients.indexOfLast { it != ring.zero } public override fun Polynomial.asConstantOrNull(): C? = @@ -354,8 +411,8 @@ public open class PolynomialSpace>( public inline operator fun Polynomial.invoke(argument: C): C = this.substitute(ring, argument) @Suppress("NOTHING_TO_INLINE") public inline operator fun Polynomial.invoke(argument: Polynomial): Polynomial = this.substitute(ring, argument) - // endregion + // endregion } /** diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Variable.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Variable.kt new file mode 100644 index 000000000..410604fd3 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Variable.kt @@ -0,0 +1,38 @@ +package space.kscience.kmath.functions + +import kotlin.reflect.KProperty + + +/** + * Represents class of labeled variables like usual + * `x`, `y`, `z`, `a`, `b`, `n`, `m`, etc. + * + * Variables does not contain any information about field (or ring, ets.) they are considered in + * and therefore about coefficient. + * + * @property name Is the label or name of variable. For `x` it is `"x"`, for `n` – `"n"`, etc. + */ +public data class Variable (val name: String) : Comparable { + /** + * Represents the variable as a string. + * + * @return Only name of the variable. + */ + override fun toString(): String = name + /** + * Compares two variables. + * Comparison is realised by comparison of variables' names. + * + * Used in [LabeledPolynomial] and [LabeledRationalFunction] to sort monomials in + * [LabeledPolynomial.toString] and [LabeledRationalFunction.toString] in lexicographic order. + * + * @see Comparable.compareTo + * @sample LabeledPolynomial.monomialComparator + * @return Only name of the variable. + */ + override fun compareTo(other: Variable): Int = name.compareTo(other.name) + + public companion object { + public operator fun getValue(thisRef: Any?, property: KProperty<*>) : Variable = Variable(property.name) + } +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt new file mode 100644 index 000000000..9e5043b8c --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.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.functions + +import space.kscience.kmath.operations.Group + + +// TODO: All of this should be moved to algebraic structures' place for utilities +// TODO: Move receiver to context receiver +/** + * Multiplication of element and integer. + * + * @receiver the multiplicand. + * @param other the multiplier. + * @return the difference. + */ +internal tailrec fun Group.optimizedMultiply(arg: C, other: Int): C = + when { + other == 0 -> zero + other == 1 -> arg + other == -1 -> -arg + other % 2 == 0 -> optimizedMultiply(arg + arg, other / 2) + other % 2 == 1 -> optimizedAddMultiplied(arg, arg + arg, other / 2) + other % 2 == -1 -> optimizedAddMultiplied(-arg, arg + arg, other / 2) + else -> error("Error in multiplication group instant by integer: got reminder by division by 2 different from 0, 1 and -1") + } + +// TODO: Move receiver to context receiver +/** + * Adds product of [arg] and [multiplier] to [base]. + * + * @receiver the algebra to provide multiplication. + * @param base the augend. + * @param arg the multiplicand. + * @param multiplier the multiplier. + * @return sum of the augend [base] and product of the multiplicand [arg] and the multiplier [multiplier]. + * @author Gleb Minaev + */ +internal tailrec fun Group.optimizedAddMultiplied(base: C, arg: C, multiplier: Int): C = + when { + multiplier == 0 -> base + multiplier == 1 -> base + arg + multiplier == -1 -> base - arg + multiplier % 2 == 0 -> optimizedAddMultiplied(base, arg + arg, multiplier / 2) + multiplier % 2 == 1 -> optimizedAddMultiplied(base + arg, arg + arg, multiplier / 2) + multiplier % 2 == -1 -> optimizedAddMultiplied(base + arg, arg + arg, multiplier / 2) + else -> error("Error in multiplication group instant by integer: got reminder by division by 2 different from 0, 1 and -1") + } \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt new file mode 100644 index 000000000..62ac31b64 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt @@ -0,0 +1,490 @@ +package space.kscience.kmath.functions + +import space.kscience.kmath.operations.* +import kotlin.contracts.* + + +// TODO: Docs + +// region Sort of legacy + +//// region Constants +// +//// TODO: Reuse underlying ring extensions +// +//context(LabeledPolynomialSpace) +//@Suppress("NOTHING_TO_INLINE") +//fun > numberConstant(value: Int): C = ring { number(value) } +// +//context(LabeledPolynomialSpace) +//fun > power(arg: C, pow: UInt): C = ring { power(arg, pow) } +// +//context(LabeledPolynomialSpace) +//fun > multiplyWithPower(base: C, arg: C, pow: UInt): C = ring { multiplyWithPower(base, arg, pow) } +// +//// endregion + +//// region Variables +// +//context(LabeledPolynomialSpace) +//fun > power(arg: Variable, pow: UInt): LabeledPolynomial = +// if (pow == 0U) one +// else LabeledPolynomial(mapOf( +// mapOf(arg to pow) to ring.one +// )) +// +//// endregion + +//// region Polynomials +// +//context(LabeledPolynomialSpace) +//fun > number(value: Int): LabeledPolynomial = ring { LabeledPolynomial(mapOf(emptyMap() to number(value))) } +// +//context(LabeledPolynomialSpace) +//fun > multiplyWithPower(base: LabeledPolynomial, arg: LabeledPolynomial, pow: UInt): LabeledPolynomial = +// when { +// arg.isZero() && pow > 0U -> base +// arg.isOne() -> base +// arg.isMinusOne() -> if (pow % 2U == 0U) base else -base +// else -> multiplyWithPowerInternalLogic(base, arg, pow) +// } +// +//// Trivial but slow as duck +//context(LabeledPolynomialSpace) +//internal tailrec fun > multiplyWithPowerInternalLogic(base: LabeledPolynomial, arg: LabeledPolynomial, exponent: UInt): LabeledPolynomial = +// when { +// exponent == 0U -> base +// exponent == 1U -> base * arg +// exponent % 2U == 0U -> multiplyWithPowerInternalLogic(base, arg * arg, exponent / 2U) +// exponent % 2U == 1U -> multiplyWithPowerInternalLogic(base * arg, arg * arg, exponent / 2U) +// else -> error("Error in raising ring instant by unsigned integer: got reminder by division by 2 different from 0 and 1") +// } +// +//// endregion + +// endregion + +// region Utilities + +// TODO: Docs +@OptIn(ExperimentalContracts::class) +public inline fun , R> A.labeledPolynomial(block: LabeledPolynomialSpace.() -> R): R { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return LabeledPolynomialSpace(this).block() +} + +// endregion + +//// region String representations +// +///** +// * Represents the polynomial as a [String] with names of variables substituted with names from [names]. +// * Consider that monomials are sorted in lexicographic order. +// */ +//context(LabeledPolynomialSpace) +//fun > LabeledPolynomial.represent(names: Map = emptyMap()): String = +// coefficients.entries +// .sortedWith { o1, o2 -> LabeledPolynomial.monomialComparator.compare(o1.key, o2.key) } +// .asSequence() +// .map { (degs, t) -> +// if (degs.isEmpty()) "$t" +// else { +// when { +// t.isOne() -> "" +// t.isMinusOne() -> "-" +// else -> "$t " +// } + +// degs +// .toSortedMap() +// .filter { it.value > 0U } +// .map { (variable, deg) -> +// val variableName = names.getOrDefault(variable, variable.toString()) +// when (deg) { +// 1U -> variableName +// else -> "$variableName^$deg" +// } +// } +// .joinToString(separator = " ") { it } +// } +// } +// .joinToString(separator = " + ") { it } +// .ifEmpty { "0" } +// +///** +// * Represents the polynomial as a [String] naming variables by [namer]. +// * Consider that monomials are sorted in lexicographic order. +// */ +//context(LabeledPolynomialSpace) +//fun > LabeledPolynomial.represent(namer: (Variable) -> String): String = +// coefficients.entries +// .sortedWith { o1, o2 -> LabeledPolynomial.monomialComparator.compare(o1.key, o2.key) } +// .asSequence() +// .map { (degs, t) -> +// if (degs.isEmpty()) "$t" +// else { +// when { +// t.isOne() -> "" +// t.isMinusOne() -> "-" +// else -> "$t " +// } + +// degs +// .toSortedMap() +// .filter { it.value > 0U } +// .map { (variable, deg) -> +// when (deg) { +// 1U -> namer(variable) +// else -> "${namer(variable)}^$deg" +// } +// } +// .joinToString(separator = " ") { it } +// } +// } +// .joinToString(separator = " + ") { it } +// .ifEmpty { "0" } +// +///** +// * Represents the polynomial as a [String] with names of variables substituted with names from [names] and with +// * brackets around the string if needed (i.e. when there are at least two addends in the representation). +// * Consider that monomials are sorted in lexicographic order. +// */ +//context(LabeledPolynomialSpace) +//fun > LabeledPolynomial.representWithBrackets(names: Map = emptyMap()): String = +// with(represent(names)) { if (coefficients.count() == 1) this else "($this)" } +// +///** +// * Represents the polynomial as a [String] naming variables by [namer] and with brackets around the string if needed +// * (i.e. when there are at least two addends in the representation). +// * Consider that monomials are sorted in lexicographic order. +// */ +//context(LabeledPolynomialSpace) +//fun > LabeledPolynomial.representWithBrackets(namer: (Variable) -> String): String = +// with(represent(namer)) { if (coefficients.count() == 1) this else "($this)" } +// +///** +// * Represents the polynomial as a [String] with names of variables substituted with names from [names]. +// * Consider that monomials are sorted in **reversed** lexicographic order. +// */ +//context(LabeledPolynomialSpace) +//fun > LabeledPolynomial.representReversed(names: Map = emptyMap()): String = +// coefficients.entries +// .sortedWith { o1, o2 -> -LabeledPolynomial.monomialComparator.compare(o1.key, o2.key) } +// .asSequence() +// .map { (degs, t) -> +// if (degs.isEmpty()) "$t" +// else { +// when { +// t.isOne() -> "" +// t.isMinusOne() -> "-" +// else -> "$t " +// } + +// degs +// .toSortedMap() +// .filter { it.value > 0U } +// .map { (variable, deg) -> +// val variableName = names.getOrDefault(variable, variable.toString()) +// when (deg) { +// 1U -> variableName +// else -> "$variableName^$deg" +// } +// } +// .joinToString(separator = " ") { it } +// } +// } +// .joinToString(separator = " + ") { it } +// .ifEmpty { "0" } +// +///** +// * Represents the polynomial as a [String] naming variables by [namer]. +// * Consider that monomials are sorted in **reversed** lexicographic order. +// */ +//context(LabeledPolynomialSpace) +//fun > LabeledPolynomial.representReversed(namer: (Variable) -> String): String = +// coefficients.entries +// .sortedWith { o1, o2 -> -LabeledPolynomial.monomialComparator.compare(o1.key, o2.key) } +// .asSequence() +// .map { (degs, t) -> +// if (degs.isEmpty()) "$t" +// else { +// when { +// t.isOne() -> "" +// t.isMinusOne() -> "-" +// else -> "$t " +// } + +// degs +// .toSortedMap() +// .filter { it.value > 0U } +// .map { (variable, deg) -> +// when (deg) { +// 1U -> namer(variable) +// else -> "${namer(variable)}^$deg" +// } +// } +// .joinToString(separator = " ") { it } +// } +// } +// .joinToString(separator = " + ") { it } +// .ifEmpty { "0" } +// +///** +// * Represents the polynomial as a [String] with names of variables substituted with names from [names] and with +// * brackets around the string if needed (i.e. when there are at least two addends in the representation). +// * Consider that monomials are sorted in **reversed** lexicographic order. +// */ +//context(LabeledPolynomialSpace) +//fun > LabeledPolynomial.representReversedWithBrackets(names: Map = emptyMap()): String = +// with(representReversed(names)) { if (coefficients.count() == 1) this else "($this)" } +// +///** +// * Represents the polynomial as a [String] naming variables by [namer] and with brackets around the string if needed +// * (i.e. when there are at least two addends in the representation). +// * Consider that monomials are sorted in **reversed** lexicographic order. +// */ +//context(LabeledPolynomialSpace) +//fun > LabeledPolynomial.representReversedWithBrackets(namer: (Variable) -> String): String = +// with(representReversed(namer)) { if (coefficients.count() == 1) this else "($this)" } +// +//// endregion + +// region Operator extensions + +//// region Field case +// +//operator fun > Polynomial.div(other: Polynomial): Polynomial { +// if (other.isZero()) throw ArithmeticException("/ by zero") +// if (isZero()) return this +// +// fun Map, T>.leadingTerm() = +// this +// .asSequence() +// .map { Pair(it.key, it.value) } +// .reduce { (accDegs, accC), (listDegs, listC) -> +// for (i in 0..accDegs.lastIndex) { +// if (accDegs[i] > listDegs.getOrElse(i) { 0 }) return@reduce accDegs to accC +// if (accDegs[i] < listDegs.getOrElse(i) { 0 }) return@reduce listDegs to listC +// } +// if (accDegs.size < listDegs.size) listDegs to listC else accDegs to accC +// } +// +// var thisCoefficients = coefficients.toMutableMap() +// val otherCoefficients = other.coefficients +// val quotientCoefficients = HashMap, T>() +// +// var (thisLeadingTermDegs, thisLeadingTermC) = thisCoefficients.leadingTerm() +// val (otherLeadingTermDegs, otherLeadingTermC) = otherCoefficients.leadingTerm() +// +// while ( +// thisLeadingTermDegs.size >= otherLeadingTermDegs.size && +// (0..otherLeadingTermDegs.lastIndex).all { thisLeadingTermDegs[it] >= otherLeadingTermDegs[it] } +// ) { +// val multiplierDegs = +// thisLeadingTermDegs +// .mapIndexed { index, deg -> deg - otherLeadingTermDegs.getOrElse(index) { 0 } } +// .cleanUp() +// val multiplierC = thisLeadingTermC / otherLeadingTermC +// +// quotientCoefficients[multiplierDegs] = multiplierC +// +// for ((degs, t) in otherCoefficients) { +// val productDegs = +// (0..max(degs.lastIndex, multiplierDegs.lastIndex)) +// .map { degs.getOrElse(it) { 0 } + multiplierDegs.getOrElse(it) { 0 } } +// .cleanUp() +// val productC = t * multiplierC +// thisCoefficients[productDegs] = +// if (productDegs in thisCoefficients) thisCoefficients[productDegs]!! - productC else -productC +// } +// +// thisCoefficients = thisCoefficients.filterValues { it.isNotZero() }.toMutableMap() +// +// if (thisCoefficients.isEmpty()) +// return Polynomial(quotientCoefficients, toCheckInput = false) +// +// val t = thisCoefficients.leadingTerm() +// thisLeadingTermDegs = t.first +// thisLeadingTermC = t.second +// } +// +// return Polynomial(quotientCoefficients, toCheckInput = false) +//} +// +//operator fun > Polynomial.div(other: T): Polynomial = +// if (other.isZero()) throw ArithmeticException("/ by zero") +// else +// Polynomial( +// coefficients +// .mapValues { it.value / other }, +// toCheckInput = false +// ) +// +//operator fun > Polynomial.rem(other: Polynomial): Polynomial { +// if (other.isZero()) throw ArithmeticException("/ by zero") +// if (isZero()) return this +// +// fun Map, T>.leadingTerm() = +// this +// .asSequence() +// .map { Pair(it.key, it.value) } +// .reduce { (accDegs, accC), (listDegs, listC) -> +// for (i in 0..accDegs.lastIndex) { +// if (accDegs[i] > listDegs.getOrElse(i) { 0 }) return@reduce accDegs to accC +// if (accDegs[i] < listDegs.getOrElse(i) { 0 }) return@reduce listDegs to listC +// } +// if (accDegs.size < listDegs.size) listDegs to listC else accDegs to accC +// } +// +// var thisCoefficients = coefficients.toMutableMap() +// val otherCoefficients = other.coefficients +// +// var (thisLeadingTermDegs, thisLeadingTermC) = thisCoefficients.leadingTerm() +// val (otherLeadingTermDegs, otherLeadingTermC) = otherCoefficients.leadingTerm() +// +// while ( +// thisLeadingTermDegs.size >= otherLeadingTermDegs.size && +// (0..otherLeadingTermDegs.lastIndex).all { thisLeadingTermDegs[it] >= otherLeadingTermDegs[it] } +// ) { +// val multiplierDegs = +// thisLeadingTermDegs +// .mapIndexed { index, deg -> deg - otherLeadingTermDegs.getOrElse(index) { 0 } } +// .cleanUp() +// val multiplierC = thisLeadingTermC / otherLeadingTermC +// +// for ((degs, t) in otherCoefficients) { +// val productDegs = +// (0..max(degs.lastIndex, multiplierDegs.lastIndex)) +// .map { degs.getOrElse(it) { 0 } + multiplierDegs.getOrElse(it) { 0 } } +// .cleanUp() +// val productC = t * multiplierC +// thisCoefficients[productDegs] = +// if (productDegs in thisCoefficients) thisCoefficients[productDegs]!! - productC else -productC +// } +// +// thisCoefficients = thisCoefficients.filterValues { it.isNotZero() }.toMutableMap() +// +// if (thisCoefficients.isEmpty()) +// return Polynomial(thisCoefficients, toCheckInput = false) +// +// val t = thisCoefficients.leadingTerm() +// thisLeadingTermDegs = t.first +// thisLeadingTermC = t.second +// } +// +// return Polynomial(thisCoefficients, toCheckInput = false) +//} +// +//infix fun > Polynomial.divrem(other: Polynomial): Polynomial.Companion.DividingResult { +// if (other.isZero()) throw ArithmeticException("/ by zero") +// if (isZero()) return Polynomial.Companion.DividingResult(this, this) +// +// fun Map, T>.leadingTerm() = +// this +// .asSequence() +// .map { Pair(it.key, it.value) } +// .reduce { (accDegs, accC), (listDegs, listC) -> +// for (i in 0..accDegs.lastIndex) { +// if (accDegs[i] > listDegs.getOrElse(i) { 0 }) return@reduce accDegs to accC +// if (accDegs[i] < listDegs.getOrElse(i) { 0 }) return@reduce listDegs to listC +// } +// if (accDegs.size < listDegs.size) listDegs to listC else accDegs to accC +// } +// +// var thisCoefficients = coefficients.toMutableMap() +// val otherCoefficients = other.coefficients +// val quotientCoefficients = HashMap, T>() +// +// var (thisLeadingTermDegs, thisLeadingTermC) = thisCoefficients.leadingTerm() +// val (otherLeadingTermDegs, otherLeadingTermC) = otherCoefficients.leadingTerm() +// +// while ( +// thisLeadingTermDegs.size >= otherLeadingTermDegs.size && +// (0..otherLeadingTermDegs.lastIndex).all { thisLeadingTermDegs[it] >= otherLeadingTermDegs[it] } +// ) { +// val multiplierDegs = +// thisLeadingTermDegs +// .mapIndexed { index, deg -> deg - otherLeadingTermDegs.getOrElse(index) { 0 } } +// .cleanUp() +// val multiplierC = thisLeadingTermC / otherLeadingTermC +// +// quotientCoefficients[multiplierDegs] = multiplierC +// +// for ((degs, t) in otherCoefficients) { +// val productDegs = +// (0..max(degs.lastIndex, multiplierDegs.lastIndex)) +// .map { degs.getOrElse(it) { 0 } + multiplierDegs.getOrElse(it) { 0 } } +// .cleanUp() +// val productC = t * multiplierC +// thisCoefficients[productDegs] = +// if (productDegs in thisCoefficients) thisCoefficients[productDegs]!! - productC else -productC +// } +// +// thisCoefficients = thisCoefficients.filterValues { it.isNotZero() }.toMutableMap() +// +// if (thisCoefficients.isEmpty()) +// return Polynomial.Companion.DividingResult( +// Polynomial(quotientCoefficients, toCheckInput = false), +// Polynomial(thisCoefficients, toCheckInput = false) +// ) +// +// val t = thisCoefficients.leadingTerm() +// thisLeadingTermDegs = t.first +// thisLeadingTermC = t.second +// } +// +// return Polynomial.Companion.DividingResult( +// Polynomial(quotientCoefficients, toCheckInput = false), +// Polynomial(thisCoefficients, toCheckInput = false) +// ) +//} +// +//// endregion + +// endregion + +//// region Polynomial substitution and functional representation +// +//public fun LabeledPolynomial.substitute(ring: Ring, args: Map): LabeledPolynomial = ring { +// if (coefficients.isEmpty()) return this@substitute +// LabeledPolynomial( +// buildMap { +// coefficients.forEach { (degs, c) -> +// val newDegs = degs.filterKeys { it !in args } +// val newC = degs.entries.asSequence().filter { it.key in args }.fold(c) { acc, (variable, deg) -> +// multiplyWithPower(acc, args[variable]!!, deg) +// } +// this[newDegs] = if (newDegs in this) this[newDegs]!! + newC else newC +// } +// } +// ) +//} +// +//// TODO: Replace with optimisation: the [result] may be unboxed, and all operations may be performed as soon as +//// possible on it +//@JvmName("substitutePolynomial") +//fun LabeledPolynomial.substitute(ring: Ring, arg: Map>) : LabeledPolynomial = +// ring.labeledPolynomial { +// if (coefficients.isEmpty()) return zero +// coefficients +// .asSequence() +// .map { (degs, c) -> +// degs.entries +// .asSequence() +// .filter { it.key in arg } +// .fold(LabeledPolynomial(mapOf(degs.filterKeys { it !in arg } to c))) { acc, (index, deg) -> +// multiplyWithPower(acc, arg[index]!!, deg) +// } +// } +// .reduce { acc, polynomial -> acc + polynomial } // TODO: Rewrite. Might be slow. +// } +// +//// TODO: Substitute rational function +// +//fun > LabeledPolynomial.asFunctionOver(ring: A): (Map) -> LabeledPolynomial = +// { substitute(ring, it) } +// +//fun > LabeledPolynomial.asPolynomialFunctionOver(ring: A): (Map>) -> LabeledPolynomial = +// { substitute(ring, it) } +// +//// endregion + +//// region Algebraic derivative and antiderivative +//// TODO +//// endregion \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt new file mode 100644 index 000000000..d4053442d --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt @@ -0,0 +1,605 @@ +package space.kscience.kmath.functions + +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.* +import kotlin.contracts.* +import kotlin.jvm.JvmName + + +// TODO: Docs + +// region Sort of legacy + +//// region Constants +// +//// TODO: Reuse underlying ring extensions +// +//context(NumberedPolynomialSpace) +//@Suppress("NOTHING_TO_INLINE") +//public fun > numberConstant(value: Int): C = ring { number(value) } +// +//context(NumberedPolynomialSpace) +//public fun > multiplyWithPower(base: C, arg: C, pow: UInt): C = ring { multiplyWithPower(base, arg, pow) } +// +//// endregion + +//// region Polynomials +// +//context(NumberedPolynomialSpace) +//public fun > number(value: Int): NumberedPolynomial = ring { NumberedPolynomial(mapOf(emptyList() to number(value))) } +// +//context(NumberedPolynomialSpace) +//public fun > multiplyWithPower(base: NumberedPolynomial, arg: NumberedPolynomial, pow: UInt): NumberedPolynomial = +// when { +// arg.isZero() && pow > 0U -> base +// arg.isOne() -> base +// arg.isMinusOne() -> if (pow % 2U == 0U) base else -base +// else -> multiplyWithPowerInternalLogic(base, arg, pow) +// } +// +//// Trivial but slow as duck +//context(NumberedPolynomialSpace) +//internal tailrec fun > multiplyWithPowerInternalLogic(base: NumberedPolynomial, arg: NumberedPolynomial, exponent: UInt): NumberedPolynomial = +// when { +// exponent == 0U -> base +// exponent == 1U -> base * arg +// exponent % 2U == 0U -> multiplyWithPowerInternalLogic(base, arg * arg, exponent / 2U) +// exponent % 2U == 1U -> multiplyWithPowerInternalLogic(base * arg, arg * arg, exponent / 2U) +// else -> error("Error in raising ring instant by unsigned integer: got reminder by division by 2 different from 0 and 1") +// } +// +//// endregion + +// endregion + +// region Utilities + +// TODO: Docs +@OptIn(ExperimentalContracts::class) +public inline fun , R> A.numberedPolynomial(block: NumberedPolynomialSpace.() -> R): R { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return NumberedPolynomialSpace(this).block() +} + +// endregion + +//// region String representations +// +///** +// * Represents the polynomial as a [String] where name of variable with index `i` is [withVariableName] + `"_${i+1}"`. +// * Consider that monomials are sorted in lexicographic order. +// */ +//context(NumberedPolynomialSpace) +//public fun > NumberedPolynomial.represent(withVariableName: String = NumberedPolynomial.defaultVariableName): String = +// coefficients.entries +// .sortedWith { o1, o2 -> NumberedPolynomial.monomialComparator.compare(o1.key, o2.key) } +// .asSequence() +// .map { (degs, t) -> +// if (degs.isEmpty()) "$t" +// else { +// when { +// t.isOne() -> "" +// t.isMinusOne() -> "-" +// else -> "$t " +// } + +// degs +// .mapIndexed { index, deg -> +// when (deg) { +// 0U -> "" +// 1U -> "${withVariableName}_${index+1}" +// else -> "${withVariableName}_${index+1}^$deg" +// } +// } +// .filter { it.isNotEmpty() } +// .joinToString(separator = " ") { it } +// } +// } +// .joinToString(separator = " + ") { it } +// .ifEmpty { "0" } +// +///** +// * Represents the polynomial as a [String] naming variables by [namer]. +// * Consider that monomials are sorted in lexicographic order. +// */ +//context(NumberedPolynomialSpace) +//public fun > NumberedPolynomial.represent(namer: (Int) -> String): String = +// coefficients.entries +// .sortedWith { o1, o2 -> NumberedPolynomial.monomialComparator.compare(o1.key, o2.key) } +// .asSequence() +// .map { (degs, t) -> +// if (degs.isEmpty()) "$t" +// else { +// when { +// t.isOne() -> "" +// t.isMinusOne() -> "-" +// else -> "$t " +// } + +// degs +// .mapIndexed { index, deg -> +// when (deg) { +// 0U -> "" +// 1U -> namer(index) +// else -> "${namer(index)}^$deg" +// } +// } +// .filter { it.isNotEmpty() } +// .joinToString(separator = " ") { it } +// } +// } +// .joinToString(separator = " + ") { it } +// .ifEmpty { "0" } +// +///** +// * Represents the polynomial as a [String] where name of variable with index `i` is [withVariableName] + `"_${i+1}"` +// * and with brackets around the string if needed (i.e. when there are at least two addends in the representation). +// * Consider that monomials are sorted in lexicographic order. +// */ +//context(NumberedPolynomialSpace) +//public fun > NumberedPolynomial.representWithBrackets(withVariableName: String = NumberedPolynomial.defaultVariableName): String = +// with(represent(withVariableName)) { if (coefficients.count() == 1) this else "($this)" } +// +///** +// * Represents the polynomial as a [String] naming variables by [namer] and with brackets around the string if needed +// * (i.e. when there are at least two addends in the representation). +// * Consider that monomials are sorted in lexicographic order. +// */ +//context(NumberedPolynomialSpace) +//public fun > NumberedPolynomial.representWithBrackets(namer: (Int) -> String): String = +// with(represent(namer)) { if (coefficients.count() == 1) this else "($this)" } +// +///** +// * Represents the polynomial as a [String] where name of variable with index `i` is [withVariableName] + `"_${i+1}"`. +// * Consider that monomials are sorted in **reversed** lexicographic order. +// */ +//context(NumberedPolynomialSpace) +//public fun > NumberedPolynomial.representReversed(withVariableName: String = NumberedPolynomial.defaultVariableName): String = +// coefficients.entries +// .sortedWith { o1, o2 -> -NumberedPolynomial.monomialComparator.compare(o1.key, o2.key) } +// .asSequence() +// .map { (degs, t) -> +// if (degs.isEmpty()) "$t" +// else { +// when { +// t.isOne() -> "" +// t.isMinusOne() -> "-" +// else -> "$t " +// } + +// degs +// .mapIndexed { index, deg -> +// when (deg) { +// 0U -> "" +// 1U -> "${withVariableName}_${index+1}" +// else -> "${withVariableName}_${index+1}^$deg" +// } +// } +// .filter { it.isNotEmpty() } +// .joinToString(separator = " ") { it } +// } +// } +// .joinToString(separator = " + ") { it } +// .ifEmpty { "0" } +// +///** +// * Represents the polynomial as a [String] naming variables by [namer]. +// * Consider that monomials are sorted in **reversed** lexicographic order. +// */ +//context(NumberedPolynomialSpace) +//public fun > NumberedPolynomial.representReversed(namer: (Int) -> String): String = +// coefficients.entries +// .sortedWith { o1, o2 -> -NumberedPolynomial.monomialComparator.compare(o1.key, o2.key) } +// .asSequence() +// .map { (degs, t) -> +// if (degs.isEmpty()) "$t" +// else { +// when { +// t.isOne() -> "" +// t.isMinusOne() -> "-" +// else -> "$t " +// } + +// degs +// .mapIndexed { index, deg -> +// when (deg) { +// 0U -> "" +// 1U -> namer(index) +// else -> "${namer(index)}^$deg" +// } +// } +// .filter { it.isNotEmpty() } +// .joinToString(separator = " ") { it } +// } +// } +// .joinToString(separator = " + ") { it } +// .ifEmpty { "0" } +// +///** +// * Represents the polynomial as a [String] where name of variable with index `i` is [withVariableName] + `"_${i+1}"` +// * and with brackets around the string if needed (i.e. when there are at least two addends in the representation). +// * Consider that monomials are sorted in **reversed** lexicographic order. +// */ +//context(NumberedPolynomialSpace) +//public fun > NumberedPolynomial.representReversedWithBrackets(withVariableName: String = NumberedPolynomial.defaultVariableName): String = +// with(representReversed(withVariableName)) { if (coefficients.count() == 1) this else "($this)" } +// +///** +// * Represents the polynomial as a [String] naming variables by [namer] and with brackets around the string if needed +// * (i.e. when there are at least two addends in the representation). +// * Consider that monomials are sorted in **reversed** lexicographic order. +// */ +//context(NumberedPolynomialSpace) +//public fun > NumberedPolynomial.representReversedWithBrackets(namer: (Int) -> String): String = +// with(representReversed(namer)) { if (coefficients.count() == 1) this else "($this)" } +// +//// endregion + +//// region Polynomial substitution and functional representation +// +//public fun NumberedPolynomial.substitute(ring: Ring, args: Map): NumberedPolynomial = ring { +// if (coefficients.isEmpty()) return this@substitute +// NumberedPolynomial( +// buildMap { +// coefficients.forEach { (degs, c) -> +// val newDegs = degs.mapIndexed { index, deg -> if (index in args) 0U else deg }.cleanUp() +// val newC = degs.foldIndexed(c) { index, acc, deg -> +// if (index in args) multiplyWithPower(acc, args[index]!!, deg) +// else acc +// } +// this[newDegs] = if (newDegs in this) this[newDegs]!! + newC else newC +// } +// } +// ) +//} +// +//// TODO: Replace with optimisation: the [result] may be unboxed, and all operations may be performed as soon as +//// possible on it +//@JvmName("substitutePolynomial") +//public fun NumberedPolynomial.substitute(ring: Ring, arg: Map>) : NumberedPolynomial = +// ring.numberedPolynomialSpace { +// if (coefficients.isEmpty()) return zero +// coefficients +// .asSequence() +// .map { (degs, c) -> +// degs.foldIndexed( +// NumberedPolynomial( +// degs.mapIndexed { index, deg -> if (index in arg) 0U else deg } to c +// ) +// ) { index, acc, deg -> if (index in arg) multiplyWithPower(acc, arg[index]!!, deg) else acc } +// } +// .reduce { acc, polynomial -> acc + polynomial } // TODO: Rewrite. Might be slow. +// } +// +//// TODO: Substitute rational function +// +//public fun > NumberedPolynomial.asFunctionOver(ring: A): (Map) -> NumberedPolynomial = +// { substitute(ring, it) } +// +//public fun > NumberedPolynomial.asPolynomialFunctionOver(ring: A): (Map>) -> NumberedPolynomial = +// { substitute(ring, it) } +// +//// endregion + +// region Operator extensions + +//// region Field case +// +//operator fun > Polynomial.div(other: Polynomial): Polynomial { +// if (other.isZero()) throw ArithmeticException("/ by zero") +// if (isZero()) return this +// +// fun Map, T>.leadingTerm() = +// this +// .asSequence() +// .map { Pair(it.key, it.value) } +// .reduce { (accDegs, accC), (listDegs, listC) -> +// for (i in 0..accDegs.lastIndex) { +// if (accDegs[i] > listDegs.getOrElse(i) { 0 }) return@reduce accDegs to accC +// if (accDegs[i] < listDegs.getOrElse(i) { 0 }) return@reduce listDegs to listC +// } +// if (accDegs.size < listDegs.size) listDegs to listC else accDegs to accC +// } +// +// var thisCoefficients = coefficients.toMutableMap() +// val otherCoefficients = other.coefficients +// val quotientCoefficients = HashMap, T>() +// +// var (thisLeadingTermDegs, thisLeadingTermC) = thisCoefficients.leadingTerm() +// val (otherLeadingTermDegs, otherLeadingTermC) = otherCoefficients.leadingTerm() +// +// while ( +// thisLeadingTermDegs.size >= otherLeadingTermDegs.size && +// (0..otherLeadingTermDegs.lastIndex).all { thisLeadingTermDegs[it] >= otherLeadingTermDegs[it] } +// ) { +// val multiplierDegs = +// thisLeadingTermDegs +// .mapIndexed { index, deg -> deg - otherLeadingTermDegs.getOrElse(index) { 0 } } +// .cleanUp() +// val multiplierC = thisLeadingTermC / otherLeadingTermC +// +// quotientCoefficients[multiplierDegs] = multiplierC +// +// for ((degs, t) in otherCoefficients) { +// val productDegs = +// (0..max(degs.lastIndex, multiplierDegs.lastIndex)) +// .map { degs.getOrElse(it) { 0 } + multiplierDegs.getOrElse(it) { 0 } } +// .cleanUp() +// val productC = t * multiplierC +// thisCoefficients[productDegs] = +// if (productDegs in thisCoefficients) thisCoefficients[productDegs]!! - productC else -productC +// } +// +// thisCoefficients = thisCoefficients.filterValues { it.isNotZero() }.toMutableMap() +// +// if (thisCoefficients.isEmpty()) +// return Polynomial(quotientCoefficients, toCheckInput = false) +// +// val t = thisCoefficients.leadingTerm() +// thisLeadingTermDegs = t.first +// thisLeadingTermC = t.second +// } +// +// return Polynomial(quotientCoefficients, toCheckInput = false) +//} +// +//operator fun > Polynomial.div(other: T): Polynomial = +// if (other.isZero()) throw ArithmeticException("/ by zero") +// else +// Polynomial( +// coefficients +// .mapValues { it.value / other }, +// toCheckInput = false +// ) +// +//operator fun > Polynomial.rem(other: Polynomial): Polynomial { +// if (other.isZero()) throw ArithmeticException("/ by zero") +// if (isZero()) return this +// +// fun Map, T>.leadingTerm() = +// this +// .asSequence() +// .map { Pair(it.key, it.value) } +// .reduce { (accDegs, accC), (listDegs, listC) -> +// for (i in 0..accDegs.lastIndex) { +// if (accDegs[i] > listDegs.getOrElse(i) { 0 }) return@reduce accDegs to accC +// if (accDegs[i] < listDegs.getOrElse(i) { 0 }) return@reduce listDegs to listC +// } +// if (accDegs.size < listDegs.size) listDegs to listC else accDegs to accC +// } +// +// var thisCoefficients = coefficients.toMutableMap() +// val otherCoefficients = other.coefficients +// +// var (thisLeadingTermDegs, thisLeadingTermC) = thisCoefficients.leadingTerm() +// val (otherLeadingTermDegs, otherLeadingTermC) = otherCoefficients.leadingTerm() +// +// while ( +// thisLeadingTermDegs.size >= otherLeadingTermDegs.size && +// (0..otherLeadingTermDegs.lastIndex).all { thisLeadingTermDegs[it] >= otherLeadingTermDegs[it] } +// ) { +// val multiplierDegs = +// thisLeadingTermDegs +// .mapIndexed { index, deg -> deg - otherLeadingTermDegs.getOrElse(index) { 0 } } +// .cleanUp() +// val multiplierC = thisLeadingTermC / otherLeadingTermC +// +// for ((degs, t) in otherCoefficients) { +// val productDegs = +// (0..max(degs.lastIndex, multiplierDegs.lastIndex)) +// .map { degs.getOrElse(it) { 0 } + multiplierDegs.getOrElse(it) { 0 } } +// .cleanUp() +// val productC = t * multiplierC +// thisCoefficients[productDegs] = +// if (productDegs in thisCoefficients) thisCoefficients[productDegs]!! - productC else -productC +// } +// +// thisCoefficients = thisCoefficients.filterValues { it.isNotZero() }.toMutableMap() +// +// if (thisCoefficients.isEmpty()) +// return Polynomial(thisCoefficients, toCheckInput = false) +// +// val t = thisCoefficients.leadingTerm() +// thisLeadingTermDegs = t.first +// thisLeadingTermC = t.second +// } +// +// return Polynomial(thisCoefficients, toCheckInput = false) +//} +// +//infix fun > Polynomial.divrem(other: Polynomial): Polynomial.Companion.DividingResult { +// if (other.isZero()) throw ArithmeticException("/ by zero") +// if (isZero()) return Polynomial.Companion.DividingResult(this, this) +// +// fun Map, T>.leadingTerm() = +// this +// .asSequence() +// .map { Pair(it.key, it.value) } +// .reduce { (accDegs, accC), (listDegs, listC) -> +// for (i in 0..accDegs.lastIndex) { +// if (accDegs[i] > listDegs.getOrElse(i) { 0 }) return@reduce accDegs to accC +// if (accDegs[i] < listDegs.getOrElse(i) { 0 }) return@reduce listDegs to listC +// } +// if (accDegs.size < listDegs.size) listDegs to listC else accDegs to accC +// } +// +// var thisCoefficients = coefficients.toMutableMap() +// val otherCoefficients = other.coefficients +// val quotientCoefficients = HashMap, T>() +// +// var (thisLeadingTermDegs, thisLeadingTermC) = thisCoefficients.leadingTerm() +// val (otherLeadingTermDegs, otherLeadingTermC) = otherCoefficients.leadingTerm() +// +// while ( +// thisLeadingTermDegs.size >= otherLeadingTermDegs.size && +// (0..otherLeadingTermDegs.lastIndex).all { thisLeadingTermDegs[it] >= otherLeadingTermDegs[it] } +// ) { +// val multiplierDegs = +// thisLeadingTermDegs +// .mapIndexed { index, deg -> deg - otherLeadingTermDegs.getOrElse(index) { 0 } } +// .cleanUp() +// val multiplierC = thisLeadingTermC / otherLeadingTermC +// +// quotientCoefficients[multiplierDegs] = multiplierC +// +// for ((degs, t) in otherCoefficients) { +// val productDegs = +// (0..max(degs.lastIndex, multiplierDegs.lastIndex)) +// .map { degs.getOrElse(it) { 0 } + multiplierDegs.getOrElse(it) { 0 } } +// .cleanUp() +// val productC = t * multiplierC +// thisCoefficients[productDegs] = +// if (productDegs in thisCoefficients) thisCoefficients[productDegs]!! - productC else -productC +// } +// +// thisCoefficients = thisCoefficients.filterValues { it.isNotZero() }.toMutableMap() +// +// if (thisCoefficients.isEmpty()) +// return Polynomial.Companion.DividingResult( +// Polynomial(quotientCoefficients, toCheckInput = false), +// Polynomial(thisCoefficients, toCheckInput = false) +// ) +// +// val t = thisCoefficients.leadingTerm() +// thisLeadingTermDegs = t.first +// thisLeadingTermC = t.second +// } +// +// return Polynomial.Companion.DividingResult( +// Polynomial(quotientCoefficients, toCheckInput = false), +// Polynomial(thisCoefficients, toCheckInput = false) +// ) +//} +// +//// endregion + +// endregion + +// region Polynomial substitution and functional representation + +// TODO: May be apply Horner's method too? +/** + * Evaluates the value of the given double polynomial for given double argument. + */ +public fun NumberedPolynomial.substitute(args: Map): NumberedPolynomial = Double.algebra { + val acc = LinkedHashMap, Double>(coefficients.size) + for ((degs, c) in coefficients) { + val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp() + val newC = args.entries.fold(c) { product, (variable, substitutor) -> + val deg = degs.getOrElse(variable) { 0u } + if (deg == 0u) product else product * substitutor.pow(deg.toInt()) + } + if (newDegs !in acc) acc[newDegs] = c + else acc[newDegs] = acc[newDegs]!! + c + } + return NumberedPolynomial(acc) +} + +/** + * Evaluates the value of the given polynomial for given argument. + * + * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). + */ +public fun NumberedPolynomial.substitute(ring: Ring, args: Map): NumberedPolynomial = ring { + val acc = LinkedHashMap, C>(coefficients.size) + for ((degs, c) in coefficients) { + val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp() + val newC = args.entries.fold(c) { product, (variable, substitutor) -> + val deg = degs.getOrElse(variable) { 0u } + if (deg == 0u) product else product * power(substitutor, deg) + } + if (newDegs !in acc) acc[newDegs] = c + else acc[newDegs] = acc[newDegs]!! + c + } + return NumberedPolynomial(acc) +} + +// TODO: (Waiting for hero) Replace with optimisation: the [result] may be unboxed, and all operations may be performed +// as soon as possible on it +@JvmName("substitutePolynomial") +public fun NumberedPolynomial.substitute(ring: Ring, args: Map>) : NumberedPolynomial = TODO() /*ring.numberedPolynomial { + val acc = LinkedHashMap, NumberedPolynomial>(coefficients.size) + for ((degs, c) in coefficients) { + val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp() + val newC = args.entries.fold(c.asNumberedPolynomial()) { product, (variable, substitutor) -> + val deg = degs.getOrElse(variable) { 0u } + if (deg == 0u) product else product * power(substitutor, deg) + } + if (newDegs !in acc) acc[newDegs] = c.asNumberedPolynomial() + else acc[newDegs] = acc[newDegs]!! + c + } +}*/ + +/** + * Represent the polynomial as a regular context-less function. + */ +public fun > NumberedPolynomial.asFunction(ring: A): (Map) -> NumberedPolynomial = { substitute(ring, it) } + +/** + * Represent the polynomial as a regular context-less function. + */ +public fun > NumberedPolynomial.asPolynomialFunctionOver(ring: A): (Map>) -> NumberedPolynomial = { substitute(ring, it) } + +// endregion + +// region Algebraic derivative and antiderivative + +/** + * Returns algebraic derivative of received polynomial. + */ +@UnstableKMathAPI +public fun NumberedPolynomial.derivativeBy( + algebra: A, + variable: Int, +): Polynomial where A : Ring, A : NumericAlgebra = algebra { + TODO() +} + +/** + * Returns algebraic derivative of received polynomial. + */ +@UnstableKMathAPI +public fun NumberedPolynomial.derivativeBy( + algebra: A, + variables: IntArray, +): Polynomial where A : Ring, A : NumericAlgebra = algebra { + TODO() +} + +/** + * Returns algebraic derivative of received polynomial. + */ +@UnstableKMathAPI +public fun NumberedPolynomial.derivativeBy( + algebra: A, + variables: Collection, +): Polynomial where A : Ring, A : NumericAlgebra = derivativeBy(algebra, variables.toIntArray()) + +/** + * Create a polynomial witch represents indefinite integral version of this polynomial + */ +@UnstableKMathAPI +public fun NumberedPolynomial.antiderivativeBy( + algebra: A, + variable: Int, +): Polynomial where A : Field, A : NumericAlgebra = algebra { + TODO() +} + +/** + * Create a polynomial witch represents indefinite integral version of this polynomial + */ +@UnstableKMathAPI +public fun NumberedPolynomial.antiderivativeBy( + algebra: A, + variables: IntArray, +): Polynomial where A : Field, A : NumericAlgebra = algebra { + TODO() +} + +/** + * Create a polynomial witch represents indefinite integral version of this polynomial + */ +@UnstableKMathAPI +public fun NumberedPolynomial.antiderivativeBy( + algebra: A, + variables: Collection, +): Polynomial where A : Field, A : NumericAlgebra = antiderivativeBy(algebra, variables.toIntArray()) + +// endregion \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt index 1a3eb7874..4d99b3a45 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt @@ -121,7 +121,7 @@ public fun Polynomial.antiderivative( ): Polynomial where A : Field, A : NumericAlgebra = algebra { val integratedCoefficients = buildList(coefficients.size + 1) { add(zero) - coefficients.forEachIndexed{ index, t -> add(t / (number(index) + one)) } + coefficients.forEachIndexed{ index, t -> add(t / number(index + 1)) } } Polynomial(integratedCoefficients) } @@ -136,4 +136,6 @@ public fun > Polynomial.integrate( ): C = algebra { val integral = antiderivative(algebra) integral.substitute(algebra, range.endInclusive) - integral.substitute(algebra, range.start) -} \ No newline at end of file +} + +// endregion \ No newline at end of file -- 2.34.1 From 033edd3febfc36983a1fd6319941ba453531b6f5 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sun, 13 Mar 2022 03:55:51 +0300 Subject: [PATCH 009/123] Removed kotlin-js-store --- kotlin-js-store/yarn.lock | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 kotlin-js-store/yarn.lock diff --git a/kotlin-js-store/yarn.lock b/kotlin-js-store/yarn.lock deleted file mode 100644 index e69de29bb..000000000 -- 2.34.1 From de53d032afbe7da603b7bc7cc919718c0c193811 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Mon, 14 Mar 2022 14:14:24 +0300 Subject: [PATCH 010/123] 1. Prototyped Rational Functions 2. Added abstract interfaces for removing boilerplates 3. Changed or added default values in interfaces 4. Renamed non-operator `equals` to `equalsTo`, and made it infix --- .../kmath/functions/AbstractPolynomial.kt | 128 ++++- .../functions/AbstractRationalFunction.kt | 500 ++++++++++++++++-- .../kmath/functions/LabeledPolynomial.kt | 24 +- .../kmath/functions/NumberedPolynomial.kt | 74 +-- .../kscience/kmath/functions/Polynomial.kt | 51 +- .../kmath/functions/RationalFunction.kt | 355 +++++++++++++ .../kmath/functions/rationalFunctionUtil.kt | 34 ++ 7 files changed, 998 insertions(+), 168 deletions(-) create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/rationalFunctionUtil.kt diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt index b7b7116f0..69c45798a 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt @@ -154,7 +154,7 @@ public interface AbstractPolynomialSpace> : Ring

* Check if the instant is NOT zero constant. */ @JvmName("constantIsNotZero") - public fun C.isNotZero(): Boolean + public fun C.isNotZero(): Boolean = !isZero() /** * Check if the instant is unit constant. */ @@ -164,7 +164,7 @@ public interface AbstractPolynomialSpace> : Ring

* Check if the instant is NOT unit constant. */ @JvmName("constantIsNotOne") - public fun C.isNotOne(): Boolean + public fun C.isNotOne(): Boolean = !isOne() /** * Check if the instant is minus unit constant. */ @@ -174,7 +174,7 @@ public interface AbstractPolynomialSpace> : Ring

* Check if the instant is NOT minus unit constant. */ @JvmName("constantIsNotMinusOne") - public fun C.isNotMinusOne(): Boolean + public fun C.isNotMinusOne(): Boolean = !isMinusOne() // endregion // region Constant-polynomial relation @@ -232,27 +232,27 @@ public interface AbstractPolynomialSpace> : Ring

/** * Check if the instant is zero polynomial. */ - public fun P.isZero(): Boolean = this == zero + public fun P.isZero(): Boolean = this equalsTo zero /** * Check if the instant is NOT zero polynomial. */ - public fun P.isNotZero(): Boolean = this != zero + public fun P.isNotZero(): Boolean = !isZero() /** * Check if the instant is unit polynomial. */ - public fun P.isOne(): Boolean = this == one + public fun P.isOne(): Boolean = this equalsTo one /** * Check if the instant is NOT unit polynomial. */ - public fun P.isNotOne(): Boolean = this != one + public fun P.isNotOne(): Boolean = !isOne() /** * Check if the instant is minus unit polynomial. */ - public fun P.isMinusOne(): Boolean = this == -one + public fun P.isMinusOne(): Boolean = this equalsTo -one /** * Check if the instant is NOT minus unit polynomial. */ - public fun P.isNotMinusOne(): Boolean = this != -one + public fun P.isNotMinusOne(): Boolean = !isMinusOne() /** * Instance of zero polynomial (zero of the polynomial ring). @@ -266,8 +266,11 @@ public interface AbstractPolynomialSpace> : Ring

/** * Checks equality of the polynomials. */ - @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") - public fun P.equals(other: P): Boolean + public infix fun P.equalsTo(other: P): Boolean + /** + * Checks NOT equality of the polynomials. + */ + public infix fun P.notEqualsTo(other: P): Boolean = !(this equalsTo other) // endregion // Not sure is it necessary... @@ -310,4 +313,107 @@ public interface AbstractPolynomialSpace> : Ring

override fun add(left: P, right: P): P = left + right override fun multiply(left: P, right: P): P = left * right // endregion +} + +/** + * Abstraction of ring of polynomials of type [P] over ring of constants of type [C]. + * + * @param C the type of constants. Polynomials have them as a coefficients in their terms. + * @param P the type of polynomials. + */ +@Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") +public interface AbstractPolynomialSpaceOverRing, A: Ring> : AbstractPolynomialSpace { + + public val ring: A + + // region Constant-integer relation + /** + * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * + * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. + */ + @JvmName("constantIntPlus") + public override operator fun C.plus(other: Int): C = ring { optimizedAddMultiplied(this@plus, one, other) } + /** + * Returns difference between the constant and the integer represented as constant (member of underlying ring). + * + * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. + */ + @JvmName("constantIntMinus") + public override operator fun C.minus(other: Int): C = ring { optimizedAddMultiplied(this@minus, one, -other) } + /** + * Returns product of the constant and the integer represented as constant (member of underlying ring). + * + * The operation is equivalent to sum of [other] copies of [this]. + */ + @JvmName("constantIntTimes") + public override operator fun C.times(other: Int): C = ring { optimizedMultiply(this@times, other) } + // endregion + + // region Integer-constant relation + /** + * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * + * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. + */ + @JvmName("intConstantPlus") + public override operator fun Int.plus(other: C): C = ring { optimizedAddMultiplied(other, one, this@plus) } + /** + * Returns difference between the integer represented as constant (member of underlying ring) and the constant. + * + * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. + */ + @JvmName("intConstantMinus") + public override operator fun Int.minus(other: C): C = ring { optimizedAddMultiplied(-other, one, this@minus) } + /** + * Returns product of the integer represented as constant (member of underlying ring) and the constant. + * + * The operation is equivalent to sum of [this] copies of [other]. + */ + @JvmName("intConstantTimes") + public override operator fun Int.times(other: C): C = ring { optimizedMultiply(other, this@times) } + // endregion + + // region Constant-constant relation + /** + * Returns negation of the constant. + */ + @JvmName("constantUnaryMinus") + @JsName("constantUnaryMinus") + public override operator fun C.unaryMinus(): C = ring { -this@unaryMinus } + /** + * Returns sum of the constants. + */ + @JvmName("constantPlus") + @JsName("constantPlus") + public override operator fun C.plus(other: C): C = ring { this@plus + other } + /** + * Returns difference of the constants. + */ + @JvmName("constantMinus") + @JsName("constantMinus") + public override operator fun C.minus(other: C): C = ring { this@minus - other } + /** + * Returns product of the constants. + */ + @JvmName("constantTimes") + @JsName("constantTimes") + public override operator fun C.times(other: C): C = ring { this@times * other } + + /** + * Check if the instant is zero constant. + */ + @JvmName("constantIsZero") + public override fun C.isZero(): Boolean = ring { this == zero } + /** + * Check if the instant is unit constant. + */ + @JvmName("constantIsOne") + public override fun C.isOne(): Boolean = ring { this == one } + /** + * Check if the instant is minus unit constant. + */ + @JvmName("constantIsMinusOne") + public override fun C.isMinusOne(): Boolean = ring { this == -one } + // endregion } \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt index 34050aa0f..9725ea078 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt @@ -13,7 +13,12 @@ import kotlin.jvm.JvmName /** * Abstraction of rational function. */ -public interface AbstractRationalFunction> +public interface AbstractRationalFunction> { + public val numerator: P + public val denominator: P + public operator fun component1(): P = numerator + public operator fun component2(): P = denominator +} @Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") public interface AbstractRationalFunctionalSpace, R: AbstractRationalFunction> : Ring { @@ -190,7 +195,7 @@ public interface AbstractRationalFunctionalSpace, R: * Check if the instant is NOT zero constant. */ @JvmName("constantIsNotZero") - public fun C.isNotZero(): Boolean + public fun C.isNotZero(): Boolean = !isZero() /** * Check if the instant is unit constant. */ @@ -200,7 +205,7 @@ public interface AbstractRationalFunctionalSpace, R: * Check if the instant is NOT unit constant. */ @JvmName("constantIsNotOne") - public fun C.isNotOne(): Boolean + public fun C.isNotOne(): Boolean = !isOne() /** * Check if the instant is minus unit constant. */ @@ -210,7 +215,7 @@ public interface AbstractRationalFunctionalSpace, R: * Check if the instant is NOT minus unit constant. */ @JvmName("constantIsNotMinusOne") - public fun C.isNotMinusOne(): Boolean + public fun C.isNotMinusOne(): Boolean = !isMinusOne() // endregion // region Constant-polynomial relation @@ -268,42 +273,45 @@ public interface AbstractRationalFunctionalSpace, R: /** * Check if the instant is zero polynomial. */ - public fun P.isZero(): Boolean = this == zeroPolynomial + public fun P.isZero(): Boolean = this equalsTo polynomialZero /** * Check if the instant is NOT zero polynomial. */ - public fun P.isNotZero(): Boolean = this != zeroPolynomial + public fun P.isNotZero(): Boolean = !isZero() /** * Check if the instant is unit polynomial. */ - public fun P.isOne(): Boolean = this == onePolynomial + public fun P.isOne(): Boolean = this equalsTo polynomialOne /** * Check if the instant is NOT unit polynomial. */ - public fun P.isNotOne(): Boolean = this != onePolynomial + public fun P.isNotOne(): Boolean = !isOne() /** * Check if the instant is minus unit polynomial. */ - public fun P.isMinusOne(): Boolean = this == -onePolynomial + public fun P.isMinusOne(): Boolean = this equalsTo -polynomialOne /** * Check if the instant is NOT minus unit polynomial. */ - public fun P.isNotMinusOne(): Boolean = this != -onePolynomial + public fun P.isNotMinusOne(): Boolean = !isMinusOne() /** * Instance of zero polynomial (zero of the polynomial ring). */ - public val zeroPolynomial: P + public val polynomialZero: P /** * Instance of unit polynomial (unit of the polynomial ring). */ - public val onePolynomial: P + public val polynomialOne: P /** * Checks equality of the polynomials. */ - @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") - public fun P.equals(other: P): Boolean + public infix fun P.equalsTo(other: P): Boolean + /** + * Checks NOT equality of the polynomials. + */ + public infix fun P.notEqualsTo(other: P): Boolean = !(this equalsTo other) // endregion // region Constant-rational relation @@ -391,27 +399,27 @@ public interface AbstractRationalFunctionalSpace, R: /** * Check if the instant is zero rational function. */ - public fun R.isZero(): Boolean = this == zero + public fun R.isZero(): Boolean = this equalsTo zero /** * Check if the instant is NOT zero rational function. */ - public fun R.isNotZero(): Boolean = this != zero + public fun R.isNotZero(): Boolean = !isZero() /** * Check if the instant is unit rational function. */ - public fun R.isOne(): Boolean = this == one + public fun R.isOne(): Boolean = this equalsTo one /** * Check if the instant is NOT unit rational function. */ - public fun R.isNotOne(): Boolean = this != one + public fun R.isNotOne(): Boolean = !isOne() /** * Check if the instant is minus unit rational function. */ - public fun R.isMinusOne(): Boolean = this == -one + public fun R.isMinusOne(): Boolean = this equalsTo -one /** * Check if the instant is NOT minus unit rational function. */ - public fun R.isNotMinusOne(): Boolean = this != -one + public fun R.isNotMinusOne(): Boolean = !isMinusOne() /** * Instance of zero rational function (zero of the rational functions ring). @@ -425,8 +433,11 @@ public interface AbstractRationalFunctionalSpace, R: /** * Checks equality of the rational functions. */ - @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") - public fun R.equals(other: R): Boolean + public infix fun R.equalsTo(other: R): Boolean + /** + * Checks NOT equality of the polynomials. + */ + public infix fun R.notEqualsTo(other: R): Boolean = !(this equalsTo other) // endregion // Not sure is it necessary... @@ -453,35 +464,31 @@ public interface AbstractRationalFunctionalSpace, R: * Checks if the instant is **not** constant non-zero polynomial (of degree no more than 0) over considered ring. */ public fun P.isNotNonZeroConstant(): Boolean = !isNonZeroConstant() - + /** + * If polynomial is a constant polynomial represents and returns it as constant. + * Otherwise, (when the polynomial is not constant polynomial) returns `null`. + */ public fun P.asConstantOrNull(): C? - + /** + * If polynomial is a constant polynomial represents and returns it as constant. + * Otherwise, (when the polynomial is not constant polynomial) raises corresponding exception. + */ public fun P.asConstant(): C = asConstantOrNull() ?: error("Can not represent non-constant polynomial as a constant") // endregion // Not sure is it necessary... - // region Polynomial properties + // region Rational properties /** - * Checks if the instant is constant polynomial (of degree no more than 0) over considered ring. + * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is + * zero, degree is -1. */ - public fun R.isConstant(): Boolean + public val R.numeratorDegree: Int get() = numerator.degree /** - * Checks if the instant is **not** constant polynomial (of degree no more than 0) over considered ring. + * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is + * zero, degree is -1. */ - public fun R.isNotConstant(): Boolean = !isConstant() - /** - * Checks if the instant is constant non-zero polynomial (of degree no more than 0) over considered ring. - */ - public fun R.isNonZeroConstant(): Boolean - /** - * Checks if the instant is **not** constant non-zero polynomial (of degree no more than 0) over considered ring. - */ - public fun R.isNotNonZeroConstant(): Boolean = !isNonZeroConstant() - - public fun R.asConstantOrNull(): C? - - public fun R.asConstant(): C = asConstantOrNull() ?: error("Can not represent non-constant polynomial as a constant") + public val R.denominatorDegree: Int get() = denominator.degree // TODO: Перенести в реализацию // fun R.substitute(argument: C): C @@ -501,5 +508,416 @@ public interface AbstractRationalFunctionalSpace, R: // region Legacy override fun add(left: R, right: R): R = left + right override fun multiply(left: R, right: R): R = left * right + // endregion +} + +@Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") +public interface AbstractRationalFunctionalSpaceOverRing, R: AbstractRationalFunction, A: Ring> : AbstractRationalFunctionalSpace { + + public val ring: A + + // region Constant-integer relation + /** + * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * + * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. + */ + @JvmName("constantIntPlus") + public override operator fun C.plus(other: Int): C = ring { optimizedAddMultiplied(this@plus, one, other) } + /** + * Returns difference between the constant and the integer represented as constant (member of underlying ring). + * + * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. + */ + @JvmName("constantIntMinus") + public override operator fun C.minus(other: Int): C = ring { optimizedAddMultiplied(this@minus, one, -other) } + /** + * Returns product of the constant and the integer represented as constant (member of underlying ring). + * + * The operation is equivalent to sum of [other] copies of [this]. + */ + @JvmName("constantIntTimes") + public override operator fun C.times(other: Int): C = ring { optimizedMultiply(this@times, other) } + // endregion + + // region Integer-constant relation + /** + * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * + * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. + */ + @JvmName("intConstantPlus") + public override operator fun Int.plus(other: C): C = ring { optimizedAddMultiplied(other, one, this@plus) } + /** + * Returns difference between the integer represented as constant (member of underlying ring) and the constant. + * + * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. + */ + @JvmName("intConstantMinus") + public override operator fun Int.minus(other: C): C = ring { optimizedAddMultiplied(-other, one, this@minus) } + /** + * Returns product of the integer represented as constant (member of underlying ring) and the constant. + * + * The operation is equivalent to sum of [this] copies of [other]. + */ + @JvmName("intConstantTimes") + public override operator fun Int.times(other: C): C = ring { optimizedMultiply(other, this@times) } + // endregion + + // region Constant-constant relation + /** + * Returns the same constant. + */ + @JvmName("constantUnaryPlus") + @JsName("constantUnaryPlus") + public override operator fun C.unaryPlus(): C = ring { +this@unaryPlus } + /** + * Returns negation of the constant. + */ + @JvmName("constantUnaryMinus") + @JsName("constantUnaryMinus") + public override operator fun C.unaryMinus(): C = ring { -this@unaryMinus } + /** + * Returns sum of the constants. + */ + @JvmName("constantPlus") + @JsName("constantPlus") + public override operator fun C.plus(other: C): C = ring { this@plus + other } + /** + * Returns difference of the constants. + */ + @JvmName("constantMinus") + @JsName("constantMinus") + public override operator fun C.minus(other: C): C = ring { this@minus - other } + /** + * Returns product of the constants. + */ + @JvmName("constantTimes") + @JsName("constantTimes") + public override operator fun C.times(other: C): C = ring { this@times * other } + + /** + * Check if the instant is zero constant. + */ + @JvmName("constantIsZero") + public override fun C.isZero(): Boolean = ring { this@isZero.isZero() } + /** + * Check if the instant is NOT zero constant. + */ + @JvmName("constantIsNotZero") + public override fun C.isNotZero(): Boolean = ring { this@isNotZero.isNotZero() } + /** + * Check if the instant is unit constant. + */ + @JvmName("constantIsOne") + public override fun C.isOne(): Boolean = ring { this@isOne.isOne() } + /** + * Check if the instant is NOT unit constant. + */ + @JvmName("constantIsNotOne") + public override fun C.isNotOne(): Boolean = ring { this@isNotOne.isNotOne() } + /** + * Check if the instant is minus unit constant. + */ + @JvmName("constantIsMinusOne") + public override fun C.isMinusOne(): Boolean = ring { this@isMinusOne.isMinusOne() } + /** + * Check if the instant is NOT minus unit constant. + */ + @JvmName("constantIsNotMinusOne") + public override fun C.isNotMinusOne(): Boolean = ring { this@isNotMinusOne.isNotMinusOne() } + // endregion +} + +@Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") +public interface AbstractRationalFunctionalSpaceOverPolynomialSpace, R: AbstractRationalFunction, A: Ring> : AbstractRationalFunctionalSpace { + + public val polynomialRing: AbstractPolynomialSpace + + // region Constant-integer relation + /** + * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * + * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. + */ + @JvmName("constantIntPlus") + public override operator fun C.plus(other: Int): C = polynomialRing { this@plus + other } + /** + * Returns difference between the constant and the integer represented as constant (member of underlying ring). + * + * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. + */ + @JvmName("constantIntMinus") + public override operator fun C.minus(other: Int): C = polynomialRing { this@minus - other } + /** + * Returns product of the constant and the integer represented as constant (member of underlying ring). + * + * The operation is equivalent to sum of [other] copies of [this]. + */ + @JvmName("constantIntTimes") + public override operator fun C.times(other: Int): C = polynomialRing { this@times * other } + // endregion + + // region Integer-constant relation + /** + * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * + * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. + */ + @JvmName("intConstantPlus") + public override operator fun Int.plus(other: C): C = polynomialRing { this@plus + other } + /** + * Returns difference between the integer represented as constant (member of underlying ring) and the constant. + * + * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. + */ + @JvmName("intConstantMinus") + public override operator fun Int.minus(other: C): C = polynomialRing { this@minus - other } + /** + * Returns product of the integer represented as constant (member of underlying ring) and the constant. + * + * The operation is equivalent to sum of [this] copies of [other]. + */ + @JvmName("intConstantTimes") + public override operator fun Int.times(other: C): C = polynomialRing { this@times * other } + // endregion + + // region Polynomial-integer relation + /** + * Returns sum of the constant and the integer represented as polynomial. + * + * The operation is equivalent to adding [other] copies of unit polynomial to [this]. + */ + public override operator fun P.plus(other: Int): P = polynomialRing { this@plus + other } + /** + * Returns difference between the constant and the integer represented as polynomial. + * + * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. + */ + public override operator fun P.minus(other: Int): P = polynomialRing { this@minus - other } + /** + * Returns product of the constant and the integer represented as polynomial. + * + * The operation is equivalent to sum of [other] copies of [this]. + */ + public override operator fun P.times(other: Int): P = polynomialRing { this@times * other } + // endregion + + // region Integer-polynomial relation + /** + * Returns sum of the integer represented as polynomial and the constant. + * + * The operation is equivalent to adding [this] copies of unit polynomial to [other]. + */ + public override operator fun Int.plus(other: P): P = polynomialRing { this@plus + other } + /** + * Returns difference between the integer represented as polynomial and the constant. + * + * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. + */ + public override operator fun Int.minus(other: P): P = polynomialRing { this@minus - other } + /** + * Returns product of the integer represented as polynomial and the constant. + * + * The operation is equivalent to sum of [this] copies of [other]. + */ + public override operator fun Int.times(other: P): P = polynomialRing { this@times * other } + // endregion + + // region Constant-constant relation + /** + * Returns the same constant. + */ + @JvmName("constantUnaryPlus") + @JsName("constantUnaryPlus") + public override operator fun C.unaryPlus(): C = polynomialRing { +this@unaryPlus } + /** + * Returns negation of the constant. + */ + @JvmName("constantUnaryMinus") + @JsName("constantUnaryMinus") + public override operator fun C.unaryMinus(): C = polynomialRing { -this@unaryMinus } + /** + * Returns sum of the constants. + */ + @JvmName("constantPlus") + @JsName("constantPlus") + public override operator fun C.plus(other: C): C = polynomialRing { this@plus + other } + /** + * Returns difference of the constants. + */ + @JvmName("constantMinus") + @JsName("constantMinus") + public override operator fun C.minus(other: C): C = polynomialRing { this@minus - other } + /** + * Returns product of the constants. + */ + @JvmName("constantTimes") + @JsName("constantTimes") + public override operator fun C.times(other: C): C = polynomialRing { this@times * other } + + /** + * Check if the instant is zero constant. + */ + @JvmName("constantIsZero") + public override fun C.isZero(): Boolean = polynomialRing { this@isZero.isZero() } + /** + * Check if the instant is NOT zero constant. + */ + @JvmName("constantIsNotZero") + public override fun C.isNotZero(): Boolean = polynomialRing { this@isNotZero.isNotZero() } + /** + * Check if the instant is unit constant. + */ + @JvmName("constantIsOne") + public override fun C.isOne(): Boolean = polynomialRing { this@isOne.isOne() } + /** + * Check if the instant is NOT unit constant. + */ + @JvmName("constantIsNotOne") + public override fun C.isNotOne(): Boolean = polynomialRing { this@isNotOne.isNotOne() } + /** + * Check if the instant is minus unit constant. + */ + @JvmName("constantIsMinusOne") + public override fun C.isMinusOne(): Boolean = polynomialRing { this@isMinusOne.isMinusOne() } + /** + * Check if the instant is NOT minus unit constant. + */ + @JvmName("constantIsNotMinusOne") + public override fun C.isNotMinusOne(): Boolean = polynomialRing { this@isNotMinusOne.isNotMinusOne() } + // endregion + + // region Constant-polynomial relation + /** + * Returns sum of the constant represented as polynomial and the polynomial. + */ + public override operator fun C.plus(other: P): P = polynomialRing { this@plus + other } + /** + * Returns difference between the constant represented as polynomial and the polynomial. + */ + public override operator fun C.minus(other: P): P = polynomialRing { this@minus - other } + /** + * Returns product of the constant represented as polynomial and the polynomial. + */ + public override operator fun C.times(other: P): P = polynomialRing { this@times * other } + // endregion + + // region Polynomial-constant relation + /** + * Returns sum of the constant represented as polynomial and the polynomial. + */ + public override operator fun P.plus(other: C): P = polynomialRing { this@plus + other } + /** + * Returns difference between the constant represented as polynomial and the polynomial. + */ + public override operator fun P.minus(other: C): P = polynomialRing { this@minus - other } + /** + * Returns product of the constant represented as polynomial and the polynomial. + */ + public override operator fun P.times(other: C): P = polynomialRing { this@times * other } + // endregion + + // region Polynomial-polynomial relation + /** + * Returns the same polynomial. + */ + public override operator fun P.unaryPlus(): P = polynomialRing { +this@unaryPlus } + /** + * Returns negation of the polynomial. + */ + public override operator fun P.unaryMinus(): P = polynomialRing { -this@unaryMinus } + /** + * Returns sum of the polynomials. + */ + public override operator fun P.plus(other: P): P = polynomialRing { this@plus + other } + /** + * Returns difference of the polynomials. + */ + public override operator fun P.minus(other: P): P = polynomialRing { this@minus - other } + /** + * Returns product of the polynomials. + */ + public override operator fun P.times(other: P): P = polynomialRing { this@times * other } + + /** + * Check if the instant is zero polynomial. + */ + public override fun P.isZero(): Boolean = polynomialRing { this@isZero.isZero() } + /** + * Check if the instant is NOT zero polynomial. + */ + public override fun P.isNotZero(): Boolean = polynomialRing { this@isNotZero.isNotZero() } + /** + * Check if the instant is unit polynomial. + */ + public override fun P.isOne(): Boolean = polynomialRing { this@isOne.isOne() } + /** + * Check if the instant is NOT unit polynomial. + */ + public override fun P.isNotOne(): Boolean = polynomialRing { this@isNotOne.isNotOne() } + /** + * Check if the instant is minus unit polynomial. + */ + public override fun P.isMinusOne(): Boolean = polynomialRing { this@isMinusOne.isMinusOne() } + /** + * Check if the instant is NOT minus unit polynomial. + */ + public override fun P.isNotMinusOne(): Boolean = polynomialRing { this@isNotMinusOne.isNotMinusOne() } + + /** + * Instance of zero polynomial (zero of the polynomial ring). + */ + public override val polynomialZero: P get() = polynomialRing.zero + /** + * Instance of unit polynomial (unit of the polynomial ring). + */ + public override val polynomialOne: P get() = polynomialRing.one + + /** + * Checks equality of the polynomials. + */ + public override infix fun P.equalsTo(other: P): Boolean = polynomialRing { this@equalsTo equalsTo other } + /** + * Checks NOT equality of the polynomials. + */ + public override infix fun P.notEqualsTo(other: P): Boolean = polynomialRing { this@notEqualsTo notEqualsTo other } + // endregion + + // Not sure is it necessary... + // region Polynomial properties + /** + * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is + * zero, degree is -1. + */ + public override val P.degree: Int get() = polynomialRing { this@degree.degree } + + /** + * Checks if the instant is constant polynomial (of degree no more than 0) over considered ring. + */ + public override fun P.isConstant(): Boolean = polynomialRing { this@isConstant.isConstant() } + /** + * Checks if the instant is **not** constant polynomial (of degree no more than 0) over considered ring. + */ + public override fun P.isNotConstant(): Boolean = polynomialRing { this@isNotConstant.isNotConstant() } + /** + * Checks if the instant is constant non-zero polynomial (of degree no more than 0) over considered ring. + */ + public override fun P.isNonZeroConstant(): Boolean = polynomialRing { this@isNonZeroConstant.isNonZeroConstant() } + /** + * Checks if the instant is **not** constant non-zero polynomial (of degree no more than 0) over considered ring. + */ + public override fun P.isNotNonZeroConstant(): Boolean = polynomialRing { this@isNotNonZeroConstant.isNotNonZeroConstant() } + /** + * If polynomial is a constant polynomial represents and returns it as constant. + * Otherwise, (when the polynomial is not constant polynomial) returns `null`. + */ + public override fun P.asConstantOrNull(): C? = polynomialRing { this@asConstantOrNull.asConstantOrNull() } + /** + * If polynomial is a constant polynomial represents and returns it as constant. + * Otherwise, (when the polynomial is not constant polynomial) raises corresponding exception. + */ + public override fun P.asConstant(): C = polynomialRing { this@asConstant.asConstant() } + // endregion } \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt index 48f6f57fa..cbd713d27 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt @@ -13,7 +13,7 @@ import kotlin.math.max * * @param C Ring in which the polynomial is considered. */ -public class LabeledPolynomial +public data class LabeledPolynomial internal constructor( /** * Map that collects coefficients of the polynomial. Every non-zero monomial @@ -788,7 +788,7 @@ public class LabeledPolynomialSpace>( isZero() -> zero other.isZero() -> zero else -> LabeledPolynomial( - buildCoefficients { + buildCoefficients(coefficients.size * other.coefficients.size) { for ((degs1, c1) in coefficients) for ((degs2, c2) in other.coefficients) { val degs = degs1.toMutableMap() degs2.mapValuesTo(degs) { (variable, deg) -> degs.getOrElse(variable) { 0u } + deg } @@ -804,7 +804,7 @@ public class LabeledPolynomialSpace>( // TODO: Docs @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") - override fun LabeledPolynomial.equals(other: LabeledPolynomial): Boolean = + override infix fun LabeledPolynomial.equalsTo(other: LabeledPolynomial): Boolean = when { this === other -> true else -> coefficients.size == other.coefficients.size && @@ -896,15 +896,9 @@ public class LabeledPolynomialSpace>( // public inline operator fun LabeledPolynomial.invoke(argument: Map>): LabeledPolynomial = this.substitute(ring, argument) // endregion - // region Legacy - @Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") - override inline fun add(left: LabeledPolynomial, right: LabeledPolynomial): LabeledPolynomial = left + right - @Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") - override inline fun multiply(left: LabeledPolynomial, right: LabeledPolynomial): LabeledPolynomial = left * right - // endregion - // region Utilities // TODO: Move to region internal utilities with context receiver + @JvmName("applyAndRemoveZerosInternal") internal fun MutableMap, C>.applyAndRemoveZeros(block: MutableMap, C>.() -> Unit) : MutableMap, C> { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) @@ -916,12 +910,20 @@ public class LabeledPolynomialSpace>( internal fun Map, C>.applyAndRemoveZeros(block: MutableMap, C>.() -> Unit) : Map, C> = toMutableMap().applyAndRemoveZeros(block) @OptIn(ExperimentalTypeInference::class) - internal fun buildCoefficients(@BuilderInference builderAction: MutableMap, C>.() -> Unit): Map, C> { + internal inline fun buildCoefficients(@BuilderInference builderAction: MutableMap, C>.() -> Unit): Map, C> { contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) } return buildMap { builderAction() for ((degs, c) in this) if (c.isZero()) this.remove(degs) } } + @OptIn(ExperimentalTypeInference::class) + internal inline fun buildCoefficients(capacity: Int, @BuilderInference builderAction: MutableMap, C>.() -> Unit): Map, C> { + contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) } + return buildMap(capacity) { + builderAction() + for ((degs, c) in this) if (c.isZero()) this.remove(degs) + } + } // endregion } \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt index f1ad9a74f..f11338161 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -13,7 +13,7 @@ import kotlin.math.max * * @param C the type of constants. */ -public class NumberedPolynomial +public data class NumberedPolynomial internal constructor( /** * Map that collects coefficients of the polynomial. Every monomial `a x_1^{d_1} ... x_n^{d_n}` is represented as @@ -259,27 +259,9 @@ public fun > C.asNumberedPolynomial() : NumberedPolynomial = Nu * @param ring the [A] instance. */ @Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE", "INAPPLICABLE_JVM_NAME") -public class NumberedPolynomialSpace>( - public val ring: A, -) : AbstractPolynomialSpace> { - // region Constant-integer relation - @JvmName("constantIntPlus") - public override operator fun C.plus(other: Int): C = ring { optimizedAddMultiplied(this@plus, one, other) } - @JvmName("constantIntMinus") - public override operator fun C.minus(other: Int): C = ring { optimizedAddMultiplied(this@minus, one, -other) } - @JvmName("constantIntTimes") - public override operator fun C.times(other: Int): C = ring { optimizedMultiply(this@times, other) } - // endregion - - // region Integer-constant relation - @JvmName("intConstantPlus") - public override operator fun Int.plus(other: C): C = ring { optimizedAddMultiplied(other, one, this@plus) } - @JvmName("intConstantMinus") - public override operator fun Int.minus(other: C): C = ring { optimizedAddMultiplied(-other, one, this@minus) } - @JvmName("intConstantTimes") - public override operator fun Int.times(other: C): C = ring { optimizedMultiply(other, this@times) } - // endregion - +public open class NumberedPolynomialSpace>( + public final override val ring: A, +) : AbstractPolynomialSpaceOverRing, A> { // region Polynomial-integer relation public override operator fun NumberedPolynomial.plus(other: Int): NumberedPolynomial = if (other == 0) this @@ -362,29 +344,6 @@ public class NumberedPolynomialSpace>( ) // endregion - // region Constant-constant relation - @JvmName("constantUnaryMinus") - override operator fun C.unaryMinus(): C = ring { -this@unaryMinus } - @JvmName("constantPlus") - override operator fun C.plus(other: C): C = ring { this@plus + other } - @JvmName("constantMinus") - override operator fun C.minus(other: C): C = ring { this@minus - other } - @JvmName("constantTimes") - override operator fun C.times(other: C): C = ring { this@times * other } - @JvmName("constantIsZero") - public override fun C.isZero(): Boolean = ring { this == zero } - @JvmName("constantIsNotZero") - public override fun C.isNotZero(): Boolean = ring { this != zero } - @JvmName("constantIsOne") - public override fun C.isOne(): Boolean = ring { this == one } - @JvmName("constantIsNotOne") - public override fun C.isNotOne(): Boolean = ring { this != one } - @JvmName("constantIsMinusOne") - public override fun C.isMinusOne(): Boolean = ring { this == -one } - @JvmName("constantIsNotMinusOne") - public override fun C.isNotMinusOne(): Boolean = ring { this != -one } - // endregion - // region Constant-polynomial relation override operator fun C.plus(other: NumberedPolynomial): NumberedPolynomial = if (this.isZero()) other @@ -521,7 +480,7 @@ public class NumberedPolynomialSpace>( other.isZero() -> zero else -> NumberedPolynomial( - buildCoefficients { + buildCoefficients(coefficients.size * other.coefficients.size) { for ((degs1, c1) in coefficients) for ((degs2, c2) in other.coefficients) { val degs = (0..max(degs1.lastIndex, degs2.lastIndex)) @@ -534,7 +493,6 @@ public class NumberedPolynomialSpace>( } public override fun NumberedPolynomial.isZero(): Boolean = coefficients.values.all { it.isZero() } - public override fun NumberedPolynomial.isNotZero(): Boolean = coefficients.values.any { it.isNotZero() } public override fun NumberedPolynomial.isOne(): Boolean = with(coefficients) { var foundAbsoluteTermAndItIsOne = false @@ -547,7 +505,6 @@ public class NumberedPolynomialSpace>( } foundAbsoluteTermAndItIsOne } - public override fun NumberedPolynomial.isNotOne(): Boolean = !isOne() public override fun NumberedPolynomial.isMinusOne(): Boolean = with(coefficients) { var foundAbsoluteTermAndItIsMinusOne = false @@ -560,7 +517,6 @@ public class NumberedPolynomialSpace>( } foundAbsoluteTermAndItIsMinusOne } - public override fun NumberedPolynomial.isNotMinusOne(): Boolean = !isMinusOne() override val zero: NumberedPolynomial = NumberedPolynomial(emptyMap()) override val one: NumberedPolynomial = @@ -572,7 +528,7 @@ public class NumberedPolynomialSpace>( // TODO: Docs @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") - override fun NumberedPolynomial.equals(other: NumberedPolynomial): Boolean = + override infix fun NumberedPolynomial.equalsTo(other: NumberedPolynomial): Boolean = when { this === other -> true else -> coefficients.size == other.coefficients.size && @@ -658,15 +614,9 @@ public class NumberedPolynomialSpace>( public inline operator fun NumberedPolynomial.invoke(argument: Map>): NumberedPolynomial = this.substitute(ring, argument) // endregion - // region Legacy - @Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") - override inline fun add(left: NumberedPolynomial, right: NumberedPolynomial): NumberedPolynomial = left + right - @Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") - override inline fun multiply(left: NumberedPolynomial, right: NumberedPolynomial): NumberedPolynomial = left * right - // endregion - // region Utilities // TODO: Move to region internal utilities with context receiver + @JvmName("applyAndRemoveZerosInternal") internal fun MutableMap, C>.applyAndRemoveZeros(block: MutableMap, C>.() -> Unit) : MutableMap, C> { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) @@ -678,12 +628,20 @@ public class NumberedPolynomialSpace>( internal fun Map, C>.applyAndRemoveZeros(block: MutableMap, C>.() -> Unit) : Map, C> = toMutableMap().applyAndRemoveZeros(block) @OptIn(ExperimentalTypeInference::class) - internal fun buildCoefficients(@BuilderInference builderAction: MutableMap, C>.() -> Unit): Map, C> { + internal inline fun buildCoefficients(@BuilderInference builderAction: MutableMap, C>.() -> Unit): Map, C> { contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) } return buildMap { builderAction() for ((degs, c) in this) if (c.isZero()) this.remove(degs) } } + @OptIn(ExperimentalTypeInference::class) + internal inline fun buildCoefficients(capacity: Int, @BuilderInference builderAction: MutableMap, C>.() -> Unit): Map, C> { + contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) } + return buildMap(capacity) { + builderAction() + for ((degs, c) in this) if (c.isZero()) this.remove(degs) + } + } // endregion } \ No newline at end of file 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 99d6b0659..2c764f4f5 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 @@ -15,7 +15,7 @@ import kotlin.math.min * * @param coefficients constant is the leftmost coefficient. */ -public class Polynomial(public val coefficients: List) : AbstractPolynomial { +public data class Polynomial(public val coefficients: List) : AbstractPolynomial { override fun toString(): String = "Polynomial$coefficients" } @@ -69,25 +69,8 @@ public fun T.asPolynomial() : Polynomial = Polynomial(listOf(this)) */ @Suppress("INAPPLICABLE_JVM_NAME") // TODO: KT-31420 public open class PolynomialSpace>( - public val ring: A, -) : AbstractPolynomialSpace> { - // region Constant-integer relation - @JvmName("constantIntPlus") - public override operator fun C.plus(other: Int): C = ring { optimizedAddMultiplied(this@plus, one, other) } - @JvmName("constantIntMinus") - public override operator fun C.minus(other: Int): C = ring { optimizedAddMultiplied(this@minus, one, -other) } - @JvmName("constantIntTimes") - public override operator fun C.times(other: Int): C = ring { optimizedMultiply(this@times, other) } - // endregion - - // region Integer-constant relation - @JvmName("intConstantPlus") - public override operator fun Int.plus(other: C): C = ring { optimizedAddMultiplied(other, one, this@plus) } - @JvmName("intConstantMinus") - public override operator fun Int.minus(other: C): C = ring { optimizedAddMultiplied(-other, one, this@minus) } - @JvmName("intConstantTimes") - public override operator fun Int.times(other: C): C = ring { optimizedMultiply(other, this@times) } - // endregion + public final override val ring: A, +) : AbstractPolynomialSpaceOverRing, A> { // region Polynomial-integer relation public override operator fun Polynomial.plus(other: Int): Polynomial = @@ -179,29 +162,6 @@ public open class PolynomialSpace>( ) // endregion - // region Constant-constant relation - @JvmName("constantUnaryMinus") - public override operator fun C.unaryMinus(): C = ring { -this@unaryMinus } - @JvmName("constantPlus") - public override operator fun C.plus(other: C): C = ring { this@plus + other } - @JvmName("constantMinus") - public override operator fun C.minus(other: C): C = ring { this@minus - other } - @JvmName("constantTimes") - public override operator fun C.times(other: C): C = ring { this@times * other } - @JvmName("constantIsZero") - public override fun C.isZero(): Boolean = ring { this == zero } - @JvmName("constantIsNotZero") - public override fun C.isNotZero(): Boolean = ring { this != zero } - @JvmName("constantIsOne") - public override fun C.isOne(): Boolean = ring { this == one } - @JvmName("constantIsNotOne") - public override fun C.isNotOne(): Boolean = ring { this != one } - @JvmName("constantIsMinusOne") - public override fun C.isMinusOne(): Boolean = ring { this == -one } - @JvmName("constantIsNotMinusOne") - public override fun C.isNotMinusOne(): Boolean = ring { this != -one } - // endregion - // region Constant-polynomial relation public override operator fun C.plus(other: Polynomial): Polynomial = if (this.isZero()) other @@ -355,19 +315,16 @@ public open class PolynomialSpace>( } public override fun Polynomial.isZero(): Boolean = coefficients.all { it.isZero() } - public override fun Polynomial.isNotZero(): Boolean = coefficients.any { it.isNotZero() } public override fun Polynomial.isOne(): Boolean = with(coefficients) { isNotEmpty() && asSequence().withIndex().any { (index, c) -> if (index == 0) c.isOne() else c.isZero() } } // TODO: It's better to write new methods like `anyIndexed`. But what's better way to do it? - public override fun Polynomial.isNotOne(): Boolean = !isOne() public override fun Polynomial.isMinusOne(): Boolean = with(coefficients) { isNotEmpty() && asSequence().withIndex().any { (index, c) -> if (index == 0) c.isMinusOne() else c.isZero() } } // TODO: It's better to write new methods like `anyIndexed`. But what's better way to do it? - public override fun Polynomial.isNotMinusOne(): Boolean = !isMinusOne() override val zero: Polynomial = Polynomial(emptyList()) override val one: Polynomial = Polynomial(listOf(ring.one)) @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") - public override fun Polynomial.equals(other: Polynomial): Boolean = + public override infix fun Polynomial.equalsTo(other: Polynomial): Boolean = when { this === other -> true else -> { diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt new file mode 100644 index 000000000..778ffb895 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt @@ -0,0 +1,355 @@ +package space.kscience.kmath.functions + +import space.kscience.kmath.operations.* +import kotlin.jvm.JvmName +import kotlin.math.max +import kotlin.math.min + + +public data class RationalFunction internal constructor ( + public override val numerator: Polynomial, + public override val denominator: Polynomial +) : AbstractRationalFunction> { + override fun toString(): String = "RationalFunction${numerator.coefficients}/${denominator.coefficients}" +} + +// region Internal utilities + +/** + * Represents internal [RationalFunction] errors. + */ +internal class RationalFunctionError : Error { + constructor(): super() + constructor(message: String): super(message) + constructor(message: String?, cause: Throwable?): super(message, cause) + constructor(cause: Throwable?): super(cause) +} + +/** + * Throws an [RationalFunction] with the given [message]. + */ +internal fun rationalFunctionError(message: Any): Nothing = throw RationalFunctionError(message.toString()) + +// endregion + +// region Constructors and converters +// Waiting for context receivers :( TODO: Replace with context receivers when they will be available + +//context(RationalFunctionSpace) +//@Suppress("FunctionName") +//internal fun > RationalFunction(numerator: Polynomial, denominator: Polynomial): RationalFunction = +// if (denominator.isZero()) throw ArithmeticException("/ by zero") +// else RationalFunction(numerator, denominator) +//context(RationalFunctionSpace) +//@Suppress("FunctionName") +//public fun > RationalFunction(numeratorCoefficients: List, denominatorCoefficients: List, reverse: Boolean = false): RationalFunction = +// RationalFunction( +// Polynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), +// Polynomial( with(denominatorCoefficients) { if (reverse) reversed() else this } ).also { if (it.isZero()) } +// ) +//context(RationalFunctionSpace) +//@Suppress("FunctionName") +//public fun > RationalFunction(numerator: Polynomial): RationalFunction = +// RationalFunction(numerator, onePolynomial) +//context(RationalFunctionSpace) +//@Suppress("FunctionName") +//public fun > RationalFunction(numeratorCoefficients: List, reverse: Boolean = false): RationalFunction = +// RationalFunction( +// Polynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ) +// ) + +// endregion + +public class RationalFunctionSpace> ( + public val ring: A, +) : AbstractRationalFunctionalSpaceOverPolynomialSpace, RationalFunction, A> { + + override val polynomialRing : PolynomialSpace = PolynomialSpace(ring) + + // region Rational-integer relation + /** + * Returns sum of the rational function and the integer represented as rational function. + * + * The operation is equivalent to adding [other] copies of unit polynomial to [this]. + */ + public override operator fun RationalFunction.plus(other: Int): RationalFunction = + RationalFunction( + numerator + denominator * other, + denominator + ) + /** + * Returns difference between the rational function and the integer represented as rational function. + * + * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. + */ + public override operator fun RationalFunction.minus(other: Int): RationalFunction = + RationalFunction( + numerator - denominator * other, + denominator + ) + /** + * Returns product of the rational function and the integer represented as rational function. + * + * The operation is equivalent to sum of [other] copies of [this]. + */ + public override operator fun RationalFunction.times(other: Int): RationalFunction = + RationalFunction( + numerator * other, + denominator + ) + // endregion + + // region Integer-Rational relation + /** + * Returns sum of the integer represented as rational function and the rational function. + * + * The operation is equivalent to adding [this] copies of unit polynomial to [other]. + */ + public override operator fun Int.plus(other: RationalFunction): RationalFunction = TODO() + /** + * Returns difference between the integer represented as rational function and the rational function. + * + * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. + */ + public override operator fun Int.minus(other: RationalFunction): RationalFunction = TODO() + /** + * Returns product of the integer represented as rational function and the rational function. + * + * The operation is equivalent to sum of [this] copies of [other]. + */ + public override operator fun Int.times(other: RationalFunction): RationalFunction = TODO() + // endregion + + // region Constant-rational relation + /** + * Returns sum of the constant represented as rational function and the rational function. + */ + public override operator fun C.plus(other: RationalFunction): RationalFunction = TODO() + /** + * Returns difference between the constant represented as polynomial and the rational function. + */ + public override operator fun C.minus(other: RationalFunction): RationalFunction = TODO() + /** + * Returns product of the constant represented as polynomial and the rational function. + */ + public override operator fun C.times(other: RationalFunction): RationalFunction = TODO() + // endregion + + // region Rational-constant relation + /** + * Returns sum of the constant represented as rational function and the rational function. + */ + public override operator fun RationalFunction.plus(other: C): RationalFunction = + RationalFunction( + numerator + denominator * other, + denominator + ) + /** + * Returns difference between the constant represented as rational function and the rational function. + */ + public override operator fun RationalFunction.minus(other: C): RationalFunction = + RationalFunction( + numerator - denominator * other, + denominator + ) + /** + * Returns product of the constant represented as rational function and the rational function. + */ + public override operator fun RationalFunction.times(other: C): RationalFunction = + RationalFunction( + numerator * other, + denominator + ) + // endregion + + // region Polynomial-rational relation + /** + * Returns sum of the polynomial represented as rational function and the rational function. + */ + public override operator fun Polynomial.plus(other: RationalFunction): RationalFunction = TODO() + /** + * Returns difference between the polynomial represented as polynomial and the rational function. + */ + public override operator fun Polynomial.minus(other: RationalFunction): RationalFunction = TODO() + /** + * Returns product of the polynomial represented as polynomial and the rational function. + */ + public override operator fun Polynomial.times(other: RationalFunction): RationalFunction = TODO() + // endregion + + // region Rational-polynomial relation + /** + * Returns sum of the polynomial represented as rational function and the rational function. + */ + public override operator fun RationalFunction.plus(other: Polynomial): RationalFunction = + RationalFunction( + numerator + denominator * other, + denominator + ) + /** + * Returns difference between the polynomial represented as rational function and the rational function. + */ + public override operator fun RationalFunction.minus(other: Polynomial): RationalFunction = + RationalFunction( + numerator - denominator * other, + denominator + ) + /** + * Returns product of the polynomial represented as rational function and the rational function. + */ + public override operator fun RationalFunction.times(other: Polynomial): RationalFunction = + RationalFunction( + numerator * other, + denominator + ) + // endregion + + // region Rational-rational relation + /** + * Returns negation of the rational function. + */ + public override operator fun RationalFunction.unaryMinus(): RationalFunction = RationalFunction(-numerator, denominator) + /** + * Returns sum of the rational functions. + */ + public override operator fun RationalFunction.plus(other: RationalFunction): RationalFunction = + RationalFunction( + numerator * other.denominator + denominator * other.numerator, + denominator * other.denominator + ) + /** + * Returns difference of the rational functions. + */ + public override operator fun RationalFunction.minus(other: RationalFunction): RationalFunction = + RationalFunction( + numerator * other.denominator - denominator * other.numerator, + denominator * other.denominator + ) + /** + * Returns product of the rational functions. + */ + public override operator fun RationalFunction.times(other: RationalFunction): RationalFunction = + RationalFunction( + numerator * other.numerator, + denominator * other.denominator + ) + + /** + * Check if the instant is zero rational function. + */ + public override fun RationalFunction.isZero(): Boolean = numerator.isZero() + /** + * Check if the instant is unit rational function. + */ + public override fun RationalFunction.isOne(): Boolean = numerator.equalsTo(denominator) + /** + * Check if the instant is minus unit rational function. + */ + public override fun RationalFunction.isMinusOne(): Boolean = (numerator + denominator).isZero() + + /** + * Instance of zero rational function (zero of the rational functions ring). + */ + public override val zero: RationalFunction = RationalFunction(polynomialZero, polynomialOne) + /** + * Instance of unit polynomial (unit of the rational functions ring). + */ + public override val one: RationalFunction = RationalFunction(polynomialOne, polynomialOne) + + /** + * Checks equality of the rational functions. + */ + @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") + public override infix fun RationalFunction.equalsTo(other: RationalFunction): Boolean = + when { + this === other -> true + numeratorDegree - denominatorDegree != with(other) { numeratorDegree - denominatorDegree } -> false + else -> numerator * other.denominator equalsTo other.numerator * denominator + } + // endregion + + // region REST TODO: Разобрать + + public operator fun RationalFunction.div(other: RationalFunction): RationalFunction = + RationalFunction( + numerator * other.denominator, + denominator * other.numerator + ) + + public operator fun RationalFunction.div(other: Polynomial): RationalFunction = + RationalFunction( + numerator, + denominator * other + ) + + public operator fun RationalFunction.div(other: C): RationalFunction = + RationalFunction( + numerator, + denominator * other + ) + + public operator fun RationalFunction.div(other: Int): RationalFunction = + RationalFunction( + numerator, + denominator * other + ) + +// operator fun invoke(arg: UnivariatePolynomial): RationalFunction = +// RationalFunction( +// numerator(arg), +// denominator(arg) +// ) +// +// operator fun invoke(arg: RationalFunction): RationalFunction { +// val num = numerator invokeRFTakeNumerator arg +// val den = denominator invokeRFTakeNumerator arg +// val degreeDif = numeratorDegree - denominatorDegree +// return if (degreeDif > 0) +// RationalFunction( +// num, +// multiplyByPower(den, arg.denominator, degreeDif) +// ) +// else +// RationalFunction( +// multiplyByPower(num, arg.denominator, -degreeDif), +// den +// ) +// } +// +// override fun toString(): String = toString(UnivariatePolynomial.variableName) +// +// fun toString(withVariableName: String = UnivariatePolynomial.variableName): String = +// when(true) { +// numerator.isZero() -> "0" +// denominator.isOne() -> numerator.toString(withVariableName) +// else -> "${numerator.toStringWithBrackets(withVariableName)}/${denominator.toStringWithBrackets(withVariableName)}" +// } +// +// fun toStringWithBrackets(withVariableName: String = UnivariatePolynomial.variableName): String = +// when(true) { +// numerator.isZero() -> "0" +// denominator.isOne() -> numerator.toStringWithBrackets(withVariableName) +// else -> "(${numerator.toStringWithBrackets(withVariableName)}/${denominator.toStringWithBrackets(withVariableName)})" +// } +// +// fun toReversedString(withVariableName: String = UnivariatePolynomial.variableName): String = +// when(true) { +// numerator.isZero() -> "0" +// denominator.isOne() -> numerator.toReversedString(withVariableName) +// else -> "${numerator.toReversedStringWithBrackets(withVariableName)}/${denominator.toReversedStringWithBrackets(withVariableName)}" +// } +// +// fun toReversedStringWithBrackets(withVariableName: String = UnivariatePolynomial.variableName): String = +// when(true) { +// numerator.isZero() -> "0" +// denominator.isOne() -> numerator.toReversedStringWithBrackets(withVariableName) +// else -> "(${numerator.toReversedStringWithBrackets(withVariableName)}/${denominator.toReversedStringWithBrackets(withVariableName)})" +// } +// +// fun removeZeros() = +// RationalFunction( +// numerator.removeZeros(), +// denominator.removeZeros() +// ) + // endregion +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/rationalFunctionUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/rationalFunctionUtil.kt new file mode 100644 index 000000000..9147bc023 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/rationalFunctionUtil.kt @@ -0,0 +1,34 @@ +package space.kscience.kmath.functions + + +// region Operator extensions + +// region Field case + +//operator fun > RationalFunction.invoke(arg: T): T = numerator(arg) / denominator(arg) +// +//fun > RationalFunction.reduced(): RationalFunction = +// polynomialGCD(numerator, denominator).let { +// RationalFunction( +// numerator / it, +// denominator / it +// ) +// } + +// endregion + +// endregion + +// region Derivatives +///** +// * Returns result of applying formal derivative to the polynomial. +// * +// * @param T Field where we are working now. +// * @return Result of the operator. +// */ +//fun > RationalFunction.derivative() = +// RationalFunction( +// numerator.derivative() * denominator - denominator.derivative() * numerator, +// denominator * denominator +// ) +// endregion \ No newline at end of file -- 2.34.1 From 07f4b83722e2b509f79a212612a952d8a0d64eba Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Mon, 14 Mar 2022 14:18:15 +0300 Subject: [PATCH 011/123] Fixed forgotten TODOs --- .../kmath/functions/RationalFunction.kt | 54 +++++++++++++++---- 1 file changed, 45 insertions(+), 9 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt index 778ffb895..78ca556db 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt @@ -105,34 +105,58 @@ public class RationalFunctionSpace> ( * * The operation is equivalent to adding [this] copies of unit polynomial to [other]. */ - public override operator fun Int.plus(other: RationalFunction): RationalFunction = TODO() + public override operator fun Int.plus(other: RationalFunction): RationalFunction = + RationalFunction( + other.denominator * this + other.numerator, + other.denominator + ) /** * Returns difference between the integer represented as rational function and the rational function. * * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. */ - public override operator fun Int.minus(other: RationalFunction): RationalFunction = TODO() + public override operator fun Int.minus(other: RationalFunction): RationalFunction = + RationalFunction( + other.denominator * this - other.numerator, + other.denominator + ) /** * Returns product of the integer represented as rational function and the rational function. * * The operation is equivalent to sum of [this] copies of [other]. */ - public override operator fun Int.times(other: RationalFunction): RationalFunction = TODO() + public override operator fun Int.times(other: RationalFunction): RationalFunction = + RationalFunction( + this * other.numerator, + other.denominator + ) // endregion // region Constant-rational relation /** * Returns sum of the constant represented as rational function and the rational function. */ - public override operator fun C.plus(other: RationalFunction): RationalFunction = TODO() + public override operator fun C.plus(other: RationalFunction): RationalFunction = + RationalFunction( + other.denominator * this + other.numerator, + other.denominator + ) /** * Returns difference between the constant represented as polynomial and the rational function. */ - public override operator fun C.minus(other: RationalFunction): RationalFunction = TODO() + public override operator fun C.minus(other: RationalFunction): RationalFunction = + RationalFunction( + other.denominator * this - other.numerator, + other.denominator + ) /** * Returns product of the constant represented as polynomial and the rational function. */ - public override operator fun C.times(other: RationalFunction): RationalFunction = TODO() + public override operator fun C.times(other: RationalFunction): RationalFunction = + RationalFunction( + this * other.numerator, + other.denominator + ) // endregion // region Rational-constant relation @@ -166,15 +190,27 @@ public class RationalFunctionSpace> ( /** * Returns sum of the polynomial represented as rational function and the rational function. */ - public override operator fun Polynomial.plus(other: RationalFunction): RationalFunction = TODO() + public override operator fun Polynomial.plus(other: RationalFunction): RationalFunction = + RationalFunction( + other.denominator * this + other.numerator, + other.denominator + ) /** * Returns difference between the polynomial represented as polynomial and the rational function. */ - public override operator fun Polynomial.minus(other: RationalFunction): RationalFunction = TODO() + public override operator fun Polynomial.minus(other: RationalFunction): RationalFunction = + RationalFunction( + other.denominator * this - other.numerator, + other.denominator + ) /** * Returns product of the polynomial represented as polynomial and the rational function. */ - public override operator fun Polynomial.times(other: RationalFunction): RationalFunction = TODO() + public override operator fun Polynomial.times(other: RationalFunction): RationalFunction = + RationalFunction( + this * other.numerator, + other.denominator + ) // endregion // region Rational-polynomial relation -- 2.34.1 From dd820da76579f93e24dcf8cf4216890f04931515 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Mon, 14 Mar 2022 19:59:53 +0300 Subject: [PATCH 012/123] 1. Prototyped rest 2 algebraic structures of rational functions 2. Added `constantZero` and `constantOne` to abstract spaces and applied them instead of `ring.zero` and `ring.one` 3. Moved logic of `R.isZero` and 5 others to `AbstractRationalFunctionalSpace` 4. Deleted forgotten overridden functions of constants 5. Added KMath contributors' copyright notes 6. Added TODO :smile: The `NumberedPolynomial`'s `countOfVariables` is a confusing --- .../kmath/functions/AbstractPolynomial.kt | 30 +- .../functions/AbstractRationalFunction.kt | 60 ++- .../kmath/functions/LabeledPolynomial.kt | 147 +++--- .../functions/LabeledRationalFunction.kt | 464 ++++++++++++++++++ .../kmath/functions/NumberedPolynomial.kt | 26 +- .../functions/NumberedRationalFunction.kt | 453 +++++++++++++++++ .../kscience/kmath/functions/Polynomial.kt | 18 +- .../kmath/functions/RationalFunction.kt | 18 +- .../kmath/functions/labeledPolynomialUtil.kt | 7 +- .../functions/labeledRationalFunctionUtil.kt | 130 +++++ .../functions/numberedRationalFunctionUtil.kt | 23 + .../kmath/functions/rationalFunctionUtil.kt | 5 + 12 files changed, 1211 insertions(+), 170 deletions(-) create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt index 69c45798a..0ca2d1409 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt @@ -149,7 +149,7 @@ public interface AbstractPolynomialSpace> : Ring

* Check if the instant is zero constant. */ @JvmName("constantIsZero") - public fun C.isZero(): Boolean + public fun C.isZero(): Boolean = this == constantZero /** * Check if the instant is NOT zero constant. */ @@ -159,7 +159,7 @@ public interface AbstractPolynomialSpace> : Ring

* Check if the instant is unit constant. */ @JvmName("constantIsOne") - public fun C.isOne(): Boolean + public fun C.isOne(): Boolean = this == constantOne /** * Check if the instant is NOT unit constant. */ @@ -169,12 +169,21 @@ public interface AbstractPolynomialSpace> : Ring

* Check if the instant is minus unit constant. */ @JvmName("constantIsMinusOne") - public fun C.isMinusOne(): Boolean + public fun C.isMinusOne(): Boolean = this == -constantOne /** * Check if the instant is NOT minus unit constant. */ @JvmName("constantIsNotMinusOne") public fun C.isNotMinusOne(): Boolean = !isMinusOne() + + /** + * Instance of zero constant (zero of the underlying ring). + */ + public val constantZero: C + /** + * Instance of unit constant (unit of the underlying ring). + */ + public val constantOne: C // endregion // region Constant-polynomial relation @@ -401,19 +410,12 @@ public interface AbstractPolynomialSpaceOverRing, A: public override operator fun C.times(other: C): C = ring { this@times * other } /** - * Check if the instant is zero constant. + * Instance of zero constant (zero of the underlying ring). */ - @JvmName("constantIsZero") - public override fun C.isZero(): Boolean = ring { this == zero } + public override val constantZero: C get() = ring.zero /** - * Check if the instant is unit constant. + * Instance of unit constant (unit of the underlying ring). */ - @JvmName("constantIsOne") - public override fun C.isOne(): Boolean = ring { this == one } - /** - * Check if the instant is minus unit constant. - */ - @JvmName("constantIsMinusOne") - public override fun C.isMinusOne(): Boolean = ring { this == -one } + public override val constantOne: C get() = ring.one // endregion } \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt index 9725ea078..df366f90f 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt @@ -190,7 +190,7 @@ public interface AbstractRationalFunctionalSpace, R: * Check if the instant is zero constant. */ @JvmName("constantIsZero") - public fun C.isZero(): Boolean + public fun C.isZero(): Boolean = this == constantZero /** * Check if the instant is NOT zero constant. */ @@ -200,7 +200,7 @@ public interface AbstractRationalFunctionalSpace, R: * Check if the instant is unit constant. */ @JvmName("constantIsOne") - public fun C.isOne(): Boolean + public fun C.isOne(): Boolean = this == constantOne /** * Check if the instant is NOT unit constant. */ @@ -210,12 +210,21 @@ public interface AbstractRationalFunctionalSpace, R: * Check if the instant is minus unit constant. */ @JvmName("constantIsMinusOne") - public fun C.isMinusOne(): Boolean + public fun C.isMinusOne(): Boolean = this == -constantOne /** * Check if the instant is NOT minus unit constant. */ @JvmName("constantIsNotMinusOne") public fun C.isNotMinusOne(): Boolean = !isMinusOne() + + /** + * Instance of zero constant (zero of the underlying ring). + */ + public val constantZero: C + /** + * Instance of unit constant (unit of the underlying ring). + */ + public val constantOne: C // endregion // region Constant-polynomial relation @@ -399,7 +408,7 @@ public interface AbstractRationalFunctionalSpace, R: /** * Check if the instant is zero rational function. */ - public fun R.isZero(): Boolean = this equalsTo zero + public fun R.isZero(): Boolean = numerator equalsTo polynomialZero /** * Check if the instant is NOT zero rational function. */ @@ -407,7 +416,7 @@ public interface AbstractRationalFunctionalSpace, R: /** * Check if the instant is unit rational function. */ - public fun R.isOne(): Boolean = this equalsTo one + public fun R.isOne(): Boolean = numerator equalsTo denominator /** * Check if the instant is NOT unit rational function. */ @@ -415,7 +424,7 @@ public interface AbstractRationalFunctionalSpace, R: /** * Check if the instant is minus unit rational function. */ - public fun R.isMinusOne(): Boolean = this equalsTo -one + public fun R.isMinusOne(): Boolean = (numerator + denominator).isZero() /** * Check if the instant is NOT minus unit rational function. */ @@ -597,35 +606,13 @@ public interface AbstractRationalFunctionalSpaceOverRing.cleanUp() = filterValues { it > 0U } //fun > Variable.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1U) to one)) // //context(LabeledPolynomialSpace) -//fun > Variable.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1U) to ring.one)) +//fun > Variable.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1U) to constantOne)) // //context(A) //fun > Variable.asLabeledPolynomial(c: C) : LabeledPolynomial = @@ -328,71 +333,54 @@ internal fun Map.cleanUp() = filterValues { it > 0U } */ @Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE", "INAPPLICABLE_JVM_NAME") public class LabeledPolynomialSpace>( - public val ring: A, -) : AbstractPolynomialSpace> { - // region Constant-integer relation - @JvmName("constantIntPlus") - public override operator fun C.plus(other: Int): C = ring { optimizedAddMultiplied(this@plus, one, other) } - @JvmName("constantIntMinus") - public override operator fun C.minus(other: Int): C = ring { optimizedAddMultiplied(this@minus, one, -other) } - @JvmName("constantIntTimes") - public override operator fun C.times(other: Int): C = ring { optimizedMultiply(this@times, other) } - // endregion - - // region Integer-constant relation - @JvmName("intConstantPlus") - public override operator fun Int.plus(other: C): C = ring { optimizedAddMultiplied(other, one, this@plus) } - @JvmName("intConstantMinus") - public override operator fun Int.minus(other: C): C = ring { optimizedAddMultiplied(-other, one, this@minus) } - @JvmName("intConstantTimes") - public override operator fun Int.times(other: C): C = ring { optimizedMultiply(other, this@times) } - // endregion + public override val ring: A, +) : AbstractPolynomialSpaceOverRing, A> { // region Variable-integer relation public operator fun Variable.plus(other: Int): LabeledPolynomial = if (other == 0) LabeledPolynomial(mapOf( - mapOf(this@plus to 1U) to ring.one, + mapOf(this@plus to 1U) to constantOne, )) else LabeledPolynomial(mapOf( - mapOf(this@plus to 1U) to ring.one, - emptyMap() to ring.one * other, + mapOf(this@plus to 1U) to constantOne, + emptyMap() to constantOne * other, )) public operator fun Variable.minus(other: Int): LabeledPolynomial = if (other == 0) LabeledPolynomial(mapOf( - mapOf(this@minus to 1U) to -ring.one, + mapOf(this@minus to 1U) to -constantOne, )) else LabeledPolynomial(mapOf( - mapOf(this@minus to 1U) to -ring.one, - emptyMap() to ring.one * other, + mapOf(this@minus to 1U) to -constantOne, + emptyMap() to constantOne * other, )) public operator fun Variable.times(other: Int): LabeledPolynomial = if (other == 0) zero else LabeledPolynomial(mapOf( - mapOf(this to 1U) to ring.one * other, + mapOf(this to 1U) to constantOne * other, )) // endregion // region Integer-variable relation public operator fun Int.plus(other: Variable): LabeledPolynomial = if (this == 0) LabeledPolynomial(mapOf( - mapOf(other to 1U) to ring.one, + mapOf(other to 1U) to constantOne, )) else LabeledPolynomial(mapOf( - mapOf(other to 1U) to ring.one, - emptyMap() to ring.one * this@plus, + mapOf(other to 1U) to constantOne, + emptyMap() to constantOne * this@plus, )) public operator fun Int.minus(other: Variable): LabeledPolynomial = if (this == 0) LabeledPolynomial(mapOf( - mapOf(other to 1U) to -ring.one, + mapOf(other to 1U) to -constantOne, )) else LabeledPolynomial(mapOf( - mapOf(other to 1U) to -ring.one, - emptyMap() to ring.one * this@minus, + mapOf(other to 1U) to -constantOne, + emptyMap() to constantOne * this@minus, )) public operator fun Int.times(other: Variable): LabeledPolynomial = if (this == 0) zero else LabeledPolynomial(mapOf( - mapOf(other to 1U) to ring.one * this@times, + mapOf(other to 1U) to constantOne * this@times, )) // endregion @@ -406,7 +394,7 @@ public class LabeledPolynomialSpace>( .apply { val degs = emptyMap() - val result = getOrElse(degs) { ring.zero } + other + val result = getOrElse(degs) { constantZero } + other if (result.isZero()) remove(degs) else this[degs] = result @@ -421,7 +409,7 @@ public class LabeledPolynomialSpace>( .apply { val degs = emptyMap() - val result = getOrElse(degs) { ring.zero } - other + val result = getOrElse(degs) { constantZero } - other if (result.isZero()) remove(degs) else this[degs] = result @@ -447,7 +435,7 @@ public class LabeledPolynomialSpace>( .apply { val degs = emptyMap() - val result = this@plus + getOrElse(degs) { ring.zero } + val result = this@plus + getOrElse(degs) { constantZero } if (result.isZero()) remove(degs) else this[degs] = result @@ -462,7 +450,7 @@ public class LabeledPolynomialSpace>( .apply { val degs = emptyMap() - val result = this@minus - getOrElse(degs) { ring.zero } + val result = this@minus - getOrElse(degs) { constantZero } if (result.isZero()) remove(degs) else this[degs] = result @@ -478,44 +466,21 @@ public class LabeledPolynomialSpace>( ) // endregion - // region Constant-constant relation - @JvmName("constantUnaryMinus") - override operator fun C.unaryMinus(): C = ring { -this@unaryMinus } - @JvmName("constantPlus") - override operator fun C.plus(other: C): C = ring { this@plus + other } - @JvmName("constantMinus") - override operator fun C.minus(other: C): C = ring { this@minus - other } - @JvmName("constantTimes") - override operator fun C.times(other: C): C = ring { this@times * other } - @JvmName("constantIsZero") - public override fun C.isZero(): Boolean = ring { this == zero } - @JvmName("constantIsNotZero") - public override fun C.isNotZero(): Boolean = ring { this != zero } - @JvmName("constantIsOne") - public override fun C.isOne(): Boolean = ring { this == one } - @JvmName("constantIsNotOne") - public override fun C.isNotOne(): Boolean = ring { this != one } - @JvmName("constantIsMinusOne") - public override fun C.isMinusOne(): Boolean = ring { this == -one } - @JvmName("constantIsNotMinusOne") - public override fun C.isNotMinusOne(): Boolean = ring { this != -one } - // endregion - // region Constant-variable relation public operator fun C.plus(other: Variable): LabeledPolynomial = if (isZero()) LabeledPolynomial(mapOf( - mapOf(other to 1U) to ring.one, + mapOf(other to 1U) to constantOne, )) else LabeledPolynomial(mapOf( - mapOf(other to 1U) to ring.one, + mapOf(other to 1U) to constantOne, emptyMap() to this@plus, )) public operator fun C.minus(other: Variable): LabeledPolynomial = if (isZero()) LabeledPolynomial(mapOf( - mapOf(other to 1U) to -ring.one, + mapOf(other to 1U) to -constantOne, )) else LabeledPolynomial(mapOf( - mapOf(other to 1U) to -ring.one, + mapOf(other to 1U) to -constantOne, emptyMap() to this@minus, )) public operator fun C.times(other: Variable): LabeledPolynomial = @@ -528,18 +493,18 @@ public class LabeledPolynomialSpace>( // region Variable-constant relation public operator fun Variable.plus(other: C): LabeledPolynomial = if (other.isZero()) LabeledPolynomial(mapOf( - mapOf(this@plus to 1U) to ring.one, + mapOf(this@plus to 1U) to constantOne, )) else LabeledPolynomial(mapOf( - mapOf(this@plus to 1U) to ring.one, + mapOf(this@plus to 1U) to constantOne, emptyMap() to other, )) public operator fun Variable.minus(other: C): LabeledPolynomial = if (other.isZero()) LabeledPolynomial(mapOf( - mapOf(this@minus to 1U) to -ring.one, + mapOf(this@minus to 1U) to -constantOne, )) else LabeledPolynomial(mapOf( - mapOf(this@minus to 1U) to -ring.one, + mapOf(this@minus to 1U) to -constantOne, emptyMap() to other, )) public operator fun Variable.times(other: C): LabeledPolynomial = @@ -559,7 +524,7 @@ public class LabeledPolynomialSpace>( .apply { val degs = emptyMap() - val result = this@plus + getOrElse(degs) { ring.zero } + val result = this@plus + getOrElse(degs) { constantZero } if (result.isZero()) remove(degs) else this[degs] = result @@ -577,7 +542,7 @@ public class LabeledPolynomialSpace>( val degs = emptyMap() - val result = this@minus - getOrElse(degs) { ring.zero } + val result = this@minus - getOrElse(degs) { constantZero } if (result.isZero()) remove(degs) else this[degs] = result @@ -607,7 +572,7 @@ public class LabeledPolynomialSpace>( .apply { val degs = emptyMap() - val result = getOrElse(degs) { ring.zero } + other + val result = getOrElse(degs) { constantZero } + other if (result.isZero()) remove(degs) else this[degs] = result @@ -628,7 +593,7 @@ public class LabeledPolynomialSpace>( val degs = emptyMap() - val result = getOrElse(degs) { ring.zero } - other + val result = getOrElse(degs) { constantZero } - other if (result.isZero()) remove(degs) else this[degs] = result @@ -651,37 +616,37 @@ public class LabeledPolynomialSpace>( // region Variable-variable relation public operator fun Variable.plus(other: Variable): LabeledPolynomial = if (this == other) LabeledPolynomial(mapOf( - mapOf(this to 1U) to ring.one * 2 + mapOf(this to 1U) to constantOne * 2 )) else LabeledPolynomial(mapOf( - mapOf(this to 1U) to ring.one, - mapOf(other to 1U) to ring.one, + mapOf(this to 1U) to constantOne, + mapOf(other to 1U) to constantOne, )) public operator fun Variable.minus(other: Variable): LabeledPolynomial = if (this == other) zero else LabeledPolynomial(mapOf( - mapOf(this to 1U) to ring.one, - mapOf(other to 1U) to -ring.one, + mapOf(this to 1U) to constantOne, + mapOf(other to 1U) to -constantOne, )) public operator fun Variable.times(other: Variable): LabeledPolynomial = if (this == other) LabeledPolynomial(mapOf( - mapOf(this to 2U) to ring.one + mapOf(this to 2U) to constantOne )) else LabeledPolynomial(mapOf( - mapOf(this to 1U, other to 1U) to ring.one, + mapOf(this to 1U, other to 1U) to constantOne, )) // endregion // region Variable-polynomial relation public operator fun Variable.plus(other: LabeledPolynomial): LabeledPolynomial = with(other.coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(mapOf(this@plus to 1u) to ring.one)) + if (isEmpty()) LabeledPolynomial(mapOf(mapOf(this@plus to 1u) to constantOne)) else LabeledPolynomial( toMutableMap() .apply { val degs = mapOf(this@plus to 1U) - val result = ring.one + getOrElse(degs) { ring.zero } + val result = constantOne + getOrElse(degs) { constantZero } if (result.isZero()) remove(degs) else this[degs] = result @@ -690,7 +655,7 @@ public class LabeledPolynomialSpace>( } public operator fun Variable.minus(other: LabeledPolynomial): LabeledPolynomial = with(other.coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(mapOf(this@minus to 1u) to ring.one)) + if (isEmpty()) LabeledPolynomial(mapOf(mapOf(this@minus to 1u) to constantOne)) else LabeledPolynomial( toMutableMap() .apply { @@ -698,7 +663,7 @@ public class LabeledPolynomialSpace>( val degs = mapOf(this@minus to 1U) - val result = ring.one - getOrElse(degs) { ring.zero } + val result = constantOne - getOrElse(degs) { constantZero } if (result.isZero()) remove(degs) else this[degs] = result @@ -715,13 +680,13 @@ public class LabeledPolynomialSpace>( // region Polynomial-variable relation public operator fun LabeledPolynomial.plus(other: Variable): LabeledPolynomial = with(coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(mapOf(other to 1u) to ring.one)) + if (isEmpty()) LabeledPolynomial(mapOf(mapOf(other to 1u) to constantOne)) else LabeledPolynomial( toMutableMap() .apply { val degs = mapOf(other to 1U) - val result = ring.one + getOrElse(degs) { ring.zero } + val result = constantOne + getOrElse(degs) { constantZero } if (result.isZero()) remove(degs) else this[degs] = result @@ -730,13 +695,13 @@ public class LabeledPolynomialSpace>( } public operator fun LabeledPolynomial.minus(other: Variable): LabeledPolynomial = with(coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(mapOf(other to 1u) to ring.one)) + if (isEmpty()) LabeledPolynomial(mapOf(mapOf(other to 1u) to constantOne)) else LabeledPolynomial( toMutableMap() .apply { val degs = mapOf(other to 1U) - val result = ring.one - getOrElse(degs) { ring.zero } + val result = constantOne - getOrElse(degs) { constantZero } if (result.isZero()) remove(degs) else this[degs] = result @@ -799,8 +764,8 @@ public class LabeledPolynomialSpace>( ) } - override val zero: LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to ring.zero)) - override val one: LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to ring.one)) + override val zero: LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to constantZero)) + override val one: LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to constantOne)) // TODO: Docs @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") @@ -872,7 +837,7 @@ public class LabeledPolynomialSpace>( override fun LabeledPolynomial.asConstantOrNull(): C? = with(coefficients) { - if(isConstant()) getOrElse(emptyMap()) { ring.zero } + if(isConstant()) getOrElse(emptyMap()) { constantZero } else null } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt new file mode 100644 index 000000000..203c9e07c --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt @@ -0,0 +1,464 @@ +/* + * 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.functions + +import space.kscience.kmath.operations.Ring +import space.kscience.kmath.operations.invoke + + +public class LabeledRationalFunction( + public override val numerator: LabeledPolynomial, + public override val denominator: LabeledPolynomial +) : AbstractRationalFunction> { + override fun toString(): String = "LabeledRationalFunction${numerator.coefficients}/${denominator.coefficients}" +} + +// region Internal utilities + +/** + * Represents internal [LabeledRationalFunction] errors. + */ +internal class LabeledRationalFunctionError : Error { + constructor(): super() + constructor(message: String): super(message) + constructor(message: String?, cause: Throwable?): super(message, cause) + constructor(cause: Throwable?): super(cause) +} + +/** + * Throws an [LabeledRationalFunctionError] with the given [message]. + */ +internal fun labeledRationalFunctionError(message: Any): Nothing = throw LabeledRationalFunctionError(message.toString()) + +// endregion + +// region Constructors and converters +// Waiting for context receivers :( TODO: Replace with context receivers when they will be available + +//context(RationalFunctionSpace) +//@Suppress("FunctionName") +//internal fun > RationalFunction(numerator: Polynomial, denominator: Polynomial): RationalFunction = +// if (denominator.isZero()) throw ArithmeticException("/ by zero") +// else RationalFunction(numerator, denominator) +//context(RationalFunctionSpace) +//@Suppress("FunctionName") +//public fun > RationalFunction(numeratorCoefficients: List, denominatorCoefficients: List, reverse: Boolean = false): RationalFunction = +// RationalFunction( +// Polynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), +// Polynomial( with(denominatorCoefficients) { if (reverse) reversed() else this } ).also { if (it.isZero()) } +// ) +//context(RationalFunctionSpace) +//@Suppress("FunctionName") +//public fun > RationalFunction(numerator: Polynomial): RationalFunction = +// RationalFunction(numerator, onePolynomial) +//context(RationalFunctionSpace) +//@Suppress("FunctionName") +//public fun > RationalFunction(numeratorCoefficients: List, reverse: Boolean = false): RationalFunction = +// RationalFunction( +// Polynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ) +// ) + +// TODO: Rewrite former constructors as fabrics +//constructor(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>) : this( +//LabeledPolynomial(numeratorCoefficients), +//LabeledPolynomial(denominatorCoefficients) +//) +// +//constructor(numeratorCoefficients: Collection, C>>, denominatorCoefficients: Collection, C>>) : this( +//LabeledPolynomial(numeratorCoefficients), +//LabeledPolynomial(denominatorCoefficients) +//) +// +//constructor(numerator: LabeledPolynomial) : this(numerator, numerator.getOne()) +//constructor(numeratorCoefficients: Map, C>) : this( +//LabeledPolynomial(numeratorCoefficients) +//) +// +//constructor(numeratorCoefficients: Collection, C>>) : this( +//LabeledPolynomial(numeratorCoefficients) +//) + +// endregion + +public class LabeledRationalFunctionSpace>( + public val ring: A, +) : AbstractRationalFunctionalSpaceOverPolynomialSpace, LabeledRationalFunction, A> { + + override val polynomialRing : LabeledPolynomialSpace = LabeledPolynomialSpace(ring) + + // region Rational-integer relation + /** + * Returns sum of the rational function and the integer represented as rational function. + * + * The operation is equivalent to adding [other] copies of unit polynomial to [this]. + */ + public override operator fun LabeledRationalFunction.plus(other: Int): LabeledRationalFunction = + LabeledRationalFunction( + numerator + denominator * other, + denominator + ) + /** + * Returns difference between the rational function and the integer represented as rational function. + * + * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. + */ + public override operator fun LabeledRationalFunction.minus(other: Int): LabeledRationalFunction = + LabeledRationalFunction( + numerator - denominator * other, + denominator + ) + /** + * Returns product of the rational function and the integer represented as rational function. + * + * The operation is equivalent to sum of [other] copies of [this]. + */ + public override operator fun LabeledRationalFunction.times(other: Int): LabeledRationalFunction = + LabeledRationalFunction( + numerator * other, + denominator + ) + // endregion + + // region Integer-Rational relation + /** + * Returns sum of the integer represented as rational function and the rational function. + * + * The operation is equivalent to adding [this] copies of unit polynomial to [other]. + */ + public override operator fun Int.plus(other: LabeledRationalFunction): LabeledRationalFunction = + LabeledRationalFunction( + other.denominator * this + other.numerator, + other.denominator + ) + /** + * Returns difference between the integer represented as rational function and the rational function. + * + * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. + */ + public override operator fun Int.minus(other: LabeledRationalFunction): LabeledRationalFunction = + LabeledRationalFunction( + other.denominator * this - other.numerator, + other.denominator + ) + /** + * Returns product of the integer represented as rational function and the rational function. + * + * The operation is equivalent to sum of [this] copies of [other]. + */ + public override operator fun Int.times(other: LabeledRationalFunction): LabeledRationalFunction = + LabeledRationalFunction( + this * other.numerator, + other.denominator + ) + // endregion + + // region Constant-rational relation + /** + * Returns sum of the constant represented as rational function and the rational function. + */ + public override operator fun C.plus(other: LabeledRationalFunction): LabeledRationalFunction = + LabeledRationalFunction( + other.denominator * this + other.numerator, + other.denominator + ) + /** + * Returns difference between the constant represented as polynomial and the rational function. + */ + public override operator fun C.minus(other: LabeledRationalFunction): LabeledRationalFunction = + LabeledRationalFunction( + other.denominator * this - other.numerator, + other.denominator + ) + /** + * Returns product of the constant represented as polynomial and the rational function. + */ + public override operator fun C.times(other: LabeledRationalFunction): LabeledRationalFunction = + LabeledRationalFunction( + this * other.numerator, + other.denominator + ) + // endregion + + // region Rational-constant relation + /** + * Returns sum of the constant represented as rational function and the rational function. + */ + public override operator fun LabeledRationalFunction.plus(other: C): LabeledRationalFunction = + LabeledRationalFunction( + numerator + denominator * other, + denominator + ) + /** + * Returns difference between the constant represented as rational function and the rational function. + */ + public override operator fun LabeledRationalFunction.minus(other: C): LabeledRationalFunction = + LabeledRationalFunction( + numerator - denominator * other, + denominator + ) + /** + * Returns product of the constant represented as rational function and the rational function. + */ + public override operator fun LabeledRationalFunction.times(other: C): LabeledRationalFunction = + LabeledRationalFunction( + numerator * other, + denominator + ) + // endregion + + // region Polynomial-rational relation + /** + * Returns sum of the polynomial represented as rational function and the rational function. + */ + public override operator fun LabeledPolynomial.plus(other: LabeledRationalFunction): LabeledRationalFunction = + LabeledRationalFunction( + other.denominator * this + other.numerator, + other.denominator + ) + /** + * Returns difference between the polynomial represented as polynomial and the rational function. + */ + public override operator fun LabeledPolynomial.minus(other: LabeledRationalFunction): LabeledRationalFunction = + LabeledRationalFunction( + other.denominator * this - other.numerator, + other.denominator + ) + /** + * Returns product of the polynomial represented as polynomial and the rational function. + */ + public override operator fun LabeledPolynomial.times(other: LabeledRationalFunction): LabeledRationalFunction = + LabeledRationalFunction( + this * other.numerator, + other.denominator + ) + // endregion + + // region Rational-polynomial relation + /** + * Returns sum of the polynomial represented as rational function and the rational function. + */ + public override operator fun LabeledRationalFunction.plus(other: LabeledPolynomial): LabeledRationalFunction = + LabeledRationalFunction( + numerator + denominator * other, + denominator + ) + /** + * Returns difference between the polynomial represented as rational function and the rational function. + */ + public override operator fun LabeledRationalFunction.minus(other: LabeledPolynomial): LabeledRationalFunction = + LabeledRationalFunction( + numerator - denominator * other, + denominator + ) + /** + * Returns product of the polynomial represented as rational function and the rational function. + */ + public override operator fun LabeledRationalFunction.times(other: LabeledPolynomial): LabeledRationalFunction = + LabeledRationalFunction( + numerator * other, + denominator + ) + // endregion + + // region Rational-rational relation + /** + * Returns negation of the rational function. + */ + public override operator fun LabeledRationalFunction.unaryMinus(): LabeledRationalFunction = LabeledRationalFunction(-numerator, denominator) + /** + * Returns sum of the rational functions. + */ + public override operator fun LabeledRationalFunction.plus(other: LabeledRationalFunction): LabeledRationalFunction = + LabeledRationalFunction( + numerator * other.denominator + denominator * other.numerator, + denominator * other.denominator + ) + /** + * Returns difference of the rational functions. + */ + public override operator fun LabeledRationalFunction.minus(other: LabeledRationalFunction): LabeledRationalFunction = + LabeledRationalFunction( + numerator * other.denominator - denominator * other.numerator, + denominator * other.denominator + ) + /** + * Returns product of the rational functions. + */ + public override operator fun LabeledRationalFunction.times(other: LabeledRationalFunction): LabeledRationalFunction = + LabeledRationalFunction( + numerator * other.numerator, + denominator * other.denominator + ) + + /** + * Instance of zero rational function (zero of the rational functions ring). + */ + public override val zero: LabeledRationalFunction = LabeledRationalFunction(polynomialZero, polynomialOne) + /** + * Instance of unit polynomial (unit of the rational functions ring). + */ + public override val one: LabeledRationalFunction = LabeledRationalFunction(polynomialOne, polynomialOne) + + /** + * Checks equality of the rational functions. + */ + @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") + public override infix fun LabeledRationalFunction.equalsTo(other: LabeledRationalFunction): Boolean { + if (this === other) return true + + if ( !(numerator.isZero() xor other.numerator.isZero()) ) return false + + val variables = this.variables union other.variables + val thisNumeratorDegrees = this.numerator.degrees + val thisDenominatorDegrees = this.denominator.degrees + val otherNumeratorDegrees = other.numerator.degrees + val otherDenominatorDegrees = other.denominator.degrees + for (variable in variables) + if ( + thisNumeratorDegrees.getOrElse(variable) { 0u } + otherDenominatorDegrees.getOrElse(variable) { 0u } + != thisDenominatorDegrees.getOrElse(variable) { 0u } + otherNumeratorDegrees.getOrElse(variable) { 0u } + ) return false + + return numerator * other.denominator equalsTo other.numerator * denominator + } + // endregion + + // region Polynomial properties + /** + * Map that associates variables (that appear in the polynomial in positive exponents) with their most exponents + * in which they are appeared in the polynomial. + * + * As consequence all values in the map are positive integers. Also, if the polynomial is constant, the map is empty. + * And keys of the map is the same as in [variables]. + */ + public val LabeledPolynomial.degrees: Map get() = polynomialRing { degrees } + /** + * Set of all variables that appear in the polynomial in positive exponents. + */ + public val LabeledPolynomial.variables: Set get() = polynomialRing { variables } + /** + * Count of all variables that appear in the polynomial in positive exponents. + */ + public val LabeledPolynomial.countOfVariables: Int get() = polynomialRing { countOfVariables } + // endregion + + // region Rational properties + /** + * Count of all variables that appear in the polynomial in positive exponents. + */ + public val LabeledRationalFunction.variables: Set + get() = numerator.variables union denominator.variables + /** + * Count of all variables that appear in the polynomial in positive exponents. + */ + public val LabeledRationalFunction.countOfVariables: Int get() = variables.size + // endregion + + // region REST TODO: Разобрать + + public operator fun LabeledRationalFunction.div(other: LabeledRationalFunction): LabeledRationalFunction = + LabeledRationalFunction( + numerator * other.denominator, + denominator * other.numerator + ) + + public operator fun LabeledRationalFunction.div(other: LabeledPolynomial): LabeledRationalFunction = + LabeledRationalFunction( + numerator, + denominator * other + ) + + public operator fun LabeledRationalFunction.div(other: C): LabeledRationalFunction = + LabeledRationalFunction( + numerator, + denominator * other + ) + +// operator fun invoke(arg: Map): LabeledRationalFunction = +// LabeledRationalFunction( +// numerator(arg), +// denominator(arg) +// ) +// +// @JvmName("invokeLabeledPolynomial") +// operator fun invoke(arg: Map>): LabeledRationalFunction = +// LabeledRationalFunction( +// numerator(arg), +// denominator(arg) +// ) +// +// @JvmName("invokeLabeledRationalFunction") +// operator fun invoke(arg: Map>): LabeledRationalFunction { +// var num = numerator invokeRFTakeNumerator arg +// var den = denominator invokeRFTakeNumerator arg +// for (variable in variables) if (variable in arg) { +// val degreeDif = degrees[variable]!! +// if (degreeDif > 0) +// den = multiplyByPower(den, arg[variable]!!.denominator, degreeDif) +// else +// num = multiplyByPower(num, arg[variable]!!.denominator, -degreeDif) +// } +// return LabeledRationalFunction(num, den) +// } +// +// override fun toString(): String = toString(emptyMap()) +// +// fun toString(names: Map = emptyMap()): String = +// when (true) { +// numerator.isZero() -> "0" +// denominator.isOne() -> numerator.toString(names) +// else -> "${numerator.toStringWithBrackets(names)}/${denominator.toStringWithBrackets(names)}" +// } +// +// fun toString(namer: (Variable) -> String): String = +// when (true) { +// numerator.isZero() -> "0" +// denominator.isOne() -> numerator.toString(namer) +// else -> "${numerator.toStringWithBrackets(namer)}/${denominator.toStringWithBrackets(namer)}" +// } +// +// fun toStringWithBrackets(names: Map = emptyMap()): String = +// when (true) { +// numerator.isZero() -> "0" +// denominator.isOne() -> numerator.toStringWithBrackets(names) +// else -> "(${numerator.toStringWithBrackets(names)}/${denominator.toStringWithBrackets(names)})" +// } +// +// fun toStringWithBrackets(namer: (Variable) -> String): String = +// when (true) { +// numerator.isZero() -> "0" +// denominator.isOne() -> numerator.toStringWithBrackets(namer) +// else -> "(${numerator.toStringWithBrackets(namer)}/${denominator.toStringWithBrackets(namer)})" +// } +// +// fun toReversedString(names: Map = emptyMap()): String = +// when (true) { +// numerator.isZero() -> "0" +// denominator.isOne() -> numerator.toReversedString(names) +// else -> "${numerator.toReversedStringWithBrackets(names)}/${denominator.toReversedStringWithBrackets(names)}" +// } +// +// fun toReversedString(namer: (Variable) -> String): String = +// when (true) { +// numerator.isZero() -> "0" +// denominator.isOne() -> numerator.toReversedString(namer) +// else -> "${numerator.toReversedStringWithBrackets(namer)}/${denominator.toReversedStringWithBrackets(namer)}" +// } +// +// fun toReversedStringWithBrackets(names: Map = emptyMap()): String = +// when (true) { +// numerator.isZero() -> "0" +// denominator.isOne() -> numerator.toReversedStringWithBrackets(names) +// else -> "(${numerator.toReversedStringWithBrackets(names)}/${denominator.toReversedStringWithBrackets(names)})" +// } +// +// fun toReversedStringWithBrackets(namer: (Variable) -> String): String = +// when (true) { +// numerator.isZero() -> "0" +// denominator.isOne() -> numerator.toReversedStringWithBrackets(namer) +// else -> "(${numerator.toReversedStringWithBrackets(namer)}/${denominator.toReversedStringWithBrackets(namer)})" +// } +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt index f11338161..39ca43945 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -1,3 +1,8 @@ +/* + * 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.functions import space.kscience.kmath.operations.* @@ -272,7 +277,7 @@ public open class NumberedPolynomialSpace>( .apply { val degs = emptyList() - val result = getOrElse(degs) { ring.zero } + other + val result = getOrElse(degs) { constantZero } + other if (result.isZero()) remove(degs) else this[degs] = result @@ -287,7 +292,7 @@ public open class NumberedPolynomialSpace>( .apply { val degs = emptyList() - val result = getOrElse(degs) { ring.zero } - other + val result = getOrElse(degs) { constantZero } - other if (result.isZero()) remove(degs) else this[degs] = result @@ -313,7 +318,7 @@ public open class NumberedPolynomialSpace>( .apply { val degs = emptyList() - val result = this@plus + getOrElse(degs) { ring.zero } + val result = this@plus + getOrElse(degs) { constantZero } if (result.isZero()) remove(degs) else this[degs] = result @@ -328,7 +333,7 @@ public open class NumberedPolynomialSpace>( .apply { val degs = emptyList() - val result = this@minus - getOrElse(degs) { ring.zero } + val result = this@minus - getOrElse(degs) { constantZero } if (result.isZero()) remove(degs) else this[degs] = result @@ -354,7 +359,7 @@ public open class NumberedPolynomialSpace>( .apply { val degs = emptyList() - val result = this@plus + getOrElse(degs) { ring.zero } + val result = this@plus + getOrElse(degs) { constantZero } if (result.isZero()) remove(degs) else this[degs] = result @@ -372,7 +377,7 @@ public open class NumberedPolynomialSpace>( val degs = emptyList() - val result = this@minus - getOrElse(degs) { ring.zero } + val result = this@minus - getOrElse(degs) { constantZero } if (result.isZero()) remove(degs) else this[degs] = result @@ -402,7 +407,7 @@ public open class NumberedPolynomialSpace>( .apply { val degs = emptyList() - val result = getOrElse(degs) { ring.zero } + other + val result = getOrElse(degs) { constantZero } + other if (result.isZero()) remove(degs) else this[degs] = result @@ -421,7 +426,7 @@ public open class NumberedPolynomialSpace>( .apply { val degs = emptyList() - val result = getOrElse(degs) { ring.zero } - other + val result = getOrElse(degs) { constantZero } - other if (result.isZero()) remove(degs) else this[degs] = result @@ -522,7 +527,7 @@ public open class NumberedPolynomialSpace>( override val one: NumberedPolynomial = NumberedPolynomial( mapOf( - listOf() to ring.one // 1 * x_1^0 * x_2^0 * ... + listOf() to constantOne // 1 * x_1^0 * x_2^0 * ... ) ) @@ -538,6 +543,7 @@ public open class NumberedPolynomialSpace>( // Not sure is it necessary... // region Polynomial properties + // TODO: Replace `countOfVariables` with `lastVariable` and create new `countOfVariables` /** * Count of all variables that appear in the polynomial in positive exponents. */ @@ -590,7 +596,7 @@ public open class NumberedPolynomialSpace>( override fun NumberedPolynomial.asConstantOrNull(): C? = with(coefficients) { - if(isConstant()) getOrElse(emptyList()) { ring.zero } + if(isConstant()) getOrElse(emptyList()) { constantZero } else null } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt new file mode 100644 index 000000000..aff18d1f4 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt @@ -0,0 +1,453 @@ +/* + * 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.functions + +import space.kscience.kmath.operations.* +import kotlin.math.max + + +public class NumberedRationalFunction internal constructor( + public override val numerator: NumberedPolynomial, + public override val denominator: NumberedPolynomial +) : AbstractRationalFunction> { + override fun toString(): String = "NumberedRationalFunction${numerator.coefficients}/${denominator.coefficients}" +} + +// region Internal utilities + +/** + * Represents internal [NumberedRationalFunction] errors. + */ +internal class NumberedRationalFunctionError : Error { + constructor(): super() + constructor(message: String): super(message) + constructor(message: String?, cause: Throwable?): super(message, cause) + constructor(cause: Throwable?): super(cause) +} + +/** + * Throws an [NumberedRationalFunctionError] with the given [message]. + */ +internal fun numberedRationalFunctionError(message: Any): Nothing = throw NumberedRationalFunctionError(message.toString()) + +// endregion + +// region Constructors and converters +// Waiting for context receivers :( TODO: Replace with context receivers when they will be available + +//context(RationalFunctionSpace) +//@Suppress("FunctionName") +//internal fun > RationalFunction(numerator: Polynomial, denominator: Polynomial): RationalFunction = +// if (denominator.isZero()) throw ArithmeticException("/ by zero") +// else RationalFunction(numerator, denominator) +//context(RationalFunctionSpace) +//@Suppress("FunctionName") +//public fun > RationalFunction(numeratorCoefficients: List, denominatorCoefficients: List, reverse: Boolean = false): RationalFunction = +// RationalFunction( +// Polynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), +// Polynomial( with(denominatorCoefficients) { if (reverse) reversed() else this } ).also { if (it.isZero()) } +// ) +//context(RationalFunctionSpace) +//@Suppress("FunctionName") +//public fun > RationalFunction(numerator: Polynomial): RationalFunction = +// RationalFunction(numerator, onePolynomial) +//context(RationalFunctionSpace) +//@Suppress("FunctionName") +//public fun > RationalFunction(numeratorCoefficients: List, reverse: Boolean = false): RationalFunction = +// RationalFunction( +// Polynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ) +// ) + +// TODO: Rewrite former constructors as fabrics +//constructor(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>) : this( +//Polynomial(numeratorCoefficients), +//Polynomial(denominatorCoefficients) +//) +//constructor(numeratorCoefficients: Collection, C>>, denominatorCoefficients: Collection, C>>) : this( +//Polynomial(numeratorCoefficients), +//Polynomial(denominatorCoefficients) +//) +//constructor(numerator: Polynomial) : this(numerator, numerator.getOne()) +//constructor(numeratorCoefficients: Map, C>) : this( +//Polynomial(numeratorCoefficients) +//) +//constructor(numeratorCoefficients: Collection, C>>) : this( +//Polynomial(numeratorCoefficients) +//) + +// endregion + +public class NumberedRationalFunctionSpace> ( + public val ring: A, +) : AbstractRationalFunctionalSpaceOverPolynomialSpace, NumberedRationalFunction, A> { + + override val polynomialRing : NumberedPolynomialSpace = NumberedPolynomialSpace(ring) + + // region Rational-integer relation + /** + * Returns sum of the rational function and the integer represented as rational function. + * + * The operation is equivalent to adding [other] copies of unit polynomial to [this]. + */ + public override operator fun NumberedRationalFunction.plus(other: Int): NumberedRationalFunction = + NumberedRationalFunction( + numerator + denominator * other, + denominator + ) + /** + * Returns difference between the rational function and the integer represented as rational function. + * + * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. + */ + public override operator fun NumberedRationalFunction.minus(other: Int): NumberedRationalFunction = + NumberedRationalFunction( + numerator - denominator * other, + denominator + ) + /** + * Returns product of the rational function and the integer represented as rational function. + * + * The operation is equivalent to sum of [other] copies of [this]. + */ + public override operator fun NumberedRationalFunction.times(other: Int): NumberedRationalFunction = + NumberedRationalFunction( + numerator * other, + denominator + ) + // endregion + + // region Integer-Rational relation + /** + * Returns sum of the integer represented as rational function and the rational function. + * + * The operation is equivalent to adding [this] copies of unit polynomial to [other]. + */ + public override operator fun Int.plus(other: NumberedRationalFunction): NumberedRationalFunction = + NumberedRationalFunction( + other.denominator * this + other.numerator, + other.denominator + ) + /** + * Returns difference between the integer represented as rational function and the rational function. + * + * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. + */ + public override operator fun Int.minus(other: NumberedRationalFunction): NumberedRationalFunction = + NumberedRationalFunction( + other.denominator * this - other.numerator, + other.denominator + ) + /** + * Returns product of the integer represented as rational function and the rational function. + * + * The operation is equivalent to sum of [this] copies of [other]. + */ + public override operator fun Int.times(other: NumberedRationalFunction): NumberedRationalFunction = + NumberedRationalFunction( + this * other.numerator, + other.denominator + ) + // endregion + + // region Constant-rational relation + /** + * Returns sum of the constant represented as rational function and the rational function. + */ + public override operator fun C.plus(other: NumberedRationalFunction): NumberedRationalFunction = + NumberedRationalFunction( + other.denominator * this + other.numerator, + other.denominator + ) + /** + * Returns difference between the constant represented as polynomial and the rational function. + */ + public override operator fun C.minus(other: NumberedRationalFunction): NumberedRationalFunction = + NumberedRationalFunction( + other.denominator * this - other.numerator, + other.denominator + ) + /** + * Returns product of the constant represented as polynomial and the rational function. + */ + public override operator fun C.times(other: NumberedRationalFunction): NumberedRationalFunction = + NumberedRationalFunction( + this * other.numerator, + other.denominator + ) + // endregion + + // region Rational-constant relation + /** + * Returns sum of the constant represented as rational function and the rational function. + */ + public override operator fun NumberedRationalFunction.plus(other: C): NumberedRationalFunction = + NumberedRationalFunction( + numerator + denominator * other, + denominator + ) + /** + * Returns difference between the constant represented as rational function and the rational function. + */ + public override operator fun NumberedRationalFunction.minus(other: C): NumberedRationalFunction = + NumberedRationalFunction( + numerator - denominator * other, + denominator + ) + /** + * Returns product of the constant represented as rational function and the rational function. + */ + public override operator fun NumberedRationalFunction.times(other: C): NumberedRationalFunction = + NumberedRationalFunction( + numerator * other, + denominator + ) + // endregion + + // region Polynomial-rational relation + /** + * Returns sum of the polynomial represented as rational function and the rational function. + */ + public override operator fun NumberedPolynomial.plus(other: NumberedRationalFunction): NumberedRationalFunction = + NumberedRationalFunction( + other.denominator * this + other.numerator, + other.denominator + ) + /** + * Returns difference between the polynomial represented as polynomial and the rational function. + */ + public override operator fun NumberedPolynomial.minus(other: NumberedRationalFunction): NumberedRationalFunction = + NumberedRationalFunction( + other.denominator * this - other.numerator, + other.denominator + ) + /** + * Returns product of the polynomial represented as polynomial and the rational function. + */ + public override operator fun NumberedPolynomial.times(other: NumberedRationalFunction): NumberedRationalFunction = + NumberedRationalFunction( + this * other.numerator, + other.denominator + ) + // endregion + + // region Rational-polynomial relation + /** + * Returns sum of the polynomial represented as rational function and the rational function. + */ + public override operator fun NumberedRationalFunction.plus(other: NumberedPolynomial): NumberedRationalFunction = + NumberedRationalFunction( + numerator + denominator * other, + denominator + ) + /** + * Returns difference between the polynomial represented as rational function and the rational function. + */ + public override operator fun NumberedRationalFunction.minus(other: NumberedPolynomial): NumberedRationalFunction = + NumberedRationalFunction( + numerator - denominator * other, + denominator + ) + /** + * Returns product of the polynomial represented as rational function and the rational function. + */ + public override operator fun NumberedRationalFunction.times(other: NumberedPolynomial): NumberedRationalFunction = + NumberedRationalFunction( + numerator * other, + denominator + ) + // endregion + + // region Rational-rational relation + /** + * Returns negation of the rational function. + */ + public override operator fun NumberedRationalFunction.unaryMinus(): NumberedRationalFunction = NumberedRationalFunction(-numerator, denominator) + /** + * Returns sum of the rational functions. + */ + public override operator fun NumberedRationalFunction.plus(other: NumberedRationalFunction): NumberedRationalFunction = + NumberedRationalFunction( + numerator * other.denominator + denominator * other.numerator, + denominator * other.denominator + ) + /** + * Returns difference of the rational functions. + */ + public override operator fun NumberedRationalFunction.minus(other: NumberedRationalFunction): NumberedRationalFunction = + NumberedRationalFunction( + numerator * other.denominator - denominator * other.numerator, + denominator * other.denominator + ) + /** + * Returns product of the rational functions. + */ + public override operator fun NumberedRationalFunction.times(other: NumberedRationalFunction): NumberedRationalFunction = + NumberedRationalFunction( + numerator * other.numerator, + denominator * other.denominator + ) + + /** + * Instance of zero rational function (zero of the rational functions ring). + */ + public override val zero: NumberedRationalFunction = NumberedRationalFunction(polynomialZero, polynomialOne) + /** + * Instance of unit polynomial (unit of the rational functions ring). + */ + public override val one: NumberedRationalFunction = NumberedRationalFunction(polynomialOne, polynomialOne) + + /** + * Checks equality of the rational functions. + */ + @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") + public override infix fun NumberedRationalFunction.equalsTo(other: NumberedRationalFunction): Boolean { + if (this === other) return true + + if ( !(numerator.isZero() xor other.numerator.isZero()) ) return false + + val countOfVariables = max(this.countOfVariables, other.countOfVariables) + val thisNumeratorDegrees = this.numerator.degrees + val thisDenominatorDegrees = this.denominator.degrees + val otherNumeratorDegrees = other.numerator.degrees + val otherDenominatorDegrees = other.denominator.degrees + for (variable in 0 until countOfVariables) + if ( + thisNumeratorDegrees.getOrElse(variable) { 0u } + otherDenominatorDegrees.getOrElse(variable) { 0u } + != thisDenominatorDegrees.getOrElse(variable) { 0u } + otherNumeratorDegrees.getOrElse(variable) { 0u } + ) return false + + return numerator * other.denominator equalsTo other.numerator * denominator + } + // endregion + + // region Polynomial properties + /** + * Count of all variables that appear in the polynomial in positive exponents. + */ + public val NumberedPolynomial.countOfVariables: Int get() = polynomialRing { countOfVariables } + /** + * List that associates indices of variables (that appear in the polynomial in positive exponents) with their most + * exponents in which the variables are appeared in the polynomial. + * + * As consequence all values in the list are non-negative integers. Also, if the polynomial is constant, the list is empty. + * And size of the list is [countOfVariables]. + */ + public val NumberedPolynomial.degrees: List get() = polynomialRing { degrees } + // endregion + + // region Rational properties + /** + * Count of all variables that appear in the polynomial in positive exponents. + */ + public val NumberedRationalFunction.countOfVariables: Int + get() = polynomialRing { max(numerator.countOfVariables, denominator.countOfVariables) } + // endregion + + // region REST TODO: Разобрать + + public operator fun NumberedRationalFunction.div(other: NumberedRationalFunction): NumberedRationalFunction = + NumberedRationalFunction( + numerator * other.denominator, + denominator * other.numerator + ) + + public operator fun NumberedRationalFunction.div(other: NumberedPolynomial): NumberedRationalFunction = + NumberedRationalFunction( + numerator, + denominator * other + ) + + public operator fun NumberedRationalFunction.div(other: C): NumberedRationalFunction = + NumberedRationalFunction( + numerator, + denominator * other + ) + +// operator fun invoke(arg: Map): NumberedRationalFunction = +// NumberedRationalFunction( +// numerator(arg), +// denominator(arg) +// ) +// +// @JvmName("invokePolynomial") +// operator fun invoke(arg: Map>): NumberedRationalFunction = +// NumberedRationalFunction( +// numerator(arg), +// denominator(arg) +// ) +// +// @JvmName("invokeRationalFunction") +// operator fun invoke(arg: Map>): NumberedRationalFunction { +// var num = numerator invokeRFTakeNumerator arg +// var den = denominator invokeRFTakeNumerator arg +// for (variable in 0 until max(numerator.countOfVariables, denominator.countOfVariables)) if (variable in arg) { +// val degreeDif = numerator.degrees.getOrElse(variable) { 0 } - denominator.degrees.getOrElse(variable) { 0 } +// if (degreeDif > 0) +// den = multiplyByPower(den, arg[variable]!!.denominator, degreeDif) +// else +// num = multiplyByPower(num, arg[variable]!!.denominator, -degreeDif) +// } +// return NumberedRationalFunction(num, den) +// } +// +// override fun toString(): String = toString(Polynomial.variableName) +// +// fun toString(withVariableName: String = Polynomial.variableName): String = +// when(true) { +// numerator.isZero() -> "0" +// denominator.isOne() -> numerator.toString(withVariableName) +// else -> "${numerator.toStringWithBrackets(withVariableName)}/${denominator.toStringWithBrackets(withVariableName)}" +// } +// +// fun toString(namer: (Int) -> String): String = +// when(true) { +// numerator.isZero() -> "0" +// denominator.isOne() -> numerator.toString(namer) +// else -> "${numerator.toStringWithBrackets(namer)}/${denominator.toStringWithBrackets(namer)}" +// } +// +// fun toStringWithBrackets(withVariableName: String = Polynomial.variableName): String = +// when(true) { +// numerator.isZero() -> "0" +// denominator.isOne() -> numerator.toStringWithBrackets(withVariableName) +// else -> "(${numerator.toStringWithBrackets(withVariableName)}/${denominator.toStringWithBrackets(withVariableName)})" +// } +// +// fun toStringWithBrackets(namer: (Int) -> String): String = +// when(true) { +// numerator.isZero() -> "0" +// denominator.isOne() -> numerator.toStringWithBrackets(namer) +// else -> "(${numerator.toStringWithBrackets(namer)}/${denominator.toStringWithBrackets(namer)})" +// } +// +// fun toReversedString(withVariableName: String = Polynomial.variableName): String = +// when(true) { +// numerator.isZero() -> "0" +// denominator.isOne() -> numerator.toReversedString(withVariableName) +// else -> "${numerator.toReversedStringWithBrackets(withVariableName)}/${denominator.toReversedStringWithBrackets(withVariableName)}" +// } +// +// fun toReversedString(namer: (Int) -> String): String = +// when(true) { +// numerator.isZero() -> "0" +// denominator.isOne() -> numerator.toReversedString(namer) +// else -> "${numerator.toReversedStringWithBrackets(namer)}/${denominator.toReversedStringWithBrackets(namer)}" +// } +// +// fun toReversedStringWithBrackets(withVariableName: String = Polynomial.variableName): String = +// when(true) { +// numerator.isZero() -> "0" +// denominator.isOne() -> numerator.toReversedStringWithBrackets(withVariableName) +// else -> "(${numerator.toReversedStringWithBrackets(withVariableName)}/${denominator.toReversedStringWithBrackets(withVariableName)})" +// } +// +// fun toReversedStringWithBrackets(namer: (Int) -> String): String = +// when(true) { +// numerator.isZero() -> "0" +// denominator.isOne() -> numerator.toReversedStringWithBrackets(namer) +// else -> "(${numerator.toReversedStringWithBrackets(namer)}/${denominator.toReversedStringWithBrackets(namer)})" +// } +} \ No newline at end of file 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 2c764f4f5..1a324f72c 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 @@ -80,7 +80,7 @@ public open class PolynomialSpace>( coefficients .toMutableList() .apply { - val result = getOrElse(0) { ring.zero } + other + val result = getOrElse(0) { constantZero } + other val isResultZero = result.isZero() when { @@ -97,7 +97,7 @@ public open class PolynomialSpace>( coefficients .toMutableList() .apply { - val result = getOrElse(0) { ring.zero } - other + val result = getOrElse(0) { constantZero } - other val isResultZero = result.isZero() when { @@ -124,7 +124,7 @@ public open class PolynomialSpace>( other.coefficients .toMutableList() .apply { - val result = this@plus + getOrElse(0) { ring.zero } + val result = this@plus + getOrElse(0) { constantZero } val isResultZero = result.isZero() when { @@ -143,7 +143,7 @@ public open class PolynomialSpace>( .apply { forEachIndexed { index, c -> if (index != 0) this[index] = -c } - val result = this@minus - getOrElse(0) { ring.zero } + val result = this@minus - getOrElse(0) { constantZero } val isResultZero = result.isZero() when { @@ -281,7 +281,7 @@ public open class PolynomialSpace>( else -> coefficients[it] + other.coefficients[it] } } - .ifEmpty { listOf(ring.zero) } + .ifEmpty { listOf(constantZero) } ) public override operator fun Polynomial.minus(other: Polynomial): Polynomial = Polynomial( @@ -293,7 +293,7 @@ public open class PolynomialSpace>( else -> coefficients[it] - other.coefficients[it] } } - .ifEmpty { listOf(ring.zero) } + .ifEmpty { listOf(constantZero) } ) public override operator fun Polynomial.times(other: Polynomial): Polynomial { val thisDegree = degree @@ -321,7 +321,7 @@ public open class PolynomialSpace>( with(coefficients) { isNotEmpty() && asSequence().withIndex().any { (index, c) -> if (index == 0) c.isMinusOne() else c.isZero() } } // TODO: It's better to write new methods like `anyIndexed`. But what's better way to do it? override val zero: Polynomial = Polynomial(emptyList()) - override val one: Polynomial = Polynomial(listOf(ring.one)) + override val one: Polynomial = Polynomial(listOf(constantZero)) @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") public override infix fun Polynomial.equalsTo(other: Polynomial): Boolean = @@ -337,12 +337,12 @@ public open class PolynomialSpace>( // region Polynomial properties - public override val Polynomial.degree: Int get() = coefficients.indexOfLast { it != ring.zero } + public override val Polynomial.degree: Int get() = coefficients.indexOfLast { it != constantZero } public override fun Polynomial.asConstantOrNull(): C? = with(coefficients) { when { - isEmpty() -> ring.zero + isEmpty() -> constantZero degree > 0 -> null else -> first() } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt index 78ca556db..e9916b634 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt @@ -1,3 +1,8 @@ +/* + * 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.functions import space.kscience.kmath.operations.* @@ -270,19 +275,6 @@ public class RationalFunctionSpace> ( denominator * other.denominator ) - /** - * Check if the instant is zero rational function. - */ - public override fun RationalFunction.isZero(): Boolean = numerator.isZero() - /** - * Check if the instant is unit rational function. - */ - public override fun RationalFunction.isOne(): Boolean = numerator.equalsTo(denominator) - /** - * Check if the instant is minus unit rational function. - */ - public override fun RationalFunction.isMinusOne(): Boolean = (numerator + denominator).isZero() - /** * Instance of zero rational function (zero of the rational functions ring). */ diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt index 62ac31b64..9cf4f2652 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt @@ -1,3 +1,8 @@ +/* + * 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.functions import space.kscience.kmath.operations.* @@ -30,7 +35,7 @@ import kotlin.contracts.* //fun > power(arg: Variable, pow: UInt): LabeledPolynomial = // if (pow == 0U) one // else LabeledPolynomial(mapOf( -// mapOf(arg to pow) to ring.one +// mapOf(arg to pow) to constantOne // )) // //// endregion diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt new file mode 100644 index 000000000..26e8ab17a --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt @@ -0,0 +1,130 @@ +package math.polynomials + +import math.ringsAndFields.* +import space.kscience.kmath.functions.LabeledRationalFunction + + +fun > T.toLabeledRationalFunction() = LabeledRationalFunction(this.toLabeledPolynomial()) + +// region Operator extensions + +// region Field case + +fun > LabeledRationalFunction.reduced(): LabeledRationalFunction { + val greatestCommonDivider = polynomialGCD(numerator, denominator) + return LabeledRationalFunction( + numerator / greatestCommonDivider, + denominator / greatestCommonDivider + ) +} + +// endregion + +// region Constants + +operator fun > T.plus(other: LabeledRationalFunction) = other + this +operator fun > Integer.plus(other: LabeledRationalFunction) = other + this +operator fun > Int.plus(other: LabeledRationalFunction) = other + this +operator fun > Long.plus(other: LabeledRationalFunction) = other + this + +operator fun > T.minus(other: LabeledRationalFunction) = -other + this +operator fun > Integer.minus(other: LabeledRationalFunction) = -other + this +operator fun > Int.minus(other: LabeledRationalFunction) = -other + this +operator fun > Long.minus(other: LabeledRationalFunction) = -other + this + +operator fun > T.times(other: LabeledRationalFunction) = other * this +operator fun > Integer.times(other: LabeledRationalFunction) = other * this +operator fun > Int.times(other: LabeledRationalFunction) = other * this +operator fun > Long.times(other: LabeledRationalFunction) = other * this + +// endregion + +// region Polynomials + +operator fun > LabeledRationalFunction.plus(other: UnivariatePolynomial) = + LabeledRationalFunction( + numerator + denominator * other.toLabeledPolynomial(), + denominator + ) +operator fun > LabeledRationalFunction.plus(other: UnivariateRationalFunction) = + LabeledRationalFunction( + numerator * other.denominator.toLabeledPolynomial() + denominator * other.numerator.toLabeledPolynomial(), + denominator * other.denominator.toLabeledPolynomial() + ) +operator fun > LabeledRationalFunction.plus(other: Polynomial) = + LabeledRationalFunction( + numerator + denominator * other.toLabeledPolynomial(), + denominator + ) +operator fun > LabeledRationalFunction.plus(other: NumberedRationalFunction) = + LabeledRationalFunction( + numerator * other.denominator.toLabeledPolynomial() + denominator * other.numerator.toLabeledPolynomial(), + denominator * other.denominator.toLabeledPolynomial() + ) + +operator fun > LabeledRationalFunction.minus(other: UnivariatePolynomial) = + LabeledRationalFunction( + numerator - denominator * other.toLabeledPolynomial(), + denominator + ) +operator fun > LabeledRationalFunction.minus(other: UnivariateRationalFunction) = + LabeledRationalFunction( + numerator * other.denominator.toLabeledPolynomial() - denominator * other.numerator.toLabeledPolynomial(), + denominator * other.denominator.toLabeledPolynomial() + ) +operator fun > LabeledRationalFunction.minus(other: Polynomial) = + LabeledRationalFunction( + numerator - denominator * other.toLabeledPolynomial(), + denominator + ) +operator fun > LabeledRationalFunction.minus(other: NumberedRationalFunction) = + LabeledRationalFunction( + numerator * other.denominator.toLabeledPolynomial() - denominator * other.numerator.toLabeledPolynomial(), + denominator * other.denominator.toLabeledPolynomial() + ) + +operator fun > LabeledRationalFunction.times(other: UnivariatePolynomial) = + LabeledRationalFunction( + numerator * other.toLabeledPolynomial(), + denominator + ) +operator fun > LabeledRationalFunction.times(other: UnivariateRationalFunction) = + LabeledRationalFunction( + numerator * other.numerator.toLabeledPolynomial(), + denominator * other.denominator.toLabeledPolynomial() + ) +operator fun > LabeledRationalFunction.times(other: Polynomial) = + LabeledRationalFunction( + numerator * other.toLabeledPolynomial(), + denominator + ) +operator fun > LabeledRationalFunction.times(other: NumberedRationalFunction) = + LabeledRationalFunction( + numerator * other.numerator.toLabeledPolynomial(), + denominator * other.denominator.toLabeledPolynomial() + ) + +operator fun > LabeledRationalFunction.div(other: UnivariatePolynomial) = + LabeledRationalFunction( + numerator, + denominator * other.toLabeledPolynomial() + ) +operator fun > LabeledRationalFunction.div(other: UnivariateRationalFunction) = + LabeledRationalFunction( + numerator * other.denominator.toLabeledPolynomial(), + denominator * other.numerator.toLabeledPolynomial() + ) +operator fun > LabeledRationalFunction.div(other: Polynomial) = + LabeledRationalFunction( + numerator, + denominator * other.toLabeledPolynomial() + ) +operator fun > LabeledRationalFunction.div(other: NumberedRationalFunction) = + LabeledRationalFunction( + numerator * other.denominator.toLabeledPolynomial(), + denominator * other.numerator.toLabeledPolynomial() + ) + +// endregion + +// endregion \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt new file mode 100644 index 000000000..7c8120c68 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt @@ -0,0 +1,23 @@ +/* + * 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.functions + + +//// region Operator extensions +// +//// region Field case +// +//fun > NumberedRationalFunction.reduced(): NumberedRationalFunction { +// val greatestCommonDivider = polynomialGCD(numerator, denominator) +// return NumberedRationalFunction( +// numerator / greatestCommonDivider, +// denominator / greatestCommonDivider +// ) +//} +// +//// endregion +// +//// endregion \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/rationalFunctionUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/rationalFunctionUtil.kt index 9147bc023..d5bbc3b82 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/rationalFunctionUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/rationalFunctionUtil.kt @@ -1,3 +1,8 @@ +/* + * 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.functions -- 2.34.1 From 44febbdd730451bb7a941f1bcc973b661bd5d63b Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Mon, 14 Mar 2022 20:19:42 +0300 Subject: [PATCH 013/123] Processed labeledRationalFunctionUtil.kt --- .../kscience/kmath/functions/Polynomial.kt | 1 - .../functions/labeledRationalFunctionUtil.kt | 147 +++--------------- 2 files changed, 20 insertions(+), 128 deletions(-) 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 1a324f72c..49184468b 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 @@ -6,7 +6,6 @@ package space.kscience.kmath.functions import space.kscience.kmath.operations.* -import kotlin.jvm.JvmName import kotlin.math.max import kotlin.math.min diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt index 26e8ab17a..575dfed48 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt @@ -1,130 +1,23 @@ -package math.polynomials +/* + * 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. + */ -import math.ringsAndFields.* -import space.kscience.kmath.functions.LabeledRationalFunction +package space.kscience.kmath.functions -fun > T.toLabeledRationalFunction() = LabeledRationalFunction(this.toLabeledPolynomial()) - -// region Operator extensions - -// region Field case - -fun > LabeledRationalFunction.reduced(): LabeledRationalFunction { - val greatestCommonDivider = polynomialGCD(numerator, denominator) - return LabeledRationalFunction( - numerator / greatestCommonDivider, - denominator / greatestCommonDivider - ) -} - -// endregion - -// region Constants - -operator fun > T.plus(other: LabeledRationalFunction) = other + this -operator fun > Integer.plus(other: LabeledRationalFunction) = other + this -operator fun > Int.plus(other: LabeledRationalFunction) = other + this -operator fun > Long.plus(other: LabeledRationalFunction) = other + this - -operator fun > T.minus(other: LabeledRationalFunction) = -other + this -operator fun > Integer.minus(other: LabeledRationalFunction) = -other + this -operator fun > Int.minus(other: LabeledRationalFunction) = -other + this -operator fun > Long.minus(other: LabeledRationalFunction) = -other + this - -operator fun > T.times(other: LabeledRationalFunction) = other * this -operator fun > Integer.times(other: LabeledRationalFunction) = other * this -operator fun > Int.times(other: LabeledRationalFunction) = other * this -operator fun > Long.times(other: LabeledRationalFunction) = other * this - -// endregion - -// region Polynomials - -operator fun > LabeledRationalFunction.plus(other: UnivariatePolynomial) = - LabeledRationalFunction( - numerator + denominator * other.toLabeledPolynomial(), - denominator - ) -operator fun > LabeledRationalFunction.plus(other: UnivariateRationalFunction) = - LabeledRationalFunction( - numerator * other.denominator.toLabeledPolynomial() + denominator * other.numerator.toLabeledPolynomial(), - denominator * other.denominator.toLabeledPolynomial() - ) -operator fun > LabeledRationalFunction.plus(other: Polynomial) = - LabeledRationalFunction( - numerator + denominator * other.toLabeledPolynomial(), - denominator - ) -operator fun > LabeledRationalFunction.plus(other: NumberedRationalFunction) = - LabeledRationalFunction( - numerator * other.denominator.toLabeledPolynomial() + denominator * other.numerator.toLabeledPolynomial(), - denominator * other.denominator.toLabeledPolynomial() - ) - -operator fun > LabeledRationalFunction.minus(other: UnivariatePolynomial) = - LabeledRationalFunction( - numerator - denominator * other.toLabeledPolynomial(), - denominator - ) -operator fun > LabeledRationalFunction.minus(other: UnivariateRationalFunction) = - LabeledRationalFunction( - numerator * other.denominator.toLabeledPolynomial() - denominator * other.numerator.toLabeledPolynomial(), - denominator * other.denominator.toLabeledPolynomial() - ) -operator fun > LabeledRationalFunction.minus(other: Polynomial) = - LabeledRationalFunction( - numerator - denominator * other.toLabeledPolynomial(), - denominator - ) -operator fun > LabeledRationalFunction.minus(other: NumberedRationalFunction) = - LabeledRationalFunction( - numerator * other.denominator.toLabeledPolynomial() - denominator * other.numerator.toLabeledPolynomial(), - denominator * other.denominator.toLabeledPolynomial() - ) - -operator fun > LabeledRationalFunction.times(other: UnivariatePolynomial) = - LabeledRationalFunction( - numerator * other.toLabeledPolynomial(), - denominator - ) -operator fun > LabeledRationalFunction.times(other: UnivariateRationalFunction) = - LabeledRationalFunction( - numerator * other.numerator.toLabeledPolynomial(), - denominator * other.denominator.toLabeledPolynomial() - ) -operator fun > LabeledRationalFunction.times(other: Polynomial) = - LabeledRationalFunction( - numerator * other.toLabeledPolynomial(), - denominator - ) -operator fun > LabeledRationalFunction.times(other: NumberedRationalFunction) = - LabeledRationalFunction( - numerator * other.numerator.toLabeledPolynomial(), - denominator * other.denominator.toLabeledPolynomial() - ) - -operator fun > LabeledRationalFunction.div(other: UnivariatePolynomial) = - LabeledRationalFunction( - numerator, - denominator * other.toLabeledPolynomial() - ) -operator fun > LabeledRationalFunction.div(other: UnivariateRationalFunction) = - LabeledRationalFunction( - numerator * other.denominator.toLabeledPolynomial(), - denominator * other.numerator.toLabeledPolynomial() - ) -operator fun > LabeledRationalFunction.div(other: Polynomial) = - LabeledRationalFunction( - numerator, - denominator * other.toLabeledPolynomial() - ) -operator fun > LabeledRationalFunction.div(other: NumberedRationalFunction) = - LabeledRationalFunction( - numerator * other.denominator.toLabeledPolynomial(), - denominator * other.numerator.toLabeledPolynomial() - ) - -// endregion - -// endregion \ No newline at end of file +//// region Operator extensions +// +//// region Field case +// +//fun > LabeledRationalFunction.reduced(): LabeledRationalFunction { +// val greatestCommonDivider = polynomialGCD(numerator, denominator) +// return LabeledRationalFunction( +// numerator / greatestCommonDivider, +// denominator / greatestCommonDivider +// ) +//} +// +//// endregion +// +//// endregion \ No newline at end of file -- 2.34.1 From fb01d851975a1e681f00f6a530431a5dd326421a Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Mon, 14 Mar 2022 22:23:50 +0300 Subject: [PATCH 014/123] Removed extra `JSName` annotations. Now everything builds --- .../kscience/kmath/functions/AbstractPolynomial.kt | 4 ---- .../kmath/functions/AbstractRationalFunction.kt | 10 ---------- 2 files changed, 14 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt index 0ca2d1409..0b16303af 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt @@ -388,25 +388,21 @@ public interface AbstractPolynomialSpaceOverRing, A: * Returns negation of the constant. */ @JvmName("constantUnaryMinus") - @JsName("constantUnaryMinus") public override operator fun C.unaryMinus(): C = ring { -this@unaryMinus } /** * Returns sum of the constants. */ @JvmName("constantPlus") - @JsName("constantPlus") public override operator fun C.plus(other: C): C = ring { this@plus + other } /** * Returns difference of the constants. */ @JvmName("constantMinus") - @JsName("constantMinus") public override operator fun C.minus(other: C): C = ring { this@minus - other } /** * Returns product of the constants. */ @JvmName("constantTimes") - @JsName("constantTimes") public override operator fun C.times(other: C): C = ring { this@times * other } /** diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt index df366f90f..cf8f3a6ef 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt @@ -578,31 +578,26 @@ public interface AbstractRationalFunctionalSpaceOverRing Date: Mon, 14 Mar 2022 23:33:00 +0300 Subject: [PATCH 015/123] Deleted useless annotations `JvmName`, `JsName` and `Suppress` --- .../kmath/functions/AbstractPolynomial.kt | 20 +---------- .../functions/AbstractRationalFunction.kt | 34 ++----------------- .../kmath/functions/LabeledPolynomial.kt | 2 -- .../functions/LabeledRationalFunction.kt | 1 - .../kmath/functions/NumberedPolynomial.kt | 2 -- .../functions/NumberedRationalFunction.kt | 1 - .../kscience/kmath/functions/Polynomial.kt | 3 +- .../kmath/functions/RationalFunction.kt | 1 - .../kmath/functions/numberedPolynomialUtil.kt | 9 ++--- 9 files changed, 9 insertions(+), 64 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt index 0b16303af..b053ffebd 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt @@ -29,21 +29,18 @@ public interface AbstractPolynomialSpace> : Ring

* * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. */ - @JvmName("constantIntPlus") public operator fun C.plus(other: Int): C /** * Returns difference between the constant and the integer represented as constant (member of underlying ring). * * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. */ - @JvmName("constantIntMinus") public operator fun C.minus(other: Int): C /** * Returns product of the constant and the integer represented as constant (member of underlying ring). * * The operation is equivalent to sum of [other] copies of [this]. */ - @JvmName("constantIntTimes") public operator fun C.times(other: Int): C // endregion @@ -53,21 +50,18 @@ public interface AbstractPolynomialSpace> : Ring

* * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. */ - @JvmName("intConstantPlus") public operator fun Int.plus(other: C): C /** * Returns difference between the integer represented as constant (member of underlying ring) and the constant. * * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. */ - @JvmName("intConstantMinus") public operator fun Int.minus(other: C): C /** * Returns product of the integer represented as constant (member of underlying ring) and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ - @JvmName("intConstantTimes") public operator fun Int.times(other: C): C // endregion @@ -148,32 +142,26 @@ public interface AbstractPolynomialSpace> : Ring

/** * Check if the instant is zero constant. */ - @JvmName("constantIsZero") public fun C.isZero(): Boolean = this == constantZero /** * Check if the instant is NOT zero constant. */ - @JvmName("constantIsNotZero") public fun C.isNotZero(): Boolean = !isZero() /** * Check if the instant is unit constant. */ - @JvmName("constantIsOne") public fun C.isOne(): Boolean = this == constantOne /** * Check if the instant is NOT unit constant. */ - @JvmName("constantIsNotOne") public fun C.isNotOne(): Boolean = !isOne() /** * Check if the instant is minus unit constant. */ - @JvmName("constantIsMinusOne") public fun C.isMinusOne(): Boolean = this == -constantOne /** * Check if the instant is NOT minus unit constant. */ - @JvmName("constantIsNotMinusOne") public fun C.isNotMinusOne(): Boolean = !isMinusOne() /** @@ -330,7 +318,7 @@ public interface AbstractPolynomialSpace> : Ring

* @param C the type of constants. Polynomials have them as a coefficients in their terms. * @param P the type of polynomials. */ -@Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") +@Suppress("INAPPLICABLE_JVM_NAME") public interface AbstractPolynomialSpaceOverRing, A: Ring> : AbstractPolynomialSpace { public val ring: A @@ -341,21 +329,18 @@ public interface AbstractPolynomialSpaceOverRing, A: * * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. */ - @JvmName("constantIntPlus") public override operator fun C.plus(other: Int): C = ring { optimizedAddMultiplied(this@plus, one, other) } /** * Returns difference between the constant and the integer represented as constant (member of underlying ring). * * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. */ - @JvmName("constantIntMinus") public override operator fun C.minus(other: Int): C = ring { optimizedAddMultiplied(this@minus, one, -other) } /** * Returns product of the constant and the integer represented as constant (member of underlying ring). * * The operation is equivalent to sum of [other] copies of [this]. */ - @JvmName("constantIntTimes") public override operator fun C.times(other: Int): C = ring { optimizedMultiply(this@times, other) } // endregion @@ -365,21 +350,18 @@ public interface AbstractPolynomialSpaceOverRing, A: * * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. */ - @JvmName("intConstantPlus") public override operator fun Int.plus(other: C): C = ring { optimizedAddMultiplied(other, one, this@plus) } /** * Returns difference between the integer represented as constant (member of underlying ring) and the constant. * * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. */ - @JvmName("intConstantMinus") public override operator fun Int.minus(other: C): C = ring { optimizedAddMultiplied(-other, one, this@minus) } /** * Returns product of the integer represented as constant (member of underlying ring) and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ - @JvmName("intConstantTimes") public override operator fun Int.times(other: C): C = ring { optimizedMultiply(other, this@times) } // endregion diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt index cf8f3a6ef..f8d3bb99b 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt @@ -28,21 +28,18 @@ public interface AbstractRationalFunctionalSpace, R: * * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. */ - @JvmName("constantIntPlus") public operator fun C.plus(other: Int): C /** * Returns difference between the constant and the integer represented as constant (member of underlying ring). * * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. */ - @JvmName("constantIntMinus") public operator fun C.minus(other: Int): C /** * Returns product of the constant and the integer represented as constant (member of underlying ring). * * The operation is equivalent to sum of [other] copies of [this]. */ - @JvmName("constantIntTimes") public operator fun C.times(other: Int): C // endregion @@ -52,21 +49,18 @@ public interface AbstractRationalFunctionalSpace, R: * * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. */ - @JvmName("intConstantPlus") public operator fun Int.plus(other: C): C /** * Returns difference between the integer represented as constant (member of underlying ring) and the constant. * * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. */ - @JvmName("intConstantMinus") public operator fun Int.minus(other: C): C /** * Returns product of the integer represented as constant (member of underlying ring) and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ - @JvmName("intConstantTimes") public operator fun Int.times(other: C): C // endregion @@ -189,32 +183,26 @@ public interface AbstractRationalFunctionalSpace, R: /** * Check if the instant is zero constant. */ - @JvmName("constantIsZero") public fun C.isZero(): Boolean = this == constantZero /** * Check if the instant is NOT zero constant. */ - @JvmName("constantIsNotZero") public fun C.isNotZero(): Boolean = !isZero() /** * Check if the instant is unit constant. */ - @JvmName("constantIsOne") public fun C.isOne(): Boolean = this == constantOne /** * Check if the instant is NOT unit constant. */ - @JvmName("constantIsNotOne") public fun C.isNotOne(): Boolean = !isOne() /** * Check if the instant is minus unit constant. */ - @JvmName("constantIsMinusOne") public fun C.isMinusOne(): Boolean = this == -constantOne /** * Check if the instant is NOT minus unit constant. */ - @JvmName("constantIsNotMinusOne") public fun C.isNotMinusOne(): Boolean = !isMinusOne() /** @@ -520,7 +508,7 @@ public interface AbstractRationalFunctionalSpace, R: // endregion } -@Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") +@Suppress("INAPPLICABLE_JVM_NAME") public interface AbstractRationalFunctionalSpaceOverRing, R: AbstractRationalFunction, A: Ring> : AbstractRationalFunctionalSpace { public val ring: A @@ -531,21 +519,18 @@ public interface AbstractRationalFunctionalSpaceOverRing, R: AbstractRationalFunction, A: Ring> : AbstractRationalFunctionalSpace { public val polynomialRing: AbstractPolynomialSpace @@ -622,21 +604,18 @@ public interface AbstractRationalFunctionalSpaceOverPolynomialSpace.cleanUp() = filterValues { it > 0U } * @param A the intersection of [Ring] of [C] and [ScaleOperations] of [C]. * @param ring the [A] instance. */ -@Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE", "INAPPLICABLE_JVM_NAME") public class LabeledPolynomialSpace>( public override val ring: A, ) : AbstractPolynomialSpaceOverRing, A> { @@ -768,7 +767,6 @@ public class LabeledPolynomialSpace>( override val one: LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to constantOne)) // TODO: Docs - @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") override infix fun LabeledPolynomial.equalsTo(other: LabeledPolynomial): Boolean = when { this === other -> true diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt index 203c9e07c..2bec1f3a4 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt @@ -305,7 +305,6 @@ public class LabeledRationalFunctionSpace>( /** * Checks equality of the rational functions. */ - @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") public override infix fun LabeledRationalFunction.equalsTo(other: LabeledRationalFunction): Boolean { if (this === other) return true diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt index 39ca43945..de5cc5658 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -263,7 +263,6 @@ public fun > C.asNumberedPolynomial() : NumberedPolynomial = Nu * @param A the intersection of [Ring] of [C] and [ScaleOperations] of [C]. * @param ring the [A] instance. */ -@Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE", "INAPPLICABLE_JVM_NAME") public open class NumberedPolynomialSpace>( public final override val ring: A, ) : AbstractPolynomialSpaceOverRing, A> { @@ -532,7 +531,6 @@ public open class NumberedPolynomialSpace>( ) // TODO: Docs - @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") override infix fun NumberedPolynomial.equalsTo(other: NumberedPolynomial): Boolean = when { this === other -> true diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt index aff18d1f4..2053cc7f9 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt @@ -302,7 +302,6 @@ public class NumberedRationalFunctionSpace> ( /** * Checks equality of the rational functions. */ - @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") public override infix fun NumberedRationalFunction.equalsTo(other: NumberedRationalFunction): Boolean { if (this === other) return true 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 49184468b..802ff7ea2 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 @@ -66,7 +66,7 @@ public fun T.asPolynomial() : Polynomial = Polynomial(listOf(this)) * @param A type of underlying ring of constants. It's [Ring] of [C]. * @param ring underlying ring of constants of type [A]. */ -@Suppress("INAPPLICABLE_JVM_NAME") // TODO: KT-31420 +//@Suppress("INAPPLICABLE_JVM_NAME") // TODO: KT-31420 public open class PolynomialSpace>( public final override val ring: A, ) : AbstractPolynomialSpaceOverRing, A> { @@ -322,7 +322,6 @@ public open class PolynomialSpace>( override val zero: Polynomial = Polynomial(emptyList()) override val one: Polynomial = Polynomial(listOf(constantZero)) - @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") public override infix fun Polynomial.equalsTo(other: Polynomial): Boolean = when { this === other -> true diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt index e9916b634..0842f0938 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt @@ -287,7 +287,6 @@ public class RationalFunctionSpace> ( /** * Checks equality of the rational functions. */ - @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") public override infix fun RationalFunction.equalsTo(other: RationalFunction): Boolean = when { this === other -> true diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt index d4053442d..558afa744 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt @@ -6,6 +6,7 @@ import kotlin.contracts.* import kotlin.jvm.JvmName + // TODO: Docs // region Sort of legacy @@ -485,8 +486,8 @@ public fun NumberedPolynomial.substitute(args: Map): Number val deg = degs.getOrElse(variable) { 0u } if (deg == 0u) product else product * substitutor.pow(deg.toInt()) } - if (newDegs !in acc) acc[newDegs] = c - else acc[newDegs] = acc[newDegs]!! + c + if (newDegs !in acc) acc[newDegs] = newC + else acc[newDegs] = acc[newDegs]!! + newC } return NumberedPolynomial(acc) } @@ -504,8 +505,8 @@ public fun NumberedPolynomial.substitute(ring: Ring, args: Map val deg = degs.getOrElse(variable) { 0u } if (deg == 0u) product else product * power(substitutor, deg) } - if (newDegs !in acc) acc[newDegs] = c - else acc[newDegs] = acc[newDegs]!! + c + if (newDegs !in acc) acc[newDegs] = newC + else acc[newDegs] = acc[newDegs]!! + newC } return NumberedPolynomial(acc) } -- 2.34.1 From ebd7f799adae2047eb5acdfec6ef5345e2a7c3d6 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Tue, 15 Mar 2022 00:47:23 +0300 Subject: [PATCH 016/123] Attempts to implement derivatives and antiderivatives --- .../kmath/functions/numberedPolynomialUtil.kt | 175 ++++++++++++++---- .../kmath/functions/polynomialUtil.kt | 32 +++- 2 files changed, 171 insertions(+), 36 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt index 558afa744..b7620e792 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt @@ -545,62 +545,169 @@ public fun > NumberedPolynomial.asPolynomialFunctionOver(ring: * Returns algebraic derivative of received polynomial. */ @UnstableKMathAPI -public fun NumberedPolynomial.derivativeBy( +public fun > NumberedPolynomial.derivativeWithRespectTo( algebra: A, variable: Int, -): Polynomial where A : Ring, A : NumericAlgebra = algebra { - TODO() +): NumberedPolynomial = algebra { + NumberedPolynomial( + buildMap(coefficients.size) { + coefficients.forEach { (degs, c) -> + put( + degs.mapIndexed { index, deg -> + when { + index != variable -> deg + deg > 0u -> deg - 1u + else -> return@forEach + } + }, + optimizedMultiply(c, degs.getOrElse(variable) { 1u }.toInt()) + ) + } + } + ) +} + +/** + * Returns algebraic derivative of received polynomial. + */ // TODO: This one does not work!!! +@UnstableKMathAPI +public fun > NumberedPolynomial.derivativeWithRespectTo( + algebra: A, + variables: IntArray, +): NumberedPolynomial = algebra { + NumberedPolynomial( + buildMap(coefficients.size) { + coefficients.forEach { (degs, c) -> + put( + degs.mapIndexed { index, deg -> + when { + index !in variables -> deg + deg > 0u -> deg - 1u + else -> return@forEach + } + }, + optimizedMultiply(c, variables.fold(1u) { acc, variable -> acc * degs.getOrElse(variable) { 1u } }.toInt()) + ) + } + } + ) +} + +/** + * Returns algebraic derivative of received polynomial. + */ // TODO: This one does not work!!! +@UnstableKMathAPI +public fun > NumberedPolynomial.derivativeWithRespectTo( + algebra: A, + variables: Collection, +): NumberedPolynomial = algebra { + NumberedPolynomial( + buildMap(coefficients.size) { + coefficients.forEach { (degs, c) -> + put( + degs.mapIndexed { index, deg -> + when { + index !in variables -> deg + deg > 0u -> deg - 1u + else -> return@forEach + } + }, + optimizedMultiply(c, variables.fold(1u) { acc, variable -> acc * degs.getOrElse(variable) { 1u } }.toInt()) + ) + } + } + ) } /** * Returns algebraic derivative of received polynomial. */ @UnstableKMathAPI -public fun NumberedPolynomial.derivativeBy( - algebra: A, - variables: IntArray, -): Polynomial where A : Ring, A : NumericAlgebra = algebra { - TODO() -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun NumberedPolynomial.derivativeBy( - algebra: A, - variables: Collection, -): Polynomial where A : Ring, A : NumericAlgebra = derivativeBy(algebra, variables.toIntArray()) - -/** - * Create a polynomial witch represents indefinite integral version of this polynomial - */ -@UnstableKMathAPI -public fun NumberedPolynomial.antiderivativeBy( +public fun > NumberedPolynomial.nthDerivativeWithRespectTo( algebra: A, variable: Int, -): Polynomial where A : Field, A : NumericAlgebra = algebra { - TODO() + order: UInt +): NumberedPolynomial = algebra { + NumberedPolynomial( + buildMap(coefficients.size) { + coefficients.forEach { (degs, c) -> + put( + degs.mapIndexed { index, deg -> + when { + index != variable -> deg + deg >= order -> deg - order + else -> return@forEach + } + }, + degs.getOrElse(variable) { 1u }.toInt().let { + (0u until order).fold(c) { acc, ord -> + optimizedMultiply(acc, ord.toInt()) + } + } + ) + } + } + ) } /** - * Create a polynomial witch represents indefinite integral version of this polynomial + * Returns algebraic antiderivative of received polynomial. */ @UnstableKMathAPI -public fun NumberedPolynomial.antiderivativeBy( +public fun > NumberedPolynomial.antiderivativeWithRespectTo( + algebra: A, + variable: Int, +): NumberedPolynomial = algebra { + NumberedPolynomial( + buildMap(coefficients.size) { + coefficients.forEach { (degs, c) -> + put( + degs.mapIndexed { index, deg -> if(index != variable) deg else deg + 1u }, + c / optimizedMultiply(one, degs.getOrElse(variable) { 1u }.toInt()) + ) + } + } + ) +} + +/** + * Returns algebraic antiderivative of received polynomial. + */ // TODO: This one does not work!!! +@UnstableKMathAPI +public fun > NumberedPolynomial.antiderivativeWithRespectTo( algebra: A, variables: IntArray, -): Polynomial where A : Field, A : NumericAlgebra = algebra { - TODO() +): NumberedPolynomial = algebra { + NumberedPolynomial( + buildMap(coefficients.size) { + coefficients.forEach { (degs, c) -> + put( + degs.mapIndexed { index, deg -> if(index !in variables) deg else deg + 1u }, + c / optimizedMultiply(one, variables.fold(1u) { acc, variable -> acc * degs.getOrElse(variable) { 1u } }.toInt()) + ) + } + } + ) } /** - * Create a polynomial witch represents indefinite integral version of this polynomial - */ + * Returns algebraic antiderivative of received polynomial. + */ // TODO: This one does not work!!! @UnstableKMathAPI -public fun NumberedPolynomial.antiderivativeBy( +public fun > NumberedPolynomial.antiderivativeWithRespectTo( algebra: A, variables: Collection, -): Polynomial where A : Field, A : NumericAlgebra = antiderivativeBy(algebra, variables.toIntArray()) +): NumberedPolynomial = algebra { + NumberedPolynomial( + buildMap(coefficients.size) { + coefficients.forEach { (degs, c) -> + put( + degs.mapIndexed { index, deg -> if(index !in variables) deg else deg + 1u }, + c / optimizedMultiply(one, variables.fold(1u) { acc, variable -> acc * degs.getOrElse(variable) { 1u } }.toInt()) + ) + } + } + ) +} // endregion \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt index 4d99b3a45..7e40b6246 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt @@ -109,11 +109,23 @@ public fun > Polynomial.asPolynomialFunctionOver(ring: A): (Po public fun Polynomial.derivative( algebra: A, ): Polynomial where A : Ring, A : NumericAlgebra = algebra { - Polynomial(coefficients.drop(1).mapIndexed { index, t -> number(index) * t }) + Polynomial(coefficients.drop(1).mapIndexed { index, c -> number(index) * c }) } /** - * Create a polynomial witch represents indefinite integral version of this polynomial + * Returns algebraic derivative of received polynomial. + */ +@UnstableKMathAPI +public fun Polynomial.nthDerivative( + algebra: A, + order: UInt, +): Polynomial where A : Ring, A : NumericAlgebra = algebra { + TODO() + Polynomial(coefficients.drop(order.toInt()).mapIndexed { index, c -> number(index) * c }) +} + +/** + * Returns algebraic antiderivative of received polynomial. */ @UnstableKMathAPI public fun Polynomial.antiderivative( @@ -126,6 +138,22 @@ public fun Polynomial.antiderivative( Polynomial(integratedCoefficients) } +/** + * Returns algebraic antiderivative of received polynomial. + */ +@UnstableKMathAPI +public fun Polynomial.nthAntiderivative( + algebra: A, + order: UInt, +): Polynomial where A : Field, A : NumericAlgebra = algebra { + TODO() + val integratedCoefficients = buildList(coefficients.size + 1) { + add(zero) + coefficients.forEachIndexed{ index, t -> add(t / number(index + 1)) } + } + Polynomial(integratedCoefficients) +} + /** * Compute a definite integral of a given polynomial in a [range] */ -- 2.34.1 From f86529d65944016631efe09218c4828feed32f03 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Tue, 15 Mar 2022 15:35:17 +0300 Subject: [PATCH 017/123] Optimized `optimizedMultiply` and `optimizedAddMultiplied` for cases of negative value of `other` and `multiplier` --- .../kscience/kmath/functions/algebraicStub.kt | 59 +++++++++++++------ 1 file changed, 42 insertions(+), 17 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt index 9e5043b8c..3c37a01ec 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt @@ -16,17 +16,11 @@ import space.kscience.kmath.operations.Group * @receiver the multiplicand. * @param other the multiplier. * @return the difference. + * @author Gleb Minaev */ -internal tailrec fun Group.optimizedMultiply(arg: C, other: Int): C = - when { - other == 0 -> zero - other == 1 -> arg - other == -1 -> -arg - other % 2 == 0 -> optimizedMultiply(arg + arg, other / 2) - other % 2 == 1 -> optimizedAddMultiplied(arg, arg + arg, other / 2) - other % 2 == -1 -> optimizedAddMultiplied(-arg, arg + arg, other / 2) - else -> error("Error in multiplication group instant by integer: got reminder by division by 2 different from 0, 1 and -1") - } +internal fun Group.optimizedMultiply(arg: C, other: Int): C = + if (other >= 0) optimizedMultiply(arg, other.toUInt()) + else optimizedMultiply(arg, (-other).toUInt()) // TODO: Move receiver to context receiver /** @@ -40,12 +34,43 @@ internal tailrec fun Group.optimizedMultiply(arg: C, other: Int): C = * @author Gleb Minaev */ internal tailrec fun Group.optimizedAddMultiplied(base: C, arg: C, multiplier: Int): C = + if (multiplier >= 0) optimizedAddMultiplied(base, arg, multiplier.toUInt()) + else optimizedAddMultiplied(base, arg, (-multiplier).toUInt()) + +// TODO: Move receiver to context receiver +/** + * Multiplication of element and integer. + * + * @receiver the multiplicand. + * @param other the multiplier. + * @return the difference. + * @author Gleb Minaev + */ +internal tailrec fun Group.optimizedMultiply(arg: C, other: UInt): C = when { - multiplier == 0 -> base - multiplier == 1 -> base + arg - multiplier == -1 -> base - arg - multiplier % 2 == 0 -> optimizedAddMultiplied(base, arg + arg, multiplier / 2) - multiplier % 2 == 1 -> optimizedAddMultiplied(base + arg, arg + arg, multiplier / 2) - multiplier % 2 == -1 -> optimizedAddMultiplied(base + arg, arg + arg, multiplier / 2) - else -> error("Error in multiplication group instant by integer: got reminder by division by 2 different from 0, 1 and -1") + other == 0u -> zero + other == 1u -> arg + other % 2u == 0u -> optimizedMultiply(arg + arg, other / 2u) + other % 2u == 1u -> optimizedAddMultiplied(arg, arg + arg, other / 2u) + else -> error("Error in multiplication group instant by unsigned integer: got reminder by division by 2 different from 0 and 1") + } + +// TODO: Move receiver to context receiver +/** + * Adds product of [arg] and [multiplier] to [base]. + * + * @receiver the algebra to provide multiplication. + * @param base the augend. + * @param arg the multiplicand. + * @param multiplier the multiplier. + * @return sum of the augend [base] and product of the multiplicand [arg] and the multiplier [multiplier]. + * @author Gleb Minaev + */ +internal tailrec fun Group.optimizedAddMultiplied(base: C, arg: C, multiplier: UInt): C = + when { + multiplier == 0u -> base + multiplier == 1u -> base + arg + multiplier % 2u == 0u -> optimizedAddMultiplied(base, arg + arg, multiplier / 2u) + multiplier % 2u == 1u -> optimizedAddMultiplied(base + arg, arg + arg, multiplier / 2u) + else -> error("Error in multiplication group instant by unsigned integer: got reminder by division by 2 different from 0 and 1") } \ No newline at end of file -- 2.34.1 From 79736a0a9b6450df9ae0a7d7209b8aa7603d36c4 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Tue, 15 Mar 2022 15:36:10 +0300 Subject: [PATCH 018/123] Forgot to remove unnecessary `tailrec` --- .../kotlin/space/kscience/kmath/functions/algebraicStub.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt index 3c37a01ec..537184ba3 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt @@ -33,7 +33,7 @@ internal fun Group.optimizedMultiply(arg: C, other: Int): C = * @return sum of the augend [base] and product of the multiplicand [arg] and the multiplier [multiplier]. * @author Gleb Minaev */ -internal tailrec fun Group.optimizedAddMultiplied(base: C, arg: C, multiplier: Int): C = +internal fun Group.optimizedAddMultiplied(base: C, arg: C, multiplier: Int): C = if (multiplier >= 0) optimizedAddMultiplied(base, arg, multiplier.toUInt()) else optimizedAddMultiplied(base, arg, (-multiplier).toUInt()) -- 2.34.1 From 1754ae06951ff0964239cc7c822b869b31ab371e Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Tue, 15 Mar 2022 16:43:22 +0300 Subject: [PATCH 019/123] Added some docs --- .../kmath/functions/AbstractPolynomial.kt | 8 +- .../functions/AbstractRationalFunction.kt | 36 +++++- .../kmath/functions/LabeledPolynomial.kt | 60 +++++++++- .../functions/LabeledRationalFunction.kt | 7 +- .../kmath/functions/NumberedPolynomial.kt | 69 ++++++++++- .../functions/NumberedRationalFunction.kt | 7 +- .../kscience/kmath/functions/Polynomial.kt | 112 +++++++++++++++--- .../kmath/functions/RationalFunction.kt | 7 +- 8 files changed, 271 insertions(+), 35 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt index b053ffebd..8bd8697e3 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt @@ -18,7 +18,7 @@ public interface AbstractPolynomial /** * Abstraction of ring of polynomials of type [P] over ring of constants of type [C]. * - * @param C the type of constants. Polynomials have them as a coefficients in their terms. + * @param C the type of constants. Polynomials have them as coefficients in their terms. * @param P the type of polynomials. */ @Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") @@ -313,10 +313,12 @@ public interface AbstractPolynomialSpace> : Ring

} /** - * Abstraction of ring of polynomials of type [P] over ring of constants of type [C]. + * Abstraction of ring of polynomials of type [P] over ring of constants of type [C]. It also assumes that there is + * provided [ring] (of type [A]), that provides constant-wise operations. * - * @param C the type of constants. Polynomials have them as a coefficients in their terms. + * @param C the type of constants. Polynomials have them as coefficients in their terms. * @param P the type of polynomials. + * @param A the type of algebraic structure (precisely, of ring) provided for constants. */ @Suppress("INAPPLICABLE_JVM_NAME") public interface AbstractPolynomialSpaceOverRing, A: Ring> : AbstractPolynomialSpace { diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt index f8d3bb99b..685cf4ca3 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt @@ -20,6 +20,14 @@ public interface AbstractRationalFunction> { public operator fun component2(): P = denominator } +/** + * Abstraction of field of rational functions of type [R] with respect to polynomials of type [P] and constants of type + * [C]. + * + * @param C the type of constants. Polynomials have them as coefficients in their terms. + * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. + * @param R the type of rational functions. + */ // TODO: Add support of field @Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") public interface AbstractRationalFunctionalSpace, R: AbstractRationalFunction> : Ring { // region Constant-integer relation @@ -508,6 +516,15 @@ public interface AbstractRationalFunctionalSpace, R: // endregion } +/** + * Abstraction of field of rational functions of type [R] with respect to polynomials of type [P] and constants of type + * [C]. It also assumes that there is provided [ring] (of type [A]), that provides constant-wise operations. + * + * @param C the type of constants. Polynomials have them as coefficients in their terms. + * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. + * @param R the type of rational functions. + * @param A the type of algebraic structure (precisely, of ring) provided for constants. + */ // TODO: Add support of field @Suppress("INAPPLICABLE_JVM_NAME") public interface AbstractRationalFunctionalSpaceOverRing, R: AbstractRationalFunction, A: Ring> : AbstractRationalFunctionalSpace { @@ -593,10 +610,25 @@ public interface AbstractRationalFunctionalSpaceOverRing, R: AbstractRationalFunction, A: Ring> : AbstractRationalFunctionalSpace { +public interface AbstractRationalFunctionalSpaceOverPolynomialSpace< + C, + P: AbstractPolynomial, + R: AbstractRationalFunction, + AP: AbstractPolynomialSpace, + > : AbstractRationalFunctionalSpace { - public val polynomialRing: AbstractPolynomialSpace + public val polynomialRing: AP // region Constant-integer relation /** diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt index 81aabb4a4..ebdaa6e26 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt @@ -384,6 +384,11 @@ public class LabeledPolynomialSpace>( // endregion // region Polynomial-integer relation + /** + * Returns sum of the polynomial and the integer represented as polynomial. + * + * The operation is equivalent to adding [other] copies of unit polynomial to [this]. + */ public override operator fun LabeledPolynomial.plus(other: Int): LabeledPolynomial = if (other == 0) this else @@ -399,6 +404,11 @@ public class LabeledPolynomialSpace>( else this[degs] = result } ) + /** + * Returns difference between the polynomial and the integer represented as polynomial. + * + * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. + */ public override operator fun LabeledPolynomial.minus(other: Int): LabeledPolynomial = if (other == 0) this else @@ -414,6 +424,11 @@ public class LabeledPolynomialSpace>( else this[degs] = result } ) + /** + * Returns product of the polynomial and the integer represented as polynomial. + * + * The operation is equivalent to sum of [other] copies of [this]. + */ public override operator fun LabeledPolynomial.times(other: Int): LabeledPolynomial = if (other == 0) zero else LabeledPolynomial( @@ -425,6 +440,11 @@ public class LabeledPolynomialSpace>( // endregion // region Integer-polynomial relation + /** + * Returns sum of the integer represented as polynomial and the polynomial. + * + * The operation is equivalent to adding [this] copies of unit polynomial to [other]. + */ public override operator fun Int.plus(other: LabeledPolynomial): LabeledPolynomial = if (this == 0) other else @@ -440,6 +460,11 @@ public class LabeledPolynomialSpace>( else this[degs] = result } ) + /** + * Returns difference between the integer represented as polynomial and the polynomial. + * + * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. + */ public override operator fun Int.minus(other: LabeledPolynomial): LabeledPolynomial = if (this == 0) other else @@ -455,6 +480,11 @@ public class LabeledPolynomialSpace>( else this[degs] = result } ) + /** + * Returns product of the integer represented as polynomial and the polynomial. + * + * The operation is equivalent to sum of [this] copies of [other]. + */ public override operator fun Int.times(other: LabeledPolynomial): LabeledPolynomial = if (this == 0) zero else LabeledPolynomial( @@ -514,6 +544,9 @@ public class LabeledPolynomialSpace>( // endregion // region Constant-polynomial relation + /** + * Returns sum of the constant represented as polynomial and the polynomial. + */ override operator fun C.plus(other: LabeledPolynomial): LabeledPolynomial = if (this.isZero()) other else with(other.coefficients) { @@ -530,6 +563,9 @@ public class LabeledPolynomialSpace>( } ) } + /** + * Returns difference between the constant represented as polynomial and the polynomial. + */ override operator fun C.minus(other: LabeledPolynomial): LabeledPolynomial = if (this.isZero()) other else with(other.coefficients) { @@ -548,6 +584,9 @@ public class LabeledPolynomialSpace>( } ) } + /** + * Returns product of the constant represented as polynomial and the polynomial. + */ override operator fun C.times(other: LabeledPolynomial): LabeledPolynomial = if (this.isZero()) zero else LabeledPolynomial( @@ -560,7 +599,7 @@ public class LabeledPolynomialSpace>( // region Polynomial-constant relation /** - * Returns sum of the polynomials. [other] is interpreted as [UnivariatePolynomial]. + * Returns sum of the constant represented as polynomial and the polynomial. */ override operator fun LabeledPolynomial.plus(other: C): LabeledPolynomial = if (other.isZero()) this @@ -579,7 +618,7 @@ public class LabeledPolynomialSpace>( ) } /** - * Returns difference of the polynomials. [other] is interpreted as [UnivariatePolynomial]. + * Returns difference between the constant represented as polynomial and the polynomial. */ override operator fun LabeledPolynomial.minus(other: C): LabeledPolynomial = if (other.isZero()) this @@ -600,7 +639,7 @@ public class LabeledPolynomialSpace>( ) } /** - * Returns product of the polynomials. [other] is interpreted as [UnivariatePolynomial]. + * Returns product of the constant represented as polynomial and the polynomial. */ override operator fun LabeledPolynomial.times(other: C): LabeledPolynomial = if (other.isZero()) zero @@ -763,10 +802,18 @@ public class LabeledPolynomialSpace>( ) } + /** + * Instance of zero polynomial (zero of the polynomial ring). + */ override val zero: LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to constantZero)) + /** + * Instance of unit polynomial (unit of the polynomial ring). + */ override val one: LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to constantOne)) - // TODO: Docs + /** + * Checks equality of the polynomials. + */ override infix fun LabeledPolynomial.equalsTo(other: LabeledPolynomial): Boolean = when { this === other -> true @@ -832,7 +879,10 @@ public class LabeledPolynomialSpace>( } foundAbsoluteTermAndItIsNotZero } - + /** + * If polynomial is a constant polynomial represents and returns it as constant. + * Otherwise, (when the polynomial is not constant polynomial) returns `null`. + */ override fun LabeledPolynomial.asConstantOrNull(): C? = with(coefficients) { if(isConstant()) getOrElse(emptyMap()) { constantZero } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt index 2bec1f3a4..df4441127 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt @@ -85,7 +85,12 @@ internal fun labeledRationalFunctionError(message: Any): Nothing = throw Labeled public class LabeledRationalFunctionSpace>( public val ring: A, -) : AbstractRationalFunctionalSpaceOverPolynomialSpace, LabeledRationalFunction, A> { +) : AbstractRationalFunctionalSpaceOverPolynomialSpace< + C, + LabeledPolynomial, + LabeledRationalFunction, + LabeledPolynomialSpace, + > { override val polynomialRing : LabeledPolynomialSpace = LabeledPolynomialSpace(ring) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt index de5cc5658..86c76949b 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -267,6 +267,11 @@ public open class NumberedPolynomialSpace>( public final override val ring: A, ) : AbstractPolynomialSpaceOverRing, A> { // region Polynomial-integer relation + /** + * Returns sum of the polynomial and the integer represented as polynomial. + * + * The operation is equivalent to adding [other] copies of unit polynomial to [this]. + */ public override operator fun NumberedPolynomial.plus(other: Int): NumberedPolynomial = if (other == 0) this else @@ -282,6 +287,11 @@ public open class NumberedPolynomialSpace>( else this[degs] = result } ) + /** + * Returns difference between the polynomial and the integer represented as polynomial. + * + * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. + */ public override operator fun NumberedPolynomial.minus(other: Int): NumberedPolynomial = if (other == 0) this else @@ -297,6 +307,11 @@ public open class NumberedPolynomialSpace>( else this[degs] = result } ) + /** + * Returns product of the polynomial and the integer represented as polynomial. + * + * The operation is equivalent to sum of [other] copies of [this]. + */ public override operator fun NumberedPolynomial.times(other: Int): NumberedPolynomial = if (other == 0) zero else NumberedPolynomial( @@ -308,6 +323,11 @@ public open class NumberedPolynomialSpace>( // endregion // region Integer-polynomial relation + /** + * Returns sum of the integer represented as polynomial and the polynomial. + * + * The operation is equivalent to adding [this] copies of unit polynomial to [other]. + */ public override operator fun Int.plus(other: NumberedPolynomial): NumberedPolynomial = if (this == 0) other else @@ -323,6 +343,11 @@ public open class NumberedPolynomialSpace>( else this[degs] = result } ) + /** + * Returns difference between the integer represented as polynomial and the polynomial. + * + * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. + */ public override operator fun Int.minus(other: NumberedPolynomial): NumberedPolynomial = if (this == 0) other else @@ -338,6 +363,11 @@ public open class NumberedPolynomialSpace>( else this[degs] = result } ) + /** + * Returns product of the integer represented as polynomial and the polynomial. + * + * The operation is equivalent to sum of [this] copies of [other]. + */ public override operator fun Int.times(other: NumberedPolynomial): NumberedPolynomial = if (this == 0) zero else NumberedPolynomial( @@ -349,6 +379,9 @@ public open class NumberedPolynomialSpace>( // endregion // region Constant-polynomial relation + /** + * Returns sum of the constant represented as polynomial and the polynomial. + */ override operator fun C.plus(other: NumberedPolynomial): NumberedPolynomial = if (this.isZero()) other else with(other.coefficients) { @@ -365,6 +398,9 @@ public open class NumberedPolynomialSpace>( } ) } + /** + * Returns difference between the constant represented as polynomial and the polynomial. + */ override operator fun C.minus(other: NumberedPolynomial): NumberedPolynomial = if (this.isZero()) -other else with(other.coefficients) { @@ -383,6 +419,9 @@ public open class NumberedPolynomialSpace>( } ) } + /** + * Returns product of the constant represented as polynomial and the polynomial. + */ override operator fun C.times(other: NumberedPolynomial): NumberedPolynomial = if (this.isZero()) zero else NumberedPolynomial( @@ -395,7 +434,7 @@ public open class NumberedPolynomialSpace>( // region Polynomial-constant relation /** - * Returns sum of the polynomials. [other] is interpreted as [NumberedPolynomial]. + * Returns sum of the constant represented as polynomial and the polynomial. */ override operator fun NumberedPolynomial.plus(other: C): NumberedPolynomial = if (other.isZero()) this @@ -414,7 +453,7 @@ public open class NumberedPolynomialSpace>( ) } /** - * Returns difference of the polynomials. [other] is interpreted as [NumberedPolynomial]. + * Returns difference between the constant represented as polynomial and the polynomial. */ override operator fun NumberedPolynomial.minus(other: C): NumberedPolynomial = if (other.isZero()) this @@ -433,7 +472,7 @@ public open class NumberedPolynomialSpace>( ) } /** - * Returns product of the polynomials. [other] is interpreted as [NumberedPolynomial]. + * Returns product of the constant represented as polynomial and the polynomial. */ override operator fun NumberedPolynomial.times(other: C): NumberedPolynomial = if (other.isZero()) zero @@ -496,7 +535,13 @@ public open class NumberedPolynomialSpace>( ) } + /** + * Check if the instant is zero polynomial. + */ public override fun NumberedPolynomial.isZero(): Boolean = coefficients.values.all { it.isZero() } + /** + * Check if the instant is unit polynomial. + */ public override fun NumberedPolynomial.isOne(): Boolean = with(coefficients) { var foundAbsoluteTermAndItIsOne = false @@ -509,6 +554,9 @@ public open class NumberedPolynomialSpace>( } foundAbsoluteTermAndItIsOne } + /** + * Check if the instant is minus unit polynomial. + */ public override fun NumberedPolynomial.isMinusOne(): Boolean = with(coefficients) { var foundAbsoluteTermAndItIsMinusOne = false @@ -522,7 +570,13 @@ public open class NumberedPolynomialSpace>( foundAbsoluteTermAndItIsMinusOne } + /** + * Instance of zero polynomial (zero of the polynomial ring). + */ override val zero: NumberedPolynomial = NumberedPolynomial(emptyMap()) + /** + * Instance of unit polynomial (unit of the polynomial ring). + */ override val one: NumberedPolynomial = NumberedPolynomial( mapOf( @@ -530,7 +584,9 @@ public open class NumberedPolynomialSpace>( ) ) - // TODO: Docs + /** + * Checks equality of the polynomials. + */ override infix fun NumberedPolynomial.equalsTo(other: NumberedPolynomial): Boolean = when { this === other -> true @@ -591,7 +647,10 @@ public open class NumberedPolynomialSpace>( } foundAbsoluteTermAndItIsNotZero } - + /** + * If polynomial is a constant polynomial represents and returns it as constant. + * Otherwise, (when the polynomial is not constant polynomial) returns `null`. + */ override fun NumberedPolynomial.asConstantOrNull(): C? = with(coefficients) { if(isConstant()) getOrElse(emptyList()) { constantZero } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt index 2053cc7f9..a81795c81 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt @@ -82,7 +82,12 @@ internal fun numberedRationalFunctionError(message: Any): Nothing = throw Number public class NumberedRationalFunctionSpace> ( public val ring: A, -) : AbstractRationalFunctionalSpaceOverPolynomialSpace, NumberedRationalFunction, A> { +) : AbstractRationalFunctionalSpaceOverPolynomialSpace< + C, + NumberedPolynomial, + NumberedRationalFunction, + NumberedPolynomialSpace, + > { override val polynomialRing : NumberedPolynomialSpace = NumberedPolynomialSpace(ring) 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 802ff7ea2..bdc725e63 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 @@ -68,10 +68,15 @@ public fun T.asPolynomial() : Polynomial = Polynomial(listOf(this)) */ //@Suppress("INAPPLICABLE_JVM_NAME") // TODO: KT-31420 public open class PolynomialSpace>( - public final override val ring: A, + public override val ring: A, ) : AbstractPolynomialSpaceOverRing, A> { // region Polynomial-integer relation + /** + * Returns sum of the polynomial and the integer represented as polynomial. + * + * The operation is equivalent to adding [other] copies of unit polynomial to [this]. + */ public override operator fun Polynomial.plus(other: Int): Polynomial = if (other == 0) this else @@ -89,6 +94,11 @@ public open class PolynomialSpace>( } } ) + /** + * Returns difference between the polynomial and the integer represented as polynomial. + * + * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. + */ public override operator fun Polynomial.minus(other: Int): Polynomial = if (other == 0) this else @@ -106,6 +116,11 @@ public open class PolynomialSpace>( } } ) + /** + * Returns product of the polynomial and the integer represented as polynomial. + * + * The operation is equivalent to sum of [other] copies of [this]. + */ public override operator fun Polynomial.times(other: Int): Polynomial = if (other == 0) zero else Polynomial( @@ -116,6 +131,11 @@ public open class PolynomialSpace>( // endregion // region Integer-polynomial relation + /** + * Returns sum of the integer represented as polynomial and the polynomial. + * + * The operation is equivalent to adding [this] copies of unit polynomial to [other]. + */ public override operator fun Int.plus(other: Polynomial): Polynomial = if (this == 0) other else @@ -133,6 +153,11 @@ public open class PolynomialSpace>( } } ) + /** + * Returns difference between the integer represented as polynomial and the polynomial. + * + * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. + */ public override operator fun Int.minus(other: Polynomial): Polynomial = if (this == 0) other else @@ -152,6 +177,11 @@ public open class PolynomialSpace>( } } ) + /** + * Returns product of the integer represented as polynomial and the polynomial. + * + * The operation is equivalent to sum of [this] copies of [other]. + */ public override operator fun Int.times(other: Polynomial): Polynomial = if (this == 0) zero else Polynomial( @@ -162,6 +192,9 @@ public open class PolynomialSpace>( // endregion // region Constant-polynomial relation + /** + * Returns sum of the constant represented as polynomial and the polynomial. + */ public override operator fun C.plus(other: Polynomial): Polynomial = if (this.isZero()) other else with(other.coefficients) { @@ -180,9 +213,9 @@ public open class PolynomialSpace>( } ) } -// if (degree == -1) UnivariatePolynomial(other) else UnivariatePolynomial( -// listOf(coefficients[0] + other) + coefficients.subList(1, degree + 1) -// ) + /** + * Returns difference between the constant represented as polynomial and the polynomial. + */ public override operator fun C.minus(other: Polynomial): Polynomial = if (this.isZero()) other else with(other.coefficients) { @@ -203,9 +236,9 @@ public open class PolynomialSpace>( } ) } -// if (degree == -1) UnivariatePolynomial(other) else UnivariatePolynomial( -// listOf(coefficients[0] + other) + coefficients.subList(1, degree + 1) -// ) + /** + * Returns product of the constant represented as polynomial and the polynomial. + */ public override operator fun C.times(other: Polynomial): Polynomial = if (this.isZero()) other else Polynomial( @@ -216,6 +249,9 @@ public open class PolynomialSpace>( // endregion // region Polynomial-constant relation + /** + * Returns sum of the constant represented as polynomial and the polynomial. + */ public override operator fun Polynomial.plus(other: C): Polynomial = if (other.isZero()) this else with(coefficients) { @@ -234,9 +270,9 @@ public open class PolynomialSpace>( } ) } -// if (degree == -1) UnivariatePolynomial(other) else UnivariatePolynomial( -// listOf(coefficients[0] + other) + coefficients.subList(1, degree + 1) -// ) + /** + * Returns difference between the constant represented as polynomial and the polynomial. + */ public override operator fun Polynomial.minus(other: C): Polynomial = if (other.isZero()) this else with(coefficients) { @@ -255,9 +291,9 @@ public open class PolynomialSpace>( } ) } -// if (degree == -1) UnivariatePolynomial(-other) else UnivariatePolynomial( -// listOf(coefficients[0] - other) + coefficients.subList(1, degree + 1) -// ) + /** + * Returns product of the constant represented as polynomial and the polynomial. + */ public override operator fun Polynomial.times(other: C): Polynomial = if (other.isZero()) this else Polynomial( @@ -268,8 +304,14 @@ public open class PolynomialSpace>( // endregion // region Polynomial-polynomial relation + /** + * Returns negation of the polynomial. + */ public override operator fun Polynomial.unaryMinus(): Polynomial = Polynomial(coefficients.map { -it }) + /** + * Returns sum of the polynomials. + */ public override operator fun Polynomial.plus(other: Polynomial): Polynomial = Polynomial( (0..max(degree, other.degree)) @@ -282,6 +324,9 @@ public open class PolynomialSpace>( } .ifEmpty { listOf(constantZero) } ) + /** + * Returns difference of the polynomials. + */ public override operator fun Polynomial.minus(other: Polynomial): Polynomial = Polynomial( (0..max(degree, other.degree)) @@ -294,6 +339,9 @@ public open class PolynomialSpace>( } .ifEmpty { listOf(constantZero) } ) + /** + * Returns product of the polynomials. + */ public override operator fun Polynomial.times(other: Polynomial): Polynomial { val thisDegree = degree val otherDegree = other.degree @@ -313,15 +361,39 @@ public open class PolynomialSpace>( } } + /** + * Check if the instant is zero polynomial. + */ public override fun Polynomial.isZero(): Boolean = coefficients.all { it.isZero() } + /** + * Check if the instant is unit polynomial. + */ public override fun Polynomial.isOne(): Boolean = - with(coefficients) { isNotEmpty() && asSequence().withIndex().any { (index, c) -> if (index == 0) c.isOne() else c.isZero() } } // TODO: It's better to write new methods like `anyIndexed`. But what's better way to do it? + with(coefficients) { + isNotEmpty() && + asSequence().withIndex().any { (index, c) -> if (index == 0) c.isOne() else c.isZero() } // TODO: It's better to write new methods like `anyIndexed`. But what's better way to do it? + } + /** + * Check if the instant is minus unit polynomial. + */ public override fun Polynomial.isMinusOne(): Boolean = - with(coefficients) { isNotEmpty() && asSequence().withIndex().any { (index, c) -> if (index == 0) c.isMinusOne() else c.isZero() } } // TODO: It's better to write new methods like `anyIndexed`. But what's better way to do it? + with(coefficients) { + isNotEmpty() && + asSequence().withIndex().any { (index, c) -> if (index == 0) c.isMinusOne() else c.isZero() } // TODO: It's better to write new methods like `anyIndexed`. But what's better way to do it? + } + /** + * Instance of zero polynomial (zero of the polynomial ring). + */ override val zero: Polynomial = Polynomial(emptyList()) + /** + * Instance of unit constant (unit of the underlying ring). + */ override val one: Polynomial = Polynomial(listOf(constantZero)) + /** + * Checks equality of the polynomials. + */ public override infix fun Polynomial.equalsTo(other: Polynomial): Boolean = when { this === other -> true @@ -334,9 +406,16 @@ public open class PolynomialSpace>( // endregion // region Polynomial properties - + /** + * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is + * zero, degree is -1. + */ public override val Polynomial.degree: Int get() = coefficients.indexOfLast { it != constantZero } + /** + * If polynomial is a constant polynomial represents and returns it as constant. + * Otherwise, (when the polynomial is not constant polynomial) returns `null`. + */ public override fun Polynomial.asConstantOrNull(): C? = with(coefficients) { when { @@ -345,7 +424,6 @@ public open class PolynomialSpace>( else -> first() } } - public override fun Polynomial.asConstant(): C = asConstantOrNull() ?: error("Can not represent non-constant polynomial as a constant") @Suppress("NOTHING_TO_INLINE") public inline fun Polynomial.substitute(argument: C): C = this.substitute(ring, argument) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt index 0842f0938..441136a64 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt @@ -67,7 +67,12 @@ internal fun rationalFunctionError(message: Any): Nothing = throw RationalFuncti public class RationalFunctionSpace> ( public val ring: A, -) : AbstractRationalFunctionalSpaceOverPolynomialSpace, RationalFunction, A> { +) : AbstractRationalFunctionalSpaceOverPolynomialSpace< + C, + Polynomial, + RationalFunction, + PolynomialSpace, + > { override val polynomialRing : PolynomialSpace = PolynomialSpace(ring) -- 2.34.1 From 91c9ea61da4f9e3ec60003ce25a6448e9b699b85 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Tue, 15 Mar 2022 18:10:11 +0300 Subject: [PATCH 020/123] Added derivative-like functions to `Polynomial` --- .../kscience/kmath/functions/Polynomial.kt | 16 +++---- .../kmath/functions/polynomialUtil.kt | 48 ++++++++++++------- 2 files changed, 39 insertions(+), 25 deletions(-) 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 bdc725e63..1ac413818 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 @@ -14,7 +14,7 @@ import kotlin.math.min * * @param coefficients constant is the leftmost coefficient. */ -public data class Polynomial(public val coefficients: List) : AbstractPolynomial { +public data class Polynomial(public val coefficients: List) : AbstractPolynomial { override fun toString(): String = "Polynomial$coefficients" } @@ -44,7 +44,7 @@ internal fun polynomialError(message: Any): Nothing = throw PolynomialError(mess * [reverse] parameter is true. */ @Suppress("FunctionName") -public fun Polynomial(coefficients: List, reverse: Boolean = false): Polynomial = +public fun Polynomial(coefficients: List, reverse: Boolean = false): Polynomial = Polynomial(with(coefficients) { if (reverse) reversed() else this }) /** @@ -52,10 +52,10 @@ public fun Polynomial(coefficients: List, reverse: Boolean = false): Poly * [reverse] parameter is true. */ @Suppress("FunctionName") -public fun Polynomial(vararg coefficients: T, reverse: Boolean = false): Polynomial = +public fun Polynomial(vararg coefficients: C, reverse: Boolean = false): Polynomial = Polynomial(with(coefficients) { if (reverse) reversed() else toList() }) -public fun T.asPolynomial() : Polynomial = Polynomial(listOf(this)) +public fun C.asPolynomial() : Polynomial = Polynomial(listOf(this)) // endregion @@ -352,7 +352,7 @@ public open class PolynomialSpace>( Polynomial( (0..(thisDegree + otherDegree)) .map { d -> - (max(0, d - otherDegree)..(min(thisDegree, d))) + (max(0, d - otherDegree)..min(thisDegree, d)) .map { coefficients[it] * other.coefficients[d - it] } .reduce { acc, rational -> acc + rational } } @@ -370,16 +370,14 @@ public open class PolynomialSpace>( */ public override fun Polynomial.isOne(): Boolean = with(coefficients) { - isNotEmpty() && - asSequence().withIndex().any { (index, c) -> if (index == 0) c.isOne() else c.isZero() } // TODO: It's better to write new methods like `anyIndexed`. But what's better way to do it? + isNotEmpty() && withIndex().any { (index, c) -> if (index == 0) c.isOne() else c.isZero() } } /** * Check if the instant is minus unit polynomial. */ public override fun Polynomial.isMinusOne(): Boolean = with(coefficients) { - isNotEmpty() && - asSequence().withIndex().any { (index, c) -> if (index == 0) c.isMinusOne() else c.isZero() } // TODO: It's better to write new methods like `anyIndexed`. But what's better way to do it? + isNotEmpty() && withIndex().any { (index, c) -> if (index == 0) c.isMinusOne() else c.isZero() } } /** diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt index 7e40b6246..a41a6cbd6 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt @@ -9,7 +9,8 @@ import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.* import kotlin.contracts.InvocationKind import kotlin.contracts.contract -import kotlin.jvm.JvmName +import kotlin.math.max +import kotlin.math.min import kotlin.math.pow @@ -77,15 +78,32 @@ public fun Polynomial.substitute(ring: Ring, arg: C): C = ring { return result } -// TODO: (Waiting for hero) Replace with optimisation: the [result] may be unboxed, and all operations may be performed -// as soon as possible on it public fun Polynomial.substitute(ring: Ring, arg: Polynomial) : Polynomial = ring.polynomial { if (coefficients.isEmpty()) return zero - var result: Polynomial = coefficients.last().asPolynomial() - for (j in coefficients.size - 2 downTo 0) { - result = (arg * result) + coefficients[j] + + val thisDegree = degree + if (thisDegree == -1) return zero + val argDegree = arg.degree + if (argDegree == -1) return coefficients[0].asPolynomial() + val constantZero = constantZero + val resultCoefs: MutableList = MutableList(thisDegree + argDegree + 1) { constantZero } + val resultCoefsUpdate: MutableList = MutableList(thisDegree + argDegree + 1) { constantZero } + var resultDegree = 0 + for (deg in thisDegree downTo 0) { + resultCoefsUpdate[0] = coefficients[deg] + for (updateDeg in 0 .. resultDegree + argDegree) { + var newC = resultCoefsUpdate[updateDeg] + for (deg1 in max(0, updateDeg - argDegree)..min(resultDegree, updateDeg)) + newC += resultCoefs[deg1] * arg.coefficients[updateDeg - deg1] + resultCoefsUpdate[updateDeg] = newC + } + resultDegree += argDegree + for (updateDeg in 0 .. resultDegree + argDegree) { + resultCoefs[updateDeg] = resultCoefsUpdate[updateDeg] + resultCoefsUpdate[updateDeg] = constantZero + } } - return result + return Polynomial(resultCoefs) } /** @@ -109,7 +127,7 @@ public fun > Polynomial.asPolynomialFunctionOver(ring: A): (Po public fun Polynomial.derivative( algebra: A, ): Polynomial where A : Ring, A : NumericAlgebra = algebra { - Polynomial(coefficients.drop(1).mapIndexed { index, c -> number(index) * c }) + Polynomial(coefficients.drop(1).mapIndexed { index, c -> number(index + 1) * c }) } /** @@ -120,8 +138,7 @@ public fun Polynomial.nthDerivative( algebra: A, order: UInt, ): Polynomial where A : Ring, A : NumericAlgebra = algebra { - TODO() - Polynomial(coefficients.drop(order.toInt()).mapIndexed { index, c -> number(index) * c }) + Polynomial(coefficients.drop(order.toInt()).mapIndexed { index, c -> (1..order.toInt()).fold(c) { acc, i -> acc * number(index + i) } }) } /** @@ -133,7 +150,7 @@ public fun Polynomial.antiderivative( ): Polynomial where A : Field, A : NumericAlgebra = algebra { val integratedCoefficients = buildList(coefficients.size + 1) { add(zero) - coefficients.forEachIndexed{ index, t -> add(t / number(index + 1)) } + coefficients.mapIndexedTo(this) { index, t -> t / number(index + 1) } } Polynomial(integratedCoefficients) } @@ -146,12 +163,11 @@ public fun Polynomial.nthAntiderivative( algebra: A, order: UInt, ): Polynomial where A : Field, A : NumericAlgebra = algebra { - TODO() - val integratedCoefficients = buildList(coefficients.size + 1) { - add(zero) - coefficients.forEachIndexed{ index, t -> add(t / number(index + 1)) } + val newCoefficients = buildList(coefficients.size + order.toInt()) { + repeat(order.toInt()) { add(zero) } + coefficients.mapIndexedTo(this) { index, c -> (1..order.toInt()).fold(c) { acc, i -> acc / number(index + i) } } } - Polynomial(integratedCoefficients) + return Polynomial(newCoefficients) } /** -- 2.34.1 From 1f9d8d34f5f0476b4ea553bdd2c99a7406d30f61 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Tue, 15 Mar 2022 20:18:39 +0300 Subject: [PATCH 021/123] Tried to add constructors and/or fabrics for polynomials --- .../kmath/functions/LabeledPolynomial.kt | 247 ++---------------- .../kmath/functions/NumberedPolynomial.kt | 223 +++++----------- .../kscience/kmath/functions/Polynomial.kt | 27 +- 3 files changed, 122 insertions(+), 375 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt index ebdaa6e26..56dad975d 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt @@ -73,254 +73,59 @@ internal fun Map.cleanUp() = filterValues { it > 0U } // region Constructors and converters -///** -// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received -// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. -// * -// * @param pairs Collection of pairs that represent monomials. -// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. -// * -// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. -// */ -//context(A) -//internal fun > LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = true): LabeledPolynomial { -// if (!toCheckInput) return LabeledPolynomial(coefs) +//context(LabeledPolynomialSpace>) +//@Suppress("FunctionName") +//internal fun LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = false) : LabeledPolynomial { +// if (!toCheckInput) return LabeledPolynomial(coefs) // -// // Map for cleaned coefficients. // val fixedCoefs = mutableMapOf, C>() // -// // Cleaning the degrees, summing monomials of the same degrees. // for (entry in coefs) { // val key = entry.key.cleanUp() // val value = entry.value // fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value // } // -// // Removing zero monomials. -// return LabeledPolynomial( -// fixedCoefs -// .filter { it.value.isNotZero() } +// return LabeledPolynomial( +// fixedCoefs.filterValues { it.isNotZero() } // ) //} -///** -// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received -// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. -// * -// * @param pairs Collection of pairs that represent monomials. -// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. -// * -// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. -// */ -//context(A) -//internal fun > LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean): LabeledPolynomial { -// if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) // -// // Map for cleaned coefficients. +//context(LabeledPolynomialSpace>) +//@Suppress("FunctionName") +//internal fun LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = false) : LabeledPolynomial { +// if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) +// // val fixedCoefs = mutableMapOf, C>() // -// // Cleaning the degrees, summing monomials of the same degrees. // for (entry in pairs) { // val key = entry.first.cleanUp() // val value = entry.second // fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value // } // -// // Removing zero monomials. -// return LabeledPolynomial( +// return LabeledPolynomial( // fixedCoefs.filterValues { it.isNotZero() } // ) //} -///** -// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received -// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. -// * -// * @param pairs Collection of pairs that represents monomials. -// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. -// * -// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. -// */ -//context(A) -//internal fun > LabeledPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean): LabeledPolynomial { -// if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) // -// // Map for cleaned coefficients. -// val fixedCoefs = mutableMapOf, C>() +//// TODO: Do not know how to make it without context receivers +//context(LabeledPolynomialSpace>) +//@Suppress("FunctionName") +//public fun LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) // -// // Cleaning the degrees, summing monomials of the same degrees. -// for (entry in pairs) { -// val key = entry.first.cleanUp() -// val value = entry.second -// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value -// } +//context(LabeledPolynomialSpace>) +//@Suppress("FunctionName") +//public fun LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) // -// // Removing zero monomials. -// return LabeledPolynomial( -// fixedCoefs.filterValues { it.isNotZero() } -// ) -//} -///** -// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received -// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. -// * -// * @param coefs Coefficients of the instants. -// * -// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. -// */ -//context(A) -//fun > LabeledPolynomial(coefs: Map, C>): LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) -///** -// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received -// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. -// * -// * @param pairs Collection of pairs that represents monomials. -// * -// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. -// */ -//context(A) -//fun > LabeledPolynomial(pairs: Collection, C>>): LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) -///** -// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received -// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. -// * -// * @param pairs Collection of pairs that represents monomials. -// * -// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. -// */ -//context(A) -//fun > LabeledPolynomial(vararg pairs: Pair, C>): LabeledPolynomial = LabeledPolynomial(*pairs, toCheckInput = true) -///** -// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received -// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. -// * -// * @param pairs Collection of pairs that represent monomials. -// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. -// * -// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. -// */ -//context(LabeledPolynomialSpace) -//internal fun > LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = true): LabeledPolynomial { -// if (!toCheckInput) return LabeledPolynomial(coefs) +//context(LabeledPolynomialSpace>) +//@Suppress("FunctionName") +//public fun LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(pairs.toList(), toCheckInput = true) // -// // Map for cleaned coefficients. -// val fixedCoefs = mutableMapOf, C>() -// -// // Cleaning the degrees, summing monomials of the same degrees. -// for (entry in coefs) { -// val key = entry.key.cleanUp() -// val value = entry.value -// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value -// } -// -// // Removing zero monomials. -// return LabeledPolynomial( -// fixedCoefs -// .filter { it.value.isNotZero() } -// ) -//} -///** -// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received -// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. -// * -// * @param pairs Collection of pairs that represent monomials. -// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. -// * -// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. -// */ -//context(LabeledPolynomialSpace) -//internal fun > LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean): LabeledPolynomial { -// if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) -// -// // Map for cleaned coefficients. -// val fixedCoefs = mutableMapOf, C>() -// -// // Cleaning the degrees, summing monomials of the same degrees. -// for (entry in pairs) { -// val key = entry.first.cleanUp() -// val value = entry.second -// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value -// } -// -// // Removing zero monomials. -// return LabeledPolynomial( -// fixedCoefs.filterValues { it.isNotZero() } -// ) -//} -///** -// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received -// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. -// * -// * @param pairs Collection of pairs that represents monomials. -// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. -// * -// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. -// */ -//context(LabeledPolynomialSpace) -//internal fun > LabeledPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean): LabeledPolynomial { -// if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) -// -// // Map for cleaned coefficients. -// val fixedCoefs = mutableMapOf, C>() -// -// // Cleaning the degrees, summing monomials of the same degrees. -// for (entry in pairs) { -// val key = entry.first.cleanUp() -// val value = entry.second -// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value -// } -// -// // Removing zero monomials. -// return LabeledPolynomial( -// fixedCoefs.filterValues { it.isNotZero() } -// ) -//} -///** -// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received -// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. -// * -// * @param coefs Coefficients of the instants. -// * -// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial(coefs: Map, C>): LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) -///** -// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received -// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. -// * -// * @param pairs Collection of pairs that represents monomials. -// * -// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial(pairs: Collection, C>>): LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) -///** -// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received -// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. -// * -// * @param pairs Collection of pairs that represents monomials. -// * -// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial(vararg pairs: Pair, C>): LabeledPolynomial = LabeledPolynomial(*pairs, toCheckInput = true) -// -//fun C.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to this)) -// -//context(A) -//fun > Variable.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1U) to one)) -// -//context(LabeledPolynomialSpace) -//fun > Variable.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1U) to constantOne)) -// -//context(A) -//fun > Variable.asLabeledPolynomial(c: C) : LabeledPolynomial = -// if(c.isZero()) LabeledPolynomial(emptyMap()) -// else LabeledPolynomial(mapOf(mapOf(this to 1U) to c)) -// -//context(LabeledPolynomialSpace) -//fun > Variable.asLabeledPolynomial(c: C) : LabeledPolynomial = -// if(c.isZero()) zero -// else LabeledPolynomial(mapOf(mapOf(this to 1U) to c)) +//context(LabeledPolynomialSpace>) +//public fun Variable.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1u) to constantOne)) + +public fun C.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to this)) // endregion diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt index 86c76949b..a1033fcc4 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -72,100 +72,10 @@ internal fun List.cleanUp() = subList(0, indexOfLast { it != 0U } + 1) // endregion // region Constructors and converters -// Waiting for context receivers :( TODO: Replace with context receivers when they will be available -//context(A) +//context(NumberedPolynomialSpace>) //@Suppress("FunctionName") -//internal fun > NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean): NumberedPolynomial { -// if (!toCheckInput) return NumberedPolynomial(coefs) -// -// val fixedCoefs = mutableMapOf, C>() -// -// for (entry in coefs) { -// val key = entry.key.cleanUp() -// val value = entry.value -// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value -// } -// -// return NumberedPolynomial( -// fixedCoefs -// .filter { it.value.isNotZero() } -// ) -//} -///** -// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received -// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. -// * -// * @param pairs Collection of pairs that represent monomials. -// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. -// * -// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. -// */ -//context(A) -//@Suppress("FunctionName") -//internal fun > NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean): NumberedPolynomial { -// if (!toCheckInput) return NumberedPolynomial(pairs.toMap()) -// -// val fixedCoefs = mutableMapOf, C>() -// -// for (entry in pairs) { -// val key = entry.first.cleanUp() -// val value = entry.second -// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value -// } -// -// return NumberedPolynomial( -// fixedCoefs -// .filter { it.value.isNotZero() } -// ) -//} -///** -// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received -// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. -// * -// * @param pairs Collection of pairs that represent monomials. -// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. -// * -// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. -// */ -//context(A) -//@Suppress("FunctionName") -//internal fun > NumberedPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean): NumberedPolynomial = -// NumberedPolynomial(pairs.toMap(), toCheckInput) -///** -// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received -// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. -// * -// * @param coefs Coefficients of the instants. -// * -// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. -// */ -//context(A) -//public fun > NumberedPolynomial(coefs: Map, C>) = NumberedPolynomial(coefs, toCheckInput = true) -///** -// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received -// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. -// * -// * @param pairs Collection of pairs that represent monomials. -// * -// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. -// */ -//context(A) -//public fun > NumberedPolynomial(pairs: Collection, C>>) = NumberedPolynomial(pairs, toCheckInput = true) -///** -// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received -// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. -// * -// * @param pairs Collection of pairs that represent monomials. -// * -// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. -// */ -//context(A) -//public fun > NumberedPolynomial(vararg pairs: Pair, C>) = NumberedPolynomial(*pairs, toCheckInput = true) -// -//context(NumberedPolynomialSpace) -//@Suppress("FunctionName") -//internal fun > NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean): NumberedPolynomial { +//internal fun NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean = false) : NumberedPolynomial { // if (!toCheckInput) return NumberedPolynomial(coefs) // // val fixedCoefs = mutableMapOf, C>() @@ -176,23 +86,14 @@ internal fun List.cleanUp() = subList(0, indexOfLast { it != 0U } + 1) // fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value // } // -// return NumberedPolynomial( -// fixedCoefs -// .filter { it.value.isNotZero() } +// return NumberedPolynomial( +// fixedCoefs.filterValues { it.isNotZero() } // ) //} -///** -// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received -// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. -// * -// * @param pairs Collection of pairs that represent monomials. -// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. -// * -// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. -// */ -//context(NumberedPolynomialSpace) +// +//context(NumberedPolynomialSpace>) //@Suppress("FunctionName") -//internal fun > NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean): NumberedPolynomial { +//internal fun NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = false) : NumberedPolynomial { // if (!toCheckInput) return NumberedPolynomial(pairs.toMap()) // // val fixedCoefs = mutableMapOf, C>() @@ -203,56 +104,25 @@ internal fun List.cleanUp() = subList(0, indexOfLast { it != 0U } + 1) // fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value // } // -// return NumberedPolynomial( -// fixedCoefs -// .filter { it.value.isNotZero() } +// return NumberedPolynomial( +// fixedCoefs.filterValues { it.isNotZero() } // ) //} -///** -// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received -// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. -// * -// * @param pairs Collection of pairs that represent monomials. -// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. -// * -// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. -// */ -//context(NumberedPolynomialSpace) +// +//// TODO: Do not know how to make it without context receivers +//context(NumberedPolynomialSpace>) //@Suppress("FunctionName") -//internal fun > NumberedPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean): NumberedPolynomial = -// NumberedPolynomial(pairs.toList(), toCheckInput) -///** -// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received -// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. -// * -// * @param coefs Coefficients of the instants. -// * -// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial(coefs: Map, C>) = NumberedPolynomial(coefs, toCheckInput = true) -///** -// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received -// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. -// * -// * @param pairs Collection of pairs that represent monomials. -// * -// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial(pairs: Collection, C>>) = NumberedPolynomial(pairs, toCheckInput = true) -///** -// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received -// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. -// * -// * @param pairs Collection of pairs that represent monomials. -// * -// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial(vararg pairs: Pair, C>) = NumberedPolynomial(*pairs, toCheckInput = true) +//public fun NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, toCheckInput = true) +// +//context(NumberedPolynomialSpace>) +//@Suppress("FunctionName") +//public fun NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, toCheckInput = true) +// +//context(NumberedPolynomialSpace>) +//@Suppress("FunctionName") +//public fun NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(pairs.toList(), toCheckInput = true) -public fun > C.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomial(mapOf(emptyList() to this)) +public fun C.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomial(mapOf(emptyList() to this)) // endregion @@ -314,7 +184,7 @@ public open class NumberedPolynomialSpace>( */ public override operator fun NumberedPolynomial.times(other: Int): NumberedPolynomial = if (other == 0) zero - else NumberedPolynomial( + else NumberedPolynomial( coefficients .applyAndRemoveZeros { mapValues { (_, c) -> c * other } @@ -707,4 +577,51 @@ public open class NumberedPolynomialSpace>( } } // endregion + + // region Constructors and converters + + @Suppress("FunctionName") + internal fun NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean = false) : NumberedPolynomial { + if (!toCheckInput) return NumberedPolynomial(coefs) + + val fixedCoefs = mutableMapOf, C>() + + for (entry in coefs) { + val key = entry.key.cleanUp() + val value = entry.value + fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value + } + + return NumberedPolynomial( + fixedCoefs.filterValues { it.isNotZero() } + ) + } + + @Suppress("FunctionName") + internal fun NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = false) : NumberedPolynomial { + if (!toCheckInput) return NumberedPolynomial(pairs.toMap()) + + val fixedCoefs = mutableMapOf, C>() + + for (entry in pairs) { + val key = entry.first.cleanUp() + val value = entry.second + fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value + } + + return NumberedPolynomial( + fixedCoefs.filterValues { it.isNotZero() } + ) + } + + @Suppress("FunctionName") + public fun NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, toCheckInput = true) + + @Suppress("FunctionName") + public fun NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, toCheckInput = true) + + @Suppress("FunctionName") + public fun NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(pairs.toList(), toCheckInput = true) + + // endregion } \ No newline at end of file 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 1ac413818..2f7976da6 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 @@ -14,7 +14,32 @@ import kotlin.math.min * * @param coefficients constant is the leftmost coefficient. */ -public data class Polynomial(public val coefficients: List) : AbstractPolynomial { +public data class Polynomial( + /** + * List that collects coefficients of the polynomial. Every monomial `a x^d` is represented as a coefficients + * `a` placed into the list with index `d`. For example coefficients of polynomial `5 x^2 - 6` can be represented as + * ``` + * listOf( + * -6, // -6 + + * 0, // 0 x + + * 5, // 5 x^2 + * ) + * ``` + * and also as + * ``` + * listOf( + * -6, // -6 + + * 0, // 0 x + + * 5, // 5 x^2 + * 0, // 0 x^3 + * 0, // 0 x^4 + * ) + * ``` + * It is recommended not to put extra zeros at end of the list (as for `0x^3` and `0x^4` in the example), but is not + * prohibited. + */ + public val coefficients: List +) : AbstractPolynomial { override fun toString(): String = "Polynomial$coefficients" } -- 2.34.1 From bb5e638b31186607bf953bff3bd2f5275f13e0c1 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Tue, 15 Mar 2022 20:38:27 +0300 Subject: [PATCH 022/123] Added polynomial spaces and scopes fabrics --- .../kmath/functions/labeledPolynomialUtil.kt | 189 +----------------- .../kmath/functions/numberedPolynomialUtil.kt | 189 +----------------- 2 files changed, 20 insertions(+), 358 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt index 9cf4f2652..5689f6e1b 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt @@ -54,7 +54,7 @@ import kotlin.contracts.* // else -> multiplyWithPowerInternalLogic(base, arg, pow) // } // -//// Trivial but slow as duck +//// Trivial but very slow //context(LabeledPolynomialSpace) //internal tailrec fun > multiplyWithPowerInternalLogic(base: LabeledPolynomial, arg: LabeledPolynomial, exponent: UInt): LabeledPolynomial = // when { @@ -71,7 +71,15 @@ import kotlin.contracts.* // region Utilities -// TODO: Docs +/** + * Crates a [LabeledPolynomialSpace] over received ring. + */ +public fun > A.labeledPolynomial(): LabeledPolynomialSpace = + LabeledPolynomialSpace(this) + +/** + * Crates a [LabeledPolynomialSpace]'s scope over received ring. + */ @OptIn(ExperimentalContracts::class) public inline fun , R> A.labeledPolynomial(block: LabeledPolynomialSpace.() -> R): R { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } @@ -254,64 +262,6 @@ public inline fun , R> A.labeledPolynomial(block: LabeledPolynomi //// region Field case // -//operator fun > Polynomial.div(other: Polynomial): Polynomial { -// if (other.isZero()) throw ArithmeticException("/ by zero") -// if (isZero()) return this -// -// fun Map, T>.leadingTerm() = -// this -// .asSequence() -// .map { Pair(it.key, it.value) } -// .reduce { (accDegs, accC), (listDegs, listC) -> -// for (i in 0..accDegs.lastIndex) { -// if (accDegs[i] > listDegs.getOrElse(i) { 0 }) return@reduce accDegs to accC -// if (accDegs[i] < listDegs.getOrElse(i) { 0 }) return@reduce listDegs to listC -// } -// if (accDegs.size < listDegs.size) listDegs to listC else accDegs to accC -// } -// -// var thisCoefficients = coefficients.toMutableMap() -// val otherCoefficients = other.coefficients -// val quotientCoefficients = HashMap, T>() -// -// var (thisLeadingTermDegs, thisLeadingTermC) = thisCoefficients.leadingTerm() -// val (otherLeadingTermDegs, otherLeadingTermC) = otherCoefficients.leadingTerm() -// -// while ( -// thisLeadingTermDegs.size >= otherLeadingTermDegs.size && -// (0..otherLeadingTermDegs.lastIndex).all { thisLeadingTermDegs[it] >= otherLeadingTermDegs[it] } -// ) { -// val multiplierDegs = -// thisLeadingTermDegs -// .mapIndexed { index, deg -> deg - otherLeadingTermDegs.getOrElse(index) { 0 } } -// .cleanUp() -// val multiplierC = thisLeadingTermC / otherLeadingTermC -// -// quotientCoefficients[multiplierDegs] = multiplierC -// -// for ((degs, t) in otherCoefficients) { -// val productDegs = -// (0..max(degs.lastIndex, multiplierDegs.lastIndex)) -// .map { degs.getOrElse(it) { 0 } + multiplierDegs.getOrElse(it) { 0 } } -// .cleanUp() -// val productC = t * multiplierC -// thisCoefficients[productDegs] = -// if (productDegs in thisCoefficients) thisCoefficients[productDegs]!! - productC else -productC -// } -// -// thisCoefficients = thisCoefficients.filterValues { it.isNotZero() }.toMutableMap() -// -// if (thisCoefficients.isEmpty()) -// return Polynomial(quotientCoefficients, toCheckInput = false) -// -// val t = thisCoefficients.leadingTerm() -// thisLeadingTermDegs = t.first -// thisLeadingTermC = t.second -// } -// -// return Polynomial(quotientCoefficients, toCheckInput = false) -//} -// //operator fun > Polynomial.div(other: T): Polynomial = // if (other.isZero()) throw ArithmeticException("/ by zero") // else @@ -321,125 +271,6 @@ public inline fun , R> A.labeledPolynomial(block: LabeledPolynomi // toCheckInput = false // ) // -//operator fun > Polynomial.rem(other: Polynomial): Polynomial { -// if (other.isZero()) throw ArithmeticException("/ by zero") -// if (isZero()) return this -// -// fun Map, T>.leadingTerm() = -// this -// .asSequence() -// .map { Pair(it.key, it.value) } -// .reduce { (accDegs, accC), (listDegs, listC) -> -// for (i in 0..accDegs.lastIndex) { -// if (accDegs[i] > listDegs.getOrElse(i) { 0 }) return@reduce accDegs to accC -// if (accDegs[i] < listDegs.getOrElse(i) { 0 }) return@reduce listDegs to listC -// } -// if (accDegs.size < listDegs.size) listDegs to listC else accDegs to accC -// } -// -// var thisCoefficients = coefficients.toMutableMap() -// val otherCoefficients = other.coefficients -// -// var (thisLeadingTermDegs, thisLeadingTermC) = thisCoefficients.leadingTerm() -// val (otherLeadingTermDegs, otherLeadingTermC) = otherCoefficients.leadingTerm() -// -// while ( -// thisLeadingTermDegs.size >= otherLeadingTermDegs.size && -// (0..otherLeadingTermDegs.lastIndex).all { thisLeadingTermDegs[it] >= otherLeadingTermDegs[it] } -// ) { -// val multiplierDegs = -// thisLeadingTermDegs -// .mapIndexed { index, deg -> deg - otherLeadingTermDegs.getOrElse(index) { 0 } } -// .cleanUp() -// val multiplierC = thisLeadingTermC / otherLeadingTermC -// -// for ((degs, t) in otherCoefficients) { -// val productDegs = -// (0..max(degs.lastIndex, multiplierDegs.lastIndex)) -// .map { degs.getOrElse(it) { 0 } + multiplierDegs.getOrElse(it) { 0 } } -// .cleanUp() -// val productC = t * multiplierC -// thisCoefficients[productDegs] = -// if (productDegs in thisCoefficients) thisCoefficients[productDegs]!! - productC else -productC -// } -// -// thisCoefficients = thisCoefficients.filterValues { it.isNotZero() }.toMutableMap() -// -// if (thisCoefficients.isEmpty()) -// return Polynomial(thisCoefficients, toCheckInput = false) -// -// val t = thisCoefficients.leadingTerm() -// thisLeadingTermDegs = t.first -// thisLeadingTermC = t.second -// } -// -// return Polynomial(thisCoefficients, toCheckInput = false) -//} -// -//infix fun > Polynomial.divrem(other: Polynomial): Polynomial.Companion.DividingResult { -// if (other.isZero()) throw ArithmeticException("/ by zero") -// if (isZero()) return Polynomial.Companion.DividingResult(this, this) -// -// fun Map, T>.leadingTerm() = -// this -// .asSequence() -// .map { Pair(it.key, it.value) } -// .reduce { (accDegs, accC), (listDegs, listC) -> -// for (i in 0..accDegs.lastIndex) { -// if (accDegs[i] > listDegs.getOrElse(i) { 0 }) return@reduce accDegs to accC -// if (accDegs[i] < listDegs.getOrElse(i) { 0 }) return@reduce listDegs to listC -// } -// if (accDegs.size < listDegs.size) listDegs to listC else accDegs to accC -// } -// -// var thisCoefficients = coefficients.toMutableMap() -// val otherCoefficients = other.coefficients -// val quotientCoefficients = HashMap, T>() -// -// var (thisLeadingTermDegs, thisLeadingTermC) = thisCoefficients.leadingTerm() -// val (otherLeadingTermDegs, otherLeadingTermC) = otherCoefficients.leadingTerm() -// -// while ( -// thisLeadingTermDegs.size >= otherLeadingTermDegs.size && -// (0..otherLeadingTermDegs.lastIndex).all { thisLeadingTermDegs[it] >= otherLeadingTermDegs[it] } -// ) { -// val multiplierDegs = -// thisLeadingTermDegs -// .mapIndexed { index, deg -> deg - otherLeadingTermDegs.getOrElse(index) { 0 } } -// .cleanUp() -// val multiplierC = thisLeadingTermC / otherLeadingTermC -// -// quotientCoefficients[multiplierDegs] = multiplierC -// -// for ((degs, t) in otherCoefficients) { -// val productDegs = -// (0..max(degs.lastIndex, multiplierDegs.lastIndex)) -// .map { degs.getOrElse(it) { 0 } + multiplierDegs.getOrElse(it) { 0 } } -// .cleanUp() -// val productC = t * multiplierC -// thisCoefficients[productDegs] = -// if (productDegs in thisCoefficients) thisCoefficients[productDegs]!! - productC else -productC -// } -// -// thisCoefficients = thisCoefficients.filterValues { it.isNotZero() }.toMutableMap() -// -// if (thisCoefficients.isEmpty()) -// return Polynomial.Companion.DividingResult( -// Polynomial(quotientCoefficients, toCheckInput = false), -// Polynomial(thisCoefficients, toCheckInput = false) -// ) -// -// val t = thisCoefficients.leadingTerm() -// thisLeadingTermDegs = t.first -// thisLeadingTermC = t.second -// } -// -// return Polynomial.Companion.DividingResult( -// Polynomial(quotientCoefficients, toCheckInput = false), -// Polynomial(thisCoefficients, toCheckInput = false) -// ) -//} -// //// endregion // endregion diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt index b7620e792..de95d0151 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt @@ -38,7 +38,7 @@ import kotlin.jvm.JvmName // else -> multiplyWithPowerInternalLogic(base, arg, pow) // } // -//// Trivial but slow as duck +//// Trivial but very slow //context(NumberedPolynomialSpace) //internal tailrec fun > multiplyWithPowerInternalLogic(base: NumberedPolynomial, arg: NumberedPolynomial, exponent: UInt): NumberedPolynomial = // when { @@ -55,7 +55,15 @@ import kotlin.jvm.JvmName // region Utilities -// TODO: Docs +/** + * Crates a [NumberedPolynomialSpace] over received ring. + */ +public fun > A.numberedPolynomial(): NumberedPolynomialSpace = + NumberedPolynomialSpace(this) + +/** + * Crates a [NumberedPolynomialSpace]'s scope over received ring. + */ @OptIn(ExperimentalContracts::class) public inline fun , R> A.numberedPolynomial(block: NumberedPolynomialSpace.() -> R): R { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } @@ -282,64 +290,6 @@ public inline fun , R> A.numberedPolynomial(block: NumberedPolyno //// region Field case // -//operator fun > Polynomial.div(other: Polynomial): Polynomial { -// if (other.isZero()) throw ArithmeticException("/ by zero") -// if (isZero()) return this -// -// fun Map, T>.leadingTerm() = -// this -// .asSequence() -// .map { Pair(it.key, it.value) } -// .reduce { (accDegs, accC), (listDegs, listC) -> -// for (i in 0..accDegs.lastIndex) { -// if (accDegs[i] > listDegs.getOrElse(i) { 0 }) return@reduce accDegs to accC -// if (accDegs[i] < listDegs.getOrElse(i) { 0 }) return@reduce listDegs to listC -// } -// if (accDegs.size < listDegs.size) listDegs to listC else accDegs to accC -// } -// -// var thisCoefficients = coefficients.toMutableMap() -// val otherCoefficients = other.coefficients -// val quotientCoefficients = HashMap, T>() -// -// var (thisLeadingTermDegs, thisLeadingTermC) = thisCoefficients.leadingTerm() -// val (otherLeadingTermDegs, otherLeadingTermC) = otherCoefficients.leadingTerm() -// -// while ( -// thisLeadingTermDegs.size >= otherLeadingTermDegs.size && -// (0..otherLeadingTermDegs.lastIndex).all { thisLeadingTermDegs[it] >= otherLeadingTermDegs[it] } -// ) { -// val multiplierDegs = -// thisLeadingTermDegs -// .mapIndexed { index, deg -> deg - otherLeadingTermDegs.getOrElse(index) { 0 } } -// .cleanUp() -// val multiplierC = thisLeadingTermC / otherLeadingTermC -// -// quotientCoefficients[multiplierDegs] = multiplierC -// -// for ((degs, t) in otherCoefficients) { -// val productDegs = -// (0..max(degs.lastIndex, multiplierDegs.lastIndex)) -// .map { degs.getOrElse(it) { 0 } + multiplierDegs.getOrElse(it) { 0 } } -// .cleanUp() -// val productC = t * multiplierC -// thisCoefficients[productDegs] = -// if (productDegs in thisCoefficients) thisCoefficients[productDegs]!! - productC else -productC -// } -// -// thisCoefficients = thisCoefficients.filterValues { it.isNotZero() }.toMutableMap() -// -// if (thisCoefficients.isEmpty()) -// return Polynomial(quotientCoefficients, toCheckInput = false) -// -// val t = thisCoefficients.leadingTerm() -// thisLeadingTermDegs = t.first -// thisLeadingTermC = t.second -// } -// -// return Polynomial(quotientCoefficients, toCheckInput = false) -//} -// //operator fun > Polynomial.div(other: T): Polynomial = // if (other.isZero()) throw ArithmeticException("/ by zero") // else @@ -349,125 +299,6 @@ public inline fun , R> A.numberedPolynomial(block: NumberedPolyno // toCheckInput = false // ) // -//operator fun > Polynomial.rem(other: Polynomial): Polynomial { -// if (other.isZero()) throw ArithmeticException("/ by zero") -// if (isZero()) return this -// -// fun Map, T>.leadingTerm() = -// this -// .asSequence() -// .map { Pair(it.key, it.value) } -// .reduce { (accDegs, accC), (listDegs, listC) -> -// for (i in 0..accDegs.lastIndex) { -// if (accDegs[i] > listDegs.getOrElse(i) { 0 }) return@reduce accDegs to accC -// if (accDegs[i] < listDegs.getOrElse(i) { 0 }) return@reduce listDegs to listC -// } -// if (accDegs.size < listDegs.size) listDegs to listC else accDegs to accC -// } -// -// var thisCoefficients = coefficients.toMutableMap() -// val otherCoefficients = other.coefficients -// -// var (thisLeadingTermDegs, thisLeadingTermC) = thisCoefficients.leadingTerm() -// val (otherLeadingTermDegs, otherLeadingTermC) = otherCoefficients.leadingTerm() -// -// while ( -// thisLeadingTermDegs.size >= otherLeadingTermDegs.size && -// (0..otherLeadingTermDegs.lastIndex).all { thisLeadingTermDegs[it] >= otherLeadingTermDegs[it] } -// ) { -// val multiplierDegs = -// thisLeadingTermDegs -// .mapIndexed { index, deg -> deg - otherLeadingTermDegs.getOrElse(index) { 0 } } -// .cleanUp() -// val multiplierC = thisLeadingTermC / otherLeadingTermC -// -// for ((degs, t) in otherCoefficients) { -// val productDegs = -// (0..max(degs.lastIndex, multiplierDegs.lastIndex)) -// .map { degs.getOrElse(it) { 0 } + multiplierDegs.getOrElse(it) { 0 } } -// .cleanUp() -// val productC = t * multiplierC -// thisCoefficients[productDegs] = -// if (productDegs in thisCoefficients) thisCoefficients[productDegs]!! - productC else -productC -// } -// -// thisCoefficients = thisCoefficients.filterValues { it.isNotZero() }.toMutableMap() -// -// if (thisCoefficients.isEmpty()) -// return Polynomial(thisCoefficients, toCheckInput = false) -// -// val t = thisCoefficients.leadingTerm() -// thisLeadingTermDegs = t.first -// thisLeadingTermC = t.second -// } -// -// return Polynomial(thisCoefficients, toCheckInput = false) -//} -// -//infix fun > Polynomial.divrem(other: Polynomial): Polynomial.Companion.DividingResult { -// if (other.isZero()) throw ArithmeticException("/ by zero") -// if (isZero()) return Polynomial.Companion.DividingResult(this, this) -// -// fun Map, T>.leadingTerm() = -// this -// .asSequence() -// .map { Pair(it.key, it.value) } -// .reduce { (accDegs, accC), (listDegs, listC) -> -// for (i in 0..accDegs.lastIndex) { -// if (accDegs[i] > listDegs.getOrElse(i) { 0 }) return@reduce accDegs to accC -// if (accDegs[i] < listDegs.getOrElse(i) { 0 }) return@reduce listDegs to listC -// } -// if (accDegs.size < listDegs.size) listDegs to listC else accDegs to accC -// } -// -// var thisCoefficients = coefficients.toMutableMap() -// val otherCoefficients = other.coefficients -// val quotientCoefficients = HashMap, T>() -// -// var (thisLeadingTermDegs, thisLeadingTermC) = thisCoefficients.leadingTerm() -// val (otherLeadingTermDegs, otherLeadingTermC) = otherCoefficients.leadingTerm() -// -// while ( -// thisLeadingTermDegs.size >= otherLeadingTermDegs.size && -// (0..otherLeadingTermDegs.lastIndex).all { thisLeadingTermDegs[it] >= otherLeadingTermDegs[it] } -// ) { -// val multiplierDegs = -// thisLeadingTermDegs -// .mapIndexed { index, deg -> deg - otherLeadingTermDegs.getOrElse(index) { 0 } } -// .cleanUp() -// val multiplierC = thisLeadingTermC / otherLeadingTermC -// -// quotientCoefficients[multiplierDegs] = multiplierC -// -// for ((degs, t) in otherCoefficients) { -// val productDegs = -// (0..max(degs.lastIndex, multiplierDegs.lastIndex)) -// .map { degs.getOrElse(it) { 0 } + multiplierDegs.getOrElse(it) { 0 } } -// .cleanUp() -// val productC = t * multiplierC -// thisCoefficients[productDegs] = -// if (productDegs in thisCoefficients) thisCoefficients[productDegs]!! - productC else -productC -// } -// -// thisCoefficients = thisCoefficients.filterValues { it.isNotZero() }.toMutableMap() -// -// if (thisCoefficients.isEmpty()) -// return Polynomial.Companion.DividingResult( -// Polynomial(quotientCoefficients, toCheckInput = false), -// Polynomial(thisCoefficients, toCheckInput = false) -// ) -// -// val t = thisCoefficients.leadingTerm() -// thisLeadingTermDegs = t.first -// thisLeadingTermC = t.second -// } -// -// return Polynomial.Companion.DividingResult( -// Polynomial(quotientCoefficients, toCheckInput = false), -// Polynomial(thisCoefficients, toCheckInput = false) -// ) -//} -// //// endregion // endregion -- 2.34.1 From 16cf1bc65e6cd1a2955c9ca3bf5e4200eae71c71 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Wed, 16 Mar 2022 00:47:07 +0300 Subject: [PATCH 023/123] Implemented all derivative-like functions --- .../kmath/functions/labeledPolynomialUtil.kt | 253 ++++++++++++++++- .../kmath/functions/numberedPolynomialUtil.kt | 255 +++++++++++------- .../kmath/functions/polynomialUtil.kt | 2 +- 3 files changed, 407 insertions(+), 103 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt index 5689f6e1b..544cca410 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt @@ -5,8 +5,10 @@ package space.kscience.kmath.functions +import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.* import kotlin.contracts.* +import kotlin.math.max // TODO: Docs @@ -321,6 +323,251 @@ public inline fun , R> A.labeledPolynomial(block: LabeledPolynomi // //// endregion -//// region Algebraic derivative and antiderivative -//// TODO -//// endregion \ No newline at end of file +// region Algebraic derivative and antiderivative + +/** + * Returns algebraic derivative of received polynomial. + */ +@UnstableKMathAPI +public fun > LabeledPolynomial.derivativeWithRespectTo( + algebra: A, + variable: Variable, +): LabeledPolynomial = algebra { + LabeledPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + if (variable !in degs) return@forEach + put( + buildMap { + degs.forEach { (vari, deg) -> + when { + vari != variable -> put(vari, deg) + deg > 1u -> put(vari, deg - 1u) + } + } + }, + optimizedMultiply(c, degs[variable]!!) + ) + } + } + ) +} + +/** + * Returns algebraic derivative of received polynomial. + */ +@UnstableKMathAPI +public fun > LabeledPolynomial.derivativeWithRespectTo( + algebra: A, + variables: Collection, +): LabeledPolynomial = algebra { + val cleanedVariables = variables.toSet() + if (cleanedVariables.isEmpty()) return this@derivativeWithRespectTo + LabeledPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + if (!degs.keys.containsAll(cleanedVariables)) return@forEach + put( + buildMap { + degs.forEach { (vari, deg) -> + when { + vari !in cleanedVariables -> put(vari, deg) + deg > 1u -> put(vari, deg - 1u) + } + } + }, + cleanedVariables.fold(c) { acc, variable -> optimizedMultiply(acc, degs[variable]!!) } + ) + } + } + ) +} + +/** + * Returns algebraic derivative of received polynomial. + */ +@UnstableKMathAPI +public fun > LabeledPolynomial.nthDerivativeWithRespectTo( + algebra: A, + variable: Variable, + order: UInt +): LabeledPolynomial = algebra { + if (order == 0u) return this@nthDerivativeWithRespectTo + LabeledPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + if (degs.getOrElse(variable) { 0u } < order) return@forEach + put( + buildMap { + degs.forEach { (vari, deg) -> + when { + vari != variable -> put(vari, deg) + deg > order -> put(vari, deg - order) + } + } + }, + degs[variable]!!.let { deg -> + (deg downTo deg - order + 1u) + .fold(c) { acc, ord -> optimizedMultiply(acc, ord) } + } + ) + } + } + ) +} + +/** + * Returns algebraic derivative of received polynomial. + */ +@UnstableKMathAPI +public fun > LabeledPolynomial.nthDerivativeWithRespectTo( + algebra: A, + variablesAndOrders: Map, +): LabeledPolynomial = algebra { + val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u } + if (filteredVariablesAndOrders.isEmpty()) return this@nthDerivativeWithRespectTo + LabeledPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + if (filteredVariablesAndOrders.any { (variable, order) -> degs.getOrElse(variable) { 0u } < order }) return@forEach + put( + buildMap { + degs.forEach { (vari, deg) -> + if (vari !in filteredVariablesAndOrders) put(vari, deg) + else { + val order = filteredVariablesAndOrders[vari]!! + if (deg > order) put(vari, deg - order) + } + } + }, + filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> + degs[index]!!.let { deg -> + (deg downTo deg - order + 1u) + .fold(acc1) { acc2, ord -> optimizedMultiply(acc2, ord) } + } + } + ) + } + } + ) +} + +/** + * Returns algebraic antiderivative of received polynomial. + */ +@UnstableKMathAPI +public fun > LabeledPolynomial.antiderivativeWithRespectTo( + algebra: A, + variable: Variable, +): LabeledPolynomial = algebra { + LabeledPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + val newDegs = buildMap(degs.size + 1) { + put(variable, 1u) + for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) + } + put( + newDegs, + c / optimizedMultiply(one, newDegs[variable]!!) + ) + } + } + ) +} + +/** + * Returns algebraic antiderivative of received polynomial. + */ +@UnstableKMathAPI +public fun > LabeledPolynomial.antiderivativeWithRespectTo( + algebra: A, + variables: Collection, +): LabeledPolynomial = algebra { + val cleanedVariables = variables.toSet() + if (cleanedVariables.isEmpty()) return this@antiderivativeWithRespectTo + LabeledPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + val newDegs = buildMap(degs.size + 1) { + for (variable in cleanedVariables) put(variable, 1u) + for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) + } + put( + newDegs, + cleanedVariables.fold(c) { acc, variable -> acc / optimizedMultiply(one, newDegs[variable]!!) } + ) + } + } + ) +} + +/** + * Returns algebraic derivative of received polynomial. + */ +@UnstableKMathAPI +public fun > LabeledPolynomial.nthAntiderivativeWithRespectTo( + algebra: A, + variable: Variable, + order: UInt +): LabeledPolynomial = algebra { + if (order == 0u) return this@nthAntiderivativeWithRespectTo + LabeledPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + val newDegs = buildMap(degs.size + 1) { + put(variable, order) + for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) + } + put( + newDegs, + newDegs[variable]!!.let { deg -> + (deg downTo deg - order + 1u) + .fold(c) { acc, ord -> acc / optimizedMultiply(one, ord) } + } + ) + } + } + ) +} + +/** + * Returns algebraic derivative of received polynomial. + */ +@UnstableKMathAPI +public fun > LabeledPolynomial.nthAntiderivativeWithRespectTo( + algebra: A, + variablesAndOrders: Map, +): LabeledPolynomial = algebra { + val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u } + if (filteredVariablesAndOrders.isEmpty()) return this@nthAntiderivativeWithRespectTo + LabeledPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + val newDegs = buildMap(degs.size + 1) { + for ((variable, order) in filteredVariablesAndOrders) put(variable, order) + for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) + } + put( + newDegs, + filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> + newDegs[index]!!.let { deg -> + (deg downTo deg - order + 1u) + .fold(acc1) { acc2, ord -> acc2 / optimizedMultiply(one, ord) } + } + } + ) + } + } + ) +} + +// endregion \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt index de95d0151..47644b26a 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt @@ -4,7 +4,7 @@ import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.* import kotlin.contracts.* import kotlin.jvm.JvmName - +import kotlin.math.max // TODO: Docs @@ -382,70 +382,51 @@ public fun > NumberedPolynomial.derivativeWithRespectTo( ): NumberedPolynomial = algebra { NumberedPolynomial( buildMap(coefficients.size) { - coefficients.forEach { (degs, c) -> - put( - degs.mapIndexed { index, deg -> - when { - index != variable -> deg - deg > 0u -> deg - 1u - else -> return@forEach - } - }, - optimizedMultiply(c, degs.getOrElse(variable) { 1u }.toInt()) - ) - } + coefficients + .forEach { (degs, c) -> + if (degs.size > variable) return@forEach + put( + degs.mapIndexed { index, deg -> + when { + index != variable -> deg + deg > 0u -> deg - 1u + else -> return@forEach + } + }.cleanUp(), + optimizedMultiply(c, degs[variable]) + ) + } } ) } /** * Returns algebraic derivative of received polynomial. - */ // TODO: This one does not work!!! -@UnstableKMathAPI -public fun > NumberedPolynomial.derivativeWithRespectTo( - algebra: A, - variables: IntArray, -): NumberedPolynomial = algebra { - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients.forEach { (degs, c) -> - put( - degs.mapIndexed { index, deg -> - when { - index !in variables -> deg - deg > 0u -> deg - 1u - else -> return@forEach - } - }, - optimizedMultiply(c, variables.fold(1u) { acc, variable -> acc * degs.getOrElse(variable) { 1u } }.toInt()) - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ // TODO: This one does not work!!! + */ @UnstableKMathAPI public fun > NumberedPolynomial.derivativeWithRespectTo( algebra: A, variables: Collection, ): NumberedPolynomial = algebra { + val cleanedVariables = variables.toSet() + if (cleanedVariables.isEmpty()) return this@derivativeWithRespectTo + val maxRespectedVariable = cleanedVariables.maxOrNull()!! NumberedPolynomial( buildMap(coefficients.size) { - coefficients.forEach { (degs, c) -> - put( - degs.mapIndexed { index, deg -> - when { - index !in variables -> deg - deg > 0u -> deg - 1u - else -> return@forEach - } - }, - optimizedMultiply(c, variables.fold(1u) { acc, variable -> acc * degs.getOrElse(variable) { 1u } }.toInt()) - ) - } + coefficients + .forEach { (degs, c) -> + if (degs.size > maxRespectedVariable) return@forEach + put( + degs.mapIndexed { index, deg -> + when { + index !in cleanedVariables -> deg + deg > 0u -> deg - 1u + else -> return@forEach + } + }.cleanUp(), + cleanedVariables.fold(c) { acc, variable -> optimizedMultiply(acc, degs[variable]) } + ) + } } ) } @@ -459,24 +440,60 @@ public fun > NumberedPolynomial.nthDerivativeWithRespectTo( variable: Int, order: UInt ): NumberedPolynomial = algebra { + if (order == 0u) return this@nthDerivativeWithRespectTo NumberedPolynomial( buildMap(coefficients.size) { - coefficients.forEach { (degs, c) -> - put( - degs.mapIndexed { index, deg -> - when { - index != variable -> deg - deg >= order -> deg - order - else -> return@forEach + coefficients + .forEach { (degs, c) -> + if (degs.size > variable) return@forEach + put( + degs.mapIndexed { index, deg -> + when { + index != variable -> deg + deg >= order -> deg - order + else -> return@forEach + } + }.cleanUp(), + degs[variable].let { deg -> + (deg downTo deg - order + 1u) + .fold(c) { acc, ord -> optimizedMultiply(acc, ord) } } - }, - degs.getOrElse(variable) { 1u }.toInt().let { - (0u until order).fold(c) { acc, ord -> - optimizedMultiply(acc, ord.toInt()) + ) + } + } + ) +} + +/** + * Returns algebraic derivative of received polynomial. + */ +@UnstableKMathAPI +public fun > NumberedPolynomial.nthDerivativeWithRespectTo( + algebra: A, + variablesAndOrders: Map, +): NumberedPolynomial = algebra { + val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u } + if (filteredVariablesAndOrders.isEmpty()) return this@nthDerivativeWithRespectTo + val maxRespectedVariable = filteredVariablesAndOrders.keys.maxOrNull()!! + NumberedPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + if (degs.size > maxRespectedVariable) return@forEach + put( + degs.mapIndexed { index, deg -> + if (index !in filteredVariablesAndOrders) return@mapIndexed deg + val order = filteredVariablesAndOrders[index]!! + if (deg >= order) deg - order else return@forEach + }.cleanUp(), + filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> + degs[index].let { deg -> + (deg downTo deg - order + 1u) + .fold(acc1) { acc2, ord -> optimizedMultiply(acc2, ord) } + } } - } - ) - } + ) + } } ) } @@ -491,52 +508,92 @@ public fun > NumberedPolynomial.antiderivativeWithRespectTo( ): NumberedPolynomial = algebra { NumberedPolynomial( buildMap(coefficients.size) { - coefficients.forEach { (degs, c) -> - put( - degs.mapIndexed { index, deg -> if(index != variable) deg else deg + 1u }, - c / optimizedMultiply(one, degs.getOrElse(variable) { 1u }.toInt()) - ) - } + coefficients + .forEach { (degs, c) -> + put( + List(max(variable + 1, degs.size)) { if (it != variable) degs[it] else degs[it] + 1u }, + c / optimizedMultiply(one, degs[variable]) + ) + } } ) } /** * Returns algebraic antiderivative of received polynomial. - */ // TODO: This one does not work!!! -@UnstableKMathAPI -public fun > NumberedPolynomial.antiderivativeWithRespectTo( - algebra: A, - variables: IntArray, -): NumberedPolynomial = algebra { - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients.forEach { (degs, c) -> - put( - degs.mapIndexed { index, deg -> if(index !in variables) deg else deg + 1u }, - c / optimizedMultiply(one, variables.fold(1u) { acc, variable -> acc * degs.getOrElse(variable) { 1u } }.toInt()) - ) - } - } - ) -} - -/** - * Returns algebraic antiderivative of received polynomial. - */ // TODO: This one does not work!!! + */ @UnstableKMathAPI public fun > NumberedPolynomial.antiderivativeWithRespectTo( algebra: A, variables: Collection, ): NumberedPolynomial = algebra { + val cleanedVariables = variables.toSet() + if (cleanedVariables.isEmpty()) return this@antiderivativeWithRespectTo + val maxRespectedVariable = cleanedVariables.maxOrNull()!! NumberedPolynomial( buildMap(coefficients.size) { - coefficients.forEach { (degs, c) -> - put( - degs.mapIndexed { index, deg -> if(index !in variables) deg else deg + 1u }, - c / optimizedMultiply(one, variables.fold(1u) { acc, variable -> acc * degs.getOrElse(variable) { 1u } }.toInt()) - ) - } + coefficients + .forEach { (degs, c) -> + put( + List(max(maxRespectedVariable + 1, degs.size)) { if (it !in variables) degs[it] else degs[it] + 1u }, + cleanedVariables.fold(c) { acc, variable -> acc / optimizedMultiply(one, degs[variable]) } + ) + } + } + ) +} + +/** + * Returns algebraic derivative of received polynomial. + */ +@UnstableKMathAPI +public fun > NumberedPolynomial.nthAntiderivativeWithRespectTo( + algebra: A, + variable: Int, + order: UInt +): NumberedPolynomial = algebra { + if (order == 0u) return this@nthAntiderivativeWithRespectTo + NumberedPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + put( + List(max(variable + 1, degs.size)) { if (it != variable) degs[it] else degs[it] + order }, + degs[variable].let { deg -> + (deg downTo deg - order + 1u) + .fold(c) { acc, ord -> acc / optimizedMultiply(one, ord) } + } + ) + } + } + ) +} + +/** + * Returns algebraic derivative of received polynomial. + */ +@UnstableKMathAPI +public fun > NumberedPolynomial.nthAntiderivativeWithRespectTo( + algebra: A, + variablesAndOrders: Map, +): NumberedPolynomial = algebra { + val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u } + if (filteredVariablesAndOrders.isEmpty()) return this@nthAntiderivativeWithRespectTo + val maxRespectedVariable = filteredVariablesAndOrders.keys.maxOrNull()!! + NumberedPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + put( + List(max(maxRespectedVariable + 1, degs.size)) { degs[it] + filteredVariablesAndOrders.getOrElse(it) { 0u } }, + filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> + degs[index].let { deg -> + (deg downTo deg - order + 1u) + .fold(acc1) { acc2, ord -> acc2 / optimizedMultiply(one, ord) } + } + } + ) + } } ) } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt index a41a6cbd6..9c8cc0090 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt @@ -138,7 +138,7 @@ public fun Polynomial.nthDerivative( algebra: A, order: UInt, ): Polynomial where A : Ring, A : NumericAlgebra = algebra { - Polynomial(coefficients.drop(order.toInt()).mapIndexed { index, c -> (1..order.toInt()).fold(c) { acc, i -> acc * number(index + i) } }) + Polynomial(coefficients.drop(order.toInt()).mapIndexed { index, c -> (index + 1..index + order.toInt()).fold(c) { acc, i -> acc * number(i) } }) } /** -- 2.34.1 From 9aa131a9c6c69145761bc63fdae436da01916634 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Wed, 16 Mar 2022 01:06:39 +0300 Subject: [PATCH 024/123] Replaced `Variable` in `Labeled...` by `Symbol` and deleted it --- .../kmath/functions/LabeledPolynomial.kt | 145 +++++++++--------- .../functions/LabeledRationalFunction.kt | 37 ++--- .../kscience/kmath/functions/Variable.kt | 38 ----- .../kmath/functions/labeledPolynomialUtil.kt | 64 ++++---- 4 files changed, 126 insertions(+), 158 deletions(-) delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Variable.kt diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt index 56dad975d..4106371cc 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt @@ -5,6 +5,7 @@ package space.kscience.kmath.functions +import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.operations.* import kotlin.contracts.InvocationKind import kotlin.contracts.contract @@ -40,9 +41,9 @@ internal constructor( * ) to (-6) * ) * ``` - * where `a`, `b` and `c` are corresponding [Variable] objects. + * where `a`, `b` and `c` are corresponding [Symbol] objects. */ - public val coefficients: Map, C> + public val coefficients: Map, C> ) : AbstractPolynomial { override fun toString(): String = "LabeledPolynomial$coefficients" } @@ -67,7 +68,7 @@ internal fun labeledPolynomialError(message: Any): Nothing = throw LabeledPolyno /** * Returns the same degrees description of the monomial, but without zero degrees. */ -internal fun Map.cleanUp() = filterValues { it > 0U } +internal fun Map.cleanUp() = filterValues { it > 0U } // endregion @@ -75,10 +76,10 @@ internal fun Map.cleanUp() = filterValues { it > 0U } //context(LabeledPolynomialSpace>) //@Suppress("FunctionName") -//internal fun LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = false) : LabeledPolynomial { +//internal fun LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = false) : LabeledPolynomial { // if (!toCheckInput) return LabeledPolynomial(coefs) // -// val fixedCoefs = mutableMapOf, C>() +// val fixedCoefs = mutableMapOf, C>() // // for (entry in coefs) { // val key = entry.key.cleanUp() @@ -93,10 +94,10 @@ internal fun Map.cleanUp() = filterValues { it > 0U } // //context(LabeledPolynomialSpace>) //@Suppress("FunctionName") -//internal fun LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = false) : LabeledPolynomial { +//internal fun LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = false) : LabeledPolynomial { // if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) // -// val fixedCoefs = mutableMapOf, C>() +// val fixedCoefs = mutableMapOf, C>() // // for (entry in pairs) { // val key = entry.first.cleanUp() @@ -112,20 +113,20 @@ internal fun Map.cleanUp() = filterValues { it > 0U } //// TODO: Do not know how to make it without context receivers //context(LabeledPolynomialSpace>) //@Suppress("FunctionName") -//public fun LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) +//public fun LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) // //context(LabeledPolynomialSpace>) //@Suppress("FunctionName") -//public fun LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) +//public fun LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) // //context(LabeledPolynomialSpace>) //@Suppress("FunctionName") -//public fun LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(pairs.toList(), toCheckInput = true) +//public fun LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(pairs.toList(), toCheckInput = true) // //context(LabeledPolynomialSpace>) -//public fun Variable.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1u) to constantOne)) +//public fun Symbol.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1u) to constantOne)) -public fun C.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to this)) +public fun C.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to this)) // endregion @@ -140,24 +141,24 @@ public class LabeledPolynomialSpace>( public override val ring: A, ) : AbstractPolynomialSpaceOverRing, A> { - // region Variable-integer relation - public operator fun Variable.plus(other: Int): LabeledPolynomial = + // region Symbol-integer relation + public operator fun Symbol.plus(other: Int): LabeledPolynomial = if (other == 0) LabeledPolynomial(mapOf( mapOf(this@plus to 1U) to constantOne, )) else LabeledPolynomial(mapOf( mapOf(this@plus to 1U) to constantOne, - emptyMap() to constantOne * other, + emptyMap() to constantOne * other, )) - public operator fun Variable.minus(other: Int): LabeledPolynomial = + public operator fun Symbol.minus(other: Int): LabeledPolynomial = if (other == 0) LabeledPolynomial(mapOf( mapOf(this@minus to 1U) to -constantOne, )) else LabeledPolynomial(mapOf( mapOf(this@minus to 1U) to -constantOne, - emptyMap() to constantOne * other, + emptyMap() to constantOne * other, )) - public operator fun Variable.times(other: Int): LabeledPolynomial = + public operator fun Symbol.times(other: Int): LabeledPolynomial = if (other == 0) zero else LabeledPolynomial(mapOf( mapOf(this to 1U) to constantOne * other, @@ -165,23 +166,23 @@ public class LabeledPolynomialSpace>( // endregion // region Integer-variable relation - public operator fun Int.plus(other: Variable): LabeledPolynomial = + public operator fun Int.plus(other: Symbol): LabeledPolynomial = if (this == 0) LabeledPolynomial(mapOf( mapOf(other to 1U) to constantOne, )) else LabeledPolynomial(mapOf( mapOf(other to 1U) to constantOne, - emptyMap() to constantOne * this@plus, + emptyMap() to constantOne * this@plus, )) - public operator fun Int.minus(other: Variable): LabeledPolynomial = + public operator fun Int.minus(other: Symbol): LabeledPolynomial = if (this == 0) LabeledPolynomial(mapOf( mapOf(other to 1U) to -constantOne, )) else LabeledPolynomial(mapOf( mapOf(other to 1U) to -constantOne, - emptyMap() to constantOne * this@minus, + emptyMap() to constantOne * this@minus, )) - public operator fun Int.times(other: Variable): LabeledPolynomial = + public operator fun Int.times(other: Symbol): LabeledPolynomial = if (this == 0) zero else LabeledPolynomial(mapOf( mapOf(other to 1U) to constantOne * this@times, @@ -201,7 +202,7 @@ public class LabeledPolynomialSpace>( coefficients .toMutableMap() .apply { - val degs = emptyMap() + val degs = emptyMap() val result = getOrElse(degs) { constantZero } + other @@ -221,7 +222,7 @@ public class LabeledPolynomialSpace>( coefficients .toMutableMap() .apply { - val degs = emptyMap() + val degs = emptyMap() val result = getOrElse(degs) { constantZero } - other @@ -257,7 +258,7 @@ public class LabeledPolynomialSpace>( other.coefficients .toMutableMap() .apply { - val degs = emptyMap() + val degs = emptyMap() val result = this@plus + getOrElse(degs) { constantZero } @@ -277,7 +278,7 @@ public class LabeledPolynomialSpace>( other.coefficients .toMutableMap() .apply { - val degs = emptyMap() + val degs = emptyMap() val result = this@minus - getOrElse(degs) { constantZero } @@ -301,47 +302,47 @@ public class LabeledPolynomialSpace>( // endregion // region Constant-variable relation - public operator fun C.plus(other: Variable): LabeledPolynomial = + public operator fun C.plus(other: Symbol): LabeledPolynomial = if (isZero()) LabeledPolynomial(mapOf( mapOf(other to 1U) to constantOne, )) else LabeledPolynomial(mapOf( mapOf(other to 1U) to constantOne, - emptyMap() to this@plus, + emptyMap() to this@plus, )) - public operator fun C.minus(other: Variable): LabeledPolynomial = + public operator fun C.minus(other: Symbol): LabeledPolynomial = if (isZero()) LabeledPolynomial(mapOf( mapOf(other to 1U) to -constantOne, )) else LabeledPolynomial(mapOf( mapOf(other to 1U) to -constantOne, - emptyMap() to this@minus, + emptyMap() to this@minus, )) - public operator fun C.times(other: Variable): LabeledPolynomial = + public operator fun C.times(other: Symbol): LabeledPolynomial = if (isZero()) zero else LabeledPolynomial(mapOf( mapOf(other to 1U) to this@times, )) // endregion - // region Variable-constant relation - public operator fun Variable.plus(other: C): LabeledPolynomial = + // region Symbol-constant relation + public operator fun Symbol.plus(other: C): LabeledPolynomial = if (other.isZero()) LabeledPolynomial(mapOf( mapOf(this@plus to 1U) to constantOne, )) else LabeledPolynomial(mapOf( mapOf(this@plus to 1U) to constantOne, - emptyMap() to other, + emptyMap() to other, )) - public operator fun Variable.minus(other: C): LabeledPolynomial = + public operator fun Symbol.minus(other: C): LabeledPolynomial = if (other.isZero()) LabeledPolynomial(mapOf( mapOf(this@minus to 1U) to -constantOne, )) else LabeledPolynomial(mapOf( mapOf(this@minus to 1U) to -constantOne, - emptyMap() to other, + emptyMap() to other, )) - public operator fun Variable.times(other: C): LabeledPolynomial = + public operator fun Symbol.times(other: C): LabeledPolynomial = if (other.isZero()) zero else LabeledPolynomial(mapOf( mapOf(this@times to 1U) to other, @@ -355,11 +356,11 @@ public class LabeledPolynomialSpace>( override operator fun C.plus(other: LabeledPolynomial): LabeledPolynomial = if (this.isZero()) other else with(other.coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to this@plus)) + if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to this@plus)) else LabeledPolynomial( toMutableMap() .apply { - val degs = emptyMap() + val degs = emptyMap() val result = this@plus + getOrElse(degs) { constantZero } @@ -374,13 +375,13 @@ public class LabeledPolynomialSpace>( override operator fun C.minus(other: LabeledPolynomial): LabeledPolynomial = if (this.isZero()) other else with(other.coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to this@minus)) + if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to this@minus)) else LabeledPolynomial( toMutableMap() .apply { forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } - val degs = emptyMap() + val degs = emptyMap() val result = this@minus - getOrElse(degs) { constantZero } @@ -409,11 +410,11 @@ public class LabeledPolynomialSpace>( override operator fun LabeledPolynomial.plus(other: C): LabeledPolynomial = if (other.isZero()) this else with(coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to other)) + if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to other)) else LabeledPolynomial( toMutableMap() .apply { - val degs = emptyMap() + val degs = emptyMap() val result = getOrElse(degs) { constantZero } + other @@ -428,13 +429,13 @@ public class LabeledPolynomialSpace>( override operator fun LabeledPolynomial.minus(other: C): LabeledPolynomial = if (other.isZero()) this else with(coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to other)) + if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to other)) else LabeledPolynomial( toMutableMap() .apply { forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } - val degs = emptyMap() + val degs = emptyMap() val result = getOrElse(degs) { constantZero } - other @@ -456,8 +457,8 @@ public class LabeledPolynomialSpace>( ) // endregion - // region Variable-variable relation - public operator fun Variable.plus(other: Variable): LabeledPolynomial = + // region Symbol-variable relation + public operator fun Symbol.plus(other: Symbol): LabeledPolynomial = if (this == other) LabeledPolynomial(mapOf( mapOf(this to 1U) to constantOne * 2 )) @@ -465,13 +466,13 @@ public class LabeledPolynomialSpace>( mapOf(this to 1U) to constantOne, mapOf(other to 1U) to constantOne, )) - public operator fun Variable.minus(other: Variable): LabeledPolynomial = + public operator fun Symbol.minus(other: Symbol): LabeledPolynomial = if (this == other) zero else LabeledPolynomial(mapOf( mapOf(this to 1U) to constantOne, mapOf(other to 1U) to -constantOne, )) - public operator fun Variable.times(other: Variable): LabeledPolynomial = + public operator fun Symbol.times(other: Symbol): LabeledPolynomial = if (this == other) LabeledPolynomial(mapOf( mapOf(this to 2U) to constantOne )) @@ -480,8 +481,8 @@ public class LabeledPolynomialSpace>( )) // endregion - // region Variable-polynomial relation - public operator fun Variable.plus(other: LabeledPolynomial): LabeledPolynomial = + // region Symbol-polynomial relation + public operator fun Symbol.plus(other: LabeledPolynomial): LabeledPolynomial = with(other.coefficients) { if (isEmpty()) LabeledPolynomial(mapOf(mapOf(this@plus to 1u) to constantOne)) else LabeledPolynomial( @@ -496,7 +497,7 @@ public class LabeledPolynomialSpace>( } ) } - public operator fun Variable.minus(other: LabeledPolynomial): LabeledPolynomial = + public operator fun Symbol.minus(other: LabeledPolynomial): LabeledPolynomial = with(other.coefficients) { if (isEmpty()) LabeledPolynomial(mapOf(mapOf(this@minus to 1u) to constantOne)) else LabeledPolynomial( @@ -513,7 +514,7 @@ public class LabeledPolynomialSpace>( } ) } - public operator fun Variable.times(other: LabeledPolynomial): LabeledPolynomial = + public operator fun Symbol.times(other: LabeledPolynomial): LabeledPolynomial = LabeledPolynomial( other.coefficients .mapKeys { (degs, _) -> degs.toMutableMap().also{ it[this] = if (this in it) it[this]!! + 1U else 1U } } @@ -521,7 +522,7 @@ public class LabeledPolynomialSpace>( // endregion // region Polynomial-variable relation - public operator fun LabeledPolynomial.plus(other: Variable): LabeledPolynomial = + public operator fun LabeledPolynomial.plus(other: Symbol): LabeledPolynomial = with(coefficients) { if (isEmpty()) LabeledPolynomial(mapOf(mapOf(other to 1u) to constantOne)) else LabeledPolynomial( @@ -536,7 +537,7 @@ public class LabeledPolynomialSpace>( } ) } - public operator fun LabeledPolynomial.minus(other: Variable): LabeledPolynomial = + public operator fun LabeledPolynomial.minus(other: Symbol): LabeledPolynomial = with(coefficients) { if (isEmpty()) LabeledPolynomial(mapOf(mapOf(other to 1u) to constantOne)) else LabeledPolynomial( @@ -551,7 +552,7 @@ public class LabeledPolynomialSpace>( } ) } - public operator fun LabeledPolynomial.times(other: Variable): LabeledPolynomial = + public operator fun LabeledPolynomial.times(other: Symbol): LabeledPolynomial = LabeledPolynomial( coefficients .mapKeys { (degs, _) -> degs.toMutableMap().also{ it[other] = if (other in it) it[other]!! + 1U else 1U } } @@ -610,11 +611,11 @@ public class LabeledPolynomialSpace>( /** * Instance of zero polynomial (zero of the polynomial ring). */ - override val zero: LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to constantZero)) + override val zero: LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to constantZero)) /** * Instance of unit polynomial (unit of the polynomial ring). */ - override val one: LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to constantOne)) + override val one: LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to constantOne)) /** * Checks equality of the polynomials. @@ -642,7 +643,7 @@ public class LabeledPolynomialSpace>( * As consequence all values in the map are positive integers. Also, if the polynomial is constant, the map is empty. * And keys of the map is the same as in [variables]. */ - public val LabeledPolynomial.degrees: Map + public val LabeledPolynomial.degrees: Map get() = buildMap { coefficients.entries.forEach { (degs, c) -> @@ -654,7 +655,7 @@ public class LabeledPolynomialSpace>( /** * Set of all variables that appear in the polynomial in positive exponents. */ - public val LabeledPolynomial.variables: Set + public val LabeledPolynomial.variables: Set get() = buildSet { coefficients.entries.forEach { (degs, c) -> if (c.isNotZero()) addAll(degs.keys) } @@ -695,29 +696,29 @@ public class LabeledPolynomialSpace>( } // @Suppress("NOTHING_TO_INLINE") -// public inline fun LabeledPolynomial.substitute(argument: Map): LabeledPolynomial = this.substitute(ring, argument) +// public inline fun LabeledPolynomial.substitute(argument: Map): LabeledPolynomial = this.substitute(ring, argument) // @Suppress("NOTHING_TO_INLINE") // @JvmName("substitutePolynomial") -// public inline fun LabeledPolynomial.substitute(argument: Map>): LabeledPolynomial = this.substitute(ring, argument) +// public inline fun LabeledPolynomial.substitute(argument: Map>): LabeledPolynomial = this.substitute(ring, argument) // // @Suppress("NOTHING_TO_INLINE") -// public inline fun LabeledPolynomial.asFunction(): (Map) -> LabeledPolynomial = { this.substitute(ring, it) } +// public inline fun LabeledPolynomial.asFunction(): (Map) -> LabeledPolynomial = { this.substitute(ring, it) } // @Suppress("NOTHING_TO_INLINE") -// public inline fun LabeledPolynomial.asFunctionOnConstants(): (Map) -> LabeledPolynomial = { this.substitute(ring, it) } +// public inline fun LabeledPolynomial.asFunctionOnConstants(): (Map) -> LabeledPolynomial = { this.substitute(ring, it) } // @Suppress("NOTHING_TO_INLINE") -// public inline fun LabeledPolynomial.asFunctionOnPolynomials(): (Map>) -> LabeledPolynomial = { this.substitute(ring, it) } +// public inline fun LabeledPolynomial.asFunctionOnPolynomials(): (Map>) -> LabeledPolynomial = { this.substitute(ring, it) } // // @Suppress("NOTHING_TO_INLINE") -// public inline operator fun LabeledPolynomial.invoke(argument: Map): LabeledPolynomial = this.substitute(ring, argument) +// public inline operator fun LabeledPolynomial.invoke(argument: Map): LabeledPolynomial = this.substitute(ring, argument) // @Suppress("NOTHING_TO_INLINE") // @JvmName("invokePolynomial") -// public inline operator fun LabeledPolynomial.invoke(argument: Map>): LabeledPolynomial = this.substitute(ring, argument) +// public inline operator fun LabeledPolynomial.invoke(argument: Map>): LabeledPolynomial = this.substitute(ring, argument) // endregion // region Utilities // TODO: Move to region internal utilities with context receiver @JvmName("applyAndRemoveZerosInternal") - internal fun MutableMap, C>.applyAndRemoveZeros(block: MutableMap, C>.() -> Unit) : MutableMap, C> { + internal fun MutableMap, C>.applyAndRemoveZeros(block: MutableMap, C>.() -> Unit) : MutableMap, C> { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } @@ -725,10 +726,10 @@ public class LabeledPolynomialSpace>( for ((degs, c) in this) if (c.isZero()) this.remove(degs) return this } - internal fun Map, C>.applyAndRemoveZeros(block: MutableMap, C>.() -> Unit) : Map, C> = + internal fun Map, C>.applyAndRemoveZeros(block: MutableMap, C>.() -> Unit) : Map, C> = toMutableMap().applyAndRemoveZeros(block) @OptIn(ExperimentalTypeInference::class) - internal inline fun buildCoefficients(@BuilderInference builderAction: MutableMap, C>.() -> Unit): Map, C> { + internal inline fun buildCoefficients(@BuilderInference builderAction: MutableMap, C>.() -> Unit): Map, C> { contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) } return buildMap { builderAction() @@ -736,7 +737,7 @@ public class LabeledPolynomialSpace>( } } @OptIn(ExperimentalTypeInference::class) - internal inline fun buildCoefficients(capacity: Int, @BuilderInference builderAction: MutableMap, C>.() -> Unit): Map, C> { + internal inline fun buildCoefficients(capacity: Int, @BuilderInference builderAction: MutableMap, C>.() -> Unit): Map, C> { contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) } return buildMap(capacity) { builderAction() diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt index df4441127..3077a2b82 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt @@ -5,6 +5,7 @@ package space.kscience.kmath.functions +import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.operations.Ring import space.kscience.kmath.operations.invoke @@ -62,22 +63,22 @@ internal fun labeledRationalFunctionError(message: Any): Nothing = throw Labeled // ) // TODO: Rewrite former constructors as fabrics -//constructor(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>) : this( +//constructor(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>) : this( //LabeledPolynomial(numeratorCoefficients), //LabeledPolynomial(denominatorCoefficients) //) // -//constructor(numeratorCoefficients: Collection, C>>, denominatorCoefficients: Collection, C>>) : this( +//constructor(numeratorCoefficients: Collection, C>>, denominatorCoefficients: Collection, C>>) : this( //LabeledPolynomial(numeratorCoefficients), //LabeledPolynomial(denominatorCoefficients) //) // //constructor(numerator: LabeledPolynomial) : this(numerator, numerator.getOne()) -//constructor(numeratorCoefficients: Map, C>) : this( +//constructor(numeratorCoefficients: Map, C>) : this( //LabeledPolynomial(numeratorCoefficients) //) // -//constructor(numeratorCoefficients: Collection, C>>) : this( +//constructor(numeratorCoefficients: Collection, C>>) : this( //LabeledPolynomial(numeratorCoefficients) //) @@ -338,11 +339,11 @@ public class LabeledRationalFunctionSpace>( * As consequence all values in the map are positive integers. Also, if the polynomial is constant, the map is empty. * And keys of the map is the same as in [variables]. */ - public val LabeledPolynomial.degrees: Map get() = polynomialRing { degrees } + public val LabeledPolynomial.degrees: Map get() = polynomialRing { degrees } /** * Set of all variables that appear in the polynomial in positive exponents. */ - public val LabeledPolynomial.variables: Set get() = polynomialRing { variables } + public val LabeledPolynomial.variables: Set get() = polynomialRing { variables } /** * Count of all variables that appear in the polynomial in positive exponents. */ @@ -353,7 +354,7 @@ public class LabeledRationalFunctionSpace>( /** * Count of all variables that appear in the polynomial in positive exponents. */ - public val LabeledRationalFunction.variables: Set + public val LabeledRationalFunction.variables: Set get() = numerator.variables union denominator.variables /** * Count of all variables that appear in the polynomial in positive exponents. @@ -381,21 +382,21 @@ public class LabeledRationalFunctionSpace>( denominator * other ) -// operator fun invoke(arg: Map): LabeledRationalFunction = +// operator fun invoke(arg: Map): LabeledRationalFunction = // LabeledRationalFunction( // numerator(arg), // denominator(arg) // ) // // @JvmName("invokeLabeledPolynomial") -// operator fun invoke(arg: Map>): LabeledRationalFunction = +// operator fun invoke(arg: Map>): LabeledRationalFunction = // LabeledRationalFunction( // numerator(arg), // denominator(arg) // ) // // @JvmName("invokeLabeledRationalFunction") -// operator fun invoke(arg: Map>): LabeledRationalFunction { +// operator fun invoke(arg: Map>): LabeledRationalFunction { // var num = numerator invokeRFTakeNumerator arg // var den = denominator invokeRFTakeNumerator arg // for (variable in variables) if (variable in arg) { @@ -410,56 +411,56 @@ public class LabeledRationalFunctionSpace>( // // override fun toString(): String = toString(emptyMap()) // -// fun toString(names: Map = emptyMap()): String = +// fun toString(names: Map = emptyMap()): String = // when (true) { // numerator.isZero() -> "0" // denominator.isOne() -> numerator.toString(names) // else -> "${numerator.toStringWithBrackets(names)}/${denominator.toStringWithBrackets(names)}" // } // -// fun toString(namer: (Variable) -> String): String = +// fun toString(namer: (Symbol) -> String): String = // when (true) { // numerator.isZero() -> "0" // denominator.isOne() -> numerator.toString(namer) // else -> "${numerator.toStringWithBrackets(namer)}/${denominator.toStringWithBrackets(namer)}" // } // -// fun toStringWithBrackets(names: Map = emptyMap()): String = +// fun toStringWithBrackets(names: Map = emptyMap()): String = // when (true) { // numerator.isZero() -> "0" // denominator.isOne() -> numerator.toStringWithBrackets(names) // else -> "(${numerator.toStringWithBrackets(names)}/${denominator.toStringWithBrackets(names)})" // } // -// fun toStringWithBrackets(namer: (Variable) -> String): String = +// fun toStringWithBrackets(namer: (Symbol) -> String): String = // when (true) { // numerator.isZero() -> "0" // denominator.isOne() -> numerator.toStringWithBrackets(namer) // else -> "(${numerator.toStringWithBrackets(namer)}/${denominator.toStringWithBrackets(namer)})" // } // -// fun toReversedString(names: Map = emptyMap()): String = +// fun toReversedString(names: Map = emptyMap()): String = // when (true) { // numerator.isZero() -> "0" // denominator.isOne() -> numerator.toReversedString(names) // else -> "${numerator.toReversedStringWithBrackets(names)}/${denominator.toReversedStringWithBrackets(names)}" // } // -// fun toReversedString(namer: (Variable) -> String): String = +// fun toReversedString(namer: (Symbol) -> String): String = // when (true) { // numerator.isZero() -> "0" // denominator.isOne() -> numerator.toReversedString(namer) // else -> "${numerator.toReversedStringWithBrackets(namer)}/${denominator.toReversedStringWithBrackets(namer)}" // } // -// fun toReversedStringWithBrackets(names: Map = emptyMap()): String = +// fun toReversedStringWithBrackets(names: Map = emptyMap()): String = // when (true) { // numerator.isZero() -> "0" // denominator.isOne() -> numerator.toReversedStringWithBrackets(names) // else -> "(${numerator.toReversedStringWithBrackets(names)}/${denominator.toReversedStringWithBrackets(names)})" // } // -// fun toReversedStringWithBrackets(namer: (Variable) -> String): String = +// fun toReversedStringWithBrackets(namer: (Symbol) -> String): String = // when (true) { // numerator.isZero() -> "0" // denominator.isOne() -> numerator.toReversedStringWithBrackets(namer) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Variable.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Variable.kt deleted file mode 100644 index 410604fd3..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Variable.kt +++ /dev/null @@ -1,38 +0,0 @@ -package space.kscience.kmath.functions - -import kotlin.reflect.KProperty - - -/** - * Represents class of labeled variables like usual - * `x`, `y`, `z`, `a`, `b`, `n`, `m`, etc. - * - * Variables does not contain any information about field (or ring, ets.) they are considered in - * and therefore about coefficient. - * - * @property name Is the label or name of variable. For `x` it is `"x"`, for `n` – `"n"`, etc. - */ -public data class Variable (val name: String) : Comparable { - /** - * Represents the variable as a string. - * - * @return Only name of the variable. - */ - override fun toString(): String = name - /** - * Compares two variables. - * Comparison is realised by comparison of variables' names. - * - * Used in [LabeledPolynomial] and [LabeledRationalFunction] to sort monomials in - * [LabeledPolynomial.toString] and [LabeledRationalFunction.toString] in lexicographic order. - * - * @see Comparable.compareTo - * @sample LabeledPolynomial.monomialComparator - * @return Only name of the variable. - */ - override fun compareTo(other: Variable): Int = name.compareTo(other.name) - - public companion object { - public operator fun getValue(thisRef: Any?, property: KProperty<*>) : Variable = Variable(property.name) - } -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt index 544cca410..9408a09f2 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt @@ -5,10 +5,14 @@ package space.kscience.kmath.functions +import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.* -import kotlin.contracts.* -import kotlin.math.max +import space.kscience.kmath.operations.Field +import space.kscience.kmath.operations.Ring +import space.kscience.kmath.operations.invoke +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract // TODO: Docs @@ -31,10 +35,10 @@ import kotlin.math.max // //// endregion -//// region Variables +//// region Symbols // //context(LabeledPolynomialSpace) -//fun > power(arg: Variable, pow: UInt): LabeledPolynomial = +//fun > power(arg: Symbol, pow: UInt): LabeledPolynomial = // if (pow == 0U) one // else LabeledPolynomial(mapOf( // mapOf(arg to pow) to constantOne @@ -45,7 +49,7 @@ import kotlin.math.max //// region Polynomials // //context(LabeledPolynomialSpace) -//fun > number(value: Int): LabeledPolynomial = ring { LabeledPolynomial(mapOf(emptyMap() to number(value))) } +//fun > number(value: Int): LabeledPolynomial = ring { LabeledPolynomial(mapOf(emptyMap() to number(value))) } // //context(LabeledPolynomialSpace) //fun > multiplyWithPower(base: LabeledPolynomial, arg: LabeledPolynomial, pow: UInt): LabeledPolynomial = @@ -97,7 +101,7 @@ public inline fun , R> A.labeledPolynomial(block: LabeledPolynomi // * Consider that monomials are sorted in lexicographic order. // */ //context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.represent(names: Map = emptyMap()): String = +//fun > LabeledPolynomial.represent(names: Map = emptyMap()): String = // coefficients.entries // .sortedWith { o1, o2 -> LabeledPolynomial.monomialComparator.compare(o1.key, o2.key) } // .asSequence() @@ -130,7 +134,7 @@ public inline fun , R> A.labeledPolynomial(block: LabeledPolynomi // * Consider that monomials are sorted in lexicographic order. // */ //context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.represent(namer: (Variable) -> String): String = +//fun > LabeledPolynomial.represent(namer: (Symbol) -> String): String = // coefficients.entries // .sortedWith { o1, o2 -> LabeledPolynomial.monomialComparator.compare(o1.key, o2.key) } // .asSequence() @@ -163,7 +167,7 @@ public inline fun , R> A.labeledPolynomial(block: LabeledPolynomi // * Consider that monomials are sorted in lexicographic order. // */ //context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.representWithBrackets(names: Map = emptyMap()): String = +//fun > LabeledPolynomial.representWithBrackets(names: Map = emptyMap()): String = // with(represent(names)) { if (coefficients.count() == 1) this else "($this)" } // ///** @@ -172,7 +176,7 @@ public inline fun , R> A.labeledPolynomial(block: LabeledPolynomi // * Consider that monomials are sorted in lexicographic order. // */ //context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.representWithBrackets(namer: (Variable) -> String): String = +//fun > LabeledPolynomial.representWithBrackets(namer: (Symbol) -> String): String = // with(represent(namer)) { if (coefficients.count() == 1) this else "($this)" } // ///** @@ -180,7 +184,7 @@ public inline fun , R> A.labeledPolynomial(block: LabeledPolynomi // * Consider that monomials are sorted in **reversed** lexicographic order. // */ //context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.representReversed(names: Map = emptyMap()): String = +//fun > LabeledPolynomial.representReversed(names: Map = emptyMap()): String = // coefficients.entries // .sortedWith { o1, o2 -> -LabeledPolynomial.monomialComparator.compare(o1.key, o2.key) } // .asSequence() @@ -213,7 +217,7 @@ public inline fun , R> A.labeledPolynomial(block: LabeledPolynomi // * Consider that monomials are sorted in **reversed** lexicographic order. // */ //context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.representReversed(namer: (Variable) -> String): String = +//fun > LabeledPolynomial.representReversed(namer: (Symbol) -> String): String = // coefficients.entries // .sortedWith { o1, o2 -> -LabeledPolynomial.monomialComparator.compare(o1.key, o2.key) } // .asSequence() @@ -246,7 +250,7 @@ public inline fun , R> A.labeledPolynomial(block: LabeledPolynomi // * Consider that monomials are sorted in **reversed** lexicographic order. // */ //context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.representReversedWithBrackets(names: Map = emptyMap()): String = +//fun > LabeledPolynomial.representReversedWithBrackets(names: Map = emptyMap()): String = // with(representReversed(names)) { if (coefficients.count() == 1) this else "($this)" } // ///** @@ -255,7 +259,7 @@ public inline fun , R> A.labeledPolynomial(block: LabeledPolynomi // * Consider that monomials are sorted in **reversed** lexicographic order. // */ //context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.representReversedWithBrackets(namer: (Variable) -> String): String = +//fun > LabeledPolynomial.representReversedWithBrackets(namer: (Symbol) -> String): String = // with(representReversed(namer)) { if (coefficients.count() == 1) this else "($this)" } // //// endregion @@ -279,7 +283,7 @@ public inline fun , R> A.labeledPolynomial(block: LabeledPolynomi //// region Polynomial substitution and functional representation // -//public fun LabeledPolynomial.substitute(ring: Ring, args: Map): LabeledPolynomial = ring { +//public fun LabeledPolynomial.substitute(ring: Ring, args: Map): LabeledPolynomial = ring { // if (coefficients.isEmpty()) return this@substitute // LabeledPolynomial( // buildMap { @@ -297,7 +301,7 @@ public inline fun , R> A.labeledPolynomial(block: LabeledPolynomi //// TODO: Replace with optimisation: the [result] may be unboxed, and all operations may be performed as soon as //// possible on it //@JvmName("substitutePolynomial") -//fun LabeledPolynomial.substitute(ring: Ring, arg: Map>) : LabeledPolynomial = +//fun LabeledPolynomial.substitute(ring: Ring, arg: Map>) : LabeledPolynomial = // ring.labeledPolynomial { // if (coefficients.isEmpty()) return zero // coefficients @@ -315,10 +319,10 @@ public inline fun , R> A.labeledPolynomial(block: LabeledPolynomi // //// TODO: Substitute rational function // -//fun > LabeledPolynomial.asFunctionOver(ring: A): (Map) -> LabeledPolynomial = +//fun > LabeledPolynomial.asFunctionOver(ring: A): (Map) -> LabeledPolynomial = // { substitute(ring, it) } // -//fun > LabeledPolynomial.asPolynomialFunctionOver(ring: A): (Map>) -> LabeledPolynomial = +//fun > LabeledPolynomial.asPolynomialFunctionOver(ring: A): (Map>) -> LabeledPolynomial = // { substitute(ring, it) } // //// endregion @@ -331,7 +335,7 @@ public inline fun , R> A.labeledPolynomial(block: LabeledPolynomi @UnstableKMathAPI public fun > LabeledPolynomial.derivativeWithRespectTo( algebra: A, - variable: Variable, + variable: Symbol, ): LabeledPolynomial = algebra { LabeledPolynomial( buildMap(coefficients.size) { @@ -360,7 +364,7 @@ public fun > LabeledPolynomial.derivativeWithRespectTo( @UnstableKMathAPI public fun > LabeledPolynomial.derivativeWithRespectTo( algebra: A, - variables: Collection, + variables: Collection, ): LabeledPolynomial = algebra { val cleanedVariables = variables.toSet() if (cleanedVariables.isEmpty()) return this@derivativeWithRespectTo @@ -391,7 +395,7 @@ public fun > LabeledPolynomial.derivativeWithRespectTo( @UnstableKMathAPI public fun > LabeledPolynomial.nthDerivativeWithRespectTo( algebra: A, - variable: Variable, + variable: Symbol, order: UInt ): LabeledPolynomial = algebra { if (order == 0u) return this@nthDerivativeWithRespectTo @@ -425,7 +429,7 @@ public fun > LabeledPolynomial.nthDerivativeWithRespectTo( @UnstableKMathAPI public fun > LabeledPolynomial.nthDerivativeWithRespectTo( algebra: A, - variablesAndOrders: Map, + variablesAndOrders: Map, ): LabeledPolynomial = algebra { val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u } if (filteredVariablesAndOrders.isEmpty()) return this@nthDerivativeWithRespectTo @@ -462,13 +466,13 @@ public fun > LabeledPolynomial.nthDerivativeWithRespectTo( @UnstableKMathAPI public fun > LabeledPolynomial.antiderivativeWithRespectTo( algebra: A, - variable: Variable, + variable: Symbol, ): LabeledPolynomial = algebra { LabeledPolynomial( buildMap(coefficients.size) { coefficients .forEach { (degs, c) -> - val newDegs = buildMap(degs.size + 1) { + val newDegs = buildMap(degs.size + 1) { put(variable, 1u) for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) } @@ -487,7 +491,7 @@ public fun > LabeledPolynomial.antiderivativeWithRespectTo( @UnstableKMathAPI public fun > LabeledPolynomial.antiderivativeWithRespectTo( algebra: A, - variables: Collection, + variables: Collection, ): LabeledPolynomial = algebra { val cleanedVariables = variables.toSet() if (cleanedVariables.isEmpty()) return this@antiderivativeWithRespectTo @@ -495,7 +499,7 @@ public fun > LabeledPolynomial.antiderivativeWithRespectTo( buildMap(coefficients.size) { coefficients .forEach { (degs, c) -> - val newDegs = buildMap(degs.size + 1) { + val newDegs = buildMap(degs.size + 1) { for (variable in cleanedVariables) put(variable, 1u) for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) } @@ -514,7 +518,7 @@ public fun > LabeledPolynomial.antiderivativeWithRespectTo( @UnstableKMathAPI public fun > LabeledPolynomial.nthAntiderivativeWithRespectTo( algebra: A, - variable: Variable, + variable: Symbol, order: UInt ): LabeledPolynomial = algebra { if (order == 0u) return this@nthAntiderivativeWithRespectTo @@ -522,7 +526,7 @@ public fun > LabeledPolynomial.nthAntiderivativeWithRespectTo buildMap(coefficients.size) { coefficients .forEach { (degs, c) -> - val newDegs = buildMap(degs.size + 1) { + val newDegs = buildMap(degs.size + 1) { put(variable, order) for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) } @@ -544,7 +548,7 @@ public fun > LabeledPolynomial.nthAntiderivativeWithRespectTo @UnstableKMathAPI public fun > LabeledPolynomial.nthAntiderivativeWithRespectTo( algebra: A, - variablesAndOrders: Map, + variablesAndOrders: Map, ): LabeledPolynomial = algebra { val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u } if (filteredVariablesAndOrders.isEmpty()) return this@nthAntiderivativeWithRespectTo @@ -552,7 +556,7 @@ public fun > LabeledPolynomial.nthAntiderivativeWithRespectTo buildMap(coefficients.size) { coefficients .forEach { (degs, c) -> - val newDegs = buildMap(degs.size + 1) { + val newDegs = buildMap(degs.size + 1) { for ((variable, order) in filteredVariablesAndOrders) put(variable, order) for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) } -- 2.34.1 From 24944cdb1639bc6bec924510686052e979bb4561 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Wed, 16 Mar 2022 15:19:27 +0300 Subject: [PATCH 025/123] Added support of `power` function to abstract structures. Implemented exponentiation by squaring as default implementation of `power`. Updated docs in algebraicStub.kt and updated realisations in it. --- .../kmath/functions/AbstractPolynomial.kt | 39 ++++-- .../functions/AbstractRationalFunction.kt | 52 ++++++-- .../kscience/kmath/functions/algebraicStub.kt | 124 ++++++++++++++---- .../kmath/functions/labeledPolynomialUtil.kt | 16 +-- .../kmath/functions/numberedPolynomialUtil.kt | 16 +-- .../kmath/functions/polynomialUtil.kt | 2 +- 6 files changed, 181 insertions(+), 68 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt index 8bd8697e3..2d2d22fd3 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt @@ -71,19 +71,19 @@ public interface AbstractPolynomialSpace> : Ring

* * The operation is equivalent to adding [other] copies of unit polynomial to [this]. */ - public operator fun P.plus(other: Int): P = optimizedAddMultiplied(this, one, other) + public operator fun P.plus(other: Int): P = addMultipliedBySquaring(this, one, other) /** * Returns difference between the polynomial and the integer represented as polynomial. * * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. */ - public operator fun P.minus(other: Int): P = optimizedAddMultiplied(this, one, -other) + public operator fun P.minus(other: Int): P = addMultipliedBySquaring(this, one, -other) /** * Returns product of the polynomial and the integer represented as polynomial. * * The operation is equivalent to sum of [other] copies of [this]. */ - public operator fun P.times(other: Int): P = optimizedMultiply(this, other) + public operator fun P.times(other: Int): P = multiplyBySquaring(this, other) // endregion // region Integer-polynomial relation @@ -92,19 +92,19 @@ public interface AbstractPolynomialSpace> : Ring

* * The operation is equivalent to adding [this] copies of unit polynomial to [other]. */ - public operator fun Int.plus(other: P): P = optimizedAddMultiplied(other, one, this) + public operator fun Int.plus(other: P): P = addMultipliedBySquaring(other, one, this) /** * Returns difference between the integer represented as polynomial and the polynomial. * * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. */ - public operator fun Int.minus(other: P): P = optimizedAddMultiplied(-other, one, this) + public operator fun Int.minus(other: P): P = addMultipliedBySquaring(-other, one, this) /** * Returns product of the integer represented as polynomial and the polynomial. * * The operation is equivalent to sum of [this] copies of [other]. */ - public operator fun Int.times(other: P): P = optimizedMultiply(other, this) + public operator fun Int.times(other: P): P = multiplyBySquaring(other, this) // endregion // region Constant-constant relation @@ -138,6 +138,12 @@ public interface AbstractPolynomialSpace> : Ring

@JvmName("constantTimes") @JsName("constantTimes") public operator fun C.times(other: C): C + /** + * Raises [arg] to the integer power [exponent]. + */ + @JvmName("constantPower") + @JsName("constantPower") + public fun power(arg: C, exponent: UInt) : C /** * Check if the instant is zero constant. @@ -225,6 +231,10 @@ public interface AbstractPolynomialSpace> : Ring

* Returns product of the polynomials. */ public override operator fun P.times(other: P): P + /** + * Raises [arg] to the integer power [exponent]. + */ + public override fun power(arg: P, exponent: UInt) : P = exponentiationBySquaring(arg, exponent) /** * Check if the instant is zero polynomial. @@ -331,19 +341,19 @@ public interface AbstractPolynomialSpaceOverRing, A: * * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. */ - public override operator fun C.plus(other: Int): C = ring { optimizedAddMultiplied(this@plus, one, other) } + public override operator fun C.plus(other: Int): C = ring { addMultipliedBySquaring(this@plus, one, other) } /** * Returns difference between the constant and the integer represented as constant (member of underlying ring). * * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. */ - public override operator fun C.minus(other: Int): C = ring { optimizedAddMultiplied(this@minus, one, -other) } + public override operator fun C.minus(other: Int): C = ring { addMultipliedBySquaring(this@minus, one, -other) } /** * Returns product of the constant and the integer represented as constant (member of underlying ring). * * The operation is equivalent to sum of [other] copies of [this]. */ - public override operator fun C.times(other: Int): C = ring { optimizedMultiply(this@times, other) } + public override operator fun C.times(other: Int): C = ring { multiplyBySquaring(this@times, other) } // endregion // region Integer-constant relation @@ -352,19 +362,19 @@ public interface AbstractPolynomialSpaceOverRing, A: * * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. */ - public override operator fun Int.plus(other: C): C = ring { optimizedAddMultiplied(other, one, this@plus) } + public override operator fun Int.plus(other: C): C = ring { addMultipliedBySquaring(other, one, this@plus) } /** * Returns difference between the integer represented as constant (member of underlying ring) and the constant. * * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. */ - public override operator fun Int.minus(other: C): C = ring { optimizedAddMultiplied(-other, one, this@minus) } + public override operator fun Int.minus(other: C): C = ring { addMultipliedBySquaring(-other, one, this@minus) } /** * Returns product of the integer represented as constant (member of underlying ring) and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ - public override operator fun Int.times(other: C): C = ring { optimizedMultiply(other, this@times) } + public override operator fun Int.times(other: C): C = ring { multiplyBySquaring(other, this@times) } // endregion // region Constant-constant relation @@ -388,6 +398,11 @@ public interface AbstractPolynomialSpaceOverRing, A: */ @JvmName("constantTimes") public override operator fun C.times(other: C): C = ring { this@times * other } + /** + * Raises [arg] to the integer power [exponent]. + */ + @JvmName("constantPower") + override fun power(arg: C, exponent: UInt): C = ring { power(arg, exponent) } /** * Instance of zero constant (zero of the underlying ring). diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt index 685cf4ca3..c6f1d7a7a 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt @@ -120,19 +120,19 @@ public interface AbstractRationalFunctionalSpace, R: * * The operation is equivalent to adding [other] copies of unit polynomial to [this]. */ - public operator fun R.plus(other: Int): R = optimizedAddMultiplied(this, one, other) + public operator fun R.plus(other: Int): R = addMultipliedBySquaring(this, one, other) /** * Returns difference between the rational function and the integer represented as rational function. * * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. */ - public operator fun R.minus(other: Int): R = optimizedAddMultiplied(this, one, -other) + public operator fun R.minus(other: Int): R = addMultipliedBySquaring(this, one, -other) /** * Returns product of the rational function and the integer represented as rational function. * * The operation is equivalent to sum of [other] copies of [this]. */ - public operator fun R.times(other: Int): R = optimizedMultiply(this, other) + public operator fun R.times(other: Int): R = multiplyBySquaring(this, other) // endregion // region Integer-Rational relation @@ -141,19 +141,19 @@ public interface AbstractRationalFunctionalSpace, R: * * The operation is equivalent to adding [this] copies of unit polynomial to [other]. */ - public operator fun Int.plus(other: R): R = optimizedAddMultiplied(other, one, this) + public operator fun Int.plus(other: R): R = addMultipliedBySquaring(other, one, this) /** * Returns difference between the integer represented as rational function and the rational function. * * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. */ - public operator fun Int.minus(other: R): R = optimizedAddMultiplied(-other, one, this) + public operator fun Int.minus(other: R): R = addMultipliedBySquaring(-other, one, this) /** * Returns product of the integer represented as rational function and the rational function. * * The operation is equivalent to sum of [this] copies of [other]. */ - public operator fun Int.times(other: R): R = optimizedMultiply(other, this) + public operator fun Int.times(other: R): R = multiplyBySquaring(other, this) // endregion // region Constant-constant relation @@ -187,6 +187,12 @@ public interface AbstractRationalFunctionalSpace, R: @JvmName("constantTimes") @JsName("constantTimes") public operator fun C.times(other: C): C + /** + * Raises [arg] to the integer power [exponent]. + */ + @JvmName("constantPower") + @JsName("constantPower") + public fun power(arg: C, exponent: UInt) : C /** * Check if the instant is zero constant. @@ -274,6 +280,10 @@ public interface AbstractRationalFunctionalSpace, R: * Returns product of the polynomials. */ public operator fun P.times(other: P): P + /** + * Raises [arg] to the integer power [exponent]. + */ + public fun power(arg: P, exponent: UInt) : P /** * Check if the instant is zero polynomial. @@ -400,6 +410,10 @@ public interface AbstractRationalFunctionalSpace, R: * Returns product of the rational functions. */ public override operator fun R.times(other: R): R + /** + * Raises [arg] to the integer power [exponent]. + */ + public override fun power(arg: R, exponent: UInt) : R = exponentiationBySquaring(arg, exponent) /** * Check if the instant is zero rational function. @@ -536,19 +550,19 @@ public interface AbstractRationalFunctionalSpaceOverRing Group.optimizedMultiply(arg: C, other: Int): C = - if (other >= 0) optimizedMultiply(arg, other.toUInt()) - else optimizedMultiply(arg, (-other).toUInt()) +internal fun Group.multiplyBySquaring(arg: C, multiplier: Int): C = + if (multiplier >= 0) multiplyBySquaring(arg, multiplier.toUInt()) + else multiplyBySquaring(-arg, (-multiplier).toUInt()) // TODO: Move receiver to context receiver /** * Adds product of [arg] and [multiplier] to [base]. * - * @receiver the algebra to provide multiplication. * @param base the augend. * @param arg the multiplicand. - * @param multiplier the multiplier. + * @param multiplier the integer multiplier. * @return sum of the augend [base] and product of the multiplicand [arg] and the multiplier [multiplier]. * @author Gleb Minaev */ -internal fun Group.optimizedAddMultiplied(base: C, arg: C, multiplier: Int): C = - if (multiplier >= 0) optimizedAddMultiplied(base, arg, multiplier.toUInt()) - else optimizedAddMultiplied(base, arg, (-multiplier).toUInt()) +internal fun GroupOps.addMultipliedBySquaring(base: C, arg: C, multiplier: Int): C = + if (multiplier >= 0) addMultipliedBySquaring(base, arg, multiplier.toUInt()) + else addMultipliedBySquaring(base, -arg, (-multiplier).toUInt()) // TODO: Move receiver to context receiver /** - * Multiplication of element and integer. + * Returns product of [arg] and integer [multiplier]. * - * @receiver the multiplicand. - * @param other the multiplier. - * @return the difference. + * This is implementation of variation of [exponentiation by squaring](https://en.wikipedia.org/wiki/Exponentiation_by_squaring) + * + * @param arg the multiplicand. + * @param multiplier the integer multiplier. + * @return product of the multiplicand [arg] and the multiplier [multiplier]. * @author Gleb Minaev */ -internal tailrec fun Group.optimizedMultiply(arg: C, other: UInt): C = +internal tailrec fun Group.multiplyBySquaring(arg: C, multiplier: UInt): C = when { - other == 0u -> zero - other == 1u -> arg - other % 2u == 0u -> optimizedMultiply(arg + arg, other / 2u) - other % 2u == 1u -> optimizedAddMultiplied(arg, arg + arg, other / 2u) + multiplier == 0u -> zero + multiplier == 1u -> arg + multiplier and 1u == 0u -> multiplyBySquaring(arg + arg, multiplier shr 1) + multiplier and 1u == 1u -> addMultipliedBySquaring(arg, arg + arg, multiplier shr 1) else -> error("Error in multiplication group instant by unsigned integer: got reminder by division by 2 different from 0 and 1") } @@ -59,18 +60,87 @@ internal tailrec fun Group.optimizedMultiply(arg: C, other: UInt): C = /** * Adds product of [arg] and [multiplier] to [base]. * - * @receiver the algebra to provide multiplication. + * This is implementation of variation of [exponentiation by squaring](https://en.wikipedia.org/wiki/Exponentiation_by_squaring) + * * @param base the augend. * @param arg the multiplicand. - * @param multiplier the multiplier. + * @param multiplier the integer multiplier. * @return sum of the augend [base] and product of the multiplicand [arg] and the multiplier [multiplier]. * @author Gleb Minaev */ -internal tailrec fun Group.optimizedAddMultiplied(base: C, arg: C, multiplier: UInt): C = +internal tailrec fun GroupOps.addMultipliedBySquaring(base: C, arg: C, multiplier: UInt): C = when { multiplier == 0u -> base multiplier == 1u -> base + arg - multiplier % 2u == 0u -> optimizedAddMultiplied(base, arg + arg, multiplier / 2u) - multiplier % 2u == 1u -> optimizedAddMultiplied(base + arg, arg + arg, multiplier / 2u) + multiplier and 1u == 0u -> addMultipliedBySquaring(base, arg + arg, multiplier shr 1) + multiplier and 1u == 1u -> addMultipliedBySquaring(base + arg, arg + arg, multiplier shr 1) + else -> error("Error in multiplication group instant by unsigned integer: got reminder by division by 2 different from 0 and 1") + } + +// TODO: Move receiver to context receiver +/** + * Raises [arg] to the integer power [exponent]. + * + * @param arg the base of the power. + * @param exponent the exponent of the power. + * @return [arg] raised to the power [exponent]. + * @author Gleb Minaev + */ +internal fun Field.exponentiationBySquaring(arg: C, exponent: Int): C = + if (exponent >= 0) exponentiationBySquaring(arg, exponent.toUInt()) + else exponentiationBySquaring(one / arg, (-exponent).toUInt()) + +// TODO: Move receiver to context receiver +/** + * Multiplies [base] and [arg] raised to the integer power [exponent]. + * + * @param base the multiplicand. + * @param arg the base of the power. + * @param exponent the exponent of the power. + * @return product of [base] and [arg] raised to the power [exponent]. + * @author Gleb Minaev + */ +internal fun Field.multiplyExponentiationBySquaring(base: C, arg: C, exponent: Int): C = + if (exponent >= 0) multiplyExponentiationBySquaring(base, arg, exponent.toUInt()) + else multiplyExponentiationBySquaring(base, one / arg, (-exponent).toUInt()) + +// TODO: Move receiver to context receiver +/** + * Raises [arg] to the integer power [exponent]. + * + * This is implementation of variation of [exponentiation by squaring](https://en.wikipedia.org/wiki/Exponentiation_by_squaring) + * + * @param arg the base of the power. + * @param exponent the exponent of the power. + * @return [arg] raised to the power [exponent]. + * @author Gleb Minaev + */ +internal tailrec fun Ring.exponentiationBySquaring(arg: C, exponent: UInt): C = + when { + exponent == 0u -> zero + exponent == 1u -> arg + exponent and 1u == 0u -> exponentiationBySquaring(arg * arg, exponent shr 1) + exponent and 1u == 1u -> multiplyExponentiationBySquaring(arg, arg * arg, exponent shr 1) + else -> error("Error in multiplication group instant by unsigned integer: got reminder by division by 2 different from 0 and 1") + } + +// TODO: Move receiver to context receiver +/** + * Multiplies [base] and [arg] raised to the integer power [exponent]. + * + * This is implementation of variation of [exponentiation by squaring](https://en.wikipedia.org/wiki/Exponentiation_by_squaring) + * + * @param base the multiplicand. + * @param arg the base of the power. + * @param exponent the exponent of the power. + * @return product of [base] and [arg] raised to the power [exponent]. + * @author Gleb Minaev + */ +internal tailrec fun RingOps.multiplyExponentiationBySquaring(base: C, arg: C, exponent: UInt): C = + when { + exponent == 0u -> base + exponent == 1u -> base + arg + exponent and 1u == 0u -> multiplyExponentiationBySquaring(base, arg * arg, exponent shr 1) + exponent and 1u == 1u -> multiplyExponentiationBySquaring(base * arg, arg * arg, exponent shr 1) else -> error("Error in multiplication group instant by unsigned integer: got reminder by division by 2 different from 0 and 1") } \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt index 9408a09f2..516e76b8f 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt @@ -351,7 +351,7 @@ public fun > LabeledPolynomial.derivativeWithRespectTo( } } }, - optimizedMultiply(c, degs[variable]!!) + multiplyBySquaring(c, degs[variable]!!) ) } } @@ -382,7 +382,7 @@ public fun > LabeledPolynomial.derivativeWithRespectTo( } } }, - cleanedVariables.fold(c) { acc, variable -> optimizedMultiply(acc, degs[variable]!!) } + cleanedVariables.fold(c) { acc, variable -> multiplyBySquaring(acc, degs[variable]!!) } ) } } @@ -415,7 +415,7 @@ public fun > LabeledPolynomial.nthDerivativeWithRespectTo( }, degs[variable]!!.let { deg -> (deg downTo deg - order + 1u) - .fold(c) { acc, ord -> optimizedMultiply(acc, ord) } + .fold(c) { acc, ord -> multiplyBySquaring(acc, ord) } } ) } @@ -451,7 +451,7 @@ public fun > LabeledPolynomial.nthDerivativeWithRespectTo( filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> degs[index]!!.let { deg -> (deg downTo deg - order + 1u) - .fold(acc1) { acc2, ord -> optimizedMultiply(acc2, ord) } + .fold(acc1) { acc2, ord -> multiplyBySquaring(acc2, ord) } } } ) @@ -478,7 +478,7 @@ public fun > LabeledPolynomial.antiderivativeWithRespectTo( } put( newDegs, - c / optimizedMultiply(one, newDegs[variable]!!) + c / multiplyBySquaring(one, newDegs[variable]!!) ) } } @@ -505,7 +505,7 @@ public fun > LabeledPolynomial.antiderivativeWithRespectTo( } put( newDegs, - cleanedVariables.fold(c) { acc, variable -> acc / optimizedMultiply(one, newDegs[variable]!!) } + cleanedVariables.fold(c) { acc, variable -> acc / multiplyBySquaring(one, newDegs[variable]!!) } ) } } @@ -534,7 +534,7 @@ public fun > LabeledPolynomial.nthAntiderivativeWithRespectTo newDegs, newDegs[variable]!!.let { deg -> (deg downTo deg - order + 1u) - .fold(c) { acc, ord -> acc / optimizedMultiply(one, ord) } + .fold(c) { acc, ord -> acc / multiplyBySquaring(one, ord) } } ) } @@ -565,7 +565,7 @@ public fun > LabeledPolynomial.nthAntiderivativeWithRespectTo filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> newDegs[index]!!.let { deg -> (deg downTo deg - order + 1u) - .fold(acc1) { acc2, ord -> acc2 / optimizedMultiply(one, ord) } + .fold(acc1) { acc2, ord -> acc2 / multiplyBySquaring(one, ord) } } } ) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt index 47644b26a..ac411fc28 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt @@ -393,7 +393,7 @@ public fun > NumberedPolynomial.derivativeWithRespectTo( else -> return@forEach } }.cleanUp(), - optimizedMultiply(c, degs[variable]) + multiplyBySquaring(c, degs[variable]) ) } } @@ -424,7 +424,7 @@ public fun > NumberedPolynomial.derivativeWithRespectTo( else -> return@forEach } }.cleanUp(), - cleanedVariables.fold(c) { acc, variable -> optimizedMultiply(acc, degs[variable]) } + cleanedVariables.fold(c) { acc, variable -> multiplyBySquaring(acc, degs[variable]) } ) } } @@ -456,7 +456,7 @@ public fun > NumberedPolynomial.nthDerivativeWithRespectTo( }.cleanUp(), degs[variable].let { deg -> (deg downTo deg - order + 1u) - .fold(c) { acc, ord -> optimizedMultiply(acc, ord) } + .fold(c) { acc, ord -> multiplyBySquaring(acc, ord) } } ) } @@ -489,7 +489,7 @@ public fun > NumberedPolynomial.nthDerivativeWithRespectTo( filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> degs[index].let { deg -> (deg downTo deg - order + 1u) - .fold(acc1) { acc2, ord -> optimizedMultiply(acc2, ord) } + .fold(acc1) { acc2, ord -> multiplyBySquaring(acc2, ord) } } } ) @@ -512,7 +512,7 @@ public fun > NumberedPolynomial.antiderivativeWithRespectTo( .forEach { (degs, c) -> put( List(max(variable + 1, degs.size)) { if (it != variable) degs[it] else degs[it] + 1u }, - c / optimizedMultiply(one, degs[variable]) + c / multiplyBySquaring(one, degs[variable]) ) } } @@ -536,7 +536,7 @@ public fun > NumberedPolynomial.antiderivativeWithRespectTo( .forEach { (degs, c) -> put( List(max(maxRespectedVariable + 1, degs.size)) { if (it !in variables) degs[it] else degs[it] + 1u }, - cleanedVariables.fold(c) { acc, variable -> acc / optimizedMultiply(one, degs[variable]) } + cleanedVariables.fold(c) { acc, variable -> acc / multiplyBySquaring(one, degs[variable]) } ) } } @@ -561,7 +561,7 @@ public fun > NumberedPolynomial.nthAntiderivativeWithRespectT List(max(variable + 1, degs.size)) { if (it != variable) degs[it] else degs[it] + order }, degs[variable].let { deg -> (deg downTo deg - order + 1u) - .fold(c) { acc, ord -> acc / optimizedMultiply(one, ord) } + .fold(c) { acc, ord -> acc / multiplyBySquaring(one, ord) } } ) } @@ -589,7 +589,7 @@ public fun > NumberedPolynomial.nthAntiderivativeWithRespectT filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> degs[index].let { deg -> (deg downTo deg - order + 1u) - .fold(acc1) { acc2, ord -> acc2 / optimizedMultiply(one, ord) } + .fold(acc1) { acc2, ord -> acc2 / multiplyBySquaring(one, ord) } } } ) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt index 9c8cc0090..2d0377d2c 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt @@ -137,7 +137,7 @@ public fun Polynomial.derivative( public fun Polynomial.nthDerivative( algebra: A, order: UInt, -): Polynomial where A : Ring, A : NumericAlgebra = algebra { +): Polynomial where A : Ring, A : NumericAlgebra = algebra { Polynomial(coefficients.drop(order.toInt()).mapIndexed { index, c -> (index + 1..index + order.toInt()).fold(c) { acc, i -> acc * number(i) } }) } -- 2.34.1 From 3c9d8a4eee586962ba59a3790c3d7ddb18572637 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Wed, 16 Mar 2022 22:44:55 +0300 Subject: [PATCH 026/123] Deleted all region marks --- .../kmath/functions/AbstractPolynomial.kt | 27 ------- .../functions/AbstractRationalFunction.kt | 79 ------------------- .../kmath/functions/LabeledPolynomial.kt | 40 +--------- .../functions/LabeledRationalFunction.kt | 27 +------ .../kmath/functions/NumberedPolynomial.kt | 29 +------ .../functions/NumberedRationalFunction.kt | 27 +------ .../kscience/kmath/functions/Polynomial.kt | 1 - .../kmath/functions/RationalFunction.kt | 24 +----- .../kmath/functions/labeledPolynomialUtil.kt | 37 +-------- .../functions/labeledRationalFunctionUtil.kt | 10 +-- .../kmath/functions/numberedPolynomialUtil.kt | 42 +--------- .../functions/numberedRationalFunctionUtil.kt | 10 +-- .../kmath/functions/polynomialUtil.kt | 14 +--- .../kmath/functions/rationalFunctionUtil.kt | 12 +-- 14 files changed, 11 insertions(+), 368 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt index 2d2d22fd3..aacf055fa 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt @@ -23,7 +23,6 @@ public interface AbstractPolynomial */ @Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") public interface AbstractPolynomialSpace> : Ring

{ - // region Constant-integer relation /** * Returns sum of the constant and the integer represented as constant (member of underlying ring). * @@ -42,9 +41,7 @@ public interface AbstractPolynomialSpace> : Ring

* The operation is equivalent to sum of [other] copies of [this]. */ public operator fun C.times(other: Int): C - // endregion - // region Integer-constant relation /** * Returns sum of the integer represented as constant (member of underlying ring) and the constant. * @@ -63,9 +60,7 @@ public interface AbstractPolynomialSpace> : Ring

* The operation is equivalent to sum of [this] copies of [other]. */ public operator fun Int.times(other: C): C - // endregion - // region Polynomial-integer relation /** * Returns sum of the polynomial and the integer represented as polynomial. * @@ -84,9 +79,7 @@ public interface AbstractPolynomialSpace> : Ring

* The operation is equivalent to sum of [other] copies of [this]. */ public operator fun P.times(other: Int): P = multiplyBySquaring(this, other) - // endregion - // region Integer-polynomial relation /** * Returns sum of the integer represented as polynomial and the polynomial. * @@ -105,9 +98,7 @@ public interface AbstractPolynomialSpace> : Ring

* The operation is equivalent to sum of [this] copies of [other]. */ public operator fun Int.times(other: P): P = multiplyBySquaring(other, this) - // endregion - // region Constant-constant relation /** * Returns the same constant. */ @@ -178,9 +169,7 @@ public interface AbstractPolynomialSpace> : Ring

* Instance of unit constant (unit of the underlying ring). */ public val constantOne: C - // endregion - // region Constant-polynomial relation /** * Returns sum of the constant represented as polynomial and the polynomial. */ @@ -193,9 +182,7 @@ public interface AbstractPolynomialSpace> : Ring

* Returns product of the constant represented as polynomial and the polynomial. */ public operator fun C.times(other: P): P - // endregion - // region Polynomial-constant relation /** * Returns sum of the constant represented as polynomial and the polynomial. */ @@ -208,9 +195,7 @@ public interface AbstractPolynomialSpace> : Ring

* Returns product of the constant represented as polynomial and the polynomial. */ public operator fun P.times(other: C): P - // endregion - // region Polynomial-polynomial relation /** * Returns the same polynomial. */ @@ -278,10 +263,7 @@ public interface AbstractPolynomialSpace> : Ring

* Checks NOT equality of the polynomials. */ public infix fun P.notEqualsTo(other: P): Boolean = !(this equalsTo other) - // endregion - // Not sure is it necessary... - // region Polynomial properties /** * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is * zero, degree is -1. @@ -314,12 +296,9 @@ public interface AbstractPolynomialSpace> : Ring

* Otherwise, (when the polynomial is not constant polynomial) raises corresponding exception. */ public fun P.asConstant(): C = asConstantOrNull() ?: error("Can not represent non-constant polynomial as a constant") - // endregion - // region Legacy of Ring interface override fun add(left: P, right: P): P = left + right override fun multiply(left: P, right: P): P = left * right - // endregion } /** @@ -335,7 +314,6 @@ public interface AbstractPolynomialSpaceOverRing, A: public val ring: A - // region Constant-integer relation /** * Returns sum of the constant and the integer represented as constant (member of underlying ring). * @@ -354,9 +332,7 @@ public interface AbstractPolynomialSpaceOverRing, A: * The operation is equivalent to sum of [other] copies of [this]. */ public override operator fun C.times(other: Int): C = ring { multiplyBySquaring(this@times, other) } - // endregion - // region Integer-constant relation /** * Returns sum of the integer represented as constant (member of underlying ring) and the constant. * @@ -375,9 +351,7 @@ public interface AbstractPolynomialSpaceOverRing, A: * The operation is equivalent to sum of [this] copies of [other]. */ public override operator fun Int.times(other: C): C = ring { multiplyBySquaring(other, this@times) } - // endregion - // region Constant-constant relation /** * Returns negation of the constant. */ @@ -412,5 +386,4 @@ public interface AbstractPolynomialSpaceOverRing, A: * Instance of unit constant (unit of the underlying ring). */ public override val constantOne: C get() = ring.one - // endregion } \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt index c6f1d7a7a..b9ca01da4 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt @@ -30,7 +30,6 @@ public interface AbstractRationalFunction> { */ // TODO: Add support of field @Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") public interface AbstractRationalFunctionalSpace, R: AbstractRationalFunction> : Ring { - // region Constant-integer relation /** * Returns sum of the constant and the integer represented as constant (member of underlying ring). * @@ -49,9 +48,7 @@ public interface AbstractRationalFunctionalSpace, R: * The operation is equivalent to sum of [other] copies of [this]. */ public operator fun C.times(other: Int): C - // endregion - // region Integer-constant relation /** * Returns sum of the integer represented as constant (member of underlying ring) and the constant. * @@ -70,9 +67,7 @@ public interface AbstractRationalFunctionalSpace, R: * The operation is equivalent to sum of [this] copies of [other]. */ public operator fun Int.times(other: C): C - // endregion - // region Polynomial-integer relation /** * Returns sum of the constant and the integer represented as polynomial. * @@ -91,9 +86,7 @@ public interface AbstractRationalFunctionalSpace, R: * The operation is equivalent to sum of [other] copies of [this]. */ public operator fun P.times(other: Int): P - // endregion - // region Integer-polynomial relation /** * Returns sum of the integer represented as polynomial and the constant. * @@ -112,9 +105,7 @@ public interface AbstractRationalFunctionalSpace, R: * The operation is equivalent to sum of [this] copies of [other]. */ public operator fun Int.times(other: P): P - // endregion - // region Rational-integer relation /** * Returns sum of the rational function and the integer represented as rational function. * @@ -133,9 +124,7 @@ public interface AbstractRationalFunctionalSpace, R: * The operation is equivalent to sum of [other] copies of [this]. */ public operator fun R.times(other: Int): R = multiplyBySquaring(this, other) - // endregion - // region Integer-Rational relation /** * Returns sum of the integer represented as rational function and the rational function. * @@ -154,9 +143,7 @@ public interface AbstractRationalFunctionalSpace, R: * The operation is equivalent to sum of [this] copies of [other]. */ public operator fun Int.times(other: R): R = multiplyBySquaring(other, this) - // endregion - // region Constant-constant relation /** * Returns the same constant. */ @@ -227,9 +214,7 @@ public interface AbstractRationalFunctionalSpace, R: * Instance of unit constant (unit of the underlying ring). */ public val constantOne: C - // endregion - // region Constant-polynomial relation /** * Returns sum of the constant represented as polynomial and the polynomial. */ @@ -242,9 +227,7 @@ public interface AbstractRationalFunctionalSpace, R: * Returns product of the constant represented as polynomial and the polynomial. */ public operator fun C.times(other: P): P - // endregion - // region Polynomial-constant relation /** * Returns sum of the constant represented as polynomial and the polynomial. */ @@ -257,9 +240,7 @@ public interface AbstractRationalFunctionalSpace, R: * Returns product of the constant represented as polynomial and the polynomial. */ public operator fun P.times(other: C): P - // endregion - // region Polynomial-polynomial relation /** * Returns the same polynomial. */ @@ -327,9 +308,7 @@ public interface AbstractRationalFunctionalSpace, R: * Checks NOT equality of the polynomials. */ public infix fun P.notEqualsTo(other: P): Boolean = !(this equalsTo other) - // endregion - // region Constant-rational relation /** * Returns sum of the constant represented as rational function and the rational function. */ @@ -342,9 +321,7 @@ public interface AbstractRationalFunctionalSpace, R: * Returns product of the constant represented as polynomial and the rational function. */ public operator fun C.times(other: R): R - // endregion - // region Rational-constant relation /** * Returns sum of the constant represented as rational function and the rational function. */ @@ -357,9 +334,7 @@ public interface AbstractRationalFunctionalSpace, R: * Returns product of the constant represented as rational function and the rational function. */ public operator fun R.times(other: C): R - // endregion - // region Polynomial-rational relation /** * Returns sum of the polynomial represented as rational function and the rational function. */ @@ -372,9 +347,7 @@ public interface AbstractRationalFunctionalSpace, R: * Returns product of the polynomial represented as polynomial and the rational function. */ public operator fun P.times(other: R): R - // endregion - // region Rational-polynomial relation /** * Returns sum of the polynomial represented as rational function and the rational function. */ @@ -387,9 +360,7 @@ public interface AbstractRationalFunctionalSpace, R: * Returns product of the polynomial represented as rational function and the rational function. */ public operator fun R.times(other: P): R - // endregion - // region Rational-rational relation /** * Returns the same rational function. */ @@ -457,10 +428,7 @@ public interface AbstractRationalFunctionalSpace, R: * Checks NOT equality of the polynomials. */ public infix fun R.notEqualsTo(other: R): Boolean = !(this equalsTo other) - // endregion - // Not sure is it necessary... - // region Polynomial properties /** * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is * zero, degree is -1. @@ -494,10 +462,6 @@ public interface AbstractRationalFunctionalSpace, R: */ public fun P.asConstant(): C = asConstantOrNull() ?: error("Can not represent non-constant polynomial as a constant") - // endregion - - // Not sure is it necessary... - // region Rational properties /** * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is * zero, degree is -1. @@ -509,25 +473,8 @@ public interface AbstractRationalFunctionalSpace, R: */ public val R.denominatorDegree: Int get() = denominator.degree - // TODO: Перенести в реализацию -// fun R.substitute(argument: C): C -// fun R.substitute(argument: P): R -// fun R.substitute(argument: R): R -// -// fun R.asFunction(): (C) -> C = /*this::substitute*/ { this.substitute(it) } -// fun R.asFunctionOnConstants(): (C) -> C = /*this::substitute*/ { this.substitute(it) } -// fun P.asFunctionOnPolynomials(): (P) -> R = /*this::substitute*/ { this.substitute(it) } -// fun R.asFunctionOnRationalFunctions(): (R) -> R = /*this::substitute*/ { this.substitute(it) } -// -// operator fun R.invoke(argument: C): C = this.substitute(argument) -// operator fun R.invoke(argument: P): R = this.substitute(argument) -// operator fun R.invoke(argument: R): R = this.substitute(argument) - // endregion - - // region Legacy override fun add(left: R, right: R): R = left + right override fun multiply(left: R, right: R): R = left * right - // endregion } /** @@ -544,7 +491,6 @@ public interface AbstractRationalFunctionalSpaceOverRing.cleanUp() = filterValues { it > 0U } -// endregion - -// region Constructors and converters - //context(LabeledPolynomialSpace>) //@Suppress("FunctionName") //internal fun LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = false) : LabeledPolynomial { @@ -128,8 +122,6 @@ internal fun Map.cleanUp() = filterValues { it > 0U } public fun C.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to this)) -// endregion - /** * Space of polynomials. * @@ -140,8 +132,6 @@ public fun C.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomia public class LabeledPolynomialSpace>( public override val ring: A, ) : AbstractPolynomialSpaceOverRing, A> { - - // region Symbol-integer relation public operator fun Symbol.plus(other: Int): LabeledPolynomial = if (other == 0) LabeledPolynomial(mapOf( mapOf(this@plus to 1U) to constantOne, @@ -163,9 +153,7 @@ public class LabeledPolynomialSpace>( else LabeledPolynomial(mapOf( mapOf(this to 1U) to constantOne * other, )) - // endregion - // region Integer-variable relation public operator fun Int.plus(other: Symbol): LabeledPolynomial = if (this == 0) LabeledPolynomial(mapOf( mapOf(other to 1U) to constantOne, @@ -187,9 +175,7 @@ public class LabeledPolynomialSpace>( else LabeledPolynomial(mapOf( mapOf(other to 1U) to constantOne * this@times, )) - // endregion - // region Polynomial-integer relation /** * Returns sum of the polynomial and the integer represented as polynomial. * @@ -243,9 +229,7 @@ public class LabeledPolynomialSpace>( mapValues { (_, c) -> c * other } } ) - // endregion - // region Integer-polynomial relation /** * Returns sum of the integer represented as polynomial and the polynomial. * @@ -299,9 +283,7 @@ public class LabeledPolynomialSpace>( mapValues { (_, c) -> this@times * c } } ) - // endregion - // region Constant-variable relation public operator fun C.plus(other: Symbol): LabeledPolynomial = if (isZero()) LabeledPolynomial(mapOf( mapOf(other to 1U) to constantOne, @@ -323,9 +305,7 @@ public class LabeledPolynomialSpace>( else LabeledPolynomial(mapOf( mapOf(other to 1U) to this@times, )) - // endregion - // region Symbol-constant relation public operator fun Symbol.plus(other: C): LabeledPolynomial = if (other.isZero()) LabeledPolynomial(mapOf( mapOf(this@plus to 1U) to constantOne, @@ -347,9 +327,7 @@ public class LabeledPolynomialSpace>( else LabeledPolynomial(mapOf( mapOf(this@times to 1U) to other, )) - // endregion - // region Constant-polynomial relation /** * Returns sum of the constant represented as polynomial and the polynomial. */ @@ -401,9 +379,7 @@ public class LabeledPolynomialSpace>( mapValues { (_, c) -> this@times * c } } ) - // endregion - // region Polynomial-constant relation /** * Returns sum of the constant represented as polynomial and the polynomial. */ @@ -455,9 +431,7 @@ public class LabeledPolynomialSpace>( mapValues { (_, c) -> c * other } } ) - // endregion - // region Symbol-variable relation public operator fun Symbol.plus(other: Symbol): LabeledPolynomial = if (this == other) LabeledPolynomial(mapOf( mapOf(this to 1U) to constantOne * 2 @@ -479,9 +453,7 @@ public class LabeledPolynomialSpace>( else LabeledPolynomial(mapOf( mapOf(this to 1U, other to 1U) to constantOne, )) - // endregion - // region Symbol-polynomial relation public operator fun Symbol.plus(other: LabeledPolynomial): LabeledPolynomial = with(other.coefficients) { if (isEmpty()) LabeledPolynomial(mapOf(mapOf(this@plus to 1u) to constantOne)) @@ -519,9 +491,7 @@ public class LabeledPolynomialSpace>( other.coefficients .mapKeys { (degs, _) -> degs.toMutableMap().also{ it[this] = if (this in it) it[this]!! + 1U else 1U } } ) - // endregion - // region Polynomial-variable relation public operator fun LabeledPolynomial.plus(other: Symbol): LabeledPolynomial = with(coefficients) { if (isEmpty()) LabeledPolynomial(mapOf(mapOf(other to 1u) to constantOne)) @@ -557,9 +527,7 @@ public class LabeledPolynomialSpace>( coefficients .mapKeys { (degs, _) -> degs.toMutableMap().also{ it[other] = if (other in it) it[other]!! + 1U else 1U } } ) - // endregion - // region Polynomial-polynomial relation /** * Returns negation of the polynomial. */ @@ -626,10 +594,7 @@ public class LabeledPolynomialSpace>( else -> coefficients.size == other.coefficients.size && coefficients.all { (key, value) -> with(other.coefficients) { key in this && this[key] == value } } } - // endregion - // Not sure is it necessary... - // region Polynomial properties /** * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is * zero, degree is -1. @@ -713,10 +678,8 @@ public class LabeledPolynomialSpace>( // @Suppress("NOTHING_TO_INLINE") // @JvmName("invokePolynomial") // public inline operator fun LabeledPolynomial.invoke(argument: Map>): LabeledPolynomial = this.substitute(ring, argument) - // endregion - // region Utilities - // TODO: Move to region internal utilities with context receiver + // TODO: Move to other internal utilities with context receiver @JvmName("applyAndRemoveZerosInternal") internal fun MutableMap, C>.applyAndRemoveZeros(block: MutableMap, C>.() -> Unit) : MutableMap, C> { contract { @@ -744,5 +707,4 @@ public class LabeledPolynomialSpace>( for ((degs, c) in this) if (c.isZero()) this.remove(degs) } } - // endregion } \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt index 3077a2b82..3908933e6 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt @@ -17,8 +17,6 @@ public class LabeledRationalFunction( override fun toString(): String = "LabeledRationalFunction${numerator.coefficients}/${denominator.coefficients}" } -// region Internal utilities - /** * Represents internal [LabeledRationalFunction] errors. */ @@ -34,9 +32,6 @@ internal class LabeledRationalFunctionError : Error { */ internal fun labeledRationalFunctionError(message: Any): Nothing = throw LabeledRationalFunctionError(message.toString()) -// endregion - -// region Constructors and converters // Waiting for context receivers :( TODO: Replace with context receivers when they will be available //context(RationalFunctionSpace) @@ -82,8 +77,6 @@ internal fun labeledRationalFunctionError(message: Any): Nothing = throw Labeled //LabeledPolynomial(numeratorCoefficients) //) -// endregion - public class LabeledRationalFunctionSpace>( public val ring: A, ) : AbstractRationalFunctionalSpaceOverPolynomialSpace< @@ -95,7 +88,6 @@ public class LabeledRationalFunctionSpace>( override val polynomialRing : LabeledPolynomialSpace = LabeledPolynomialSpace(ring) - // region Rational-integer relation /** * Returns sum of the rational function and the integer represented as rational function. * @@ -126,9 +118,7 @@ public class LabeledRationalFunctionSpace>( numerator * other, denominator ) - // endregion - // region Integer-Rational relation /** * Returns sum of the integer represented as rational function and the rational function. * @@ -159,9 +149,7 @@ public class LabeledRationalFunctionSpace>( this * other.numerator, other.denominator ) - // endregion - // region Constant-rational relation /** * Returns sum of the constant represented as rational function and the rational function. */ @@ -186,9 +174,7 @@ public class LabeledRationalFunctionSpace>( this * other.numerator, other.denominator ) - // endregion - // region Rational-constant relation /** * Returns sum of the constant represented as rational function and the rational function. */ @@ -213,9 +199,7 @@ public class LabeledRationalFunctionSpace>( numerator * other, denominator ) - // endregion - // region Polynomial-rational relation /** * Returns sum of the polynomial represented as rational function and the rational function. */ @@ -240,9 +224,7 @@ public class LabeledRationalFunctionSpace>( this * other.numerator, other.denominator ) - // endregion - // region Rational-polynomial relation /** * Returns sum of the polynomial represented as rational function and the rational function. */ @@ -267,9 +249,7 @@ public class LabeledRationalFunctionSpace>( numerator * other, denominator ) - // endregion - // region Rational-rational relation /** * Returns negation of the rational function. */ @@ -329,9 +309,7 @@ public class LabeledRationalFunctionSpace>( return numerator * other.denominator equalsTo other.numerator * denominator } - // endregion - // region Polynomial properties /** * Map that associates variables (that appear in the polynomial in positive exponents) with their most exponents * in which they are appeared in the polynomial. @@ -348,9 +326,7 @@ public class LabeledRationalFunctionSpace>( * Count of all variables that appear in the polynomial in positive exponents. */ public val LabeledPolynomial.countOfVariables: Int get() = polynomialRing { countOfVariables } - // endregion - // region Rational properties /** * Count of all variables that appear in the polynomial in positive exponents. */ @@ -360,9 +336,8 @@ public class LabeledRationalFunctionSpace>( * Count of all variables that appear in the polynomial in positive exponents. */ public val LabeledRationalFunction.countOfVariables: Int get() = variables.size - // endregion - // region REST TODO: Разобрать + // TODO: Разобрать public operator fun LabeledRationalFunction.div(other: LabeledRationalFunction): LabeledRationalFunction = LabeledRationalFunction( diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt index a1033fcc4..fe6bb597d 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -47,8 +47,6 @@ internal constructor( override fun toString(): String = "NumberedPolynomial$coefficients" } -// region Internal utilities - /** * Represents internal [Polynomial] errors. */ @@ -69,10 +67,6 @@ internal fun numberedPolynomialError(message: Any): Nothing = throw PolynomialEr */ internal fun List.cleanUp() = subList(0, indexOfLast { it != 0U } + 1) -// endregion - -// region Constructors and converters - //context(NumberedPolynomialSpace>) //@Suppress("FunctionName") //internal fun NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean = false) : NumberedPolynomial { @@ -124,8 +118,6 @@ internal fun List.cleanUp() = subList(0, indexOfLast { it != 0U } + 1) public fun C.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomial(mapOf(emptyList() to this)) -// endregion - /** * Space of polynomials. * @@ -136,7 +128,6 @@ public fun C.asNumberedPolynomial() : NumberedPolynomial = NumberedPolyno public open class NumberedPolynomialSpace>( public final override val ring: A, ) : AbstractPolynomialSpaceOverRing, A> { - // region Polynomial-integer relation /** * Returns sum of the polynomial and the integer represented as polynomial. * @@ -190,9 +181,7 @@ public open class NumberedPolynomialSpace>( mapValues { (_, c) -> c * other } } ) - // endregion - // region Integer-polynomial relation /** * Returns sum of the integer represented as polynomial and the polynomial. * @@ -246,9 +235,7 @@ public open class NumberedPolynomialSpace>( mapValues { (_, c) -> this@times * c } } ) - // endregion - // region Constant-polynomial relation /** * Returns sum of the constant represented as polynomial and the polynomial. */ @@ -300,9 +287,7 @@ public open class NumberedPolynomialSpace>( mapValues { (_, c) -> this@times * c } } ) - // endregion - // region Polynomial-constant relation /** * Returns sum of the constant represented as polynomial and the polynomial. */ @@ -352,9 +337,7 @@ public open class NumberedPolynomialSpace>( mapValues { (_, c) -> c * other } } ) - // endregion - // region Polynomial-polynomial relation /** * Returns negation of the polynomial. */ @@ -463,10 +446,7 @@ public open class NumberedPolynomialSpace>( else -> coefficients.size == other.coefficients.size && coefficients.all { (key, value) -> with(other.coefficients) { key in this && this[key] == value } } } - // endregion - // Not sure is it necessary... - // region Polynomial properties // TODO: Replace `countOfVariables` with `lastVariable` and create new `countOfVariables` /** * Count of all variables that appear in the polynomial in positive exponents. @@ -545,10 +525,8 @@ public open class NumberedPolynomialSpace>( @Suppress("NOTHING_TO_INLINE") @JvmName("invokePolynomial") public inline operator fun NumberedPolynomial.invoke(argument: Map>): NumberedPolynomial = this.substitute(ring, argument) - // endregion - // region Utilities - // TODO: Move to region internal utilities with context receiver + // TODO: Move to other internal utilities with context receiver @JvmName("applyAndRemoveZerosInternal") internal fun MutableMap, C>.applyAndRemoveZeros(block: MutableMap, C>.() -> Unit) : MutableMap, C> { contract { @@ -576,9 +554,6 @@ public open class NumberedPolynomialSpace>( for ((degs, c) in this) if (c.isZero()) this.remove(degs) } } - // endregion - - // region Constructors and converters @Suppress("FunctionName") internal fun NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean = false) : NumberedPolynomial { @@ -622,6 +597,4 @@ public open class NumberedPolynomialSpace>( @Suppress("FunctionName") public fun NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(pairs.toList(), toCheckInput = true) - - // endregion } \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt index a81795c81..745df10e8 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt @@ -16,8 +16,6 @@ public class NumberedRationalFunction internal constructor( override fun toString(): String = "NumberedRationalFunction${numerator.coefficients}/${denominator.coefficients}" } -// region Internal utilities - /** * Represents internal [NumberedRationalFunction] errors. */ @@ -33,9 +31,6 @@ internal class NumberedRationalFunctionError : Error { */ internal fun numberedRationalFunctionError(message: Any): Nothing = throw NumberedRationalFunctionError(message.toString()) -// endregion - -// region Constructors and converters // Waiting for context receivers :( TODO: Replace with context receivers when they will be available //context(RationalFunctionSpace) @@ -78,8 +73,6 @@ internal fun numberedRationalFunctionError(message: Any): Nothing = throw Number //Polynomial(numeratorCoefficients) //) -// endregion - public class NumberedRationalFunctionSpace> ( public val ring: A, ) : AbstractRationalFunctionalSpaceOverPolynomialSpace< @@ -91,7 +84,6 @@ public class NumberedRationalFunctionSpace> ( override val polynomialRing : NumberedPolynomialSpace = NumberedPolynomialSpace(ring) - // region Rational-integer relation /** * Returns sum of the rational function and the integer represented as rational function. * @@ -122,9 +114,7 @@ public class NumberedRationalFunctionSpace> ( numerator * other, denominator ) - // endregion - // region Integer-Rational relation /** * Returns sum of the integer represented as rational function and the rational function. * @@ -155,9 +145,7 @@ public class NumberedRationalFunctionSpace> ( this * other.numerator, other.denominator ) - // endregion - // region Constant-rational relation /** * Returns sum of the constant represented as rational function and the rational function. */ @@ -182,9 +170,7 @@ public class NumberedRationalFunctionSpace> ( this * other.numerator, other.denominator ) - // endregion - // region Rational-constant relation /** * Returns sum of the constant represented as rational function and the rational function. */ @@ -209,9 +195,7 @@ public class NumberedRationalFunctionSpace> ( numerator * other, denominator ) - // endregion - // region Polynomial-rational relation /** * Returns sum of the polynomial represented as rational function and the rational function. */ @@ -236,9 +220,7 @@ public class NumberedRationalFunctionSpace> ( this * other.numerator, other.denominator ) - // endregion - // region Rational-polynomial relation /** * Returns sum of the polynomial represented as rational function and the rational function. */ @@ -263,9 +245,7 @@ public class NumberedRationalFunctionSpace> ( numerator * other, denominator ) - // endregion - // region Rational-rational relation /** * Returns negation of the rational function. */ @@ -325,9 +305,7 @@ public class NumberedRationalFunctionSpace> ( return numerator * other.denominator equalsTo other.numerator * denominator } - // endregion - // region Polynomial properties /** * Count of all variables that appear in the polynomial in positive exponents. */ @@ -340,17 +318,14 @@ public class NumberedRationalFunctionSpace> ( * And size of the list is [countOfVariables]. */ public val NumberedPolynomial.degrees: List get() = polynomialRing { degrees } - // endregion - // region Rational properties /** * Count of all variables that appear in the polynomial in positive exponents. */ public val NumberedRationalFunction.countOfVariables: Int get() = polynomialRing { max(numerator.countOfVariables, denominator.countOfVariables) } - // endregion - // region REST TODO: Разобрать + // TODO: Разобрать public operator fun NumberedRationalFunction.div(other: NumberedRationalFunction): NumberedRationalFunction = NumberedRationalFunction( 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 2f7976da6..3f3838f53 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 @@ -91,7 +91,6 @@ public fun C.asPolynomial() : Polynomial = Polynomial(listOf(this)) * @param A type of underlying ring of constants. It's [Ring] of [C]. * @param ring underlying ring of constants of type [A]. */ -//@Suppress("INAPPLICABLE_JVM_NAME") // TODO: KT-31420 public open class PolynomialSpace>( public override val ring: A, ) : AbstractPolynomialSpaceOverRing, A> { diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt index 441136a64..5ff3edd2e 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt @@ -18,8 +18,6 @@ public data class RationalFunction internal constructor ( override fun toString(): String = "RationalFunction${numerator.coefficients}/${denominator.coefficients}" } -// region Internal utilities - /** * Represents internal [RationalFunction] errors. */ @@ -35,9 +33,6 @@ internal class RationalFunctionError : Error { */ internal fun rationalFunctionError(message: Any): Nothing = throw RationalFunctionError(message.toString()) -// endregion - -// region Constructors and converters // Waiting for context receivers :( TODO: Replace with context receivers when they will be available //context(RationalFunctionSpace) @@ -63,8 +58,6 @@ internal fun rationalFunctionError(message: Any): Nothing = throw RationalFuncti // Polynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ) // ) -// endregion - public class RationalFunctionSpace> ( public val ring: A, ) : AbstractRationalFunctionalSpaceOverPolynomialSpace< @@ -76,7 +69,6 @@ public class RationalFunctionSpace> ( override val polynomialRing : PolynomialSpace = PolynomialSpace(ring) - // region Rational-integer relation /** * Returns sum of the rational function and the integer represented as rational function. * @@ -107,9 +99,7 @@ public class RationalFunctionSpace> ( numerator * other, denominator ) - // endregion - // region Integer-Rational relation /** * Returns sum of the integer represented as rational function and the rational function. * @@ -140,9 +130,7 @@ public class RationalFunctionSpace> ( this * other.numerator, other.denominator ) - // endregion - // region Constant-rational relation /** * Returns sum of the constant represented as rational function and the rational function. */ @@ -167,9 +155,7 @@ public class RationalFunctionSpace> ( this * other.numerator, other.denominator ) - // endregion - // region Rational-constant relation /** * Returns sum of the constant represented as rational function and the rational function. */ @@ -194,9 +180,7 @@ public class RationalFunctionSpace> ( numerator * other, denominator ) - // endregion - // region Polynomial-rational relation /** * Returns sum of the polynomial represented as rational function and the rational function. */ @@ -221,9 +205,7 @@ public class RationalFunctionSpace> ( this * other.numerator, other.denominator ) - // endregion - // region Rational-polynomial relation /** * Returns sum of the polynomial represented as rational function and the rational function. */ @@ -248,9 +230,7 @@ public class RationalFunctionSpace> ( numerator * other, denominator ) - // endregion - // region Rational-rational relation /** * Returns negation of the rational function. */ @@ -298,9 +278,8 @@ public class RationalFunctionSpace> ( numeratorDegree - denominatorDegree != with(other) { numeratorDegree - denominatorDegree } -> false else -> numerator * other.denominator equalsTo other.numerator * denominator } - // endregion - // region REST TODO: Разобрать + // TODO: Разобрать public operator fun RationalFunction.div(other: RationalFunction): RationalFunction = RationalFunction( @@ -383,5 +362,4 @@ public class RationalFunctionSpace> ( // numerator.removeZeros(), // denominator.removeZeros() // ) - // endregion } \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt index 516e76b8f..19417d767 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt @@ -17,10 +17,6 @@ import kotlin.contracts.contract // TODO: Docs -// region Sort of legacy - -//// region Constants -// //// TODO: Reuse underlying ring extensions // //context(LabeledPolynomialSpace) @@ -33,9 +29,7 @@ import kotlin.contracts.contract //context(LabeledPolynomialSpace) //fun > multiplyWithPower(base: C, arg: C, pow: UInt): C = ring { multiplyWithPower(base, arg, pow) } // -//// endregion -//// region Symbols // //context(LabeledPolynomialSpace) //fun > power(arg: Symbol, pow: UInt): LabeledPolynomial = @@ -44,9 +38,7 @@ import kotlin.contracts.contract // mapOf(arg to pow) to constantOne // )) // -//// endregion -//// region Polynomials // //context(LabeledPolynomialSpace) //fun > number(value: Int): LabeledPolynomial = ring { LabeledPolynomial(mapOf(emptyMap() to number(value))) } @@ -71,11 +63,6 @@ import kotlin.contracts.contract // else -> error("Error in raising ring instant by unsigned integer: got reminder by division by 2 different from 0 and 1") // } // -//// endregion - -// endregion - -// region Utilities /** * Crates a [LabeledPolynomialSpace] over received ring. @@ -92,10 +79,6 @@ public inline fun , R> A.labeledPolynomial(block: LabeledPolynomi return LabeledPolynomialSpace(this).block() } -// endregion - -//// region String representations -// ///** // * Represents the polynomial as a [String] with names of variables substituted with names from [names]. // * Consider that monomials are sorted in lexicographic order. @@ -261,13 +244,7 @@ public inline fun , R> A.labeledPolynomial(block: LabeledPolynomi //context(LabeledPolynomialSpace) //fun > LabeledPolynomial.representReversedWithBrackets(namer: (Symbol) -> String): String = // with(representReversed(namer)) { if (coefficients.count() == 1) this else "($this)" } -// -//// endregion -// region Operator extensions - -//// region Field case -// //operator fun > Polynomial.div(other: T): Polynomial = // if (other.isZero()) throw ArithmeticException("/ by zero") // else @@ -276,13 +253,7 @@ public inline fun , R> A.labeledPolynomial(block: LabeledPolynomi // .mapValues { it.value / other }, // toCheckInput = false // ) -// -//// endregion -// endregion - -//// region Polynomial substitution and functional representation -// //public fun LabeledPolynomial.substitute(ring: Ring, args: Map): LabeledPolynomial = ring { // if (coefficients.isEmpty()) return this@substitute // LabeledPolynomial( @@ -324,10 +295,6 @@ public inline fun , R> A.labeledPolynomial(block: LabeledPolynomi // //fun > LabeledPolynomial.asPolynomialFunctionOver(ring: A): (Map>) -> LabeledPolynomial = // { substitute(ring, it) } -// -//// endregion - -// region Algebraic derivative and antiderivative /** * Returns algebraic derivative of received polynomial. @@ -572,6 +539,4 @@ public fun > LabeledPolynomial.nthAntiderivativeWithRespectTo } } ) -} - -// endregion \ No newline at end of file +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt index 575dfed48..61f443871 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt @@ -6,18 +6,10 @@ package space.kscience.kmath.functions -//// region Operator extensions -// -//// region Field case -// //fun > LabeledRationalFunction.reduced(): LabeledRationalFunction { // val greatestCommonDivider = polynomialGCD(numerator, denominator) // return LabeledRationalFunction( // numerator / greatestCommonDivider, // denominator / greatestCommonDivider // ) -//} -// -//// endregion -// -//// endregion \ No newline at end of file +//} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt index ac411fc28..b2778343d 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt @@ -9,10 +9,6 @@ import kotlin.math.max // TODO: Docs -// region Sort of legacy - -//// region Constants -// //// TODO: Reuse underlying ring extensions // //context(NumberedPolynomialSpace) @@ -21,11 +17,7 @@ import kotlin.math.max // //context(NumberedPolynomialSpace) //public fun > multiplyWithPower(base: C, arg: C, pow: UInt): C = ring { multiplyWithPower(base, arg, pow) } -// -//// endregion -//// region Polynomials -// //context(NumberedPolynomialSpace) //public fun > number(value: Int): NumberedPolynomial = ring { NumberedPolynomial(mapOf(emptyList() to number(value))) } // @@ -48,12 +40,6 @@ import kotlin.math.max // exponent % 2U == 1U -> multiplyWithPowerInternalLogic(base * arg, arg * arg, exponent / 2U) // else -> error("Error in raising ring instant by unsigned integer: got reminder by division by 2 different from 0 and 1") // } -// -//// endregion - -// endregion - -// region Utilities /** * Crates a [NumberedPolynomialSpace] over received ring. @@ -70,10 +56,6 @@ public inline fun , R> A.numberedPolynomial(block: NumberedPolyno return NumberedPolynomialSpace(this).block() } -// endregion - -//// region String representations -// ///** // * Represents the polynomial as a [String] where name of variable with index `i` is [withVariableName] + `"_${i+1}"`. // * Consider that monomials are sorted in lexicographic order. @@ -237,11 +219,7 @@ public inline fun , R> A.numberedPolynomial(block: NumberedPolyno //context(NumberedPolynomialSpace) //public fun > NumberedPolynomial.representReversedWithBrackets(namer: (Int) -> String): String = // with(representReversed(namer)) { if (coefficients.count() == 1) this else "($this)" } -// -//// endregion -//// region Polynomial substitution and functional representation -// //public fun NumberedPolynomial.substitute(ring: Ring, args: Map): NumberedPolynomial = ring { // if (coefficients.isEmpty()) return this@substitute // NumberedPolynomial( @@ -283,13 +261,7 @@ public inline fun , R> A.numberedPolynomial(block: NumberedPolyno // //public fun > NumberedPolynomial.asPolynomialFunctionOver(ring: A): (Map>) -> NumberedPolynomial = // { substitute(ring, it) } -// -//// endregion -// region Operator extensions - -//// region Field case -// //operator fun > Polynomial.div(other: T): Polynomial = // if (other.isZero()) throw ArithmeticException("/ by zero") // else @@ -298,12 +270,6 @@ public inline fun , R> A.numberedPolynomial(block: NumberedPolyno // .mapValues { it.value / other }, // toCheckInput = false // ) -// -//// endregion - -// endregion - -// region Polynomial substitution and functional representation // TODO: May be apply Horner's method too? /** @@ -368,10 +334,6 @@ public fun > NumberedPolynomial.asFunction(ring: A): (Map> NumberedPolynomial.asPolynomialFunctionOver(ring: A): (Map>) -> NumberedPolynomial = { substitute(ring, it) } -// endregion - -// region Algebraic derivative and antiderivative - /** * Returns algebraic derivative of received polynomial. */ @@ -596,6 +558,4 @@ public fun > NumberedPolynomial.nthAntiderivativeWithRespectT } } ) -} - -// endregion \ No newline at end of file +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt index 7c8120c68..035e201f7 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt @@ -6,18 +6,10 @@ package space.kscience.kmath.functions -//// region Operator extensions -// -//// region Field case -// //fun > NumberedRationalFunction.reduced(): NumberedRationalFunction { // val greatestCommonDivider = polynomialGCD(numerator, denominator) // return NumberedRationalFunction( // numerator / greatestCommonDivider, // denominator / greatestCommonDivider // ) -//} -// -//// endregion -// -//// endregion \ No newline at end of file +//} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt index 2d0377d2c..e6d6b1ae6 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt @@ -14,8 +14,6 @@ import kotlin.math.min import kotlin.math.pow -// region Utilities - /** * Removes zeros on the end of the coefficient list of polynomial. */ @@ -51,10 +49,6 @@ public inline fun A.scalablePolynomial(block: ScalablePolynomialSpace< return ScalablePolynomialSpace(this).block() } -// endregion - -// region Polynomial substitution and functional representation - // TODO: May be apply Horner's method too? /** * Evaluates the value of the given double polynomial for given double argument. @@ -116,10 +110,6 @@ public fun > Polynomial.asFunction(ring: A): (C) -> C = { subs */ public fun > Polynomial.asPolynomialFunctionOver(ring: A): (Polynomial) -> Polynomial = { substitute(ring, it) } -// endregion - -// region Algebraic derivative and antiderivative - /** * Returns algebraic derivative of received polynomial. */ @@ -180,6 +170,4 @@ public fun > Polynomial.integrate( ): C = algebra { val integral = antiderivative(algebra) integral.substitute(algebra, range.endInclusive) - integral.substitute(algebra, range.start) -} - -// endregion \ No newline at end of file +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/rationalFunctionUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/rationalFunctionUtil.kt index d5bbc3b82..359c781b5 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/rationalFunctionUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/rationalFunctionUtil.kt @@ -6,10 +6,6 @@ package space.kscience.kmath.functions -// region Operator extensions - -// region Field case - //operator fun > RationalFunction.invoke(arg: T): T = numerator(arg) / denominator(arg) // //fun > RationalFunction.reduced(): RationalFunction = @@ -20,11 +16,6 @@ package space.kscience.kmath.functions // ) // } -// endregion - -// endregion - -// region Derivatives ///** // * Returns result of applying formal derivative to the polynomial. // * @@ -35,5 +26,4 @@ package space.kscience.kmath.functions // RationalFunction( // numerator.derivative() * denominator - denominator.derivative() * numerator, // denominator * denominator -// ) -// endregion \ No newline at end of file +// ) \ No newline at end of file -- 2.34.1 From 75fd9207352c2cdbd4ad4de1275a0f8639f83f76 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Wed, 16 Mar 2022 23:22:51 +0300 Subject: [PATCH 027/123] Deleted suddenly missed region marks and unused error classes --- .../kmath/functions/LabeledPolynomial.kt | 15 -------- .../functions/LabeledRationalFunction.kt | 15 -------- .../kmath/functions/NumberedPolynomial.kt | 17 +-------- .../functions/NumberedRationalFunction.kt | 15 -------- .../kscience/kmath/functions/Polynomial.kt | 37 ------------------- .../kmath/functions/RationalFunction.kt | 15 -------- 6 files changed, 1 insertion(+), 113 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt index f4dd74b94..d263b7102 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt @@ -48,21 +48,6 @@ internal constructor( override fun toString(): String = "LabeledPolynomial$coefficients" } -/** - * Represents internal [LabeledPolynomial] errors. - */ -internal class LabeledPolynomialError: Error { - constructor(): super() - constructor(message: String): super(message) - constructor(message: String?, cause: Throwable?): super(message, cause) - constructor(cause: Throwable?): super(cause) -} - -/** - * Throws an [LabeledPolynomialError] with the given [message]. - */ -internal fun labeledPolynomialError(message: Any): Nothing = throw LabeledPolynomialError(message.toString()) - /** * Returns the same degrees description of the monomial, but without zero degrees. */ diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt index 3908933e6..9b5022f85 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt @@ -17,21 +17,6 @@ public class LabeledRationalFunction( override fun toString(): String = "LabeledRationalFunction${numerator.coefficients}/${denominator.coefficients}" } -/** - * Represents internal [LabeledRationalFunction] errors. - */ -internal class LabeledRationalFunctionError : Error { - constructor(): super() - constructor(message: String): super(message) - constructor(message: String?, cause: Throwable?): super(message, cause) - constructor(cause: Throwable?): super(cause) -} - -/** - * Throws an [LabeledRationalFunctionError] with the given [message]. - */ -internal fun labeledRationalFunctionError(message: Any): Nothing = throw LabeledRationalFunctionError(message.toString()) - // Waiting for context receivers :( TODO: Replace with context receivers when they will be available //context(RationalFunctionSpace) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt index fe6bb597d..307b78f29 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -48,22 +48,7 @@ internal constructor( } /** - * Represents internal [Polynomial] errors. - */ -internal class NumberedPolynomialError : Error { - constructor(): super() - constructor(message: String): super(message) - constructor(message: String?, cause: Throwable?): super(message, cause) - constructor(cause: Throwable?): super(cause) -} - -/** - * Throws an [PolynomialError] with the given [message]. - */ -internal fun numberedPolynomialError(message: Any): Nothing = throw PolynomialError(message.toString()) - -/** - * Returns the same degrees description of the monomial, but without extra zero degrees on the end. + * Returns the same degrees' description of the monomial, but without extra zero degrees on the end. */ internal fun List.cleanUp() = subList(0, indexOfLast { it != 0U } + 1) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt index 745df10e8..8e3b3b1c5 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt @@ -16,21 +16,6 @@ public class NumberedRationalFunction internal constructor( override fun toString(): String = "NumberedRationalFunction${numerator.coefficients}/${denominator.coefficients}" } -/** - * Represents internal [NumberedRationalFunction] errors. - */ -internal class NumberedRationalFunctionError : Error { - constructor(): super() - constructor(message: String): super(message) - constructor(message: String?, cause: Throwable?): super(message, cause) - constructor(cause: Throwable?): super(cause) -} - -/** - * Throws an [NumberedRationalFunctionError] with the given [message]. - */ -internal fun numberedRationalFunctionError(message: Any): Nothing = throw NumberedRationalFunctionError(message.toString()) - // Waiting for context receivers :( TODO: Replace with context receivers when they will be available //context(RationalFunctionSpace) 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 3f3838f53..c6f649fe8 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 @@ -43,27 +43,6 @@ public data class Polynomial( override fun toString(): String = "Polynomial$coefficients" } -// region Internal utilities - -/** - * Represents internal [Polynomial] errors. - */ -internal class PolynomialError : Error { - constructor(): super() - constructor(message: String): super(message) - constructor(message: String?, cause: Throwable?): super(message, cause) - constructor(cause: Throwable?): super(cause) -} - -/** - * Throws an [PolynomialError] with the given [message]. - */ -internal fun polynomialError(message: Any): Nothing = throw PolynomialError(message.toString()) - -// endregion - -// region Constructors and converters - /** * Returns a [Polynomial] instance with given [coefficients]. The collection of coefficients will be reversed if * [reverse] parameter is true. @@ -82,8 +61,6 @@ public fun Polynomial(vararg coefficients: C, reverse: Boolean = false): Pol public fun C.asPolynomial() : Polynomial = Polynomial(listOf(this)) -// endregion - /** * Space of univariate polynomials constructed over ring. * @@ -94,8 +71,6 @@ public fun C.asPolynomial() : Polynomial = Polynomial(listOf(this)) public open class PolynomialSpace>( public override val ring: A, ) : AbstractPolynomialSpaceOverRing, A> { - - // region Polynomial-integer relation /** * Returns sum of the polynomial and the integer represented as polynomial. * @@ -152,9 +127,7 @@ public open class PolynomialSpace>( .subList(0, degree + 1) .map { it * other } ) - // endregion - // region Integer-polynomial relation /** * Returns sum of the integer represented as polynomial and the polynomial. * @@ -213,9 +186,7 @@ public open class PolynomialSpace>( .subList(0, other.degree + 1) .map { it * this } ) - // endregion - // region Constant-polynomial relation /** * Returns sum of the constant represented as polynomial and the polynomial. */ @@ -270,9 +241,7 @@ public open class PolynomialSpace>( .subList(0, other.degree + 1) .map { it * this } ) - // endregion - // region Polynomial-constant relation /** * Returns sum of the constant represented as polynomial and the polynomial. */ @@ -325,9 +294,7 @@ public open class PolynomialSpace>( .subList(0, degree + 1) .map { it * other } ) - // endregion - // region Polynomial-polynomial relation /** * Returns negation of the polynomial. */ @@ -425,9 +392,7 @@ public open class PolynomialSpace>( else false } } - // endregion - // region Polynomial properties /** * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is * zero, degree is -1. @@ -466,8 +431,6 @@ public open class PolynomialSpace>( public inline operator fun Polynomial.invoke(argument: C): C = this.substitute(ring, argument) @Suppress("NOTHING_TO_INLINE") public inline operator fun Polynomial.invoke(argument: Polynomial): Polynomial = this.substitute(ring, argument) - - // endregion } /** diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt index 5ff3edd2e..f4ae64e81 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt @@ -18,21 +18,6 @@ public data class RationalFunction internal constructor ( override fun toString(): String = "RationalFunction${numerator.coefficients}/${denominator.coefficients}" } -/** - * Represents internal [RationalFunction] errors. - */ -internal class RationalFunctionError : Error { - constructor(): super() - constructor(message: String): super(message) - constructor(message: String?, cause: Throwable?): super(message, cause) - constructor(cause: Throwable?): super(cause) -} - -/** - * Throws an [RationalFunction] with the given [message]. - */ -internal fun rationalFunctionError(message: Any): Nothing = throw RationalFunctionError(message.toString()) - // Waiting for context receivers :( TODO: Replace with context receivers when they will be available //context(RationalFunctionSpace) -- 2.34.1 From 2082175af5e9e811d3a6dfa3079a7dcb2d25a2fe Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Wed, 16 Mar 2022 23:31:07 +0300 Subject: [PATCH 028/123] Fixed typos. --- .../kmath/functions/LabeledPolynomial.kt | 2 +- .../space/kscience/kmath/functions/Polynomial.kt | 2 +- .../kscience/kmath/functions/RationalFunction.kt | 5 +---- .../kmath/functions/labeledPolynomialUtil.kt | 4 ++-- .../kmath/functions/numberedPolynomialUtil.kt | 16 ++++++++-------- .../kscience/kmath/functions/polynomialUtil.kt | 8 ++++---- 6 files changed, 17 insertions(+), 20 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt index d263b7102..369c7078a 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt @@ -49,7 +49,7 @@ internal constructor( } /** - * Returns the same degrees description of the monomial, but without zero degrees. + * Returns the same degrees' description of the monomial, but without zero degrees. */ internal fun Map.cleanUp() = filterValues { it > 0U } 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 c6f649fe8..220bde8ff 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 @@ -425,7 +425,7 @@ public open class PolynomialSpace>( public inline fun Polynomial.asFunctionOnPolynomials(): (Polynomial) -> Polynomial = { this.substitute(ring, it) } /** - * Evaluates the polynomial for the given value [arg]. + * Evaluates the polynomial for the given value [argument]. */ @Suppress("NOTHING_TO_INLINE") public inline operator fun Polynomial.invoke(argument: C): C = this.substitute(ring, argument) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt index f4ae64e81..226eddce9 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt @@ -5,10 +5,7 @@ package space.kscience.kmath.functions -import space.kscience.kmath.operations.* -import kotlin.jvm.JvmName -import kotlin.math.max -import kotlin.math.min +import space.kscience.kmath.operations.Ring public data class RationalFunction internal constructor ( diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt index 19417d767..27fdd7d7b 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt @@ -65,13 +65,13 @@ import kotlin.contracts.contract // /** - * Crates a [LabeledPolynomialSpace] over received ring. + * Creates a [LabeledPolynomialSpace] over a received ring. */ public fun > A.labeledPolynomial(): LabeledPolynomialSpace = LabeledPolynomialSpace(this) /** - * Crates a [LabeledPolynomialSpace]'s scope over received ring. + * Creates a [LabeledPolynomialSpace]'s scope over a received ring. */ @OptIn(ExperimentalContracts::class) public inline fun , R> A.labeledPolynomial(block: LabeledPolynomialSpace.() -> R): R { diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt index b2778343d..d544ca93c 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt @@ -42,13 +42,13 @@ import kotlin.math.max // } /** - * Crates a [NumberedPolynomialSpace] over received ring. + * Creates a [NumberedPolynomialSpace] over a received ring. */ public fun > A.numberedPolynomial(): NumberedPolynomialSpace = NumberedPolynomialSpace(this) /** - * Crates a [NumberedPolynomialSpace]'s scope over received ring. + * Creates a [NumberedPolynomialSpace]'s scope over a received ring. */ @OptIn(ExperimentalContracts::class) public inline fun , R> A.numberedPolynomial(block: NumberedPolynomialSpace.() -> R): R { @@ -279,9 +279,9 @@ public fun NumberedPolynomial.substitute(args: Map): Number val acc = LinkedHashMap, Double>(coefficients.size) for ((degs, c) in coefficients) { val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp() - val newC = args.entries.fold(c) { product, (variable, substitutor) -> + val newC = args.entries.fold(c) { product, (variable, substitution) -> val deg = degs.getOrElse(variable) { 0u } - if (deg == 0u) product else product * substitutor.pow(deg.toInt()) + if (deg == 0u) product else product * substitution.pow(deg.toInt()) } if (newDegs !in acc) acc[newDegs] = newC else acc[newDegs] = acc[newDegs]!! + newC @@ -298,9 +298,9 @@ public fun NumberedPolynomial.substitute(ring: Ring, args: Map val acc = LinkedHashMap, C>(coefficients.size) for ((degs, c) in coefficients) { val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp() - val newC = args.entries.fold(c) { product, (variable, substitutor) -> + val newC = args.entries.fold(c) { product, (variable, substitution) -> val deg = degs.getOrElse(variable) { 0u } - if (deg == 0u) product else product * power(substitutor, deg) + if (deg == 0u) product else product * power(substitution, deg) } if (newDegs !in acc) acc[newDegs] = newC else acc[newDegs] = acc[newDegs]!! + newC @@ -315,9 +315,9 @@ public fun NumberedPolynomial.substitute(ring: Ring, args: Map, NumberedPolynomial>(coefficients.size) for ((degs, c) in coefficients) { val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp() - val newC = args.entries.fold(c.asNumberedPolynomial()) { product, (variable, substitutor) -> + val newC = args.entries.fold(c.asNumberedPolynomial()) { product, (variable, substitution) -> val deg = degs.getOrElse(variable) { 0u } - if (deg == 0u) product else product * power(substitutor, deg) + if (deg == 0u) product else product * power(substitution, deg) } if (newDegs !in acc) acc[newDegs] = c.asNumberedPolynomial() else acc[newDegs] = acc[newDegs]!! + c diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt index e6d6b1ae6..a0c11b0a8 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt @@ -22,13 +22,13 @@ import kotlin.math.pow // if (degree > -1) Polynomial(coefficients.subList(0, degree + 1)) else zero /** - * Crates a [PolynomialSpace] over received ring. + * Creates a [PolynomialSpace] over a received ring. */ public fun > A.polynomial(): PolynomialSpace = PolynomialSpace(this) /** - * Crates a [PolynomialSpace]'s scope over received ring. + * Creates a [PolynomialSpace]'s scope over a received ring. */ public inline fun , R> A.polynomial(block: PolynomialSpace.() -> R): R { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } @@ -36,13 +36,13 @@ public inline fun , R> A.polynomial(block: PolynomialSpace. } /** - * Crates a [ScalablePolynomialSpace] over received scalable ring. + * Creates a [ScalablePolynomialSpace] over a received scalable ring. */ public fun A.scalablePolynomial(): ScalablePolynomialSpace where A : Ring, A : ScaleOperations = ScalablePolynomialSpace(this) /** - * Crates a [ScalablePolynomialSpace]'s scope over received scalable ring. + * Creates a [ScalablePolynomialSpace]'s scope over a received scalable ring. */ public inline fun A.scalablePolynomial(block: ScalablePolynomialSpace.() -> R): R where A : Ring, A : ScaleOperations { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } -- 2.34.1 From e5186d469a68cf6284e7e1151cad184b33e25821 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Thu, 17 Mar 2022 02:12:40 +0300 Subject: [PATCH 029/123] Fixed issue with confusing `countOfVariables` in `Numbered...` --- .../kmath/functions/NumberedPolynomial.kt | 26 ++++++++++---- .../functions/NumberedRationalFunction.kt | 34 ++++++++++++++++--- 2 files changed, 48 insertions(+), 12 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt index 307b78f29..37c0c96f0 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -432,12 +432,12 @@ public open class NumberedPolynomialSpace>( coefficients.all { (key, value) -> with(other.coefficients) { key in this && this[key] == value } } } - // TODO: Replace `countOfVariables` with `lastVariable` and create new `countOfVariables` /** - * Count of all variables that appear in the polynomial in positive exponents. + * Maximal index (ID) of variable occurring in the polynomial with positive power. If there is no such variable, + * the result is `-1`. */ - public val NumberedPolynomial.countOfVariables: Int - get() = coefficients.entries.maxOfOrNull { (degs, c) -> if (c.isZero()) 0 else degs.size } ?: 0 + public val NumberedPolynomial.lastVariable: Int + get() = coefficients.entries.maxOfOrNull { (degs, c) -> if (c.isZero()) -1 else degs.lastIndex } ?: -1 /** * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is * zero, degree is -1. @@ -449,18 +449,30 @@ public open class NumberedPolynomialSpace>( * exponents in which the variables are appeared in the polynomial. * * As consequence all values in the list are non-negative integers. Also, if the polynomial is constant, the list is empty. - * And size of the list is [countOfVariables]. + * And last index of the list is [lastVariable]. */ public val NumberedPolynomial.degrees: List get() = - buildList(countOfVariables) { - repeat(countOfVariables) { add(0U) } + MutableList(lastVariable + 1) { 0u }.apply { coefficients.entries.forEach { (degs, c) -> if (c.isNotZero()) degs.forEachIndexed { index, deg -> this[index] = max(this[index], deg) } } } + /** + * Count of variables occurring in the polynomial with positive power. If there is no such variable, + * the result is `0`. + */ + public val NumberedPolynomial.countOfVariables: Int + get() = + MutableList(lastVariable + 1) { false }.apply { + coefficients.entries.forEach { (degs, c) -> + if (c.isNotZero()) degs.forEachIndexed { index, deg -> + if (deg != 0u) this[index] = true + } + } + }.count { it } /** * Checks if the instant is constant polynomial (of degree no more than 0) over considered ring. diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt index 8e3b3b1c5..6542bc89b 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt @@ -277,12 +277,12 @@ public class NumberedRationalFunctionSpace> ( if ( !(numerator.isZero() xor other.numerator.isZero()) ) return false - val countOfVariables = max(this.countOfVariables, other.countOfVariables) + val countOfVariables = max(this.lastVariable, other.lastVariable) val thisNumeratorDegrees = this.numerator.degrees val thisDenominatorDegrees = this.denominator.degrees val otherNumeratorDegrees = other.numerator.degrees val otherDenominatorDegrees = other.denominator.degrees - for (variable in 0 until countOfVariables) + for (variable in 0 .. countOfVariables) if ( thisNumeratorDegrees.getOrElse(variable) { 0u } + otherDenominatorDegrees.getOrElse(variable) { 0u } != thisDenominatorDegrees.getOrElse(variable) { 0u } + otherNumeratorDegrees.getOrElse(variable) { 0u } @@ -292,9 +292,10 @@ public class NumberedRationalFunctionSpace> ( } /** - * Count of all variables that appear in the polynomial in positive exponents. + * Maximal index (ID) of variable occurring in the polynomial with positive power. If there is no such variable, + * the result is `-1`. */ - public val NumberedPolynomial.countOfVariables: Int get() = polynomialRing { countOfVariables } + public val NumberedPolynomial.lastVariable: Int get() = polynomialRing { lastVariable } /** * List that associates indices of variables (that appear in the polynomial in positive exponents) with their most * exponents in which the variables are appeared in the polynomial. @@ -303,12 +304,35 @@ public class NumberedRationalFunctionSpace> ( * And size of the list is [countOfVariables]. */ public val NumberedPolynomial.degrees: List get() = polynomialRing { degrees } + /** + * Count of variables occurring in the polynomial with positive power. If there is no such variable, + * the result is `0`. + */ + public val NumberedPolynomial.countOfVariables: Int get() = polynomialRing { countOfVariables } /** * Count of all variables that appear in the polynomial in positive exponents. */ + public val NumberedRationalFunction.lastVariable: Int + get() = polynomialRing { max(numerator.lastVariable, denominator.lastVariable) } + /** + * Count of variables occurring in the rational function with positive power. If there is no such variable, + * the result is `0`. + */ public val NumberedRationalFunction.countOfVariables: Int - get() = polynomialRing { max(numerator.countOfVariables, denominator.countOfVariables) } + get() = + MutableList(lastVariable + 1) { false }.apply { + numerator.coefficients.entries.forEach { (degs, c) -> + if (c.isNotZero()) degs.forEachIndexed { index, deg -> + if (deg != 0u) this[index] = true + } + } + denominator.coefficients.entries.forEach { (degs, c) -> + if (c.isNotZero()) degs.forEachIndexed { index, deg -> + if (deg != 0u) this[index] = true + } + } + }.count { it } // TODO: Разобрать -- 2.34.1 From a8a95c9df7727f0a2b4bada88c122a912e8b1796 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Thu, 17 Mar 2022 02:15:48 +0300 Subject: [PATCH 030/123] Fixed typo --- .../space/kscience/kmath/functions/NumberedRationalFunction.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt index 6542bc89b..78ba233f5 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt @@ -301,7 +301,7 @@ public class NumberedRationalFunctionSpace> ( * exponents in which the variables are appeared in the polynomial. * * As consequence all values in the list are non-negative integers. Also, if the polynomial is constant, the list is empty. - * And size of the list is [countOfVariables]. + * And last index of the list is [lastVariable]. */ public val NumberedPolynomial.degrees: List get() = polynomialRing { degrees } /** -- 2.34.1 From ffd3ae76844499ca9a6ac46ce23eaa7fc87f06e3 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Thu, 17 Mar 2022 16:02:41 +0300 Subject: [PATCH 031/123] Optimized allocation during coefficients generation in `Polynomial` --- .../kscience/kmath/functions/Polynomial.kt | 114 ++++++++++++------ 1 file changed, 79 insertions(+), 35 deletions(-) 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 220bde8ff..862ee6a60 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 @@ -6,6 +6,10 @@ package space.kscience.kmath.functions import space.kscience.kmath.operations.* +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract +import kotlin.experimental.ExperimentalTypeInference +import kotlin.jvm.JvmName import kotlin.math.max import kotlin.math.min @@ -124,8 +128,9 @@ public open class PolynomialSpace>( if (other == 0) zero else Polynomial( coefficients - .subList(0, degree + 1) - .map { it * other } + .applyAndRemoveZeros { + map { it * other } + } ) /** @@ -183,8 +188,9 @@ public open class PolynomialSpace>( if (this == 0) zero else Polynomial( other.coefficients - .subList(0, other.degree + 1) - .map { it * this } + .applyAndRemoveZeros { + map { it * this@times } + } ) /** @@ -238,8 +244,9 @@ public open class PolynomialSpace>( if (this.isZero()) other else Polynomial( other.coefficients - .subList(0, other.degree + 1) - .map { it * this } + .applyAndRemoveZeros { + map { it * this@times } + } ) /** @@ -291,8 +298,9 @@ public open class PolynomialSpace>( if (other.isZero()) this else Polynomial( coefficients - .subList(0, degree + 1) - .map { it * other } + .applyAndRemoveZeros { + map { it * other } + } ) /** @@ -303,33 +311,35 @@ public open class PolynomialSpace>( /** * Returns sum of the polynomials. */ - public override operator fun Polynomial.plus(other: Polynomial): Polynomial = - Polynomial( - (0..max(degree, other.degree)) - .map { - when { - it > degree -> other.coefficients[it] - it > other.degree -> coefficients[it] - else -> coefficients[it] + other.coefficients[it] - } + public override operator fun Polynomial.plus(other: Polynomial): Polynomial { + val thisDegree = degree + val otherDegree = other.degree + return Polynomial( + Coefficients(max(thisDegree, otherDegree) + 1) { + when { + it > thisDegree -> other.coefficients[it] + it > otherDegree -> coefficients[it] + else -> coefficients[it] + other.coefficients[it] } - .ifEmpty { listOf(constantZero) } + } ) + } /** * Returns difference of the polynomials. */ - public override operator fun Polynomial.minus(other: Polynomial): Polynomial = - Polynomial( - (0..max(degree, other.degree)) - .map { - when { - it > degree -> -other.coefficients[it] - it > other.degree -> coefficients[it] - else -> coefficients[it] - other.coefficients[it] - } + public override operator fun Polynomial.minus(other: Polynomial): Polynomial { + val thisDegree = degree + val otherDegree = other.degree + return Polynomial( + Coefficients(max(thisDegree, otherDegree) + 1) { + when { + it > thisDegree -> -other.coefficients[it] + it > otherDegree -> coefficients[it] + else -> coefficients[it] - other.coefficients[it] } - .ifEmpty { listOf(constantZero) } + } ) + } /** * Returns product of the polynomials. */ @@ -341,13 +351,11 @@ public open class PolynomialSpace>( otherDegree == -1 -> zero else -> Polynomial( - (0..(thisDegree + otherDegree)) - .map { d -> - (max(0, d - otherDegree)..min(thisDegree, d)) - .map { coefficients[it] * other.coefficients[d - it] } - .reduce { acc, rational -> acc + rational } - } - .run { subList(0, indexOfLast { it.isNotZero() } + 1) } + Coefficients(thisDegree + otherDegree + 1) { d -> + (max(0, d - otherDegree)..min(thisDegree, d)) + .map { coefficients[it] * other.coefficients[d - it] } + .reduce { acc, rational -> acc + rational } + } ) } } @@ -431,6 +439,42 @@ public open class PolynomialSpace>( public inline operator fun Polynomial.invoke(argument: C): C = this.substitute(ring, argument) @Suppress("NOTHING_TO_INLINE") public inline operator fun Polynomial.invoke(argument: Polynomial): Polynomial = this.substitute(ring, argument) + + // TODO: Move to other internal utilities with context receiver + @JvmName("applyAndRemoveZerosInternal") + internal inline fun MutableList.applyAndRemoveZeros(block: MutableList.() -> Unit) : MutableList { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + block() + while (elementAt(lastIndex).isZero()) removeAt(lastIndex) + return this + } + internal inline fun List.applyAndRemoveZeros(block: MutableList.() -> Unit) : List = + toMutableList().applyAndRemoveZeros(block) + 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) } + return list + } + internal inline fun Coefficients(size: Int, init: (index: Int) -> C): List = MutableCoefficients(size, init) + @OptIn(ExperimentalTypeInference::class) + internal inline fun buildCoefficients(@BuilderInference builderAction: MutableList.() -> Unit): List { + contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) } + return buildList { + builderAction() + while (elementAt(lastIndex).isZero()) removeAt(lastIndex) + } + } + @OptIn(ExperimentalTypeInference::class) + internal inline fun buildCoefficients(capacity: Int, @BuilderInference builderAction: MutableList.() -> Unit): List { + contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) } + return buildList(capacity) { + builderAction() + while (elementAt(lastIndex).isZero()) removeAt(lastIndex) + } + } } /** -- 2.34.1 From d63c4acf101849c0bbe2242d841bf7faaf6047e3 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Thu, 17 Mar 2022 16:27:02 +0300 Subject: [PATCH 032/123] Added space and scope fabrics for RFs --- .../functions/labeledRationalFunctionUtil.kt | 18 ++++++++++++++++++ .../functions/numberedRationalFunctionUtil.kt | 18 ++++++++++++++++++ .../kmath/functions/rationalFunctionUtil.kt | 18 ++++++++++++++++++ 3 files changed, 54 insertions(+) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt index 61f443871..d79e8eda3 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt @@ -5,6 +5,24 @@ package space.kscience.kmath.functions +import space.kscience.kmath.operations.Ring +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract + + +/** + * Creates a [LabeledRationalFunctionSpace] over a received ring. + */ +public fun > A.labeledRationalFunction(): LabeledRationalFunctionSpace = + LabeledRationalFunctionSpace(this) + +/** + * Creates a [RationalFunctionSpace]'s scope over a received ring. + */ +public inline fun , R> A.labeledRationalFunction(block: LabeledRationalFunctionSpace.() -> R): R { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return LabeledRationalFunctionSpace(this).block() +} //fun > LabeledRationalFunction.reduced(): LabeledRationalFunction { // val greatestCommonDivider = polynomialGCD(numerator, denominator) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt index 035e201f7..cc725f981 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt @@ -5,6 +5,24 @@ package space.kscience.kmath.functions +import space.kscience.kmath.operations.Ring +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract + + +/** + * Creates a [NumberedRationalFunctionSpace] over a received ring. + */ +public fun > A.numberedRationalFunction(): NumberedRationalFunctionSpace = + NumberedRationalFunctionSpace(this) + +/** + * Creates a [RationalFunctionSpace]'s scope over a received ring. + */ +public inline fun , R> A.numberedRationalFunction(block: NumberedRationalFunctionSpace.() -> R): R { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return NumberedRationalFunctionSpace(this).block() +} //fun > NumberedRationalFunction.reduced(): NumberedRationalFunction { // val greatestCommonDivider = polynomialGCD(numerator, denominator) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/rationalFunctionUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/rationalFunctionUtil.kt index 359c781b5..456a1fa2b 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/rationalFunctionUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/rationalFunctionUtil.kt @@ -5,6 +5,24 @@ package space.kscience.kmath.functions +import space.kscience.kmath.operations.Ring +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract + + +/** + * Creates a [RationalFunctionSpace] over a received ring. + */ +public fun > A.rationalFunction(): RationalFunctionSpace = + RationalFunctionSpace(this) + +/** + * Creates a [RationalFunctionSpace]'s scope over a received ring. + */ +public inline fun , R> A.rationalFunction(block: RationalFunctionSpace.() -> R): R { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return RationalFunctionSpace(this).block() +} //operator fun > RationalFunction.invoke(arg: T): T = numerator(arg) / denominator(arg) // -- 2.34.1 From 86553e9f35aa5891b89bdcd187ff348dcc9955fb Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Thu, 17 Mar 2022 16:28:41 +0300 Subject: [PATCH 033/123] Added utilities. Rewrote polynomial-in-polynomial substitution --- .../kmath/functions/polynomialUtil.kt | 55 ++++++++++++++++--- 1 file changed, 46 insertions(+), 9 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt index a0c11b0a8..c624380be 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt @@ -49,6 +49,41 @@ public inline fun A.scalablePolynomial(block: ScalablePolynomialSpace< return ScalablePolynomialSpace(this).block() } +@Suppress("NOTHING_TO_INLINE") +internal inline fun iadd( + ring: Ring, + augend: MutableList, + addend: List, + degree: Int +) = ring { + for (deg in 0 .. degree) augend[deg] += addend[deg] +} + +@Suppress("NOTHING_TO_INLINE") +internal inline fun addTo( + ring: Ring, + augend: List, + addend: List, + degree: Int, + target: MutableList +) = ring { + for (deg in 0 .. degree) target[deg] = augend[deg] + addend[deg] +} + +@Suppress("NOTHING_TO_INLINE") +internal inline fun multiplyAddingTo( + ring: Ring, + multiplicand: List, + multiplicandDegree: Int, + multiplier: List, + multiplierDegree: Int, + target: MutableList +) = ring { + for (d in 0 .. multiplicandDegree + multiplierDegree) + for (k in max(0, d - multiplierDegree)..min(multiplicandDegree, d)) + target[d] += multiplicand[k] * multiplier[d - k] +} + // TODO: May be apply Horner's method too? /** * Evaluates the value of the given double polynomial for given double argument. @@ -80,19 +115,21 @@ public fun Polynomial.substitute(ring: Ring, arg: Polynomial) : Pol val argDegree = arg.degree if (argDegree == -1) return coefficients[0].asPolynomial() val constantZero = constantZero - val resultCoefs: MutableList = MutableList(thisDegree + argDegree + 1) { constantZero } - val resultCoefsUpdate: MutableList = MutableList(thisDegree + argDegree + 1) { constantZero } + val resultCoefs: MutableList = MutableList(thisDegree * argDegree + 1) { constantZero } + val resultCoefsUpdate: MutableList = MutableList(thisDegree * argDegree + 1) { constantZero } var resultDegree = 0 for (deg in thisDegree downTo 0) { resultCoefsUpdate[0] = coefficients[deg] - for (updateDeg in 0 .. resultDegree + argDegree) { - var newC = resultCoefsUpdate[updateDeg] - for (deg1 in max(0, updateDeg - argDegree)..min(resultDegree, updateDeg)) - newC += resultCoefs[deg1] * arg.coefficients[updateDeg - deg1] - resultCoefsUpdate[updateDeg] = newC - } + multiplyAddingTo( + ring=ring, + multiplicand = resultCoefs, + multiplicandDegree = resultDegree, + multiplier = arg.coefficients, + multiplierDegree = argDegree, + target = resultCoefsUpdate + ) resultDegree += argDegree - for (updateDeg in 0 .. resultDegree + argDegree) { + for (updateDeg in 0 .. resultDegree) { resultCoefs[updateDeg] = resultCoefsUpdate[updateDeg] resultCoefsUpdate[updateDeg] = constantZero } -- 2.34.1 From ed2f14b68e7f799fcbe370bf744256a278cfcf74 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Fri, 18 Mar 2022 01:47:03 +0300 Subject: [PATCH 034/123] Optimised existing substitution function. Prototyped substitution for RFs. --- .../kmath/functions/polynomialUtil.kt | 63 ++++--- .../kmath/functions/rationalFunctionUtil.kt | 174 ++++++++++++++++++ 2 files changed, 210 insertions(+), 27 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt index c624380be..1a7245b9f 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt @@ -50,24 +50,36 @@ public inline fun A.scalablePolynomial(block: ScalablePolynomialSpace< } @Suppress("NOTHING_TO_INLINE") -internal inline fun iadd( - ring: Ring, - augend: MutableList, - addend: List, - degree: Int -) = ring { - for (deg in 0 .. degree) augend[deg] += addend[deg] +internal inline fun copyTo( + origin: List, + originDegree: Int, + target: MutableList, +) { + for (deg in 0 .. originDegree) target[deg] = origin[deg] } @Suppress("NOTHING_TO_INLINE") -internal inline fun addTo( +internal inline fun multiplyAddingToUpdater( ring: Ring, - augend: List, - addend: List, - degree: Int, - target: MutableList -) = ring { - for (deg in 0 .. degree) target[deg] = augend[deg] + addend[deg] + multiplicand: MutableList, + multiplicandDegree: Int, + multiplier: List, + multiplierDegree: Int, + updater: MutableList, + zero: C, +) { + multiplyAddingTo( + ring = ring, + multiplicand = multiplicand, + multiplicandDegree = multiplicandDegree, + multiplier = multiplier, + multiplierDegree = multiplierDegree, + target = updater + ) + for (updateDeg in 0 .. multiplicandDegree + multiplierDegree) { + multiplicand[updateDeg] = updater[updateDeg] + updater[updateDeg] = zero + } } @Suppress("NOTHING_TO_INLINE") @@ -107,32 +119,29 @@ public fun Polynomial.substitute(ring: Ring, arg: C): C = ring { return result } -public fun Polynomial.substitute(ring: Ring, arg: Polynomial) : Polynomial = ring.polynomial { - if (coefficients.isEmpty()) return zero +public fun Polynomial.substitute(ring: Ring, arg: Polynomial) : Polynomial = ring { + if (coefficients.isEmpty()) return Polynomial(emptyList()) - val thisDegree = degree - if (thisDegree == -1) return zero - val argDegree = arg.degree + val thisDegree = coefficients.indexOfLast { it != zero } + if (thisDegree == -1) return Polynomial(emptyList()) + val argDegree = arg.coefficients.indexOfLast { it != zero } if (argDegree == -1) return coefficients[0].asPolynomial() - val constantZero = constantZero + val constantZero = zero val resultCoefs: MutableList = MutableList(thisDegree * argDegree + 1) { constantZero } val resultCoefsUpdate: MutableList = MutableList(thisDegree * argDegree + 1) { constantZero } var resultDegree = 0 for (deg in thisDegree downTo 0) { resultCoefsUpdate[0] = coefficients[deg] - multiplyAddingTo( - ring=ring, + multiplyAddingToUpdater( + ring = ring, multiplicand = resultCoefs, multiplicandDegree = resultDegree, multiplier = arg.coefficients, multiplierDegree = argDegree, - target = resultCoefsUpdate + updater = resultCoefsUpdate, + zero = constantZero ) resultDegree += argDegree - for (updateDeg in 0 .. resultDegree) { - resultCoefs[updateDeg] = resultCoefsUpdate[updateDeg] - resultCoefsUpdate[updateDeg] = constantZero - } } return Polynomial(resultCoefs) } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/rationalFunctionUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/rationalFunctionUtil.kt index 456a1fa2b..8d2073834 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/rationalFunctionUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/rationalFunctionUtil.kt @@ -5,9 +5,12 @@ package space.kscience.kmath.functions +import space.kscience.kmath.operations.Field import space.kscience.kmath.operations.Ring +import space.kscience.kmath.operations.invoke import kotlin.contracts.InvocationKind import kotlin.contracts.contract +import kotlin.math.max /** @@ -24,6 +27,177 @@ public inline fun , R> A.rationalFunction(block: RationalFunction return RationalFunctionSpace(this).block() } +/** + * Evaluates the value of the given double polynomial for given double argument. + */ +public fun RationalFunction.substitute(arg: Double): Double = + numerator.substitute(arg) / denominator.substitute(arg) + +/** + * Evaluates the value of the given polynomial for given argument. + * + * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). + */ +public fun RationalFunction.substitute(ring: Field, arg: C): C = ring { + numerator.substitute(ring, arg) / denominator.substitute(ring, arg) +} + +/** + * Returns numerator (polynomial) of rational function gotten by substitution rational function [arg] to the polynomial instance. + * More concrete, if [arg] is a fraction `f(x)/g(x)` and the receiving instance is `p(x)`, then + * ``` + * p(f/g) * g^deg(p) + * ``` + * is returned. + * + * Used in [Polynomial.substitute] and [RationalFunction.substitute] for performance optimisation. + */ // TODO: Дописать +internal fun Polynomial.substituteRationalFunctionTakeNumerator(ring: Ring, arg: RationalFunction): Polynomial = ring { + if (coefficients.isEmpty()) return Polynomial(emptyList()) + + val thisDegree = coefficients.indexOfLast { it != zero } + if (thisDegree == -1) return Polynomial(emptyList()) + val thisDegreeLog2 = 31 - thisDegree.countLeadingZeroBits() + val numeratorDegree = arg.numerator.coefficients.indexOfLast { it != zero } + val denominatorDegree = arg.denominator.coefficients.indexOfLast { it != zero } + val argDegree = max(numeratorDegree, denominatorDegree) + val constantZero = zero + val powersOf2 = buildList(thisDegreeLog2 + 1) { + var result = 1 + for (exp in 0 .. thisDegreeLog2) { + add(result) + result = result shl 1 + } + } + val hashes = powersOf2.runningReduce { acc, i -> acc + i } + val numeratorPowers = buildList>(thisDegreeLog2 + 1) { + add(arg.numerator.coefficients) + repeat(thisDegreeLog2) { + val next = MutableList(powersOf2[it + 1] * numeratorDegree + 1) { constantZero } + add(next) + val last = last() + multiplyAddingTo( + ring = ring, + multiplicand = last, + multiplicandDegree = powersOf2[it] * numeratorDegree + 1, + multiplier = last, + multiplierDegree = powersOf2[it] * numeratorDegree + 1, + target = next, + ) + } + } + val denominatorPowers = buildList>(thisDegreeLog2 + 1) { + add(arg.denominator.coefficients) + repeat(thisDegreeLog2) { + val next = MutableList(powersOf2[it + 1] * denominatorDegree + 1) { constantZero } + add(next) + val last = last() + multiplyAddingTo( + ring = ring, + multiplicand = last, + multiplicandDegree = powersOf2[it] * denominatorDegree + 1, + multiplier = last, + multiplierDegree = powersOf2[it] * denominatorDegree + 1, + target = next, + ) + } + } + val levelResultCoefsPool = buildList>(thisDegreeLog2 + 1) { + repeat(thisDegreeLog2 + 1) { + add(MutableList(hashes[it] * argDegree) { constantZero }) + } + } + val edgedMultiplier = MutableList(0) { TODO() } + val edgedMultiplierUpdater = MutableList(0) { TODO() } + + fun MutableList.reset() { + for (i in indices) set(i, constantZero) + } + + fun processLevel(level: Int, start: Int, end: Int) : List { + val levelResultCoefs = levelResultCoefsPool[level + 1] + + if (level == -1) { + levelResultCoefs[0] = coefficients[start] + } else { + levelResultCoefs.reset() + multiplyAddingTo( + ring = ring, + multiplicand = processLevel(level = level - 1, start = start, end = (start + end) / 2), + multiplicandDegree = hashes[level] * argDegree, + multiplier = denominatorPowers[level], + multiplierDegree = powersOf2[level] * denominatorDegree, + target = levelResultCoefs + ) + multiplyAddingTo( + ring = ring, + multiplicand = processLevel(level = level - 1, start = (start + end) / 2, end = end), + multiplicandDegree = hashes[level] * argDegree, + multiplier = numeratorPowers[level], + multiplierDegree = powersOf2[level] * numeratorDegree, + target = levelResultCoefs + ) + } + + return levelResultCoefs + } + + fun processLevelEdged(level: Int, start: Int, end: Int) : List { + val levelResultCoefs = levelResultCoefsPool[level + 1] + + if (level == -1) { + levelResultCoefs[0] = coefficients[start] + } else { + val levelsPowerOf2 = powersOf2[level] + if (end - start >= levelsPowerOf2) { + multiplyAddingTo( + ring = ring, + multiplicand = processLevelEdged(level = level - 1, start = start + levelsPowerOf2, end = end), + multiplicandDegree = hashes[level] * argDegree, // TODO: Ввести переменную + multiplier = numeratorPowers[level], + multiplierDegree = powersOf2[level] * numeratorDegree, + target = levelResultCoefs + ) + multiplyAddingTo( + ring = ring, + multiplicand = processLevel(level = level - 1, start = start, end = start + levelsPowerOf2), + multiplicandDegree = hashes[level] * argDegree, + multiplier = edgedMultiplier, + multiplierDegree = max((hashes[level] and thisDegree) - powersOf2[level] + 1, 0) * denominatorDegree, // TODO: Ввести переменную + target = levelResultCoefs + ) + if (level != thisDegreeLog2) { + multiplyAddingToUpdater( + ring = ring, + multiplicand = edgedMultiplier, + multiplicandDegree = max((hashes[level] and thisDegree) - powersOf2[level] + 1, 0) * denominatorDegree, // TODO: Ввести переменную + multiplier = denominatorPowers[level], + multiplierDegree = powersOf2[level] * denominatorDegree, + updater = edgedMultiplierUpdater, + zero = constantZero + ) + } + } else { + copyTo( + origin = processLevelEdged(level = level - 1, start = start + levelsPowerOf2, end = end), + originDegree = hashes[level] * argDegree, // TODO: Ввести переменную + target = levelResultCoefs + ) + } + } + + return levelResultCoefs + } + + return Polynomial( + processLevelEdged( + level = thisDegreeLog2, + start = 0, + end = thisDegree + 1 + ) + ) +} + //operator fun > RationalFunction.invoke(arg: T): T = numerator(arg) / denominator(arg) // //fun > RationalFunction.reduced(): RationalFunction = -- 2.34.1 From cdc85291bc5d5c9313e25c5d11649415155087d0 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Fri, 18 Mar 2022 20:04:21 +0300 Subject: [PATCH 035/123] Fixed bug in implementations of polynomial operations --- .../kmath/functions/LabeledPolynomial.kt | 26 +++++++++---------- .../kmath/functions/NumberedPolynomial.kt | 26 +++++++++---------- .../kscience/kmath/functions/Polynomial.kt | 10 ++++--- .../kmath/functions/polynomialUtil.kt | 1 - 4 files changed, 30 insertions(+), 33 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt index 369c7078a..76f5fc29c 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt @@ -211,7 +211,7 @@ public class LabeledPolynomialSpace>( else LabeledPolynomial( coefficients .applyAndRemoveZeros { - mapValues { (_, c) -> c * other } + for (degs in keys) this[degs] = this[degs]!! * other } ) @@ -265,7 +265,7 @@ public class LabeledPolynomialSpace>( else LabeledPolynomial( other.coefficients .applyAndRemoveZeros { - mapValues { (_, c) -> this@times * c } + for (degs in keys) this[degs] = this@times * this[degs]!! } ) @@ -361,7 +361,7 @@ public class LabeledPolynomialSpace>( else LabeledPolynomial( other.coefficients .applyAndRemoveZeros { - mapValues { (_, c) -> this@times * c } + for (degs in keys) this[degs] = this@times * this[degs]!! } ) @@ -413,7 +413,7 @@ public class LabeledPolynomialSpace>( else LabeledPolynomial( coefficients .applyAndRemoveZeros { - mapValues { (_, c) -> c * other } + for (degs in keys) this[degs] = this[degs]!! * other } ) @@ -525,22 +525,20 @@ public class LabeledPolynomialSpace>( */ override operator fun LabeledPolynomial.plus(other: LabeledPolynomial): LabeledPolynomial = LabeledPolynomial( - coefficients - .applyAndRemoveZeros { - other.coefficients - .mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! + value else value } - } + buildCoefficients(coefficients.size + other.coefficients.size) { + other.coefficients.mapValuesTo(this) { it.value } + other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! + value else value } + } ) /** * Returns difference of the polynomials. */ override operator fun LabeledPolynomial.minus(other: LabeledPolynomial): LabeledPolynomial = LabeledPolynomial( - coefficients - .applyAndRemoveZeros { - other.coefficients - .mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! - value else -value } - } + buildCoefficients(coefficients.size + other.coefficients.size) { + other.coefficients.mapValuesTo(this) { it.value } + other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! - value else -value } + } ) /** * Returns product of the polynomials. diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt index 37c0c96f0..88349f003 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -163,7 +163,7 @@ public open class NumberedPolynomialSpace>( else NumberedPolynomial( coefficients .applyAndRemoveZeros { - mapValues { (_, c) -> c * other } + for (degs in keys) this[degs] = this[degs]!! * other } ) @@ -217,7 +217,7 @@ public open class NumberedPolynomialSpace>( else NumberedPolynomial( other.coefficients .applyAndRemoveZeros { - mapValues { (_, c) -> this@times * c } + for (degs in keys) this[degs] = this@times * this[degs]!! } ) @@ -269,7 +269,7 @@ public open class NumberedPolynomialSpace>( else NumberedPolynomial( other.coefficients .applyAndRemoveZeros { - mapValues { (_, c) -> this@times * c } + for (degs in keys) this[degs] = this@times * this[degs]!! } ) @@ -319,7 +319,7 @@ public open class NumberedPolynomialSpace>( else NumberedPolynomial( coefficients .applyAndRemoveZeros { - mapValues { (_, c) -> c * other } + for (degs in keys) this[degs] = this[degs]!! * other } ) @@ -335,22 +335,20 @@ public open class NumberedPolynomialSpace>( */ override operator fun NumberedPolynomial.plus(other: NumberedPolynomial): NumberedPolynomial = NumberedPolynomial( - coefficients - .applyAndRemoveZeros { - other.coefficients - .mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! + value else value } - } + buildCoefficients(coefficients.size + other.coefficients.size) { + other.coefficients.mapValuesTo(this) { it.value } + other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! + value else value } + } ) /** * Returns difference of the polynomials. */ override operator fun NumberedPolynomial.minus(other: NumberedPolynomial): NumberedPolynomial = NumberedPolynomial( - coefficients - .applyAndRemoveZeros { - other.coefficients - .mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! - value else -value } - } + buildCoefficients(coefficients.size + other.coefficients.size) { + other.coefficients.mapValuesTo(this) { it.value } + other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! - value else -value } + } ) /** * Returns product of the polynomials. 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 862ee6a60..a60ca563a 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 @@ -129,7 +129,7 @@ public open class PolynomialSpace>( else Polynomial( coefficients .applyAndRemoveZeros { - map { it * other } + for (deg in indices) this[deg] = this[deg] * other } ) @@ -189,7 +189,7 @@ public open class PolynomialSpace>( else Polynomial( other.coefficients .applyAndRemoveZeros { - map { it * this@times } + for (deg in indices) this[deg] = this@times * this[deg] } ) @@ -245,7 +245,7 @@ public open class PolynomialSpace>( else Polynomial( other.coefficients .applyAndRemoveZeros { - map { it * this@times } + for (deg in indices) this[deg] = this@times * this[deg] } ) @@ -299,7 +299,7 @@ public open class PolynomialSpace>( else Polynomial( coefficients .applyAndRemoveZeros { - map { it * other } + for (deg in indices) this[deg] = this[deg] * other } ) @@ -452,12 +452,14 @@ public open class PolynomialSpace>( } internal inline fun List.applyAndRemoveZeros(block: MutableList.() -> Unit) : List = toMutableList().applyAndRemoveZeros(block) + @Suppress("FunctionName") 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) } return list } + @Suppress("FunctionName") internal inline fun Coefficients(size: Int, init: (index: Int) -> C): List = MutableCoefficients(size, init) @OptIn(ExperimentalTypeInference::class) internal inline fun buildCoefficients(@BuilderInference builderAction: MutableList.() -> Unit): List { diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt index 1a7245b9f..84c8d2e88 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt @@ -96,7 +96,6 @@ internal inline fun multiplyAddingTo( target[d] += multiplicand[k] * multiplier[d - k] } -// TODO: May be apply Horner's method too? /** * Evaluates the value of the given double polynomial for given double argument. */ -- 2.34.1 From 85cd3b4de64b35718d603033dba4aec97879578d Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Fri, 18 Mar 2022 20:39:01 +0300 Subject: [PATCH 036/123] Added some test. Fixed bug in algebraicStub.kt --- .../kscience/kmath/functions/algebraicStub.kt | 2 +- .../kmath/functions/AlgebraicStubTest.kt | 589 ++++++++++++++++++ .../kmath/functions/PolynomialTest.kt | 5 +- 3 files changed, 593 insertions(+), 3 deletions(-) create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/AlgebraicStubTest.kt diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt index ee81f3d79..ca93e4259 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt @@ -139,7 +139,7 @@ internal tailrec fun Ring.exponentiationBySquaring(arg: C, exponent: UInt internal tailrec fun RingOps.multiplyExponentiationBySquaring(base: C, arg: C, exponent: UInt): C = when { exponent == 0u -> base - exponent == 1u -> base + arg + exponent == 1u -> base * arg exponent and 1u == 0u -> multiplyExponentiationBySquaring(base, arg * arg, exponent shr 1) exponent and 1u == 1u -> multiplyExponentiationBySquaring(base * arg, arg * arg, exponent shr 1) else -> error("Error in multiplication group instant by unsigned integer: got reminder by division by 2 different from 0 and 1") diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/AlgebraicStubTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/AlgebraicStubTest.kt new file mode 100644 index 000000000..fe4a82f11 --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/AlgebraicStubTest.kt @@ -0,0 +1,589 @@ +/* + * 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.functions + + +import space.kscience.kmath.operations.invoke +import space.kscience.kmath.operations.Field +import kotlin.jvm.JvmInline +import kotlin.test.Test +import kotlin.test.assertEquals + +@JvmInline +value class Expr(val expr: String) + +object ExprRing : Field { + override fun Expr.unaryMinus(): Expr = Expr("-${expr}") + override fun add(left: Expr, right: Expr): Expr = Expr("(${left.expr} + ${right.expr})") + override fun multiply(left: Expr, right: Expr): Expr = Expr("(${left.expr} * ${right.expr})") + override val zero: Expr = Expr("0") + override val one: Expr = Expr("1") + override fun divide(left: Expr, right: Expr): Expr = Expr("(${left.expr} / ${right.expr})") + override fun scale(a: Expr, value: Double): Expr = Expr("(${a.expr} / $value)") +} + +class AlgebraicStubTest { + @Test + fun test_addMultipliedBySquaring_for_UInt() { + ExprRing { + assertEquals( + "57", + addMultipliedBySquaring(Expr("57"), Expr("179"), 0u).expr, + "tried addMultipliedBySquaring(57, 179, 0u)" + ) + assertEquals( + "(57 + 179)", + addMultipliedBySquaring(Expr("57"), Expr("179"), 1u).expr, + "tried addMultipliedBySquaring(57, 179, 1u)" + ) + assertEquals( + "(57 + (179 + 179))", + addMultipliedBySquaring(Expr("57"), Expr("179"), 2u).expr, + "tried addMultipliedBySquaring(57, 179, 2u)" + ) + assertEquals( + "((57 + 179) + (179 + 179))", + addMultipliedBySquaring(Expr("57"), Expr("179"), 3u).expr, + "tried addMultipliedBySquaring(57, 179, 3u)" + ) + assertEquals( + "(57 + ((179 + 179) + (179 + 179)))", + addMultipliedBySquaring(Expr("57"), Expr("179"), 4u).expr, + "tried addMultipliedBySquaring(57, 179, 4u)" + ) + assertEquals( + "((57 + 179) + ((179 + 179) + (179 + 179)))", + addMultipliedBySquaring(Expr("57"), Expr("179"), 5u).expr, + "tried addMultipliedBySquaring(57, 179, 5u)" + ) + assertEquals( + "((57 + (179 + 179)) + ((179 + 179) + (179 + 179)))", + addMultipliedBySquaring(Expr("57"), Expr("179"), 6u).expr, + "tried addMultipliedBySquaring(57, 179, 6u)" + ) + assertEquals( + "(((57 + 179) + (179 + 179)) + ((179 + 179) + (179 + 179)))", + addMultipliedBySquaring(Expr("57"), Expr("179"), 7u).expr, + "tried addMultipliedBySquaring(57, 179, 7u)" + ) + assertEquals( + "(57 + (((179 + 179) + (179 + 179)) + ((179 + 179) + (179 + 179))))", + addMultipliedBySquaring(Expr("57"), Expr("179"), 8u).expr, + "tried addMultipliedBySquaring(57, 179, 8u)" + ) + } + } + @Test + fun test_multiplyBySquaring_for_UInt() { + ExprRing { + assertEquals( + "0", + multiplyBySquaring(Expr("57"), 0u).expr, + "tried multiplyBySquaring(57, 0u)" + ) + assertEquals( + "57", + multiplyBySquaring(Expr("57"), 1u).expr, + "tried multiplyBySquaring(57, 1u)" + ) + assertEquals( + "(57 + 57)", + multiplyBySquaring(Expr("57"), 2u).expr, + "tried multiplyBySquaring(57, 2u)" + ) + assertEquals( + "(57 + (57 + 57))", + multiplyBySquaring(Expr("57"), 3u).expr, + "tried multiplyBySquaring(57, 3u)" + ) + assertEquals( + "((57 + 57) + (57 + 57))", + multiplyBySquaring(Expr("57"), 4u).expr, + "tried multiplyBySquaring(57, 4u)" + ) + assertEquals( + "(57 + ((57 + 57) + (57 + 57)))", + multiplyBySquaring(Expr("57"), 5u).expr, + "tried multiplyBySquaring(57, 5u)" + ) + assertEquals( + "((57 + 57) + ((57 + 57) + (57 + 57)))", + multiplyBySquaring(Expr("57"), 6u).expr, + "tried multiplyBySquaring(57, 6u)" + ) + assertEquals( + "((57 + (57 + 57)) + ((57 + 57) + (57 + 57)))", + multiplyBySquaring(Expr("57"), 7u).expr, + "tried multiplyBySquaring(57, 7u)" + ) + assertEquals( + "(((57 + 57) + (57 + 57)) + ((57 + 57) + (57 + 57)))", + multiplyBySquaring(Expr("57"), 8u).expr, + "tried multiplyBySquaring(57, 8u)" + ) + } + } + @Test + fun test_addMultipliedBySquaring_for_Int() { + ExprRing { + assertEquals( + "57", + addMultipliedBySquaring(Expr("57"), Expr("179"), 0).expr, + "tried addMultipliedBySquaring(57, 179, 0)" + ) + assertEquals( + "(57 + 179)", + addMultipliedBySquaring(Expr("57"), Expr("179"), 1).expr, + "tried addMultipliedBySquaring(57, 179, 1)" + ) + assertEquals( + "(57 + -179)", + addMultipliedBySquaring(Expr("57"), Expr("179"), -1).expr, + "tried addMultipliedBySquaring(57, 179, -1)" + ) + assertEquals( + "(57 + (179 + 179))", + addMultipliedBySquaring(Expr("57"), Expr("179"), 2).expr, + "tried addMultipliedBySquaring(57, 179, 2)" + ) + assertEquals( + "(57 + (-179 + -179))", + addMultipliedBySquaring(Expr("57"), Expr("179"), -2).expr, + "tried addMultipliedBySquaring(57, 179, -2)" + ) + assertEquals( + "((57 + 179) + (179 + 179))", + addMultipliedBySquaring(Expr("57"), Expr("179"), 3).expr, + "tried addMultipliedBySquaring(57, 179, 3)" + ) + assertEquals( + "((57 + -179) + (-179 + -179))", + addMultipliedBySquaring(Expr("57"), Expr("179"), -3).expr, + "tried addMultipliedBySquaring(57, 179, -3)" + ) + assertEquals( + "(57 + ((179 + 179) + (179 + 179)))", + addMultipliedBySquaring(Expr("57"), Expr("179"), 4).expr, + "tried addMultipliedBySquaring(57, 179, 4)" + ) + assertEquals( + "(57 + ((-179 + -179) + (-179 + -179)))", + addMultipliedBySquaring(Expr("57"), Expr("179"), -4).expr, + "tried addMultipliedBySquaring(57, 179, -4)" + ) + assertEquals( + "((57 + 179) + ((179 + 179) + (179 + 179)))", + addMultipliedBySquaring(Expr("57"), Expr("179"), 5).expr, + "tried addMultipliedBySquaring(57, 179, 5)" + ) + assertEquals( + "((57 + -179) + ((-179 + -179) + (-179 + -179)))", + addMultipliedBySquaring(Expr("57"), Expr("179"), -5).expr, + "tried addMultipliedBySquaring(57, 179, -5)" + ) + assertEquals( + "((57 + (179 + 179)) + ((179 + 179) + (179 + 179)))", + addMultipliedBySquaring(Expr("57"), Expr("179"), 6).expr, + "tried addMultipliedBySquaring(57, 179, 6)" + ) + assertEquals( + "((57 + (-179 + -179)) + ((-179 + -179) + (-179 + -179)))", + addMultipliedBySquaring(Expr("57"), Expr("179"), -6).expr, + "tried addMultipliedBySquaring(57, 179, -6)" + ) + assertEquals( + "(((57 + 179) + (179 + 179)) + ((179 + 179) + (179 + 179)))", + addMultipliedBySquaring(Expr("57"), Expr("179"), 7).expr, + "tried addMultipliedBySquaring(57, 179, 7)" + ) + assertEquals( + "(((57 + -179) + (-179 + -179)) + ((-179 + -179) + (-179 + -179)))", + addMultipliedBySquaring(Expr("57"), Expr("179"), -7).expr, + "tried addMultipliedBySquaring(57, 179, -7)" + ) + assertEquals( + "(57 + (((179 + 179) + (179 + 179)) + ((179 + 179) + (179 + 179))))", + addMultipliedBySquaring(Expr("57"), Expr("179"), 8).expr, + "tried addMultipliedBySquaring(57, 179, 8)" + ) + assertEquals( + "(57 + (((-179 + -179) + (-179 + -179)) + ((-179 + -179) + (-179 + -179))))", + addMultipliedBySquaring(Expr("57"), Expr("179"), -8).expr, + "tried addMultipliedBySquaring(57, 179, -8)" + ) + } + } + @Test + fun test_multiplyBySquaring_for_Int() { + ExprRing { + assertEquals( + "0", + multiplyBySquaring(Expr("57"), 0).expr, + "tried multiplyBySquaring(57, 0)" + ) + assertEquals( + "57", + multiplyBySquaring(Expr("57"), 1).expr, + "tried multiplyBySquaring(57, 1)" + ) + assertEquals( + "-57", + multiplyBySquaring(Expr("57"), -1).expr, + "tried multiplyBySquaring(57, -1)" + ) + assertEquals( + "(57 + 57)", + multiplyBySquaring(Expr("57"), 2).expr, + "tried multiplyBySquaring(57, 2)" + ) + assertEquals( + "(-57 + -57)", + multiplyBySquaring(Expr("57"), -2).expr, + "tried multiplyBySquaring(57, -2)" + ) + assertEquals( + "(57 + (57 + 57))", + multiplyBySquaring(Expr("57"), 3).expr, + "tried multiplyBySquaring(57, 3)" + ) + assertEquals( + "(-57 + (-57 + -57))", + multiplyBySquaring(Expr("57"), -3).expr, + "tried multiplyBySquaring(57, -3)" + ) + assertEquals( + "((57 + 57) + (57 + 57))", + multiplyBySquaring(Expr("57"), 4).expr, + "tried multiplyBySquaring(57, 4)" + ) + assertEquals( + "((-57 + -57) + (-57 + -57))", + multiplyBySquaring(Expr("57"), -4).expr, + "tried multiplyBySquaring(57, -4)" + ) + assertEquals( + "(57 + ((57 + 57) + (57 + 57)))", + multiplyBySquaring(Expr("57"), 5).expr, + "tried multiplyBySquaring(57, 5)" + ) + assertEquals( + "(-57 + ((-57 + -57) + (-57 + -57)))", + multiplyBySquaring(Expr("57"), -5).expr, + "tried multiplyBySquaring(57, -5)" + ) + assertEquals( + "((57 + 57) + ((57 + 57) + (57 + 57)))", + multiplyBySquaring(Expr("57"), 6).expr, + "tried multiplyBySquaring(57, 6)" + ) + assertEquals( + "((-57 + -57) + ((-57 + -57) + (-57 + -57)))", + multiplyBySquaring(Expr("57"), -6).expr, + "tried multiplyBySquaring(57, -6)" + ) + assertEquals( + "((57 + (57 + 57)) + ((57 + 57) + (57 + 57)))", + multiplyBySquaring(Expr("57"), 7).expr, + "tried multiplyBySquaring(57, 7)" + ) + assertEquals( + "((-57 + (-57 + -57)) + ((-57 + -57) + (-57 + -57)))", + multiplyBySquaring(Expr("57"), -7).expr, + "tried multiplyBySquaring(57, -7)" + ) + assertEquals( + "(((57 + 57) + (57 + 57)) + ((57 + 57) + (57 + 57)))", + multiplyBySquaring(Expr("57"), 8).expr, + "tried multiplyBySquaring(57, 8)" + ) + assertEquals( + "(((-57 + -57) + (-57 + -57)) + ((-57 + -57) + (-57 + -57)))", + multiplyBySquaring(Expr("57"), -8).expr, + "tried multiplyBySquaring(57, -8)" + ) + } + } + @Test + fun test_multiplyExponentiationBySquaring_for_UInt() { + ExprRing { + assertEquals( + "57", + multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 0u).expr, + "tried multiplyExponentiationBySquaring(57, 179, 0u)" + ) + assertEquals( + "(57 * 179)", + multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 1u).expr, + "tried multiplyExponentiationBySquaring(57, 179, 1u)" + ) + assertEquals( + "(57 * (179 * 179))", + multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 2u).expr, + "tried multiplyExponentiationBySquaring(57, 179, 2u)" + ) + assertEquals( + "((57 * 179) * (179 * 179))", + multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 3u).expr, + "tried multiplyExponentiationBySquaring(57, 179, 3u)" + ) + assertEquals( + "(57 * ((179 * 179) * (179 * 179)))", + multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 4u).expr, + "tried multiplyExponentiationBySquaring(57, 179, 4u)" + ) + assertEquals( + "((57 * 179) * ((179 * 179) * (179 * 179)))", + multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 5u).expr, + "tried multiplyExponentiationBySquaring(57, 179, 5u)" + ) + assertEquals( + "((57 * (179 * 179)) * ((179 * 179) * (179 * 179)))", + multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 6u).expr, + "tried multiplyExponentiationBySquaring(57, 179, 6u)" + ) + assertEquals( + "(((57 * 179) * (179 * 179)) * ((179 * 179) * (179 * 179)))", + multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 7u).expr, + "tried multiplyExponentiationBySquaring(57, 179, 7u)" + ) + assertEquals( + "(57 * (((179 * 179) * (179 * 179)) * ((179 * 179) * (179 * 179))))", + multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 8u).expr, + "tried multiplyExponentiationBySquaring(57, 179, 8u)" + ) + } + } + @Test + fun test_exponentiationBySquaring_for_UInt() { + ExprRing { + assertEquals( + "0", + exponentiationBySquaring(Expr("57"), 0u).expr, + "tried exponentiationBySquaring(57, 0u)" + ) + assertEquals( + "57", + exponentiationBySquaring(Expr("57"), 1u).expr, + "tried exponentiationBySquaring(57, 1u)" + ) + assertEquals( + "(57 * 57)", + exponentiationBySquaring(Expr("57"), 2u).expr, + "tried exponentiationBySquaring(57, 2u)" + ) + assertEquals( + "(57 * (57 * 57))", + exponentiationBySquaring(Expr("57"), 3u).expr, + "tried exponentiationBySquaring(57, 3u)" + ) + assertEquals( + "((57 * 57) * (57 * 57))", + exponentiationBySquaring(Expr("57"), 4u).expr, + "tried exponentiationBySquaring(57, 4u)" + ) + assertEquals( + "(57 * ((57 * 57) * (57 * 57)))", + exponentiationBySquaring(Expr("57"), 5u).expr, + "tried exponentiationBySquaring(57, 5u)" + ) + assertEquals( + "((57 * 57) * ((57 * 57) * (57 * 57)))", + exponentiationBySquaring(Expr("57"), 6u).expr, + "tried exponentiationBySquaring(57, 6u)" + ) + assertEquals( + "((57 * (57 * 57)) * ((57 * 57) * (57 * 57)))", + exponentiationBySquaring(Expr("57"), 7u).expr, + "tried exponentiationBySquaring(57, 7u)" + ) + assertEquals( + "(((57 * 57) * (57 * 57)) * ((57 * 57) * (57 * 57)))", + exponentiationBySquaring(Expr("57"), 8u).expr, + "tried exponentiationBySquaring(57, 8u)" + ) + } + } + @Test + fun test_multiplyExponentiationBySquaring_for_Int() { + ExprRing { + assertEquals( + "57", + multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 0).expr, + "tried multiplyExponentiationBySquaring(57, 179, 0)" + ) + assertEquals( + "(57 * 179)", + multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 1).expr, + "tried multiplyExponentiationBySquaring(57, 179, 1)" + ) + assertEquals( + "(57 * (1 / 179))", + multiplyExponentiationBySquaring(Expr("57"), Expr("179"), -1).expr, + "tried multiplyExponentiationBySquaring(57, 179, -1)" + ) + assertEquals( + "(57 * (179 * 179))", + multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 2).expr, + "tried multiplyExponentiationBySquaring(57, 179, 2)" + ) + assertEquals( + "(57 * ((1 / 179) * (1 / 179)))", + multiplyExponentiationBySquaring(Expr("57"), Expr("179"), -2).expr, + "tried multiplyExponentiationBySquaring(57, 179, -2)" + ) + assertEquals( + "((57 * 179) * (179 * 179))", + multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 3).expr, + "tried multiplyExponentiationBySquaring(57, 179, 3)" + ) + assertEquals( + "((57 * (1 / 179)) * ((1 / 179) * (1 / 179)))", + multiplyExponentiationBySquaring(Expr("57"), Expr("179"), -3).expr, + "tried multiplyExponentiationBySquaring(57, 179, -3)" + ) + assertEquals( + "(57 * ((179 * 179) * (179 * 179)))", + multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 4).expr, + "tried multiplyExponentiationBySquaring(57, 179, 4)" + ) + assertEquals( + "(57 * (((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179))))", + multiplyExponentiationBySquaring(Expr("57"), Expr("179"), -4).expr, + "tried multiplyExponentiationBySquaring(57, 179, -4)" + ) + assertEquals( + "((57 * 179) * ((179 * 179) * (179 * 179)))", + multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 5).expr, + "tried multiplyExponentiationBySquaring(57, 179, 5)" + ) + assertEquals( + "((57 * (1 / 179)) * (((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179))))", + multiplyExponentiationBySquaring(Expr("57"), Expr("179"), -5).expr, + "tried multiplyExponentiationBySquaring(57, 179, -5)" + ) + assertEquals( + "((57 * (179 * 179)) * ((179 * 179) * (179 * 179)))", + multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 6).expr, + "tried multiplyExponentiationBySquaring(57, 179, 6)" + ) + assertEquals( + "((57 * ((1 / 179) * (1 / 179))) * (((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179))))", + multiplyExponentiationBySquaring(Expr("57"), Expr("179"), -6).expr, + "tried multiplyExponentiationBySquaring(57, 179, -6)" + ) + assertEquals( + "(((57 * 179) * (179 * 179)) * ((179 * 179) * (179 * 179)))", + multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 7).expr, + "tried multiplyExponentiationBySquaring(57, 179, 7)" + ) + assertEquals( + "(((57 * (1 / 179)) * ((1 / 179) * (1 / 179))) * (((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179))))", + multiplyExponentiationBySquaring(Expr("57"), Expr("179"), -7).expr, + "tried multiplyExponentiationBySquaring(57, 179, -7)" + ) + assertEquals( + "(57 * (((179 * 179) * (179 * 179)) * ((179 * 179) * (179 * 179))))", + multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 8).expr, + "tried multiplyExponentiationBySquaring(57, 179, 8)" + ) + assertEquals( + "(57 * ((((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179))) * (((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179)))))", + multiplyExponentiationBySquaring(Expr("57"), Expr("179"), -8).expr, + "tried multiplyExponentiationBySquaring(57, 179, -8)" + ) + } + } + @Test + fun test_exponentiationBySquaring_for_Int() { + ExprRing { + assertEquals( + "0", + exponentiationBySquaring(Expr("57"), 0).expr, + "tried exponentiationBySquaring(57, 0)" + ) + assertEquals( + "57", + exponentiationBySquaring(Expr("57"), 1).expr, + "tried exponentiationBySquaring(57, 1)" + ) + assertEquals( + "(1 / 57)", + exponentiationBySquaring(Expr("57"), -1).expr, + "tried exponentiationBySquaring(57, -1)" + ) + assertEquals( + "(57 * 57)", + exponentiationBySquaring(Expr("57"), 2).expr, + "tried exponentiationBySquaring(57, 2)" + ) + assertEquals( + "((1 / 57) * (1 / 57))", + exponentiationBySquaring(Expr("57"), -2).expr, + "tried exponentiationBySquaring(57, -2)" + ) + assertEquals( + "(57 * (57 * 57))", + exponentiationBySquaring(Expr("57"), 3).expr, + "tried exponentiationBySquaring(57, 3)" + ) + assertEquals( + "((1 / 57) * ((1 / 57) * (1 / 57)))", + exponentiationBySquaring(Expr("57"), -3).expr, + "tried exponentiationBySquaring(57, -3)" + ) + assertEquals( + "((57 * 57) * (57 * 57))", + exponentiationBySquaring(Expr("57"), 4).expr, + "tried exponentiationBySquaring(57, 4)" + ) + assertEquals( + "(((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57)))", + exponentiationBySquaring(Expr("57"), -4).expr, + "tried exponentiationBySquaring(57, -4)" + ) + assertEquals( + "(57 * ((57 * 57) * (57 * 57)))", + exponentiationBySquaring(Expr("57"), 5).expr, + "tried exponentiationBySquaring(57, 5)" + ) + assertEquals( + "((1 / 57) * (((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57))))", + exponentiationBySquaring(Expr("57"), -5).expr, + "tried exponentiationBySquaring(57, -5)" + ) + assertEquals( + "((57 * 57) * ((57 * 57) * (57 * 57)))", + exponentiationBySquaring(Expr("57"), 6).expr, + "tried exponentiationBySquaring(57, 6)" + ) + assertEquals( + "(((1 / 57) * (1 / 57)) * (((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57))))", + exponentiationBySquaring(Expr("57"), -6).expr, + "tried exponentiationBySquaring(57, -6)" + ) + assertEquals( + "((57 * (57 * 57)) * ((57 * 57) * (57 * 57)))", + exponentiationBySquaring(Expr("57"), 7).expr, + "tried exponentiationBySquaring(57, 7)" + ) + assertEquals( + "(((1 / 57) * ((1 / 57) * (1 / 57))) * (((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57))))", + exponentiationBySquaring(Expr("57"), -7).expr, + "tried exponentiationBySquaring(57, -7)" + ) + assertEquals( + "(((57 * 57) * (57 * 57)) * ((57 * 57) * (57 * 57)))", + exponentiationBySquaring(Expr("57"), 8).expr, + "tried exponentiationBySquaring(57, 8)" + ) + assertEquals( + "((((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57))) * (((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57))))", + exponentiationBySquaring(Expr("57"), -8).expr, + "tried exponentiationBySquaring(57, -8)" + ) + } + } +} \ No newline at end of file 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 e0f0e32a4..a11242b2a 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 @@ -12,11 +12,12 @@ import kotlin.test.assertEquals class PolynomialTest { @Test fun simple_polynomial_test() { + val polynomial : Polynomial Double.algebra.scalablePolynomial { val x = Polynomial(listOf(0.0, 1.0)) - val polynomial = x * x - 2 * x + 1 - assertEquals(0.0, polynomial.substitute(1.0), 0.001) + polynomial = x * x - 2 * x + 1 } + assertEquals(0.0, polynomial.substitute(1.0), 0.001) } @Test fun testIntegration() { -- 2.34.1 From a965f5683f055daf20058f81e62fc8cc16e48141 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sat, 19 Mar 2022 16:54:30 +0300 Subject: [PATCH 037/123] Added some tests and some utilities for tests. Fixed bug in utility of PolynomialSpace. --- .../kscience/kmath/functions/Polynomial.kt | 8 +- .../kmath/functions/PolynomialTest.kt | 67 +++ .../kscience/kmath/test/misc/Rational.kt | 387 ++++++++++++++++++ .../test/misc/RationalWithMemorization.kt | 113 +++++ .../kscience/kmath/test/misc/memorization.kt | 51 +++ .../space/kscience/kmath/test/misc/misc.kt | 25 ++ 6 files changed, 647 insertions(+), 4 deletions(-) create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/RationalWithMemorization.kt create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/memorization.kt create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt 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 -- 2.34.1 From 90a7c4d901d6383b2de5326b0fa852f27bc47320 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sat, 19 Mar 2022 18:08:43 +0300 Subject: [PATCH 038/123] Simplified use of Rational (current BigInt are hard to use and actually useless). Added tests, fixed bug. --- .../kmath/functions/NumberedPolynomial.kt | 8 +- .../kscience/kmath/functions/Polynomial.kt | 2 +- .../kmath/functions/PolynomialTest.kt | 225 +++++++++-- .../kscience/kmath/test/misc/Rational.kt | 348 +++--------------- .../test/misc/RationalWithMemorization.kt | 42 +-- .../space/kscience/kmath/test/misc/misc.kt | 17 +- 6 files changed, 268 insertions(+), 374 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt index 88349f003..c05bc30ec 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -246,7 +246,7 @@ public open class NumberedPolynomialSpace>( override operator fun C.minus(other: NumberedPolynomial): NumberedPolynomial = if (this.isZero()) -other else with(other.coefficients) { - if (isEmpty()) NumberedPolynomial(mapOf(listOf() to this@minus)) + if (isEmpty()) NumberedPolynomial(mapOf(emptyList() to this@minus)) else NumberedPolynomial( toMutableMap() .apply { @@ -279,7 +279,7 @@ public open class NumberedPolynomialSpace>( override operator fun NumberedPolynomial.plus(other: C): NumberedPolynomial = if (other.isZero()) this else with(coefficients) { - if (isEmpty()) NumberedPolynomial(mapOf(listOf() to other)) + if (isEmpty()) NumberedPolynomial(mapOf(emptyList() to other)) else NumberedPolynomial( toMutableMap() .apply { @@ -298,7 +298,7 @@ public open class NumberedPolynomialSpace>( override operator fun NumberedPolynomial.minus(other: C): NumberedPolynomial = if (other.isZero()) this else with(coefficients) { - if (isEmpty()) NumberedPolynomial(mapOf(listOf() to other)) + if (isEmpty()) NumberedPolynomial(mapOf(emptyList() to other)) else NumberedPolynomial( toMutableMap() .apply { @@ -416,7 +416,7 @@ public open class NumberedPolynomialSpace>( override val one: NumberedPolynomial = NumberedPolynomial( mapOf( - listOf() to constantOne // 1 * x_1^0 * x_2^0 * ... + emptyList() to constantOne // 1 * x_1^0 * x_2^0 * ... ) ) 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 3f0d073b3..722566f5d 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 @@ -276,7 +276,7 @@ public open class PolynomialSpace>( public override operator fun Polynomial.minus(other: C): Polynomial = if (other.isZero()) this else with(coefficients) { - if (isEmpty()) Polynomial(listOf(other)) + if (isEmpty()) Polynomial(listOf(-other)) else Polynomial( toMutableList() .apply { 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 9e3dea615..e2970d953 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,16 +5,173 @@ 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_Int_plus() { + RationalField.polynomial { + assertEquals( + Polynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), + Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + -3, + "test 1" + ) + assertEquals( + Polynomial(Rational(0), Rational(0), Rational(0), Rational(0)), + Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + 2, + "test 2" + ) + assertEquals( + Polynomial(), + Polynomial(Rational(-2)) + 2, + "test 3" + ) + assertEquals( + Polynomial(), + Polynomial() + 0, + "test 4" + ) + assertEquals( + Polynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), + Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + 1, + "test 5" + ) + assertEquals( + Polynomial(Rational(-1)), + Polynomial(Rational(-2)) + 1, + "test 6" + ) + assertEquals( + Polynomial(Rational(2)), + Polynomial() + 2, + "test 7" + ) + } + } + @Test + fun test_Polynomial_Int_minus() { + RationalField.polynomial { + assertEquals( + Polynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), + Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - -3, + "test 1" + ) + assertEquals( + Polynomial(Rational(0), Rational(0), Rational(0), Rational(0)), + Polynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - 2, + "test 2" + ) + assertEquals( + Polynomial(), + Polynomial(Rational(2)) - 2, + "test 3" + ) + assertEquals( + Polynomial(), + Polynomial() - 0, + "test 4" + ) + assertEquals( + Polynomial(Rational(1), Rational(0), Rational(0), Rational(0)), + Polynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - 1, + "test 5" + ) + assertEquals( + Polynomial(Rational(1)), + Polynomial(Rational(2)) - 1, + "test 6" + ) + assertEquals( + Polynomial(Rational(-2)), + Polynomial() - 2, + "test 7" + ) + } + } + @Test + fun test_Polynomial_Constant_plus() { + RationalField.polynomial { + assertEquals( + Polynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), + Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + Rational(-3), + "test 1" + ) + assertEquals( + Polynomial(Rational(0), Rational(0), Rational(0), Rational(0)), + Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + Rational(2), + "test 2" + ) + assertEquals( + Polynomial(), + Polynomial(Rational(-2)) + Rational(2), + "test 3" + ) + assertEquals( + Polynomial(), + Polynomial() + Rational(0), + "test 4" + ) + assertEquals( + Polynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), + Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + Rational(1), + "test 5" + ) + assertEquals( + Polynomial(Rational(-1)), + Polynomial(Rational(-2)) + Rational(1), + "test 6" + ) + assertEquals( + Polynomial(Rational(2)), + Polynomial() + Rational(2), + "test 7" + ) + } + } + @Test + fun test_Polynomial_Constant_minus() { + RationalField.polynomial { + assertEquals( + Polynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), + Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - Rational(-3), + "test 1" + ) + assertEquals( + Polynomial(Rational(0), Rational(0), Rational(0), Rational(0)), + Polynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - Rational(2), + "test 2" + ) + assertEquals( + Polynomial(), + Polynomial(Rational(2)) - Rational(2), + "test 3" + ) + assertEquals( + Polynomial(), + Polynomial() - Rational(0), + "test 4" + ) + assertEquals( + Polynomial(Rational(1), Rational(0), Rational(0), Rational(0)), + Polynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - Rational(1), + "test 5" + ) + assertEquals( + Polynomial(Rational(1)), + Polynomial(Rational(2)) - Rational(1), + "test 6" + ) + assertEquals( + Polynomial(Rational(-2)), + Polynomial() - Rational(2), + "test 7" + ) + } + } @Test fun test_Polynomial_Polynomial_plus() { RationalField.polynomial { @@ -48,35 +205,39 @@ class PolynomialTest { ) } } -// @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 test_Polynomial_Polynomial_minus() { + RationalField.polynomial { + // (5/9 - 8/9 x - 8/7 x^2) - (-5/7 + 5/1 x + 5/8 x^2) ?= 80/63 - 53/9 x - 99/56 x^2 + assertEquals( + Polynomial(Rational(80, 63), Rational(-53, 9), Rational(-99, 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 - 59/12 x - 2/4 x^2 + assertEquals( + Polynomial(Rational(-2, 9), Rational(-59, 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) ?= 10/7 + 19/6 x - 2/3 x^2 + assertEquals( + Polynomial(Rational(10, 7), Rational(19, 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 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 index fad13f88a..842e354db 100644 --- 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 @@ -6,54 +6,23 @@ 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) +class Rational { + companion object { + val ZERO: Rational = Rational(0L) + val ONE: Rational = Rational(1L) } - /** - * 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 + val numerator: Long + val denominator: Long - /** - * 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) { + internal constructor(numerator: Long, denominator: Long, toCheckInput: Boolean = true) { if (toCheckInput) { - if (denominator == I0) throw ArithmeticException("/ by zero") + if (denominator == 0L) throw ArithmeticException("/ by zero") - val greatestCommonDivider = gcd(numerator, denominator).let { if (denominator < I0) -it else it } + val greatestCommonDivider = gcd(numerator, denominator).let { if (denominator < 0L) -it else it } this.numerator = numerator / greatestCommonDivider this.denominator = denominator / greatestCommonDivider @@ -63,303 +32,86 @@ public class Rational: Comparable { } } - /** - * 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) + constructor(numerator: Int, denominator: Int) : this(numerator.toLong(), denominator.toLong(), true) + constructor(numerator: Int, denominator: Long) : this(numerator.toLong(), denominator, true) + constructor(numerator: Long, denominator: Int) : this(numerator, denominator.toLong(), true) + constructor(numerator: Long, denominator: Long) : this(numerator, denominator, true) + constructor(numerator: Int) : this(numerator.toLong(), 1L, false) + constructor(numerator: Long) : this(numerator, 1L, 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 = + operator fun unaryPlus(): Rational = this + operator fun unaryMinus(): Rational = Rational(-this.numerator, this.denominator) + 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 = + operator fun plus(other: Int): Rational = + Rational( + numerator + denominator * other.toLong(), + denominator + ) + operator fun plus(other: Long): 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 = + 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 = + operator fun minus(other: Int): Rational = + Rational( + numerator - denominator * other.toLong(), + denominator + ) + operator fun minus(other: Long): 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 = + 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 = + operator fun times(other: Int): Rational = + Rational( + numerator * other.toLong(), + denominator + ) + operator fun times(other: Long): 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 = + 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 = + operator fun div(other: Int): Rational = + Rational( + numerator, + denominator * other.toLong() + ) + operator fun div(other: Long): 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 + is Int -> numerator == other && denominator == 1L + is Long -> numerator == other && denominator == 1L 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) + override fun hashCode(): Int = 31 * numerator.hashCode() + denominator.hashCode() - /** - * 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" + override fun toString(): String = if (denominator == 1L) "$numerator" else "$numerator/$denominator" } @@ -368,7 +120,7 @@ public class Rational: Comparable { */ @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") @OptIn(UnstableKMathAPI::class) -public object RationalField : Field, NumbersAddOps { +object RationalField : Field, NumbersAddOps { override inline val zero: Rational get() = Rational.ZERO override inline val one: Rational get() = Rational.ONE 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 index 6aa5ecc09..05d9115fa 100644 --- 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 @@ -12,7 +12,7 @@ class RationalWithMemorization private constructor( val value: Rational, override val memory : OperationsMemory ): WithMemorization { - public companion object { + companion object { /** * Constant containing the zero (the additive identity) of the [Rational] field. */ @@ -22,48 +22,42 @@ class RationalWithMemorization private constructor( */ 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 {}) + constructor(numerator: Int, denominator: Int) : this(Rational(numerator, denominator), object : Endpoint {}) + constructor(numerator: Int, denominator: Long) : this(Rational(numerator, denominator), object : Endpoint {}) + constructor(numerator: Long, denominator: Int) : this(Rational(numerator, denominator), object : Endpoint {}) + constructor(numerator: Long, denominator: Long) : this(Rational(numerator, denominator), object : Endpoint {}) + constructor(numerator: Int) : this(Rational(numerator), object : Endpoint {}) + constructor(numerator: Long) : this(Rational(numerator), object : Endpoint {}) - public operator fun unaryPlus(): RationalWithMemorization = this - public operator fun unaryMinus(): RationalWithMemorization = RationalWithMemorization( + operator fun unaryPlus(): RationalWithMemorization = this + operator fun unaryMinus(): RationalWithMemorization = RationalWithMemorization( -value, object : Negation { override val negated: OperationsMemory = memory } ) - public operator fun plus(other: RationalWithMemorization): RationalWithMemorization = RationalWithMemorization( + 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( + 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( + 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( + operator fun div(other: RationalWithMemorization): RationalWithMemorization = RationalWithMemorization( value / other.value, object : Quotient { override val dividend: OperationsMemory = memory @@ -71,16 +65,16 @@ class RationalWithMemorization private constructor( } ) - public override fun equals(other: Any?): Boolean = + override fun equals(other: Any?): Boolean = other is RationalWithMemorization && value == other.value - public override fun hashCode(): Int = value.hashCode() + override fun hashCode(): Int = value.hashCode() - public override fun toString(): String = value.toString() + override fun toString(): String = value.toString() } @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") -public object RationalWithMemorizationRing : Ring { +object RationalWithMemorizationRing : Ring { override inline val zero: RationalWithMemorization get() = RationalWithMemorization.ZERO override inline val one: RationalWithMemorization get() = RationalWithMemorization.ONE @@ -94,7 +88,7 @@ public object RationalWithMemorizationRing : Ring { } @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") -public object RationalWithMemorizationField : Field { +object RationalWithMemorizationField : Field { override inline val zero: RationalWithMemorization get() = RationalWithMemorization.ZERO override inline val one: RationalWithMemorization get() = RationalWithMemorization.ONE 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 index eab29842c..2eb421024 100644 --- 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 @@ -5,21 +5,8 @@ package space.kscience.kmath.test.misc -import space.kscience.kmath.operations.* -import space.kscience.kmath.operations.BigInt.Companion.ZERO as I0 +import kotlin.math.abs // 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 +tailrec fun gcd(a: Long, b: Long): Long = if (a == 0L) abs(b) else gcd(b % a, a) \ No newline at end of file -- 2.34.1 From 5d4514a742d0c36dabf2b0e03243f61381453313 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sat, 19 Mar 2022 19:35:41 +0300 Subject: [PATCH 039/123] More test tools! More tests!! More fixes of stupid bugs!!! :sob: --- .../kscience/kmath/functions/Polynomial.kt | 2 +- .../kmath/functions/PolynomialTest.kt | 224 +++++++++++++++++- .../kscience/kmath/test/misc/IntModulo.kt | 142 +++++++++++ .../kscience/kmath/test/misc/Rational.kt | 4 - .../space/kscience/kmath/test/misc/misc.kt | 25 +- 5 files changed, 387 insertions(+), 10 deletions(-) create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt 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 722566f5d..9c1f9efae 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 @@ -220,7 +220,7 @@ public open class PolynomialSpace>( public override operator fun C.minus(other: Polynomial): Polynomial = if (this.isZero()) other else with(other.coefficients) { - if (isEmpty()) Polynomial(listOf(-this@minus)) + if (isEmpty()) Polynomial(listOf(this@minus)) else Polynomial( toMutableList() .apply { 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 e2970d953..0bf34f198 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 @@ -6,11 +6,11 @@ package space.kscience.kmath.functions import space.kscience.kmath.operations.algebra -import space.kscience.kmath.test.misc.Rational -import space.kscience.kmath.test.misc.RationalField +import space.kscience.kmath.test.misc.* import kotlin.test.Test import kotlin.test.assertEquals + class PolynomialTest { @Test fun test_Polynomial_Int_plus() { @@ -93,6 +93,116 @@ class PolynomialTest { } } @Test + fun test_Polynomial_Int_times() { + IntModuloRing(35).polynomial { + assertEquals( + Polynomial(34, 2, 1, 20, 2), + Polynomial(22, 26, 13, 15, 26) * 27, + "test 1" + ) + assertEquals( + Polynomial(), + Polynomial(7, 0, 49, 21, 14) * 15, + "test 2" + ) + } + } + @Test + fun test_Int_Polynomial_plus() { + RationalField.polynomial { + assertEquals( + Polynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), + -3 + Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)), + "test 1" + ) + assertEquals( + Polynomial(Rational(0), Rational(0), Rational(0), Rational(0)), + 2 + Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), + "test 2" + ) + assertEquals( + Polynomial(), + 2 + Polynomial(Rational(-2)), + "test 3" + ) + assertEquals( + Polynomial(), + 0 + Polynomial(), + "test 4" + ) + assertEquals( + Polynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), + 1 + Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), + "test 5" + ) + assertEquals( + Polynomial(Rational(-1)), + 1 + Polynomial(Rational(-2)), + "test 6" + ) + assertEquals( + Polynomial(Rational(2)), + 2 + Polynomial(), + "test 7" + ) + } + } + @Test + fun test_Int_Polynomial_minus() { + RationalField.polynomial { + assertEquals( + Polynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), + 3 - Polynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), + "test 1" + ) + assertEquals( + Polynomial(Rational(0), Rational(0), Rational(0), Rational(0)), + -2 - Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), + "test 2" + ) + assertEquals( + Polynomial(), + -2 - Polynomial(Rational(-2)), + "test 3" + ) + assertEquals( + Polynomial(), + 0 - Polynomial(), + "test 4" + ) + assertEquals( + Polynomial(Rational(1), Rational(0), Rational(0), Rational(0)), + -1 - Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), + "test 5" + ) + assertEquals( + Polynomial(Rational(1)), + -1 - Polynomial(Rational(-2)), + "test 6" + ) + assertEquals( + Polynomial(Rational(-2)), + -2 - Polynomial(), + "test 7" + ) + } + } + @Test + fun test_Int_Polynomial_times() { + IntModuloRing(35).polynomial { + assertEquals( + Polynomial(34, 2, 1, 20, 2), + 27 * Polynomial(22, 26, 13, 15, 26), + "test 1" + ) + assertEquals( + Polynomial(), + 15 * Polynomial(7, 0, 49, 21, 14), + "test 2" + ) + } + } + @Test fun test_Polynomial_Constant_plus() { RationalField.polynomial { assertEquals( @@ -173,6 +283,116 @@ class PolynomialTest { } } @Test + fun test_Polynomial_Constant_times() { + IntModuloRing(35).polynomial { + assertEquals( + Polynomial(34, 2, 1, 20, 2), + Polynomial(22, 26, 13, 15, 26) * number(27), + "test 1" + ) + assertEquals( + Polynomial(), + Polynomial(7, 0, 49, 21, 14) * number(15), + "test 2" + ) + } + } + @Test + fun test_Constant_Polynomial_plus() { + RationalField.polynomial { + assertEquals( + Polynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), + Rational(-3) + Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)), + "test 1" + ) + assertEquals( + Polynomial(Rational(0), Rational(0), Rational(0), Rational(0)), + Rational(2) + Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), + "test 2" + ) + assertEquals( + Polynomial(), + Rational(2) + Polynomial(Rational(-2)), + "test 3" + ) + assertEquals( + Polynomial(), + Rational(0) + Polynomial(), + "test 4" + ) + assertEquals( + Polynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), + Rational(1) + Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), + "test 5" + ) + assertEquals( + Polynomial(Rational(-1)), + Rational(1) + Polynomial(Rational(-2)), + "test 6" + ) + assertEquals( + Polynomial(Rational(2)), + Rational(2) + Polynomial(), + "test 7" + ) + } + } + @Test + fun test_Constant_Polynomial_minus() { + RationalField.polynomial { + assertEquals( + Polynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), + Rational(3) - Polynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), + "test 1" + ) + assertEquals( + Polynomial(Rational(0), Rational(0), Rational(0), Rational(0)), + Rational(-2) - Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), + "test 2" + ) + assertEquals( + Polynomial(), + Rational(-2) - Polynomial(Rational(-2)), + "test 3" + ) + assertEquals( + Polynomial(), + Rational(0) - Polynomial(), + "test 4" + ) + assertEquals( + Polynomial(Rational(1), Rational(0), Rational(0), Rational(0)), + Rational(-1) - Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), + "test 5" + ) + assertEquals( + Polynomial(Rational(1)), + Rational(-1) - Polynomial(Rational(-2)), + "test 6" + ) + assertEquals( + Polynomial(Rational(-2)), + Rational(-2) - Polynomial(), + "test 7" + ) + } + } + @Test + fun test_Constant_Polynomial_times() { + IntModuloRing(35).polynomial { + assertEquals( + Polynomial(34, 2, 1, 20, 2), + 27 * Polynomial(22, 26, 13, 15, 26), + "test 1" + ) + assertEquals( + Polynomial(), + 15 * Polynomial(7, 0, 49, 21, 14), + "test 2" + ) + } + } + @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 diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt new file mode 100644 index 000000000..a8a8a09bc --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt @@ -0,0 +1,142 @@ +/* + * 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.functions.Polynomial +import space.kscience.kmath.functions.PolynomialSpace +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.Ring + + +class IntModulo { + val residue: Int + val modulus: Int + + @PublishedApi + internal constructor(residue: Int, modulus: Int, toCheckInput: Boolean = true) { + if (toCheckInput) { + require(modulus != 0) { "modulus can not be zero" } + this.modulus = if (modulus < 0) -modulus else modulus + this.residue = residue.mod(modulus) + } else { + this.residue = residue + this.modulus = modulus + } + } + + constructor(residue: Int, modulus: Int) : this(residue, modulus, true) + + operator fun unaryPlus(): IntModulo = this + operator fun unaryMinus(): IntModulo = + IntModulo( + if (residue == 0) 0 else modulus - residue, + modulus, + toCheckInput = false + ) + operator fun plus(other: IntModulo): IntModulo { + require(modulus == other.modulus) { "can not add two residue different modulo" } + return IntModulo( + (residue + other.residue) % modulus, + modulus, + toCheckInput = false + ) + } + operator fun plus(other: Int): IntModulo = + IntModulo( + (residue + other) % modulus, + modulus, + toCheckInput = false + ) + operator fun minus(other: IntModulo): IntModulo { + require(modulus == other.modulus) { "can not subtract two residue different modulo" } + return IntModulo( + (residue - other.residue) % modulus, + modulus, + toCheckInput = false + ) + } + operator fun minus(other: Int): IntModulo = + IntModulo( + (residue - other) % modulus, + modulus, + toCheckInput = false + ) + operator fun times(other: IntModulo): IntModulo { + require(modulus == other.modulus) { "can not multiply two residue different modulo" } + return IntModulo( + (residue * other.residue) % modulus, + modulus, + toCheckInput = false + ) + } + operator fun times(other: Int): IntModulo = + IntModulo( + (residue * other) % modulus, + modulus, + toCheckInput = false + ) + operator fun div(other: IntModulo): IntModulo { + require(modulus == other.modulus) { "can not divide two residue different modulo" } + val (reciprocalCandidate, gcdOfOtherResidueAndModulus) = bezoutIdentityWithGCD(other.residue, modulus) + require(gcdOfOtherResidueAndModulus == 1) { "can not divide to residue that has non-trivial GCD with modulo" } + return IntModulo( + (residue * reciprocalCandidate) % modulus, + modulus, + toCheckInput = false + ) + } + operator fun div(other: Int): IntModulo { + val (reciprocalCandidate, gcdOfOtherResidueAndModulus) = bezoutIdentityWithGCD(other, modulus) + require(gcdOfOtherResidueAndModulus == 1) { "can not divide to residue that has non-trivial GCD with modulo" } + return IntModulo( + (residue * reciprocalCandidate) % modulus, + modulus, + toCheckInput = false + ) + } + override fun equals(other: Any?): Boolean = + when (other) { + is IntModulo -> residue == other.residue && modulus == other.modulus + else -> false + } + + override fun hashCode(): Int = residue.hashCode() + + override fun toString(): String = "$residue mod $modulus" +} + +@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") +@OptIn(UnstableKMathAPI::class) +class IntModuloRing : Ring { + + val modulus: Int + + constructor(modulus: Int) { + require(modulus != 0) { "modulus can not be zero" } + this.modulus = if (modulus < 0) -modulus else modulus + } + + override inline val zero: IntModulo get() = IntModulo(0, modulus, toCheckInput = false) + override inline val one: IntModulo get() = IntModulo(0, modulus, toCheckInput = false) + + fun number(arg: Int) = IntModulo(arg, modulus, toCheckInput = false) + + override inline fun add(left: IntModulo, right: IntModulo): IntModulo = left + right + override inline fun multiply(left: IntModulo, right: IntModulo): IntModulo = left * right + + override inline fun IntModulo.unaryMinus(): IntModulo = -this + override inline fun IntModulo.plus(arg: IntModulo): IntModulo = this + arg + override inline fun IntModulo.minus(arg: IntModulo): IntModulo = this - arg + override inline fun IntModulo.times(arg: IntModulo): IntModulo = this * arg + inline fun IntModulo.div(arg: IntModulo): IntModulo = this / arg +} + +fun PolynomialSpace.number(arg: Int) = IntModulo(arg, ring.modulus, toCheckInput = false) + +fun PolynomialSpace.Polynomial(vararg coefs: Int): Polynomial = + Polynomial(coefs.map { IntModulo(it, ring.modulus) }) +fun IntModuloRing.Polynomial(vararg coefs: Int): Polynomial = + Polynomial(coefs.map { IntModulo(it, modulus) }) \ No newline at end of file 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 index 842e354db..72bb5942c 100644 --- 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 @@ -114,10 +114,6 @@ class Rational { override fun toString(): String = if (denominator == 1L) "$numerator" else "$numerator/$denominator" } - -/** - * Algebraic structure for rational numbers. - */ @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") @OptIn(UnstableKMathAPI::class) object RationalField : Field, NumbersAddOps { 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 index 2eb421024..cc647fa2c 100644 --- 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 @@ -5,8 +5,27 @@ package space.kscience.kmath.test.misc -import kotlin.math.abs - // TODO: Move to corresponding module "kmath-number-theory" -tailrec fun gcd(a: Long, b: Long): Long = if (a == 0L) abs(b) else gcd(b % a, a) \ No newline at end of file +import kotlin.math.abs + + +data class BezoutIdentityWithGCD(val first: T, val second: T, val gcd: T) + +tailrec fun gcd(a: Long, b: Long): Long = if (a == 0L) abs(b) else gcd(b % a, a) + +fun bezoutIdentityWithGCD(a: Int, b: Int): BezoutIdentityWithGCD = + when { + a < 0 && b < 0 -> with(bezoutIdentityWithGCDInternalLogic(-a, -b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(-first, -second, gcd) } + a < 0 -> with(bezoutIdentityWithGCDInternalLogic(-a, b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(-first, second, gcd) } + b < 0 -> with(bezoutIdentityWithGCDInternalLogic(a, -b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(first, -second, gcd) } + else -> bezoutIdentityWithGCDInternalLogic(a, b, 1, 0, 0, 1) + } + +internal tailrec fun bezoutIdentityWithGCDInternalLogic(a: Int, b: Int, m1: Int, m2: Int, m3: Int, m4: Int): BezoutIdentityWithGCD = + if (b == 0) BezoutIdentityWithGCD(m1, m3, a) + else { + val quotient = a / b + val reminder = a % b + bezoutIdentityWithGCDInternalLogic(b, reminder, m2, m1 - quotient * m2, m4, m3 - quotient * m4) + } \ No newline at end of file -- 2.34.1 From fbc21101bbcb2cbc9a383fa2c18d635cba72c25e Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sun, 20 Mar 2022 06:26:52 +0300 Subject: [PATCH 040/123] Added test. Fixed isOne and isMinusOne for Polynomial. --- .../kscience/kmath/functions/Polynomial.kt | 6 +- .../kmath/functions/PolynomialTest.kt | 86 ++++++++++++++++--- .../kmath/functions/PolynomialUtilTest.kt | 27 ++++++ 3 files changed, 104 insertions(+), 15 deletions(-) create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt 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 9c1f9efae..7e0f6f62d 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 @@ -369,14 +369,14 @@ public open class PolynomialSpace>( */ public override fun Polynomial.isOne(): Boolean = with(coefficients) { - isNotEmpty() && withIndex().any { (index, c) -> if (index == 0) c.isOne() else c.isZero() } + isNotEmpty() && withIndex().all { (index, c) -> if (index == 0) c.isOne() else c.isZero() } } /** * Check if the instant is minus unit polynomial. */ public override fun Polynomial.isMinusOne(): Boolean = with(coefficients) { - isNotEmpty() && withIndex().any { (index, c) -> if (index == 0) c.isMinusOne() else c.isZero() } + isNotEmpty() && withIndex().all { (index, c) -> if (index == 0) c.isMinusOne() else c.isZero() } } /** @@ -415,7 +415,7 @@ public open class PolynomialSpace>( with(coefficients) { when { isEmpty() -> constantZero - degree > 0 -> null + withIndex().any { (index, c) -> index == 0 || c.isZero() } -> null else -> first() } } 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 0bf34f198..85b309467 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,10 +5,8 @@ package space.kscience.kmath.functions -import space.kscience.kmath.operations.algebra import space.kscience.kmath.test.misc.* -import kotlin.test.Test -import kotlin.test.assertEquals +import kotlin.test.* class PolynomialTest { @@ -393,6 +391,21 @@ class PolynomialTest { } } @Test + fun test_Polynomial_unaryMinus() { + RationalField.polynomial { + assertEquals( + Polynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), + -Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)), + "test 1" + ) + assertEquals( + Polynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7), Rational(0), Rational(0)), + -Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7), Rational(0), Rational(0)), + "test 2" + ) + } + } + @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 @@ -459,17 +472,66 @@ class PolynomialTest { } } @Test - fun simple_polynomial_test() { - val polynomial : Polynomial - Double.algebra.scalablePolynomial { - val x = Polynomial(listOf(0.0, 1.0)) - polynomial = x * x - 2 * x + 1 + fun test_Polynomial_Polynomial_times() { + IntModuloRing(35).polynomial { + // (1 + x + x^2) * (1 - x + x^2) ?= 1 + x^2 + x^4 + assertEquals( + Polynomial(1, 0, 1, 0, 1), + Polynomial(1, -1, 1) * Polynomial(1, 1, 1), + "test 1" + ) + // Spoiler: 5 * 7 = 0 + assertEquals( + Polynomial(), + Polynomial(5, -25, 10) * Polynomial(21, 14, -7), + "test 2" + ) } - assertEquals(0.0, polynomial.substitute(1.0), 0.001) } @Test - fun testIntegration() { - val polynomial = Polynomial(1.0, -2.0, 1.0) - assertEquals(0.0, polynomial.substitute(1.0), 0.001) + fun test_Polynomial_isZero() { + RationalField.polynomial { + assertTrue("test 1") { Polynomial().isZero() } + assertTrue("test 2") { Polynomial(Rational(0)).isZero() } + assertTrue("test 3") { Polynomial(Rational(0), Rational(0)).isZero() } + assertTrue("test 4") { Polynomial(Rational(0), Rational(0), Rational(0)).isZero() } + assertFalse("test 5") { Polynomial(Rational(3, 5)).isZero() } + assertFalse("test 6") { Polynomial(Rational(3, 5), Rational(0)).isZero() } + assertFalse("test 7") { Polynomial(Rational(0), Rational(3, 5), Rational(0)).isZero() } + } + } + @Test + fun test_Polynomial_isOne() { + RationalField.polynomial { + assertFalse("test 1") { Polynomial().isOne() } + assertFalse("test 2") { Polynomial(Rational(0)).isOne() } + assertFalse("test 3") { Polynomial(Rational(0), Rational(0)).isOne() } + assertFalse("test 4") { Polynomial(Rational(0), Rational(0), Rational(0)).isOne() } + assertFalse("test 5") { Polynomial(Rational(3, 5)).isOne() } + assertTrue("test 6") { Polynomial(Rational(5, 5)).isOne() } + assertFalse("test 7") { Polynomial(Rational(3, 5), Rational(0)).isOne() } + assertTrue("test 8") { Polynomial(Rational(3, 3), Rational(0)).isOne() } + assertFalse("test 9") { Polynomial(Rational(0), Rational(3, 5), Rational(0)).isOne() } + assertFalse("test 10") { Polynomial(Rational(0), Rational(5, 5), Rational(0)).isOne() } + assertFalse("test 11") { Polynomial(Rational(1), Rational(3, 5), Rational(0)).isOne() } + assertFalse("test 12") { Polynomial(Rational(1), Rational(5, 5), Rational(0)).isOne() } + } + } + @Test + fun test_Polynomial_isMinusOne() { + RationalField.polynomial { + assertFalse("test 1") { Polynomial().isMinusOne() } + assertFalse("test 2") { Polynomial(Rational(0)).isMinusOne() } + assertFalse("test 3") { Polynomial(Rational(0), Rational(0)).isMinusOne() } + assertFalse("test 4") { Polynomial(Rational(0), Rational(0), Rational(0)).isMinusOne() } + assertFalse("test 5") { Polynomial(Rational(3, 5)).isMinusOne() } + assertTrue("test 6") { Polynomial(Rational(-5, 5)).isMinusOne() } + assertFalse("test 7") { Polynomial(Rational(3, 5), Rational(0)).isMinusOne() } + assertTrue("test 8") { Polynomial(Rational(-3, 3), Rational(0)).isMinusOne() } + assertFalse("test 9") { Polynomial(Rational(0), Rational(3, 5), Rational(0)).isMinusOne() } + assertFalse("test 10") { Polynomial(Rational(0), Rational(5, -5), Rational(0)).isMinusOne() } + assertFalse("test 11") { Polynomial(Rational(-1), Rational(3, 5), Rational(0)).isMinusOne() } + assertFalse("test 12") { Polynomial(Rational(-1), Rational(5, -5), Rational(0)).isMinusOne() } + } } } \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt new file mode 100644 index 000000000..b9dd74800 --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt @@ -0,0 +1,27 @@ +/* + * 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.functions + +import space.kscience.kmath.operations.algebra +import kotlin.test.Test +import kotlin.test.assertEquals + +class PolynomialUtilTest { + @Test + fun simple_polynomial_test() { + val polynomial : Polynomial + Double.algebra.scalablePolynomial { + val x = Polynomial(listOf(0.0, 1.0)) + polynomial = x * x - 2 * x + 1 + } + assertEquals(0.0, polynomial.substitute(1.0), 0.001) + } + @Test + fun testIntegration() { + val polynomial = Polynomial(1.0, -2.0, 1.0) + assertEquals(0.0, polynomial.substitute(1.0), 0.001) + } +} \ No newline at end of file -- 2.34.1 From 25ec59b9851e71e3a652e043002a50902e8479b4 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sun, 20 Mar 2022 23:22:39 +0300 Subject: [PATCH 041/123] Finished with tests for Polynomial. --- .../kscience/kmath/functions/Polynomial.kt | 17 +- .../kmath/functions/polynomialUtil.kt | 50 ++-- .../kmath/functions/PolynomialTest.kt | 154 ++++++++++++ .../kmath/functions/PolynomialUtilTest.kt | 223 +++++++++++++++++- 4 files changed, 407 insertions(+), 37 deletions(-) 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 7e0f6f62d..d6c959fd1 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 @@ -386,7 +386,7 @@ public open class PolynomialSpace>( /** * Instance of unit constant (unit of the underlying ring). */ - override val one: Polynomial = Polynomial(listOf(constantZero)) + override val one: Polynomial = Polynomial(listOf(constantOne)) /** * Checks equality of the polynomials. @@ -394,11 +394,8 @@ public open class PolynomialSpace>( public override infix fun Polynomial.equalsTo(other: Polynomial): Boolean = when { this === other -> true - else -> { - if (this.degree == other.degree) - (0..degree).all { coefficients[it] == other.coefficients[it] } - else false - } + this.degree == other.degree -> (0..degree).all { coefficients[it] == other.coefficients[it] } + else -> false } /** @@ -415,8 +412,8 @@ public open class PolynomialSpace>( with(coefficients) { when { isEmpty() -> constantZero - withIndex().any { (index, c) -> index == 0 || c.isZero() } -> null - else -> first() + withIndex().all { (index, c) -> index == 0 || c.isZero() } -> first() + else -> null } } @@ -489,8 +486,6 @@ public open class PolynomialSpace>( public class ScalablePolynomialSpace( ring: A, ) : PolynomialSpace(ring), ScaleOperations> where A : Ring, A : ScaleOperations { - override fun scale(a: Polynomial, value: Double): Polynomial = - ring { Polynomial(List(a.coefficients.size) { index -> a.coefficients[index] * value }) } - + ring { Polynomial(a.coefficients.map { scale(it, value) }) } } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt index 84c8d2e88..afaf27a52 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt @@ -127,9 +127,10 @@ public fun Polynomial.substitute(ring: Ring, arg: Polynomial) : Pol if (argDegree == -1) return coefficients[0].asPolynomial() val constantZero = zero val resultCoefs: MutableList = MutableList(thisDegree * argDegree + 1) { constantZero } + resultCoefs[0] = coefficients[thisDegree] val resultCoefsUpdate: MutableList = MutableList(thisDegree * argDegree + 1) { constantZero } var resultDegree = 0 - for (deg in thisDegree downTo 0) { + for (deg in thisDegree - 1 downTo 0) { resultCoefsUpdate[0] = coefficients[deg] multiplyAddingToUpdater( ring = ring, @@ -142,6 +143,8 @@ public fun Polynomial.substitute(ring: Ring, arg: Polynomial) : Pol ) resultDegree += argDegree } + + with(resultCoefs) { while (isNotEmpty() && elementAt(lastIndex) == constantZero) removeAt(lastIndex) } return Polynomial(resultCoefs) } @@ -162,7 +165,12 @@ public fun > Polynomial.asPolynomialFunctionOver(ring: A): (Po public fun Polynomial.derivative( algebra: A, ): Polynomial where A : Ring, A : NumericAlgebra = algebra { - Polynomial(coefficients.drop(1).mapIndexed { index, c -> number(index + 1) * c }) + Polynomial( + buildList(max(0, coefficients.size - 1)) { + for (deg in 1 .. coefficients.lastIndex) add(number(deg) * coefficients[deg]) + while (isNotEmpty() && elementAt(lastIndex) == algebra.zero) removeAt(lastIndex) + } + ) } /** @@ -171,9 +179,16 @@ public fun Polynomial.derivative( @UnstableKMathAPI public fun Polynomial.nthDerivative( algebra: A, - order: UInt, + order: Int, ): Polynomial where A : Ring, A : NumericAlgebra = algebra { - Polynomial(coefficients.drop(order.toInt()).mapIndexed { index, c -> (index + 1..index + order.toInt()).fold(c) { acc, i -> acc * number(i) } }) + require(order >= 0) { "Order of derivative must be non-negative" } + Polynomial( + buildList(max(0, coefficients.size - order)) { + for (deg in order.. coefficients.lastIndex) + add((deg - order + 1 .. deg).fold(coefficients[deg]) { acc, d -> acc * number(d) }) + while (isNotEmpty() && elementAt(lastIndex) == algebra.zero) removeAt(lastIndex) + } + ) } /** @@ -183,11 +198,13 @@ public fun Polynomial.nthDerivative( public fun Polynomial.antiderivative( algebra: A, ): Polynomial where A : Field, A : NumericAlgebra = algebra { - val integratedCoefficients = buildList(coefficients.size + 1) { - add(zero) - coefficients.mapIndexedTo(this) { index, t -> t / number(index + 1) } - } - Polynomial(integratedCoefficients) + Polynomial( + buildList(coefficients.size + 1) { + add(zero) + coefficients.mapIndexedTo(this) { index, t -> t / number(index + 1) } + while (isNotEmpty() && elementAt(lastIndex) == algebra.zero) removeAt(lastIndex) + } + ) } /** @@ -196,13 +213,16 @@ public fun Polynomial.antiderivative( @UnstableKMathAPI public fun Polynomial.nthAntiderivative( algebra: A, - order: UInt, + order: Int, ): Polynomial where A : Field, A : NumericAlgebra = algebra { - val newCoefficients = buildList(coefficients.size + order.toInt()) { - repeat(order.toInt()) { add(zero) } - coefficients.mapIndexedTo(this) { index, c -> (1..order.toInt()).fold(c) { acc, i -> acc / number(index + i) } } - } - return Polynomial(newCoefficients) + require(order >= 0) { "Order of antiderivative must be non-negative" } + Polynomial( + buildList(coefficients.size + order) { + repeat(order) { add(zero) } + coefficients.mapIndexedTo(this) { index, c -> (1..order).fold(c) { acc, i -> acc / number(index + i) } } + while (isNotEmpty() && elementAt(lastIndex) == algebra.zero) 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 85b309467..141bdd436 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 @@ -534,4 +534,158 @@ class PolynomialTest { assertFalse("test 12") { Polynomial(Rational(-1), Rational(5, -5), Rational(0)).isMinusOne() } } } + @Test + fun test_Polynomial_equalsTo() { + RationalField.polynomial { + assertTrue("test 1") { + Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) equalsTo + Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + } + assertTrue("test 2") { + Polynomial(Rational(5, 9), Rational(0), Rational(-8, 7)) equalsTo + Polynomial(Rational(5, 9), Rational(0), Rational(-8, 7)) + } + assertTrue("test 3") { + Polynomial(Rational(0), Rational(0), Rational(-8, 7), Rational(0), Rational(0)) equalsTo + Polynomial(Rational(0), Rational(0), Rational(-8, 7)) + } + assertFalse("test 4") { + Polynomial(Rational(5, 9), Rational(5, 7), Rational(-8, 7)) equalsTo + Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + } + assertFalse("test 5") { + Polynomial(Rational(8, 3), Rational(0), Rational(-8, 7)) equalsTo + Polynomial(Rational(5, 9), Rational(0), Rational(-8, 7)) + } + assertFalse("test 6") { + Polynomial(Rational(0), Rational(0), Rational(-8, 7), Rational(0), Rational(0)) equalsTo + Polynomial(Rational(0), Rational(0), Rational(8, 7)) + } + } + } + @Test + fun test_Polynomial_degree() { + RationalField.polynomial { + assertEquals( + 2, + Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)).degree, + "test 1" + ) + assertEquals( + -1, + Polynomial().degree, + "test 2" + ) + assertEquals( + -1, + Polynomial(Rational(0)).degree, + "test 3" + ) + assertEquals( + -1, + Polynomial(Rational(0), Rational(0)).degree, + "test 4" + ) + assertEquals( + -1, + Polynomial(Rational(0), Rational(0), Rational(0)).degree, + "test 5" + ) + assertEquals( + 0, + Polynomial(Rational(5, 9)).degree, + "test 6" + ) + assertEquals( + 0, + Polynomial(Rational(5, 9), Rational(0)).degree, + "test 7" + ) + assertEquals( + 0, + Polynomial(Rational(5, 9), Rational(0), Rational(0)).degree, + "test 8" + ) + assertEquals( + 2, + Polynomial(Rational(0), Rational(0), Rational(-8, 7)).degree, + "test 9" + ) + assertEquals( + 2, + Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7), Rational(0), Rational(0)).degree, + "test 10" + ) + assertEquals( + 2, + Polynomial(Rational(0), Rational(0), Rational(-8, 7), Rational(0), Rational(0)).degree, + "test 11" + ) + } + } + @Test + fun test_Polynomial_asConstantOrNull() { + RationalField.polynomial { + assertEquals( + Rational(0), + Polynomial().asConstantOrNull(), + "test 1" + ) + assertEquals( + Rational(0), + Polynomial(Rational(0)).asConstantOrNull(), + "test 2" + ) + assertEquals( + Rational(0), + Polynomial(Rational(0), Rational(0)).asConstantOrNull(), + "test 3" + ) + assertEquals( + Rational(0), + Polynomial(Rational(0), Rational(0), Rational(0)).asConstantOrNull(), + "test 4" + ) + assertEquals( + Rational(-7, 9), + Polynomial(Rational(-7, 9)).asConstantOrNull(), + "test 5" + ) + assertEquals( + Rational(-7, 9), + Polynomial(Rational(-7, 9), Rational(0)).asConstantOrNull(), + "test 6" + ) + assertEquals( + Rational(-7, 9), + Polynomial(Rational(-7, 9), Rational(0), Rational(0)).asConstantOrNull(), + "test 7" + ) + assertEquals( + null, + Polynomial(Rational(0), Rational(-7, 9)).asConstantOrNull(), + "test 8" + ) + assertEquals( + null, + Polynomial(Rational(0), Rational(-7, 9), Rational(0)).asConstantOrNull(), + "test 9" + ) + assertEquals( + null, + Polynomial(Rational(0), Rational(0), Rational(-7, 9)).asConstantOrNull(), + "test 10" + ) + assertEquals( + null, + Polynomial(Rational(4, 15), Rational(0), Rational(-7, 9)).asConstantOrNull(), + "test 11" + ) + assertEquals( + null, + Polynomial(Rational(4, 15), Rational(0), Rational(-7, 9), Rational(0)).asConstantOrNull(), + "test 12" + ) + } + } } \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt index b9dd74800..fbae61ed1 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt @@ -5,23 +5,224 @@ package space.kscience.kmath.functions -import space.kscience.kmath.operations.algebra +import space.kscience.kmath.test.misc.Rational +import space.kscience.kmath.test.misc.RationalField import kotlin.test.Test import kotlin.test.assertEquals +import kotlin.test.assertFailsWith class PolynomialUtilTest { @Test - fun simple_polynomial_test() { - val polynomial : Polynomial - Double.algebra.scalablePolynomial { - val x = Polynomial(listOf(0.0, 1.0)) - polynomial = x * x - 2 * x + 1 - } - assertEquals(0.0, polynomial.substitute(1.0), 0.001) - } - @Test - fun testIntegration() { + fun test_substitute_Double() { val polynomial = Polynomial(1.0, -2.0, 1.0) assertEquals(0.0, polynomial.substitute(1.0), 0.001) } + @Test + fun test_substitute_Constant() { + assertEquals( + Rational(0), + Polynomial(Rational(1), Rational(-2), Rational(1)).substitute(RationalField, Rational(1)), + "test 1" + ) + assertEquals( + Rational(25057, 21000), + Polynomial(Rational(5,8), Rational(8, 3), Rational(4, 7), Rational(3, 2)) + .substitute(RationalField, Rational(1, 5)), + "test 2" + ) + assertEquals( + Rational(2983, 5250), + Polynomial(Rational(0), Rational(8, 3), Rational(4, 7), Rational(3, 2)) + .substitute(RationalField, Rational(1, 5)), + "test 3" + ) + assertEquals( + Rational(4961, 4200), + Polynomial(Rational(5,8), Rational(8, 3), Rational(4, 7), Rational(0)) + .substitute(RationalField, Rational(1, 5)), + "test 4" + ) + assertEquals( + Rational(3511, 3000), + Polynomial(Rational(5,8), Rational(8, 3), Rational(0), Rational(3, 2)) + .substitute(RationalField, Rational(1, 5)), + "test 5" + ) + } + @Test + fun test_substitute_Polynomial() { + assertEquals( + Polynomial(), + Polynomial(Rational(1), Rational(-2), Rational(1)).substitute(RationalField, Polynomial(Rational(1))), + "test 1" + ) + assertEquals( + Polynomial(Rational(709, 378), Rational(155, 252), Rational(19, 525), Rational(2, 875)), + Polynomial(Rational(1, 7), Rational(9, 4), Rational(1, 3), Rational(2, 7)) + .substitute(RationalField, Polynomial(Rational(6, 9), Rational(1, 5))), + "test 2" + ) + assertEquals( + Polynomial(Rational(655, 378), Rational(155, 252), Rational(19, 525), Rational(2, 875)), + Polynomial(Rational(0), Rational(9, 4), Rational(1, 3), Rational(2, 7)) + .substitute(RationalField, Polynomial(Rational(6, 9), Rational(1, 5))), + "test 3" + ) + assertEquals( + Polynomial(Rational(677, 378), Rational(97, 180), Rational(1, 75)), + Polynomial(Rational(1, 7), Rational(9, 4), Rational(1, 3), Rational(0)) + .substitute(RationalField, Polynomial(Rational(6, 9), Rational(1, 5))), + "test 4" + ) + assertEquals( + Polynomial(Rational(653, 378), Rational(221, 420), Rational(4, 175), Rational(2, 875)), + Polynomial(Rational(1, 7), Rational(9, 4), Rational(0), Rational(2, 7)) + .substitute(RationalField, Polynomial(Rational(6, 9), Rational(1, 5))), + "test 5" + ) + assertEquals( + Polynomial(Rational(89, 54)), + Polynomial(Rational(0), Rational(9, 4), Rational(1, 3), Rational(0)) + .substitute(RationalField, Polynomial(Rational(6, 9), Rational(0))), + "test 6" + ) + } + @Test + fun test_derivative() { + assertEquals( + Polynomial(Rational(-2), Rational(2)), + Polynomial(Rational(1), Rational(-2), Rational(1)).derivative(RationalField), + "test 1" + ) + assertEquals( + Polynomial(Rational(-8, 3), Rational(8, 9), Rational(15, 7), Rational(-20, 9)), + Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).derivative(RationalField), + "test 2" + ) + assertEquals( + Polynomial(Rational(0), Rational(8, 9), Rational(15, 7), Rational(-20, 9)), + Polynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).derivative(RationalField), + "test 3" + ) + assertEquals( + Polynomial(Rational(-8, 3), Rational(8, 9), Rational(15, 7)), + Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).derivative(RationalField), + "test 4" + ) + } + @Test + fun test_nthDerivative() { + assertEquals( + Polynomial(Rational(-2), Rational(2)), + Polynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 1), + "test 1" + ) + assertFailsWith("test2") { + Polynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, -1) + } + assertEquals( + Polynomial(Rational(1), Rational(-2), Rational(1)), + Polynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 0), + "test 3" + ) + assertEquals( + Polynomial(Rational(2)), + Polynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 2), + "test 4" + ) + assertEquals( + Polynomial(), + Polynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 3), + "test 5" + ) + assertEquals( + Polynomial(), + Polynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 4), + "test 6" + ) + assertEquals( + Polynomial(Rational(8, 9), Rational(30, 7), Rational(-20, 3)), + Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthDerivative(RationalField, 2), + "test 7" + ) + assertEquals( + Polynomial(Rational(8, 9), Rational(30, 7), Rational(-20, 3)), + Polynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthDerivative(RationalField, 2), + "test 8" + ) + assertEquals( + Polynomial(Rational(8, 9), Rational(30, 7)), + Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).nthDerivative(RationalField, 2), + "test 9" + ) + } + @Test + fun test_antiderivative() { + assertEquals( + Polynomial(Rational(0), Rational(1), Rational(-1), Rational(1, 3)), + Polynomial(Rational(1), Rational(-2), Rational(1)).antiderivative(RationalField), + "test 1" + ) + assertEquals( + Polynomial(Rational(0), Rational(1, 5), Rational(-4, 3), Rational(4, 27), Rational(5, 28), Rational(-1, 9)), + Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).antiderivative(RationalField), + "test 2" + ) + assertEquals( + Polynomial(Rational(0), Rational(0), Rational(0), Rational(4, 27), Rational(5, 28), Rational(-1, 9)), + Polynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).antiderivative(RationalField), + "test 3" + ) + assertEquals( + Polynomial(Rational(0), Rational(1, 5), Rational(-4, 3), Rational(4, 27), Rational(5, 28)), + Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).antiderivative(RationalField), + "test 4" + ) + } + @Test + fun test_nthAntiderivative() { + assertEquals( + Polynomial(Rational(0), Rational(1), Rational(-1), Rational(1, 3)), + Polynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 1), + "test 1" + ) + assertFailsWith("test2") { + Polynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, -1) + } + assertEquals( + Polynomial(Rational(1), Rational(-2), Rational(1)), + Polynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 0), + "test 3" + ) + assertEquals( + Polynomial(Rational(0), Rational(0), Rational(1, 2), Rational(-1, 3), Rational(1, 12)), + Polynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 2), + "test 4" + ) + assertEquals( + Polynomial(Rational(0), Rational(0), Rational(0), Rational(1, 6), Rational(-1, 12), Rational(1, 60)), + Polynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 3), + "test 5" + ) + assertEquals( + Polynomial(Rational(0), Rational(0), Rational(0), Rational(0), Rational(1, 24), Rational(-1, 60), Rational(1, 360)), + Polynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 4), + "test 6" + ) + assertEquals( + Polynomial(Rational(0), Rational(0), Rational(1, 10), Rational(-4, 9), Rational(1, 27), Rational(1, 28), Rational(-1, 54)), + Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthAntiderivative(RationalField, 2), + "test 7" + ) + assertEquals( + Polynomial(Rational(0), Rational(0), Rational(0), Rational(0), Rational(1, 27), Rational(1, 28), Rational(-1, 54)), + Polynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthAntiderivative(RationalField, 2), + "test 8" + ) + assertEquals( + Polynomial(Rational(0), Rational(0), Rational(1, 10), Rational(-4, 9), Rational(1, 27), Rational(1, 28)), + Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).nthAntiderivative(RationalField, 2), + "test 9" + ) + } } \ No newline at end of file -- 2.34.1 From 88e0dcf413d518e571118eb5d1bf3310110bad5c Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Mon, 21 Mar 2022 18:26:09 +0300 Subject: [PATCH 042/123] Added usage of more correct exceptions. --- .../kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt | 2 +- .../space/kscience/kmath/functions/AbstractRationalFunction.kt | 2 +- .../kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt index aacf055fa..fd1b51fae 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt @@ -295,7 +295,7 @@ public interface AbstractPolynomialSpace> : Ring

* If polynomial is a constant polynomial represents and returns it as constant. * Otherwise, (when the polynomial is not constant polynomial) raises corresponding exception. */ - public fun P.asConstant(): C = asConstantOrNull() ?: error("Can not represent non-constant polynomial as a constant") + public fun P.asConstant(): C = requireNotNull(asConstantOrNull()) { "Can not represent non-constant polynomial as a constant" } override fun add(left: P, right: P): P = left + right override fun multiply(left: P, right: P): P = left * right diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt index b9ca01da4..cdc4bf530 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt @@ -460,7 +460,7 @@ public interface AbstractRationalFunctionalSpace, R: * If polynomial is a constant polynomial represents and returns it as constant. * Otherwise, (when the polynomial is not constant polynomial) raises corresponding exception. */ - public fun P.asConstant(): C = asConstantOrNull() ?: error("Can not represent non-constant polynomial as a constant") + public fun P.asConstant(): C = requireNotNull(asConstantOrNull()) { "Can not represent non-constant polynomial as a constant" } /** * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt index fbae61ed1..21c5436d3 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt @@ -11,6 +11,7 @@ import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertFailsWith + class PolynomialUtilTest { @Test fun test_substitute_Double() { -- 2.34.1 From 83d57c7295a7b79a9991417c8ede01efc935a54d Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Mon, 21 Mar 2022 21:22:25 +0300 Subject: [PATCH 043/123] Added RFs' interface to remove another boilerplate. Fixed bug in RFs' equalsTo. --- .../functions/AbstractRationalFunction.kt | 228 +++++++++++++++++- .../functions/LabeledRationalFunction.kt | 216 ++--------------- .../functions/NumberedRationalFunction.kt | 216 ++--------------- .../kmath/functions/RationalFunction.kt | 221 ++--------------- 4 files changed, 277 insertions(+), 604 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt index cdc4bf530..7feab3dfb 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt @@ -423,7 +423,13 @@ public interface AbstractRationalFunctionalSpace, R: /** * Checks equality of the rational functions. */ - public infix fun R.equalsTo(other: R): Boolean + public infix fun R.equalsTo(other: R): Boolean = + when { + this === other -> true + numerator.isZero() != other.numerator.isZero() -> false + numeratorDegree - denominatorDegree != with(other) { numeratorDegree - denominatorDegree } -> false + else -> numerator * other.denominator equalsTo other.numerator * denominator + } /** * Checks NOT equality of the polynomials. */ @@ -857,4 +863,224 @@ public interface AbstractRationalFunctionalSpaceOverPolynomialSpace< * Otherwise, (when the polynomial is not constant polynomial) raises corresponding exception. */ public override fun P.asConstant(): C = polynomialRing { this@asConstant.asConstant() } +} + +/** + * Abstraction of field of rational functions of type [R] with respect to polynomials of type [P] and constants of type + * [C]. It also assumes that there is provided [polynomialRing] (of type [AP]), that provides constant- and + * polynomial-wise operations. + * + * @param C the type of constants. Polynomials have them as coefficients in their terms. + * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. + * @param R the type of rational functions. + * @param AP the type of algebraic structure (precisely, of ring) provided for polynomials. + */ // TODO: Add support of field +@Suppress("INAPPLICABLE_JVM_NAME") +public abstract class AbstractPolynomialFractionsSpace< + C, + P: AbstractPolynomial, + R: AbstractRationalFunction, + > : AbstractRationalFunctionalSpace { + protected abstract fun constructRationalFunction(numerator: P, denominator: P) : R + + /** + * Returns sum of the rational function and the integer represented as rational function. + * + * The operation is equivalent to adding [other] copies of unit polynomial to [this]. + */ + public override operator fun R.plus(other: Int): R = + constructRationalFunction( + numerator + denominator * other, + denominator + ) + /** + * Returns difference between the rational function and the integer represented as rational function. + * + * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. + */ + public override operator fun R.minus(other: Int): R = + constructRationalFunction( + numerator - denominator * other, + denominator + ) + /** + * Returns product of the rational function and the integer represented as rational function. + * + * The operation is equivalent to sum of [other] copies of [this]. + */ + public override operator fun R.times(other: Int): R = + constructRationalFunction( + numerator * other, + denominator + ) + + /** + * Returns sum of the integer represented as rational function and the rational function. + * + * The operation is equivalent to adding [this] copies of unit polynomial to [other]. + */ + public override operator fun Int.plus(other: R): R = + constructRationalFunction( + other.denominator * this + other.numerator, + other.denominator + ) + /** + * Returns difference between the integer represented as rational function and the rational function. + * + * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. + */ + public override operator fun Int.minus(other: R): R = + constructRationalFunction( + other.denominator * this - other.numerator, + other.denominator + ) + /** + * Returns product of the integer represented as rational function and the rational function. + * + * The operation is equivalent to sum of [this] copies of [other]. + */ + public override operator fun Int.times(other: R): R = + constructRationalFunction( + this * other.numerator, + other.denominator + ) + + /** + * Returns sum of the constant represented as rational function and the rational function. + */ + public override operator fun C.plus(other: R): R = + constructRationalFunction( + other.denominator * this + other.numerator, + other.denominator + ) + /** + * Returns difference between the constant represented as polynomial and the rational function. + */ + public override operator fun C.minus(other: R): R = + constructRationalFunction( + other.denominator * this - other.numerator, + other.denominator + ) + /** + * Returns product of the constant represented as polynomial and the rational function. + */ + public override operator fun C.times(other: R): R = + constructRationalFunction( + this * other.numerator, + other.denominator + ) + + /** + * Returns sum of the constant represented as rational function and the rational function. + */ + public override operator fun R.plus(other: C): R = + constructRationalFunction( + numerator + denominator * other, + denominator + ) + /** + * Returns difference between the constant represented as rational function and the rational function. + */ + public override operator fun R.minus(other: C): R = + constructRationalFunction( + numerator - denominator * other, + denominator + ) + /** + * Returns product of the constant represented as rational function and the rational function. + */ + public override operator fun R.times(other: C): R = + constructRationalFunction( + numerator * other, + denominator + ) + + /** + * Returns sum of the polynomial represented as rational function and the rational function. + */ + public override operator fun P.plus(other: R): R = + constructRationalFunction( + other.denominator * this + other.numerator, + other.denominator + ) + /** + * Returns difference between the polynomial represented as polynomial and the rational function. + */ + public override operator fun P.minus(other: R): R = + constructRationalFunction( + other.denominator * this - other.numerator, + other.denominator + ) + /** + * Returns product of the polynomial represented as polynomial and the rational function. + */ + public override operator fun P.times(other: R): R = + constructRationalFunction( + this * other.numerator, + other.denominator + ) + + /** + * Returns sum of the polynomial represented as rational function and the rational function. + */ + public override operator fun R.plus(other: P): R = + constructRationalFunction( + numerator + denominator * other, + denominator + ) + /** + * Returns difference between the polynomial represented as rational function and the rational function. + */ + public override operator fun R.minus(other: P): R = + constructRationalFunction( + numerator - denominator * other, + denominator + ) + /** + * Returns product of the polynomial represented as rational function and the rational function. + */ + public override operator fun R.times(other: P): R = + constructRationalFunction( + numerator * other, + denominator + ) + + /** + * Returns negation of the rational function. + */ + public override operator fun R.unaryMinus(): R = constructRationalFunction(-numerator, denominator) + /** + * Returns sum of the rational functions. + */ + public override operator fun R.plus(other: R): R = + constructRationalFunction( + numerator * other.denominator + denominator * other.numerator, + denominator * other.denominator + ) + /** + * Returns difference of the rational functions. + */ + public override operator fun R.minus(other: R): R = + constructRationalFunction( + numerator * other.denominator - denominator * other.numerator, + denominator * other.denominator + ) + /** + * Returns product of the rational functions. + */ + public override operator fun R.times(other: R): R = + constructRationalFunction( + numerator * other.numerator, + denominator * other.denominator + ) + + /** + * Instance of zero rational function (zero of the rational functions ring). + */ + public override val zero: R get() = constructRationalFunction(polynomialZero, polynomialOne) + + /** + * Instance of unit polynomial (unit of the rational functions ring). + */ + public override val one: R get() = constructRationalFunction(polynomialOne, polynomialOne) } \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt index 9b5022f85..09b0b25ae 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt @@ -64,205 +64,25 @@ public class LabeledRationalFunction( public class LabeledRationalFunctionSpace>( public val ring: A, -) : AbstractRationalFunctionalSpaceOverPolynomialSpace< - C, - LabeledPolynomial, - LabeledRationalFunction, - LabeledPolynomialSpace, - > { +) : + AbstractRationalFunctionalSpaceOverPolynomialSpace< + C, + LabeledPolynomial, + LabeledRationalFunction, + LabeledPolynomialSpace, + >, + AbstractPolynomialFractionsSpace< + C, + LabeledPolynomial, + LabeledRationalFunction, + >() { override val polynomialRing : LabeledPolynomialSpace = LabeledPolynomialSpace(ring) - - /** - * Returns sum of the rational function and the integer represented as rational function. - * - * The operation is equivalent to adding [other] copies of unit polynomial to [this]. - */ - public override operator fun LabeledRationalFunction.plus(other: Int): LabeledRationalFunction = - LabeledRationalFunction( - numerator + denominator * other, - denominator - ) - /** - * Returns difference between the rational function and the integer represented as rational function. - * - * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. - */ - public override operator fun LabeledRationalFunction.minus(other: Int): LabeledRationalFunction = - LabeledRationalFunction( - numerator - denominator * other, - denominator - ) - /** - * Returns product of the rational function and the integer represented as rational function. - * - * The operation is equivalent to sum of [other] copies of [this]. - */ - public override operator fun LabeledRationalFunction.times(other: Int): LabeledRationalFunction = - LabeledRationalFunction( - numerator * other, - denominator - ) - - /** - * Returns sum of the integer represented as rational function and the rational function. - * - * The operation is equivalent to adding [this] copies of unit polynomial to [other]. - */ - public override operator fun Int.plus(other: LabeledRationalFunction): LabeledRationalFunction = - LabeledRationalFunction( - other.denominator * this + other.numerator, - other.denominator - ) - /** - * Returns difference between the integer represented as rational function and the rational function. - * - * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. - */ - public override operator fun Int.minus(other: LabeledRationalFunction): LabeledRationalFunction = - LabeledRationalFunction( - other.denominator * this - other.numerator, - other.denominator - ) - /** - * Returns product of the integer represented as rational function and the rational function. - * - * The operation is equivalent to sum of [this] copies of [other]. - */ - public override operator fun Int.times(other: LabeledRationalFunction): LabeledRationalFunction = - LabeledRationalFunction( - this * other.numerator, - other.denominator - ) - - /** - * Returns sum of the constant represented as rational function and the rational function. - */ - public override operator fun C.plus(other: LabeledRationalFunction): LabeledRationalFunction = - LabeledRationalFunction( - other.denominator * this + other.numerator, - other.denominator - ) - /** - * Returns difference between the constant represented as polynomial and the rational function. - */ - public override operator fun C.minus(other: LabeledRationalFunction): LabeledRationalFunction = - LabeledRationalFunction( - other.denominator * this - other.numerator, - other.denominator - ) - /** - * Returns product of the constant represented as polynomial and the rational function. - */ - public override operator fun C.times(other: LabeledRationalFunction): LabeledRationalFunction = - LabeledRationalFunction( - this * other.numerator, - other.denominator - ) - - /** - * Returns sum of the constant represented as rational function and the rational function. - */ - public override operator fun LabeledRationalFunction.plus(other: C): LabeledRationalFunction = - LabeledRationalFunction( - numerator + denominator * other, - denominator - ) - /** - * Returns difference between the constant represented as rational function and the rational function. - */ - public override operator fun LabeledRationalFunction.minus(other: C): LabeledRationalFunction = - LabeledRationalFunction( - numerator - denominator * other, - denominator - ) - /** - * Returns product of the constant represented as rational function and the rational function. - */ - public override operator fun LabeledRationalFunction.times(other: C): LabeledRationalFunction = - LabeledRationalFunction( - numerator * other, - denominator - ) - - /** - * Returns sum of the polynomial represented as rational function and the rational function. - */ - public override operator fun LabeledPolynomial.plus(other: LabeledRationalFunction): LabeledRationalFunction = - LabeledRationalFunction( - other.denominator * this + other.numerator, - other.denominator - ) - /** - * Returns difference between the polynomial represented as polynomial and the rational function. - */ - public override operator fun LabeledPolynomial.minus(other: LabeledRationalFunction): LabeledRationalFunction = - LabeledRationalFunction( - other.denominator * this - other.numerator, - other.denominator - ) - /** - * Returns product of the polynomial represented as polynomial and the rational function. - */ - public override operator fun LabeledPolynomial.times(other: LabeledRationalFunction): LabeledRationalFunction = - LabeledRationalFunction( - this * other.numerator, - other.denominator - ) - - /** - * Returns sum of the polynomial represented as rational function and the rational function. - */ - public override operator fun LabeledRationalFunction.plus(other: LabeledPolynomial): LabeledRationalFunction = - LabeledRationalFunction( - numerator + denominator * other, - denominator - ) - /** - * Returns difference between the polynomial represented as rational function and the rational function. - */ - public override operator fun LabeledRationalFunction.minus(other: LabeledPolynomial): LabeledRationalFunction = - LabeledRationalFunction( - numerator - denominator * other, - denominator - ) - /** - * Returns product of the polynomial represented as rational function and the rational function. - */ - public override operator fun LabeledRationalFunction.times(other: LabeledPolynomial): LabeledRationalFunction = - LabeledRationalFunction( - numerator * other, - denominator - ) - - /** - * Returns negation of the rational function. - */ - public override operator fun LabeledRationalFunction.unaryMinus(): LabeledRationalFunction = LabeledRationalFunction(-numerator, denominator) - /** - * Returns sum of the rational functions. - */ - public override operator fun LabeledRationalFunction.plus(other: LabeledRationalFunction): LabeledRationalFunction = - LabeledRationalFunction( - numerator * other.denominator + denominator * other.numerator, - denominator * other.denominator - ) - /** - * Returns difference of the rational functions. - */ - public override operator fun LabeledRationalFunction.minus(other: LabeledRationalFunction): LabeledRationalFunction = - LabeledRationalFunction( - numerator * other.denominator - denominator * other.numerator, - denominator * other.denominator - ) - /** - * Returns product of the rational functions. - */ - public override operator fun LabeledRationalFunction.times(other: LabeledRationalFunction): LabeledRationalFunction = - LabeledRationalFunction( - numerator * other.numerator, - denominator * other.denominator - ) + override fun constructRationalFunction( + numerator: LabeledPolynomial, + denominator: LabeledPolynomial + ): LabeledRationalFunction = + LabeledRationalFunction(numerator, denominator) /** * Instance of zero rational function (zero of the rational functions ring). @@ -279,7 +99,7 @@ public class LabeledRationalFunctionSpace>( public override infix fun LabeledRationalFunction.equalsTo(other: LabeledRationalFunction): Boolean { if (this === other) return true - if ( !(numerator.isZero() xor other.numerator.isZero()) ) return false + if (numerator.isZero() != other.numerator.isZero()) return false val variables = this.variables union other.variables val thisNumeratorDegrees = this.numerator.degrees diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt index 78ba233f5..4927460fb 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt @@ -60,205 +60,25 @@ public class NumberedRationalFunction internal constructor( public class NumberedRationalFunctionSpace> ( public val ring: A, -) : AbstractRationalFunctionalSpaceOverPolynomialSpace< - C, - NumberedPolynomial, - NumberedRationalFunction, - NumberedPolynomialSpace, - > { +) : + AbstractRationalFunctionalSpaceOverPolynomialSpace< + C, + NumberedPolynomial, + NumberedRationalFunction, + NumberedPolynomialSpace, + >, + AbstractPolynomialFractionsSpace< + C, + NumberedPolynomial, + NumberedRationalFunction, + >() { override val polynomialRing : NumberedPolynomialSpace = NumberedPolynomialSpace(ring) - - /** - * Returns sum of the rational function and the integer represented as rational function. - * - * The operation is equivalent to adding [other] copies of unit polynomial to [this]. - */ - public override operator fun NumberedRationalFunction.plus(other: Int): NumberedRationalFunction = - NumberedRationalFunction( - numerator + denominator * other, - denominator - ) - /** - * Returns difference between the rational function and the integer represented as rational function. - * - * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. - */ - public override operator fun NumberedRationalFunction.minus(other: Int): NumberedRationalFunction = - NumberedRationalFunction( - numerator - denominator * other, - denominator - ) - /** - * Returns product of the rational function and the integer represented as rational function. - * - * The operation is equivalent to sum of [other] copies of [this]. - */ - public override operator fun NumberedRationalFunction.times(other: Int): NumberedRationalFunction = - NumberedRationalFunction( - numerator * other, - denominator - ) - - /** - * Returns sum of the integer represented as rational function and the rational function. - * - * The operation is equivalent to adding [this] copies of unit polynomial to [other]. - */ - public override operator fun Int.plus(other: NumberedRationalFunction): NumberedRationalFunction = - NumberedRationalFunction( - other.denominator * this + other.numerator, - other.denominator - ) - /** - * Returns difference between the integer represented as rational function and the rational function. - * - * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. - */ - public override operator fun Int.minus(other: NumberedRationalFunction): NumberedRationalFunction = - NumberedRationalFunction( - other.denominator * this - other.numerator, - other.denominator - ) - /** - * Returns product of the integer represented as rational function and the rational function. - * - * The operation is equivalent to sum of [this] copies of [other]. - */ - public override operator fun Int.times(other: NumberedRationalFunction): NumberedRationalFunction = - NumberedRationalFunction( - this * other.numerator, - other.denominator - ) - - /** - * Returns sum of the constant represented as rational function and the rational function. - */ - public override operator fun C.plus(other: NumberedRationalFunction): NumberedRationalFunction = - NumberedRationalFunction( - other.denominator * this + other.numerator, - other.denominator - ) - /** - * Returns difference between the constant represented as polynomial and the rational function. - */ - public override operator fun C.minus(other: NumberedRationalFunction): NumberedRationalFunction = - NumberedRationalFunction( - other.denominator * this - other.numerator, - other.denominator - ) - /** - * Returns product of the constant represented as polynomial and the rational function. - */ - public override operator fun C.times(other: NumberedRationalFunction): NumberedRationalFunction = - NumberedRationalFunction( - this * other.numerator, - other.denominator - ) - - /** - * Returns sum of the constant represented as rational function and the rational function. - */ - public override operator fun NumberedRationalFunction.plus(other: C): NumberedRationalFunction = - NumberedRationalFunction( - numerator + denominator * other, - denominator - ) - /** - * Returns difference between the constant represented as rational function and the rational function. - */ - public override operator fun NumberedRationalFunction.minus(other: C): NumberedRationalFunction = - NumberedRationalFunction( - numerator - denominator * other, - denominator - ) - /** - * Returns product of the constant represented as rational function and the rational function. - */ - public override operator fun NumberedRationalFunction.times(other: C): NumberedRationalFunction = - NumberedRationalFunction( - numerator * other, - denominator - ) - - /** - * Returns sum of the polynomial represented as rational function and the rational function. - */ - public override operator fun NumberedPolynomial.plus(other: NumberedRationalFunction): NumberedRationalFunction = - NumberedRationalFunction( - other.denominator * this + other.numerator, - other.denominator - ) - /** - * Returns difference between the polynomial represented as polynomial and the rational function. - */ - public override operator fun NumberedPolynomial.minus(other: NumberedRationalFunction): NumberedRationalFunction = - NumberedRationalFunction( - other.denominator * this - other.numerator, - other.denominator - ) - /** - * Returns product of the polynomial represented as polynomial and the rational function. - */ - public override operator fun NumberedPolynomial.times(other: NumberedRationalFunction): NumberedRationalFunction = - NumberedRationalFunction( - this * other.numerator, - other.denominator - ) - - /** - * Returns sum of the polynomial represented as rational function and the rational function. - */ - public override operator fun NumberedRationalFunction.plus(other: NumberedPolynomial): NumberedRationalFunction = - NumberedRationalFunction( - numerator + denominator * other, - denominator - ) - /** - * Returns difference between the polynomial represented as rational function and the rational function. - */ - public override operator fun NumberedRationalFunction.minus(other: NumberedPolynomial): NumberedRationalFunction = - NumberedRationalFunction( - numerator - denominator * other, - denominator - ) - /** - * Returns product of the polynomial represented as rational function and the rational function. - */ - public override operator fun NumberedRationalFunction.times(other: NumberedPolynomial): NumberedRationalFunction = - NumberedRationalFunction( - numerator * other, - denominator - ) - - /** - * Returns negation of the rational function. - */ - public override operator fun NumberedRationalFunction.unaryMinus(): NumberedRationalFunction = NumberedRationalFunction(-numerator, denominator) - /** - * Returns sum of the rational functions. - */ - public override operator fun NumberedRationalFunction.plus(other: NumberedRationalFunction): NumberedRationalFunction = - NumberedRationalFunction( - numerator * other.denominator + denominator * other.numerator, - denominator * other.denominator - ) - /** - * Returns difference of the rational functions. - */ - public override operator fun NumberedRationalFunction.minus(other: NumberedRationalFunction): NumberedRationalFunction = - NumberedRationalFunction( - numerator * other.denominator - denominator * other.numerator, - denominator * other.denominator - ) - /** - * Returns product of the rational functions. - */ - public override operator fun NumberedRationalFunction.times(other: NumberedRationalFunction): NumberedRationalFunction = - NumberedRationalFunction( - numerator * other.numerator, - denominator * other.denominator - ) + override fun constructRationalFunction( + numerator: NumberedPolynomial, + denominator: NumberedPolynomial + ): NumberedRationalFunction = + NumberedRationalFunction(numerator, denominator) /** * Instance of zero rational function (zero of the rational functions ring). @@ -275,7 +95,7 @@ public class NumberedRationalFunctionSpace> ( public override infix fun NumberedRationalFunction.equalsTo(other: NumberedRationalFunction): Boolean { if (this === other) return true - if ( !(numerator.isZero() xor other.numerator.isZero()) ) return false + if (numerator.isZero() != other.numerator.isZero()) return false val countOfVariables = max(this.lastVariable, other.lastVariable) val thisNumeratorDegrees = this.numerator.degrees diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt index 226eddce9..506aa4004 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt @@ -42,205 +42,22 @@ public data class RationalFunction internal constructor ( public class RationalFunctionSpace> ( public val ring: A, -) : AbstractRationalFunctionalSpaceOverPolynomialSpace< - C, - Polynomial, - RationalFunction, - PolynomialSpace, - > { +) : + AbstractRationalFunctionalSpaceOverPolynomialSpace< + C, + Polynomial, + RationalFunction, + PolynomialSpace, + >, + AbstractPolynomialFractionsSpace< + C, + Polynomial, + RationalFunction, + >() { override val polynomialRing : PolynomialSpace = PolynomialSpace(ring) - - /** - * Returns sum of the rational function and the integer represented as rational function. - * - * The operation is equivalent to adding [other] copies of unit polynomial to [this]. - */ - public override operator fun RationalFunction.plus(other: Int): RationalFunction = - RationalFunction( - numerator + denominator * other, - denominator - ) - /** - * Returns difference between the rational function and the integer represented as rational function. - * - * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. - */ - public override operator fun RationalFunction.minus(other: Int): RationalFunction = - RationalFunction( - numerator - denominator * other, - denominator - ) - /** - * Returns product of the rational function and the integer represented as rational function. - * - * The operation is equivalent to sum of [other] copies of [this]. - */ - public override operator fun RationalFunction.times(other: Int): RationalFunction = - RationalFunction( - numerator * other, - denominator - ) - - /** - * Returns sum of the integer represented as rational function and the rational function. - * - * The operation is equivalent to adding [this] copies of unit polynomial to [other]. - */ - public override operator fun Int.plus(other: RationalFunction): RationalFunction = - RationalFunction( - other.denominator * this + other.numerator, - other.denominator - ) - /** - * Returns difference between the integer represented as rational function and the rational function. - * - * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. - */ - public override operator fun Int.minus(other: RationalFunction): RationalFunction = - RationalFunction( - other.denominator * this - other.numerator, - other.denominator - ) - /** - * Returns product of the integer represented as rational function and the rational function. - * - * The operation is equivalent to sum of [this] copies of [other]. - */ - public override operator fun Int.times(other: RationalFunction): RationalFunction = - RationalFunction( - this * other.numerator, - other.denominator - ) - - /** - * Returns sum of the constant represented as rational function and the rational function. - */ - public override operator fun C.plus(other: RationalFunction): RationalFunction = - RationalFunction( - other.denominator * this + other.numerator, - other.denominator - ) - /** - * Returns difference between the constant represented as polynomial and the rational function. - */ - public override operator fun C.minus(other: RationalFunction): RationalFunction = - RationalFunction( - other.denominator * this - other.numerator, - other.denominator - ) - /** - * Returns product of the constant represented as polynomial and the rational function. - */ - public override operator fun C.times(other: RationalFunction): RationalFunction = - RationalFunction( - this * other.numerator, - other.denominator - ) - - /** - * Returns sum of the constant represented as rational function and the rational function. - */ - public override operator fun RationalFunction.plus(other: C): RationalFunction = - RationalFunction( - numerator + denominator * other, - denominator - ) - /** - * Returns difference between the constant represented as rational function and the rational function. - */ - public override operator fun RationalFunction.minus(other: C): RationalFunction = - RationalFunction( - numerator - denominator * other, - denominator - ) - /** - * Returns product of the constant represented as rational function and the rational function. - */ - public override operator fun RationalFunction.times(other: C): RationalFunction = - RationalFunction( - numerator * other, - denominator - ) - - /** - * Returns sum of the polynomial represented as rational function and the rational function. - */ - public override operator fun Polynomial.plus(other: RationalFunction): RationalFunction = - RationalFunction( - other.denominator * this + other.numerator, - other.denominator - ) - /** - * Returns difference between the polynomial represented as polynomial and the rational function. - */ - public override operator fun Polynomial.minus(other: RationalFunction): RationalFunction = - RationalFunction( - other.denominator * this - other.numerator, - other.denominator - ) - /** - * Returns product of the polynomial represented as polynomial and the rational function. - */ - public override operator fun Polynomial.times(other: RationalFunction): RationalFunction = - RationalFunction( - this * other.numerator, - other.denominator - ) - - /** - * Returns sum of the polynomial represented as rational function and the rational function. - */ - public override operator fun RationalFunction.plus(other: Polynomial): RationalFunction = - RationalFunction( - numerator + denominator * other, - denominator - ) - /** - * Returns difference between the polynomial represented as rational function and the rational function. - */ - public override operator fun RationalFunction.minus(other: Polynomial): RationalFunction = - RationalFunction( - numerator - denominator * other, - denominator - ) - /** - * Returns product of the polynomial represented as rational function and the rational function. - */ - public override operator fun RationalFunction.times(other: Polynomial): RationalFunction = - RationalFunction( - numerator * other, - denominator - ) - - /** - * Returns negation of the rational function. - */ - public override operator fun RationalFunction.unaryMinus(): RationalFunction = RationalFunction(-numerator, denominator) - /** - * Returns sum of the rational functions. - */ - public override operator fun RationalFunction.plus(other: RationalFunction): RationalFunction = - RationalFunction( - numerator * other.denominator + denominator * other.numerator, - denominator * other.denominator - ) - /** - * Returns difference of the rational functions. - */ - public override operator fun RationalFunction.minus(other: RationalFunction): RationalFunction = - RationalFunction( - numerator * other.denominator - denominator * other.numerator, - denominator * other.denominator - ) - /** - * Returns product of the rational functions. - */ - public override operator fun RationalFunction.times(other: RationalFunction): RationalFunction = - RationalFunction( - numerator * other.numerator, - denominator * other.denominator - ) + override fun constructRationalFunction(numerator: Polynomial, denominator: Polynomial): RationalFunction = + RationalFunction(numerator, denominator) /** * Instance of zero rational function (zero of the rational functions ring). @@ -251,16 +68,6 @@ public class RationalFunctionSpace> ( */ public override val one: RationalFunction = RationalFunction(polynomialOne, polynomialOne) - /** - * Checks equality of the rational functions. - */ - public override infix fun RationalFunction.equalsTo(other: RationalFunction): Boolean = - when { - this === other -> true - numeratorDegree - denominatorDegree != with(other) { numeratorDegree - denominatorDegree } -> false - else -> numerator * other.denominator equalsTo other.numerator * denominator - } - // TODO: Разобрать public operator fun RationalFunction.div(other: RationalFunction): RationalFunction = -- 2.34.1 From 51b0d232b561ecc57fe6d6660c9a9d104a447dd2 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Mon, 21 Mar 2022 23:21:55 +0300 Subject: [PATCH 044/123] Renamed `AbstractPolynomialFractionsSpace` to `PolynomialSpaceOfFractions` --- .../kscience/kmath/functions/AbstractRationalFunction.kt | 5 ++--- .../kscience/kmath/functions/LabeledRationalFunction.kt | 2 +- .../kscience/kmath/functions/NumberedRationalFunction.kt | 2 +- .../space/kscience/kmath/functions/RationalFunction.kt | 2 +- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt index 7feab3dfb..c9c0b3920 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt @@ -867,8 +867,7 @@ public interface AbstractRationalFunctionalSpaceOverPolynomialSpace< /** * Abstraction of field of rational functions of type [R] with respect to polynomials of type [P] and constants of type - * [C]. It also assumes that there is provided [polynomialRing] (of type [AP]), that provides constant- and - * polynomial-wise operations. + * [C]. It also assumes that there is provided constructor * * @param C the type of constants. Polynomials have them as coefficients in their terms. * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. @@ -876,7 +875,7 @@ public interface AbstractRationalFunctionalSpaceOverPolynomialSpace< * @param AP the type of algebraic structure (precisely, of ring) provided for polynomials. */ // TODO: Add support of field @Suppress("INAPPLICABLE_JVM_NAME") -public abstract class AbstractPolynomialFractionsSpace< +public abstract class PolynomialSpaceOfFractions< C, P: AbstractPolynomial, R: AbstractRationalFunction, diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt index 09b0b25ae..92bd344ac 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt @@ -71,7 +71,7 @@ public class LabeledRationalFunctionSpace>( LabeledRationalFunction, LabeledPolynomialSpace, >, - AbstractPolynomialFractionsSpace< + PolynomialSpaceOfFractions< C, LabeledPolynomial, LabeledRationalFunction, diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt index 4927460fb..4da715e3f 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt @@ -67,7 +67,7 @@ public class NumberedRationalFunctionSpace> ( NumberedRationalFunction, NumberedPolynomialSpace, >, - AbstractPolynomialFractionsSpace< + PolynomialSpaceOfFractions< C, NumberedPolynomial, NumberedRationalFunction, diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt index 506aa4004..51c1e2f80 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt @@ -49,7 +49,7 @@ public class RationalFunctionSpace> ( RationalFunction, PolynomialSpace, >, - AbstractPolynomialFractionsSpace< + PolynomialSpaceOfFractions< C, Polynomial, RationalFunction, -- 2.34.1 From c6d1068df465dca4374dde7cb1395cb9dbcff8f9 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Mon, 21 Mar 2022 23:47:10 +0300 Subject: [PATCH 045/123] Renamed `Polynomial`, etc. to `ListPolynomial`, etc. and `AbstractPolynomial` to `Polynomial`. As it was advised by @CommanderTvis. --- .../kmath/functions/AbstractPolynomial.kt | 389 ------ .../functions/AbstractRationalFunction.kt | 1085 --------------- .../kmath/functions/LabeledPolynomial.kt | 4 +- .../functions/LabeledRationalFunction.kt | 4 +- .../kmath/functions/ListPolynomial.kt | 491 +++++++ .../kmath/functions/ListRationalFunction.kt | 154 +++ .../kmath/functions/NumberedPolynomial.kt | 4 +- .../functions/NumberedRationalFunction.kt | 4 +- .../kscience/kmath/functions/Piecewise.kt | 22 +- .../kscience/kmath/functions/Polynomial.kt | 644 ++++----- .../kmath/functions/RationalFunction.kt | 1175 +++++++++++++++-- .../functions/labeledRationalFunctionUtil.kt | 2 +- ...olynomialUtil.kt => listPolynomialUtil.kt} | 66 +- ...ionUtil.kt => listRationalFunctionUtil.kt} | 26 +- .../functions/numberedRationalFunctionUtil.kt | 2 +- .../kmath/interpolation/LinearInterpolator.kt | 4 +- .../kmath/interpolation/SplineInterpolator.kt | 4 +- .../kmath/functions/ListPolynomialTest.kt | 705 ++++++++++ .../kmath/functions/ListPolynomialUtilTest.kt | 229 ++++ .../kmath/functions/PolynomialTest.kt | 691 ---------- .../kmath/functions/PolynomialUtilTest.kt | 229 ---- .../kmath/integration/SplineIntegralTest.kt | 4 +- .../kscience/kmath/test/misc/IntModulo.kt | 14 +- 23 files changed, 2983 insertions(+), 2969 deletions(-) delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt rename kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/{polynomialUtil.kt => listPolynomialUtil.kt} (72%) rename kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/{rationalFunctionUtil.kt => listRationalFunctionUtil.kt} (88%) create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt delete mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt delete mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt deleted file mode 100644 index fd1b51fae..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt +++ /dev/null @@ -1,389 +0,0 @@ -/* - * 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.functions - -import space.kscience.kmath.operations.* -import kotlin.js.JsName -import kotlin.jvm.JvmName - - -/** - * Abstraction of polynomials. - */ -public interface AbstractPolynomial - -/** - * Abstraction of ring of polynomials of type [P] over ring of constants of type [C]. - * - * @param C the type of constants. Polynomials have them as coefficients in their terms. - * @param P the type of polynomials. - */ -@Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") -public interface AbstractPolynomialSpace> : Ring

{ - /** - * Returns sum of the constant and the integer represented as constant (member of underlying ring). - * - * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. - */ - public operator fun C.plus(other: Int): C - /** - * Returns difference between the constant and the integer represented as constant (member of underlying ring). - * - * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. - */ - public operator fun C.minus(other: Int): C - /** - * Returns product of the constant and the integer represented as constant (member of underlying ring). - * - * The operation is equivalent to sum of [other] copies of [this]. - */ - public operator fun C.times(other: Int): C - - /** - * Returns sum of the integer represented as constant (member of underlying ring) and the constant. - * - * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. - */ - public operator fun Int.plus(other: C): C - /** - * Returns difference between the integer represented as constant (member of underlying ring) and the constant. - * - * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. - */ - public operator fun Int.minus(other: C): C - /** - * Returns product of the integer represented as constant (member of underlying ring) and the constant. - * - * The operation is equivalent to sum of [this] copies of [other]. - */ - public operator fun Int.times(other: C): C - - /** - * Returns sum of the polynomial and the integer represented as polynomial. - * - * The operation is equivalent to adding [other] copies of unit polynomial to [this]. - */ - public operator fun P.plus(other: Int): P = addMultipliedBySquaring(this, one, other) - /** - * Returns difference between the polynomial and the integer represented as polynomial. - * - * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. - */ - public operator fun P.minus(other: Int): P = addMultipliedBySquaring(this, one, -other) - /** - * Returns product of the polynomial and the integer represented as polynomial. - * - * The operation is equivalent to sum of [other] copies of [this]. - */ - public operator fun P.times(other: Int): P = multiplyBySquaring(this, other) - - /** - * Returns sum of the integer represented as polynomial and the polynomial. - * - * The operation is equivalent to adding [this] copies of unit polynomial to [other]. - */ - public operator fun Int.plus(other: P): P = addMultipliedBySquaring(other, one, this) - /** - * Returns difference between the integer represented as polynomial and the polynomial. - * - * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. - */ - public operator fun Int.minus(other: P): P = addMultipliedBySquaring(-other, one, this) - /** - * Returns product of the integer represented as polynomial and the polynomial. - * - * The operation is equivalent to sum of [this] copies of [other]. - */ - public operator fun Int.times(other: P): P = multiplyBySquaring(other, this) - - /** - * Returns the same constant. - */ - @JvmName("constantUnaryPlus") - @JsName("constantUnaryPlus") - public operator fun C.unaryPlus(): C = this - /** - * Returns negation of the constant. - */ - @JvmName("constantUnaryMinus") - @JsName("constantUnaryMinus") - public operator fun C.unaryMinus(): C - /** - * Returns sum of the constants. - */ - @JvmName("constantPlus") - @JsName("constantPlus") - public operator fun C.plus(other: C): C - /** - * Returns difference of the constants. - */ - @JvmName("constantMinus") - @JsName("constantMinus") - public operator fun C.minus(other: C): C - /** - * Returns product of the constants. - */ - @JvmName("constantTimes") - @JsName("constantTimes") - public operator fun C.times(other: C): C - /** - * Raises [arg] to the integer power [exponent]. - */ - @JvmName("constantPower") - @JsName("constantPower") - public fun power(arg: C, exponent: UInt) : C - - /** - * Check if the instant is zero constant. - */ - public fun C.isZero(): Boolean = this == constantZero - /** - * Check if the instant is NOT zero constant. - */ - public fun C.isNotZero(): Boolean = !isZero() - /** - * Check if the instant is unit constant. - */ - public fun C.isOne(): Boolean = this == constantOne - /** - * Check if the instant is NOT unit constant. - */ - public fun C.isNotOne(): Boolean = !isOne() - /** - * Check if the instant is minus unit constant. - */ - public fun C.isMinusOne(): Boolean = this == -constantOne - /** - * Check if the instant is NOT minus unit constant. - */ - public fun C.isNotMinusOne(): Boolean = !isMinusOne() - - /** - * Instance of zero constant (zero of the underlying ring). - */ - public val constantZero: C - /** - * Instance of unit constant (unit of the underlying ring). - */ - public val constantOne: C - - /** - * Returns sum of the constant represented as polynomial and the polynomial. - */ - public operator fun C.plus(other: P): P - /** - * Returns difference between the constant represented as polynomial and the polynomial. - */ - public operator fun C.minus(other: P): P - /** - * Returns product of the constant represented as polynomial and the polynomial. - */ - public operator fun C.times(other: P): P - - /** - * Returns sum of the constant represented as polynomial and the polynomial. - */ - public operator fun P.plus(other: C): P - /** - * Returns difference between the constant represented as polynomial and the polynomial. - */ - public operator fun P.minus(other: C): P - /** - * Returns product of the constant represented as polynomial and the polynomial. - */ - public operator fun P.times(other: C): P - - /** - * Returns the same polynomial. - */ - public override operator fun P.unaryPlus(): P = this - /** - * Returns negation of the polynomial. - */ - public override operator fun P.unaryMinus(): P - /** - * Returns sum of the polynomials. - */ - public override operator fun P.plus(other: P): P - /** - * Returns difference of the polynomials. - */ - public override operator fun P.minus(other: P): P - /** - * Returns product of the polynomials. - */ - public override operator fun P.times(other: P): P - /** - * Raises [arg] to the integer power [exponent]. - */ - public override fun power(arg: P, exponent: UInt) : P = exponentiationBySquaring(arg, exponent) - - /** - * Check if the instant is zero polynomial. - */ - public fun P.isZero(): Boolean = this equalsTo zero - /** - * Check if the instant is NOT zero polynomial. - */ - public fun P.isNotZero(): Boolean = !isZero() - /** - * Check if the instant is unit polynomial. - */ - public fun P.isOne(): Boolean = this equalsTo one - /** - * Check if the instant is NOT unit polynomial. - */ - public fun P.isNotOne(): Boolean = !isOne() - /** - * Check if the instant is minus unit polynomial. - */ - public fun P.isMinusOne(): Boolean = this equalsTo -one - /** - * Check if the instant is NOT minus unit polynomial. - */ - public fun P.isNotMinusOne(): Boolean = !isMinusOne() - - /** - * Instance of zero polynomial (zero of the polynomial ring). - */ - public override val zero: P - /** - * Instance of unit polynomial (unit of the polynomial ring). - */ - public override val one: P - - /** - * Checks equality of the polynomials. - */ - public infix fun P.equalsTo(other: P): Boolean - /** - * Checks NOT equality of the polynomials. - */ - public infix fun P.notEqualsTo(other: P): Boolean = !(this equalsTo other) - - /** - * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is - * zero, degree is -1. - */ - public val P.degree: Int - - /** - * Checks if the instant is constant polynomial (of degree no more than 0) over considered ring. - */ - public fun P.isConstant(): Boolean = degree <= 0 - /** - * Checks if the instant is **not** constant polynomial (of degree no more than 0) over considered ring. - */ - public fun P.isNotConstant(): Boolean = !isConstant() - /** - * Checks if the instant is constant non-zero polynomial (of degree no more than 0) over considered ring. - */ - public fun P.isNonZeroConstant(): Boolean = degree == 0 - /** - * Checks if the instant is **not** constant non-zero polynomial (of degree no more than 0) over considered ring. - */ - public fun P.isNotNonZeroConstant(): Boolean = !isNonZeroConstant() - /** - * If polynomial is a constant polynomial represents and returns it as constant. - * Otherwise, (when the polynomial is not constant polynomial) returns `null`. - */ - public fun P.asConstantOrNull(): C? - /** - * If polynomial is a constant polynomial represents and returns it as constant. - * Otherwise, (when the polynomial is not constant polynomial) raises corresponding exception. - */ - public fun P.asConstant(): C = requireNotNull(asConstantOrNull()) { "Can not represent non-constant polynomial as a constant" } - - override fun add(left: P, right: P): P = left + right - override fun multiply(left: P, right: P): P = left * right -} - -/** - * Abstraction of ring of polynomials of type [P] over ring of constants of type [C]. It also assumes that there is - * provided [ring] (of type [A]), that provides constant-wise operations. - * - * @param C the type of constants. Polynomials have them as coefficients in their terms. - * @param P the type of polynomials. - * @param A the type of algebraic structure (precisely, of ring) provided for constants. - */ -@Suppress("INAPPLICABLE_JVM_NAME") -public interface AbstractPolynomialSpaceOverRing, A: Ring> : AbstractPolynomialSpace { - - public val ring: A - - /** - * Returns sum of the constant and the integer represented as constant (member of underlying ring). - * - * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. - */ - public override operator fun C.plus(other: Int): C = ring { addMultipliedBySquaring(this@plus, one, other) } - /** - * Returns difference between the constant and the integer represented as constant (member of underlying ring). - * - * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. - */ - public override operator fun C.minus(other: Int): C = ring { addMultipliedBySquaring(this@minus, one, -other) } - /** - * Returns product of the constant and the integer represented as constant (member of underlying ring). - * - * The operation is equivalent to sum of [other] copies of [this]. - */ - public override operator fun C.times(other: Int): C = ring { multiplyBySquaring(this@times, other) } - - /** - * Returns sum of the integer represented as constant (member of underlying ring) and the constant. - * - * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. - */ - public override operator fun Int.plus(other: C): C = ring { addMultipliedBySquaring(other, one, this@plus) } - /** - * Returns difference between the integer represented as constant (member of underlying ring) and the constant. - * - * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. - */ - public override operator fun Int.minus(other: C): C = ring { addMultipliedBySquaring(-other, one, this@minus) } - /** - * Returns product of the integer represented as constant (member of underlying ring) and the constant. - * - * The operation is equivalent to sum of [this] copies of [other]. - */ - public override operator fun Int.times(other: C): C = ring { multiplyBySquaring(other, this@times) } - - /** - * Returns negation of the constant. - */ - @JvmName("constantUnaryMinus") - public override operator fun C.unaryMinus(): C = ring { -this@unaryMinus } - /** - * Returns sum of the constants. - */ - @JvmName("constantPlus") - public override operator fun C.plus(other: C): C = ring { this@plus + other } - /** - * Returns difference of the constants. - */ - @JvmName("constantMinus") - public override operator fun C.minus(other: C): C = ring { this@minus - other } - /** - * Returns product of the constants. - */ - @JvmName("constantTimes") - public override operator fun C.times(other: C): C = ring { this@times * other } - /** - * Raises [arg] to the integer power [exponent]. - */ - @JvmName("constantPower") - override fun power(arg: C, exponent: UInt): C = ring { power(arg, exponent) } - - /** - * Instance of zero constant (zero of the underlying ring). - */ - public override val constantZero: C get() = ring.zero - /** - * Instance of unit constant (unit of the underlying ring). - */ - public override val constantOne: C get() = ring.one -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt deleted file mode 100644 index c9c0b3920..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt +++ /dev/null @@ -1,1085 +0,0 @@ -/* - * 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.functions - -import space.kscience.kmath.operations.* -import kotlin.js.JsName -import kotlin.jvm.JvmName - - -/** - * Abstraction of rational function. - */ -public interface AbstractRationalFunction> { - public val numerator: P - public val denominator: P - public operator fun component1(): P = numerator - public operator fun component2(): P = denominator -} - -/** - * Abstraction of field of rational functions of type [R] with respect to polynomials of type [P] and constants of type - * [C]. - * - * @param C the type of constants. Polynomials have them as coefficients in their terms. - * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. - * @param R the type of rational functions. - */ // TODO: Add support of field -@Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") -public interface AbstractRationalFunctionalSpace, R: AbstractRationalFunction> : Ring { - /** - * Returns sum of the constant and the integer represented as constant (member of underlying ring). - * - * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. - */ - public operator fun C.plus(other: Int): C - /** - * Returns difference between the constant and the integer represented as constant (member of underlying ring). - * - * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. - */ - public operator fun C.minus(other: Int): C - /** - * Returns product of the constant and the integer represented as constant (member of underlying ring). - * - * The operation is equivalent to sum of [other] copies of [this]. - */ - public operator fun C.times(other: Int): C - - /** - * Returns sum of the integer represented as constant (member of underlying ring) and the constant. - * - * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. - */ - public operator fun Int.plus(other: C): C - /** - * Returns difference between the integer represented as constant (member of underlying ring) and the constant. - * - * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. - */ - public operator fun Int.minus(other: C): C - /** - * Returns product of the integer represented as constant (member of underlying ring) and the constant. - * - * The operation is equivalent to sum of [this] copies of [other]. - */ - public operator fun Int.times(other: C): C - - /** - * Returns sum of the constant and the integer represented as polynomial. - * - * The operation is equivalent to adding [other] copies of unit polynomial to [this]. - */ - public operator fun P.plus(other: Int): P - /** - * Returns difference between the constant and the integer represented as polynomial. - * - * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. - */ - public operator fun P.minus(other: Int): P - /** - * Returns product of the constant and the integer represented as polynomial. - * - * The operation is equivalent to sum of [other] copies of [this]. - */ - public operator fun P.times(other: Int): P - - /** - * Returns sum of the integer represented as polynomial and the constant. - * - * The operation is equivalent to adding [this] copies of unit polynomial to [other]. - */ - public operator fun Int.plus(other: P): P - /** - * Returns difference between the integer represented as polynomial and the constant. - * - * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. - */ - public operator fun Int.minus(other: P): P - /** - * Returns product of the integer represented as polynomial and the constant. - * - * The operation is equivalent to sum of [this] copies of [other]. - */ - public operator fun Int.times(other: P): P - - /** - * Returns sum of the rational function and the integer represented as rational function. - * - * The operation is equivalent to adding [other] copies of unit polynomial to [this]. - */ - public operator fun R.plus(other: Int): R = addMultipliedBySquaring(this, one, other) - /** - * Returns difference between the rational function and the integer represented as rational function. - * - * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. - */ - public operator fun R.minus(other: Int): R = addMultipliedBySquaring(this, one, -other) - /** - * Returns product of the rational function and the integer represented as rational function. - * - * The operation is equivalent to sum of [other] copies of [this]. - */ - public operator fun R.times(other: Int): R = multiplyBySquaring(this, other) - - /** - * Returns sum of the integer represented as rational function and the rational function. - * - * The operation is equivalent to adding [this] copies of unit polynomial to [other]. - */ - public operator fun Int.plus(other: R): R = addMultipliedBySquaring(other, one, this) - /** - * Returns difference between the integer represented as rational function and the rational function. - * - * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. - */ - public operator fun Int.minus(other: R): R = addMultipliedBySquaring(-other, one, this) - /** - * Returns product of the integer represented as rational function and the rational function. - * - * The operation is equivalent to sum of [this] copies of [other]. - */ - public operator fun Int.times(other: R): R = multiplyBySquaring(other, this) - - /** - * Returns the same constant. - */ - @JvmName("constantUnaryPlus") - @JsName("constantUnaryPlus") - public operator fun C.unaryPlus(): C = this - /** - * Returns negation of the constant. - */ - @JvmName("constantUnaryMinus") - @JsName("constantUnaryMinus") - public operator fun C.unaryMinus(): C - /** - * Returns sum of the constants. - */ - @JvmName("constantPlus") - @JsName("constantPlus") - public operator fun C.plus(other: C): C - /** - * Returns difference of the constants. - */ - @JvmName("constantMinus") - @JsName("constantMinus") - public operator fun C.minus(other: C): C - /** - * Returns product of the constants. - */ - @JvmName("constantTimes") - @JsName("constantTimes") - public operator fun C.times(other: C): C - /** - * Raises [arg] to the integer power [exponent]. - */ - @JvmName("constantPower") - @JsName("constantPower") - public fun power(arg: C, exponent: UInt) : C - - /** - * Check if the instant is zero constant. - */ - public fun C.isZero(): Boolean = this == constantZero - /** - * Check if the instant is NOT zero constant. - */ - public fun C.isNotZero(): Boolean = !isZero() - /** - * Check if the instant is unit constant. - */ - public fun C.isOne(): Boolean = this == constantOne - /** - * Check if the instant is NOT unit constant. - */ - public fun C.isNotOne(): Boolean = !isOne() - /** - * Check if the instant is minus unit constant. - */ - public fun C.isMinusOne(): Boolean = this == -constantOne - /** - * Check if the instant is NOT minus unit constant. - */ - public fun C.isNotMinusOne(): Boolean = !isMinusOne() - - /** - * Instance of zero constant (zero of the underlying ring). - */ - public val constantZero: C - /** - * Instance of unit constant (unit of the underlying ring). - */ - public val constantOne: C - - /** - * Returns sum of the constant represented as polynomial and the polynomial. - */ - public operator fun C.plus(other: P): P - /** - * Returns difference between the constant represented as polynomial and the polynomial. - */ - public operator fun C.minus(other: P): P - /** - * Returns product of the constant represented as polynomial and the polynomial. - */ - public operator fun C.times(other: P): P - - /** - * Returns sum of the constant represented as polynomial and the polynomial. - */ - public operator fun P.plus(other: C): P - /** - * Returns difference between the constant represented as polynomial and the polynomial. - */ - public operator fun P.minus(other: C): P - /** - * Returns product of the constant represented as polynomial and the polynomial. - */ - public operator fun P.times(other: C): P - - /** - * Returns the same polynomial. - */ - public operator fun P.unaryPlus(): P = this - /** - * Returns negation of the polynomial. - */ - public operator fun P.unaryMinus(): P - /** - * Returns sum of the polynomials. - */ - public operator fun P.plus(other: P): P - /** - * Returns difference of the polynomials. - */ - public operator fun P.minus(other: P): P - /** - * Returns product of the polynomials. - */ - public operator fun P.times(other: P): P - /** - * Raises [arg] to the integer power [exponent]. - */ - public fun power(arg: P, exponent: UInt) : P - - /** - * Check if the instant is zero polynomial. - */ - public fun P.isZero(): Boolean = this equalsTo polynomialZero - /** - * Check if the instant is NOT zero polynomial. - */ - public fun P.isNotZero(): Boolean = !isZero() - /** - * Check if the instant is unit polynomial. - */ - public fun P.isOne(): Boolean = this equalsTo polynomialOne - /** - * Check if the instant is NOT unit polynomial. - */ - public fun P.isNotOne(): Boolean = !isOne() - /** - * Check if the instant is minus unit polynomial. - */ - public fun P.isMinusOne(): Boolean = this equalsTo -polynomialOne - /** - * Check if the instant is NOT minus unit polynomial. - */ - public fun P.isNotMinusOne(): Boolean = !isMinusOne() - - /** - * Instance of zero polynomial (zero of the polynomial ring). - */ - public val polynomialZero: P - /** - * Instance of unit polynomial (unit of the polynomial ring). - */ - public val polynomialOne: P - - /** - * Checks equality of the polynomials. - */ - public infix fun P.equalsTo(other: P): Boolean - /** - * Checks NOT equality of the polynomials. - */ - public infix fun P.notEqualsTo(other: P): Boolean = !(this equalsTo other) - - /** - * Returns sum of the constant represented as rational function and the rational function. - */ - public operator fun C.plus(other: R): R - /** - * Returns difference between the constant represented as polynomial and the rational function. - */ - public operator fun C.minus(other: R): R - /** - * Returns product of the constant represented as polynomial and the rational function. - */ - public operator fun C.times(other: R): R - - /** - * Returns sum of the constant represented as rational function and the rational function. - */ - public operator fun R.plus(other: C): R - /** - * Returns difference between the constant represented as rational function and the rational function. - */ - public operator fun R.minus(other: C): R - /** - * Returns product of the constant represented as rational function and the rational function. - */ - public operator fun R.times(other: C): R - - /** - * Returns sum of the polynomial represented as rational function and the rational function. - */ - public operator fun P.plus(other: R): R - /** - * Returns difference between the polynomial represented as polynomial and the rational function. - */ - public operator fun P.minus(other: R): R - /** - * Returns product of the polynomial represented as polynomial and the rational function. - */ - public operator fun P.times(other: R): R - - /** - * Returns sum of the polynomial represented as rational function and the rational function. - */ - public operator fun R.plus(other: P): R - /** - * Returns difference between the polynomial represented as rational function and the rational function. - */ - public operator fun R.minus(other: P): R - /** - * Returns product of the polynomial represented as rational function and the rational function. - */ - public operator fun R.times(other: P): R - - /** - * Returns the same rational function. - */ - public override operator fun R.unaryPlus(): R = this - /** - * Returns negation of the rational function. - */ - public override operator fun R.unaryMinus(): R - /** - * Returns sum of the rational functions. - */ - public override operator fun R.plus(other: R): R - /** - * Returns difference of the rational functions. - */ - public override operator fun R.minus(other: R): R - /** - * Returns product of the rational functions. - */ - public override operator fun R.times(other: R): R - /** - * Raises [arg] to the integer power [exponent]. - */ - public override fun power(arg: R, exponent: UInt) : R = exponentiationBySquaring(arg, exponent) - - /** - * Check if the instant is zero rational function. - */ - public fun R.isZero(): Boolean = numerator equalsTo polynomialZero - /** - * Check if the instant is NOT zero rational function. - */ - public fun R.isNotZero(): Boolean = !isZero() - /** - * Check if the instant is unit rational function. - */ - public fun R.isOne(): Boolean = numerator equalsTo denominator - /** - * Check if the instant is NOT unit rational function. - */ - public fun R.isNotOne(): Boolean = !isOne() - /** - * Check if the instant is minus unit rational function. - */ - public fun R.isMinusOne(): Boolean = (numerator + denominator).isZero() - /** - * Check if the instant is NOT minus unit rational function. - */ - public fun R.isNotMinusOne(): Boolean = !isMinusOne() - - /** - * Instance of zero rational function (zero of the rational functions ring). - */ - public override val zero: R - /** - * Instance of unit polynomial (unit of the rational functions ring). - */ - public override val one: R - - /** - * Checks equality of the rational functions. - */ - public infix fun R.equalsTo(other: R): Boolean = - when { - this === other -> true - numerator.isZero() != other.numerator.isZero() -> false - numeratorDegree - denominatorDegree != with(other) { numeratorDegree - denominatorDegree } -> false - else -> numerator * other.denominator equalsTo other.numerator * denominator - } - /** - * Checks NOT equality of the polynomials. - */ - public infix fun R.notEqualsTo(other: R): Boolean = !(this equalsTo other) - - /** - * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is - * zero, degree is -1. - */ - public val P.degree: Int - - /** - * Checks if the instant is constant polynomial (of degree no more than 0) over considered ring. - */ - public fun P.isConstant(): Boolean = degree <= 0 - /** - * Checks if the instant is **not** constant polynomial (of degree no more than 0) over considered ring. - */ - public fun P.isNotConstant(): Boolean = !isConstant() - /** - * Checks if the instant is constant non-zero polynomial (of degree no more than 0) over considered ring. - */ - public fun P.isNonZeroConstant(): Boolean = degree == 0 - /** - * Checks if the instant is **not** constant non-zero polynomial (of degree no more than 0) over considered ring. - */ - public fun P.isNotNonZeroConstant(): Boolean = !isNonZeroConstant() - /** - * If polynomial is a constant polynomial represents and returns it as constant. - * Otherwise, (when the polynomial is not constant polynomial) returns `null`. - */ - public fun P.asConstantOrNull(): C? - /** - * If polynomial is a constant polynomial represents and returns it as constant. - * Otherwise, (when the polynomial is not constant polynomial) raises corresponding exception. - */ - public fun P.asConstant(): C = requireNotNull(asConstantOrNull()) { "Can not represent non-constant polynomial as a constant" } - - /** - * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is - * zero, degree is -1. - */ - public val R.numeratorDegree: Int get() = numerator.degree - /** - * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is - * zero, degree is -1. - */ - public val R.denominatorDegree: Int get() = denominator.degree - - override fun add(left: R, right: R): R = left + right - override fun multiply(left: R, right: R): R = left * right -} - -/** - * Abstraction of field of rational functions of type [R] with respect to polynomials of type [P] and constants of type - * [C]. It also assumes that there is provided [ring] (of type [A]), that provides constant-wise operations. - * - * @param C the type of constants. Polynomials have them as coefficients in their terms. - * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. - * @param R the type of rational functions. - * @param A the type of algebraic structure (precisely, of ring) provided for constants. - */ // TODO: Add support of field -@Suppress("INAPPLICABLE_JVM_NAME") -public interface AbstractRationalFunctionalSpaceOverRing, R: AbstractRationalFunction, A: Ring> : AbstractRationalFunctionalSpace { - - public val ring: A - - /** - * Returns sum of the constant and the integer represented as constant (member of underlying ring). - * - * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. - */ - public override operator fun C.plus(other: Int): C = ring { addMultipliedBySquaring(this@plus, one, other) } - /** - * Returns difference between the constant and the integer represented as constant (member of underlying ring). - * - * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. - */ - public override operator fun C.minus(other: Int): C = ring { addMultipliedBySquaring(this@minus, one, -other) } - /** - * Returns product of the constant and the integer represented as constant (member of underlying ring). - * - * The operation is equivalent to sum of [other] copies of [this]. - */ - public override operator fun C.times(other: Int): C = ring { multiplyBySquaring(this@times, other) } - - /** - * Returns sum of the integer represented as constant (member of underlying ring) and the constant. - * - * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. - */ - public override operator fun Int.plus(other: C): C = ring { addMultipliedBySquaring(other, one, this@plus) } - /** - * Returns difference between the integer represented as constant (member of underlying ring) and the constant. - * - * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. - */ - public override operator fun Int.minus(other: C): C = ring { addMultipliedBySquaring(-other, one, this@minus) } - /** - * Returns product of the integer represented as constant (member of underlying ring) and the constant. - * - * The operation is equivalent to sum of [this] copies of [other]. - */ - public override operator fun Int.times(other: C): C = ring { multiplyBySquaring(other, this@times) } - - /** - * Returns the same constant. - */ - @JvmName("constantUnaryPlus") - public override operator fun C.unaryPlus(): C = ring { +this@unaryPlus } - /** - * Returns negation of the constant. - */ - @JvmName("constantUnaryMinus") - public override operator fun C.unaryMinus(): C = ring { -this@unaryMinus } - /** - * Returns sum of the constants. - */ - @JvmName("constantPlus") - public override operator fun C.plus(other: C): C = ring { this@plus + other } - /** - * Returns difference of the constants. - */ - @JvmName("constantMinus") - public override operator fun C.minus(other: C): C = ring { this@minus - other } - /** - * Returns product of the constants. - */ - @JvmName("constantTimes") - public override operator fun C.times(other: C): C = ring { this@times * other } - /** - * Raises [arg] to the integer power [exponent]. - */ - @JvmName("constantPower") - public override fun power(arg: C, exponent: UInt) : C = ring { power(arg, exponent) } - - /** - * Instance of zero constant (zero of the underlying ring). - */ - public override val constantZero: C get() = ring.zero - /** - * Instance of unit constant (unit of the underlying ring). - */ - public override val constantOne: C get() = ring.one -} - -/** - * Abstraction of field of rational functions of type [R] with respect to polynomials of type [P] and constants of type - * [C]. It also assumes that there is provided [polynomialRing] (of type [AP]), that provides constant- and - * polynomial-wise operations. - * - * @param C the type of constants. Polynomials have them as coefficients in their terms. - * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. - * @param R the type of rational functions. - * @param AP the type of algebraic structure (precisely, of ring) provided for polynomials. - */ // TODO: Add support of field -@Suppress("INAPPLICABLE_JVM_NAME") -public interface AbstractRationalFunctionalSpaceOverPolynomialSpace< - C, - P: AbstractPolynomial, - R: AbstractRationalFunction, - AP: AbstractPolynomialSpace, - > : AbstractRationalFunctionalSpace { - - public val polynomialRing: AP - - /** - * Returns sum of the constant and the integer represented as constant (member of underlying ring). - * - * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. - */ - public override operator fun C.plus(other: Int): C = polynomialRing { this@plus + other } - /** - * Returns difference between the constant and the integer represented as constant (member of underlying ring). - * - * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. - */ - public override operator fun C.minus(other: Int): C = polynomialRing { this@minus - other } - /** - * Returns product of the constant and the integer represented as constant (member of underlying ring). - * - * The operation is equivalent to sum of [other] copies of [this]. - */ - public override operator fun C.times(other: Int): C = polynomialRing { this@times * other } - - /** - * Returns sum of the integer represented as constant (member of underlying ring) and the constant. - * - * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. - */ - public override operator fun Int.plus(other: C): C = polynomialRing { this@plus + other } - /** - * Returns difference between the integer represented as constant (member of underlying ring) and the constant. - * - * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. - */ - public override operator fun Int.minus(other: C): C = polynomialRing { this@minus - other } - /** - * Returns product of the integer represented as constant (member of underlying ring) and the constant. - * - * The operation is equivalent to sum of [this] copies of [other]. - */ - public override operator fun Int.times(other: C): C = polynomialRing { this@times * other } - - /** - * Returns sum of the constant and the integer represented as polynomial. - * - * The operation is equivalent to adding [other] copies of unit polynomial to [this]. - */ - public override operator fun P.plus(other: Int): P = polynomialRing { this@plus + other } - /** - * Returns difference between the constant and the integer represented as polynomial. - * - * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. - */ - public override operator fun P.minus(other: Int): P = polynomialRing { this@minus - other } - /** - * Returns product of the constant and the integer represented as polynomial. - * - * The operation is equivalent to sum of [other] copies of [this]. - */ - public override operator fun P.times(other: Int): P = polynomialRing { this@times * other } - - /** - * Returns sum of the integer represented as polynomial and the constant. - * - * The operation is equivalent to adding [this] copies of unit polynomial to [other]. - */ - public override operator fun Int.plus(other: P): P = polynomialRing { this@plus + other } - /** - * Returns difference between the integer represented as polynomial and the constant. - * - * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. - */ - public override operator fun Int.minus(other: P): P = polynomialRing { this@minus - other } - /** - * Returns product of the integer represented as polynomial and the constant. - * - * The operation is equivalent to sum of [this] copies of [other]. - */ - public override operator fun Int.times(other: P): P = polynomialRing { this@times * other } - - /** - * Returns the same constant. - */ - @JvmName("constantUnaryPlus") - public override operator fun C.unaryPlus(): C = polynomialRing { +this@unaryPlus } - /** - * Returns negation of the constant. - */ - @JvmName("constantUnaryMinus") - public override operator fun C.unaryMinus(): C = polynomialRing { -this@unaryMinus } - /** - * Returns sum of the constants. - */ - @JvmName("constantPlus") - public override operator fun C.plus(other: C): C = polynomialRing { this@plus + other } - /** - * Returns difference of the constants. - */ - @JvmName("constantMinus") - public override operator fun C.minus(other: C): C = polynomialRing { this@minus - other } - /** - * Returns product of the constants. - */ - @JvmName("constantTimes") - public override operator fun C.times(other: C): C = polynomialRing { this@times * other } - /** - * Raises [arg] to the integer power [exponent]. - */ - @JvmName("constantPower") - public override fun power(arg: C, exponent: UInt) : C = polynomialRing { power(arg, exponent) } - - /** - * Check if the instant is zero constant. - */ - public override fun C.isZero(): Boolean = polynomialRing { this@isZero.isZero() } - /** - * Check if the instant is NOT zero constant. - */ - public override fun C.isNotZero(): Boolean = polynomialRing { this@isNotZero.isNotZero() } - /** - * Check if the instant is unit constant. - */ - public override fun C.isOne(): Boolean = polynomialRing { this@isOne.isOne() } - /** - * Check if the instant is NOT unit constant. - */ - public override fun C.isNotOne(): Boolean = polynomialRing { this@isNotOne.isNotOne() } - /** - * Check if the instant is minus unit constant. - */ - public override fun C.isMinusOne(): Boolean = polynomialRing { this@isMinusOne.isMinusOne() } - /** - * Check if the instant is NOT minus unit constant. - */ - public override fun C.isNotMinusOne(): Boolean = polynomialRing { this@isNotMinusOne.isNotMinusOne() } - - /** - * Instance of zero constant (zero of the underlying ring). - */ - public override val constantZero: C get() = polynomialRing.constantZero - /** - * Instance of unit constant (unit of the underlying ring). - */ - public override val constantOne: C get() = polynomialRing.constantOne - - /** - * Returns sum of the constant represented as polynomial and the polynomial. - */ - public override operator fun C.plus(other: P): P = polynomialRing { this@plus + other } - /** - * Returns difference between the constant represented as polynomial and the polynomial. - */ - public override operator fun C.minus(other: P): P = polynomialRing { this@minus - other } - /** - * Returns product of the constant represented as polynomial and the polynomial. - */ - public override operator fun C.times(other: P): P = polynomialRing { this@times * other } - - /** - * Returns sum of the constant represented as polynomial and the polynomial. - */ - public override operator fun P.plus(other: C): P = polynomialRing { this@plus + other } - /** - * Returns difference between the constant represented as polynomial and the polynomial. - */ - public override operator fun P.minus(other: C): P = polynomialRing { this@minus - other } - /** - * Returns product of the constant represented as polynomial and the polynomial. - */ - public override operator fun P.times(other: C): P = polynomialRing { this@times * other } - - /** - * Returns the same polynomial. - */ - public override operator fun P.unaryPlus(): P = polynomialRing { +this@unaryPlus } - /** - * Returns negation of the polynomial. - */ - public override operator fun P.unaryMinus(): P = polynomialRing { -this@unaryMinus } - /** - * Returns sum of the polynomials. - */ - public override operator fun P.plus(other: P): P = polynomialRing { this@plus + other } - /** - * Returns difference of the polynomials. - */ - public override operator fun P.minus(other: P): P = polynomialRing { this@minus - other } - /** - * Returns product of the polynomials. - */ - public override operator fun P.times(other: P): P = polynomialRing { this@times * other } - /** - * Raises [arg] to the integer power [exponent]. - */ - public override fun power(arg: P, exponent: UInt) : P = polynomialRing { power(arg, exponent) } - - /** - * Check if the instant is zero polynomial. - */ - public override fun P.isZero(): Boolean = polynomialRing { this@isZero.isZero() } - /** - * Check if the instant is NOT zero polynomial. - */ - public override fun P.isNotZero(): Boolean = polynomialRing { this@isNotZero.isNotZero() } - /** - * Check if the instant is unit polynomial. - */ - public override fun P.isOne(): Boolean = polynomialRing { this@isOne.isOne() } - /** - * Check if the instant is NOT unit polynomial. - */ - public override fun P.isNotOne(): Boolean = polynomialRing { this@isNotOne.isNotOne() } - /** - * Check if the instant is minus unit polynomial. - */ - public override fun P.isMinusOne(): Boolean = polynomialRing { this@isMinusOne.isMinusOne() } - /** - * Check if the instant is NOT minus unit polynomial. - */ - public override fun P.isNotMinusOne(): Boolean = polynomialRing { this@isNotMinusOne.isNotMinusOne() } - - /** - * Instance of zero polynomial (zero of the polynomial ring). - */ - public override val polynomialZero: P get() = polynomialRing.zero - /** - * Instance of unit polynomial (unit of the polynomial ring). - */ - public override val polynomialOne: P get() = polynomialRing.one - - /** - * Checks equality of the polynomials. - */ - public override infix fun P.equalsTo(other: P): Boolean = polynomialRing { this@equalsTo equalsTo other } - /** - * Checks NOT equality of the polynomials. - */ - public override infix fun P.notEqualsTo(other: P): Boolean = polynomialRing { this@notEqualsTo notEqualsTo other } - - /** - * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is - * zero, degree is -1. - */ - public override val P.degree: Int get() = polynomialRing { this@degree.degree } - - /** - * Checks if the instant is constant polynomial (of degree no more than 0) over considered ring. - */ - public override fun P.isConstant(): Boolean = polynomialRing { this@isConstant.isConstant() } - /** - * Checks if the instant is **not** constant polynomial (of degree no more than 0) over considered ring. - */ - public override fun P.isNotConstant(): Boolean = polynomialRing { this@isNotConstant.isNotConstant() } - /** - * Checks if the instant is constant non-zero polynomial (of degree no more than 0) over considered ring. - */ - public override fun P.isNonZeroConstant(): Boolean = polynomialRing { this@isNonZeroConstant.isNonZeroConstant() } - /** - * Checks if the instant is **not** constant non-zero polynomial (of degree no more than 0) over considered ring. - */ - public override fun P.isNotNonZeroConstant(): Boolean = polynomialRing { this@isNotNonZeroConstant.isNotNonZeroConstant() } - /** - * If polynomial is a constant polynomial represents and returns it as constant. - * Otherwise, (when the polynomial is not constant polynomial) returns `null`. - */ - public override fun P.asConstantOrNull(): C? = polynomialRing { this@asConstantOrNull.asConstantOrNull() } - /** - * If polynomial is a constant polynomial represents and returns it as constant. - * Otherwise, (when the polynomial is not constant polynomial) raises corresponding exception. - */ - public override fun P.asConstant(): C = polynomialRing { this@asConstant.asConstant() } -} - -/** - * Abstraction of field of rational functions of type [R] with respect to polynomials of type [P] and constants of type - * [C]. It also assumes that there is provided constructor - * - * @param C the type of constants. Polynomials have them as coefficients in their terms. - * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. - * @param R the type of rational functions. - * @param AP the type of algebraic structure (precisely, of ring) provided for polynomials. - */ // TODO: Add support of field -@Suppress("INAPPLICABLE_JVM_NAME") -public abstract class PolynomialSpaceOfFractions< - C, - P: AbstractPolynomial, - R: AbstractRationalFunction, - > : AbstractRationalFunctionalSpace { - protected abstract fun constructRationalFunction(numerator: P, denominator: P) : R - - /** - * Returns sum of the rational function and the integer represented as rational function. - * - * The operation is equivalent to adding [other] copies of unit polynomial to [this]. - */ - public override operator fun R.plus(other: Int): R = - constructRationalFunction( - numerator + denominator * other, - denominator - ) - /** - * Returns difference between the rational function and the integer represented as rational function. - * - * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. - */ - public override operator fun R.minus(other: Int): R = - constructRationalFunction( - numerator - denominator * other, - denominator - ) - /** - * Returns product of the rational function and the integer represented as rational function. - * - * The operation is equivalent to sum of [other] copies of [this]. - */ - public override operator fun R.times(other: Int): R = - constructRationalFunction( - numerator * other, - denominator - ) - - /** - * Returns sum of the integer represented as rational function and the rational function. - * - * The operation is equivalent to adding [this] copies of unit polynomial to [other]. - */ - public override operator fun Int.plus(other: R): R = - constructRationalFunction( - other.denominator * this + other.numerator, - other.denominator - ) - /** - * Returns difference between the integer represented as rational function and the rational function. - * - * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. - */ - public override operator fun Int.minus(other: R): R = - constructRationalFunction( - other.denominator * this - other.numerator, - other.denominator - ) - /** - * Returns product of the integer represented as rational function and the rational function. - * - * The operation is equivalent to sum of [this] copies of [other]. - */ - public override operator fun Int.times(other: R): R = - constructRationalFunction( - this * other.numerator, - other.denominator - ) - - /** - * Returns sum of the constant represented as rational function and the rational function. - */ - public override operator fun C.plus(other: R): R = - constructRationalFunction( - other.denominator * this + other.numerator, - other.denominator - ) - /** - * Returns difference between the constant represented as polynomial and the rational function. - */ - public override operator fun C.minus(other: R): R = - constructRationalFunction( - other.denominator * this - other.numerator, - other.denominator - ) - /** - * Returns product of the constant represented as polynomial and the rational function. - */ - public override operator fun C.times(other: R): R = - constructRationalFunction( - this * other.numerator, - other.denominator - ) - - /** - * Returns sum of the constant represented as rational function and the rational function. - */ - public override operator fun R.plus(other: C): R = - constructRationalFunction( - numerator + denominator * other, - denominator - ) - /** - * Returns difference between the constant represented as rational function and the rational function. - */ - public override operator fun R.minus(other: C): R = - constructRationalFunction( - numerator - denominator * other, - denominator - ) - /** - * Returns product of the constant represented as rational function and the rational function. - */ - public override operator fun R.times(other: C): R = - constructRationalFunction( - numerator * other, - denominator - ) - - /** - * Returns sum of the polynomial represented as rational function and the rational function. - */ - public override operator fun P.plus(other: R): R = - constructRationalFunction( - other.denominator * this + other.numerator, - other.denominator - ) - /** - * Returns difference between the polynomial represented as polynomial and the rational function. - */ - public override operator fun P.minus(other: R): R = - constructRationalFunction( - other.denominator * this - other.numerator, - other.denominator - ) - /** - * Returns product of the polynomial represented as polynomial and the rational function. - */ - public override operator fun P.times(other: R): R = - constructRationalFunction( - this * other.numerator, - other.denominator - ) - - /** - * Returns sum of the polynomial represented as rational function and the rational function. - */ - public override operator fun R.plus(other: P): R = - constructRationalFunction( - numerator + denominator * other, - denominator - ) - /** - * Returns difference between the polynomial represented as rational function and the rational function. - */ - public override operator fun R.minus(other: P): R = - constructRationalFunction( - numerator - denominator * other, - denominator - ) - /** - * Returns product of the polynomial represented as rational function and the rational function. - */ - public override operator fun R.times(other: P): R = - constructRationalFunction( - numerator * other, - denominator - ) - - /** - * Returns negation of the rational function. - */ - public override operator fun R.unaryMinus(): R = constructRationalFunction(-numerator, denominator) - /** - * Returns sum of the rational functions. - */ - public override operator fun R.plus(other: R): R = - constructRationalFunction( - numerator * other.denominator + denominator * other.numerator, - denominator * other.denominator - ) - /** - * Returns difference of the rational functions. - */ - public override operator fun R.minus(other: R): R = - constructRationalFunction( - numerator * other.denominator - denominator * other.numerator, - denominator * other.denominator - ) - /** - * Returns product of the rational functions. - */ - public override operator fun R.times(other: R): R = - constructRationalFunction( - numerator * other.numerator, - denominator * other.denominator - ) - - /** - * Instance of zero rational function (zero of the rational functions ring). - */ - public override val zero: R get() = constructRationalFunction(polynomialZero, polynomialOne) - - /** - * Instance of unit polynomial (unit of the rational functions ring). - */ - public override val one: R get() = constructRationalFunction(polynomialOne, polynomialOne) -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt index 76f5fc29c..968f77b20 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt @@ -44,7 +44,7 @@ internal constructor( * where `a`, `b` and `c` are corresponding [Symbol] objects. */ public val coefficients: Map, C> -) : AbstractPolynomial { +) : Polynomial { override fun toString(): String = "LabeledPolynomial$coefficients" } @@ -116,7 +116,7 @@ public fun C.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomia */ public class LabeledPolynomialSpace>( public override val ring: A, -) : AbstractPolynomialSpaceOverRing, A> { +) : PolynomialSpaceOverRing, A> { public operator fun Symbol.plus(other: Int): LabeledPolynomial = if (other == 0) LabeledPolynomial(mapOf( mapOf(this@plus to 1U) to constantOne, diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt index 92bd344ac..f347f9191 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt @@ -13,7 +13,7 @@ import space.kscience.kmath.operations.invoke public class LabeledRationalFunction( public override val numerator: LabeledPolynomial, public override val denominator: LabeledPolynomial -) : AbstractRationalFunction> { +) : RationalFunction> { override fun toString(): String = "LabeledRationalFunction${numerator.coefficients}/${denominator.coefficients}" } @@ -65,7 +65,7 @@ public class LabeledRationalFunction( public class LabeledRationalFunctionSpace>( public val ring: A, ) : - AbstractRationalFunctionalSpaceOverPolynomialSpace< + RationalFunctionalSpaceOverPolynomialSpace< C, LabeledPolynomial, LabeledRationalFunction, diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt new file mode 100644 index 000000000..b97c1e0b4 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt @@ -0,0 +1,491 @@ +/* + * 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.functions + +import space.kscience.kmath.operations.* +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract +import kotlin.experimental.ExperimentalTypeInference +import kotlin.jvm.JvmName +import kotlin.math.max +import kotlin.math.min + +/** + * Polynomial model without fixation on specific context they are applied to. + * + * @param coefficients constant is the leftmost coefficient. + */ +public data class ListPolynomial( + /** + * List that collects coefficients of the polynomial. Every monomial `a x^d` is represented as a coefficients + * `a` placed into the list with index `d`. For example coefficients of polynomial `5 x^2 - 6` can be represented as + * ``` + * listOf( + * -6, // -6 + + * 0, // 0 x + + * 5, // 5 x^2 + * ) + * ``` + * and also as + * ``` + * listOf( + * -6, // -6 + + * 0, // 0 x + + * 5, // 5 x^2 + * 0, // 0 x^3 + * 0, // 0 x^4 + * ) + * ``` + * It is recommended not to put extra zeros at end of the list (as for `0x^3` and `0x^4` in the example), but is not + * prohibited. + */ + public val coefficients: List +) : Polynomial { + override fun toString(): String = "Polynomial$coefficients" +} + +/** + * Returns a [ListPolynomial] instance with given [coefficients]. The collection of coefficients will be reversed if + * [reverse] parameter is true. + */ +@Suppress("FunctionName") +public fun ListPolynomial(coefficients: List, reverse: Boolean = false): ListPolynomial = + ListPolynomial(with(coefficients) { if (reverse) reversed() else this }) + +/** + * Returns a [ListPolynomial] instance with given [coefficients]. The collection of coefficients will be reversed if + * [reverse] parameter is true. + */ +@Suppress("FunctionName") +public fun ListPolynomial(vararg coefficients: C, reverse: Boolean = false): ListPolynomial = + ListPolynomial(with(coefficients) { if (reverse) reversed() else toList() }) + +public fun C.asPolynomial() : ListPolynomial = ListPolynomial(listOf(this)) + +/** + * Space of univariate polynomials constructed over ring. + * + * @param C the type of constants. Polynomials have them as a coefficients in their terms. + * @param A type of underlying ring of constants. It's [Ring] of [C]. + * @param ring underlying ring of constants of type [A]. + */ +public open class ListPolynomialSpace>( + public override val ring: A, +) : PolynomialSpaceOverRing, A> { + /** + * Returns sum of the polynomial and the integer represented as polynomial. + * + * The operation is equivalent to adding [other] copies of unit polynomial to [this]. + */ + public override operator fun ListPolynomial.plus(other: Int): ListPolynomial = + if (other == 0) this + else + ListPolynomial( + coefficients + .toMutableList() + .apply { + val result = getOrElse(0) { constantZero } + other + val isResultZero = result.isZero() + + when { + size == 0 && !isResultZero -> add(result) + size > 1 || !isResultZero -> this[0] = result + else -> clear() + } + } + ) + /** + * Returns difference between the polynomial and the integer represented as polynomial. + * + * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. + */ + public override operator fun ListPolynomial.minus(other: Int): ListPolynomial = + if (other == 0) this + else + ListPolynomial( + coefficients + .toMutableList() + .apply { + val result = getOrElse(0) { constantZero } - other + val isResultZero = result.isZero() + + when { + size == 0 && !isResultZero -> add(result) + size > 1 || !isResultZero -> this[0] = result + else -> clear() + } + } + ) + /** + * Returns product of the polynomial and the integer represented as polynomial. + * + * The operation is equivalent to sum of [other] copies of [this]. + */ + public override operator fun ListPolynomial.times(other: Int): ListPolynomial = + if (other == 0) zero + else ListPolynomial( + coefficients + .applyAndRemoveZeros { + for (deg in indices) this[deg] = this[deg] * other + } + ) + + /** + * Returns sum of the integer represented as polynomial and the polynomial. + * + * The operation is equivalent to adding [this] copies of unit polynomial to [other]. + */ + public override operator fun Int.plus(other: ListPolynomial): ListPolynomial = + if (this == 0) other + else + ListPolynomial( + other.coefficients + .toMutableList() + .apply { + val result = this@plus + getOrElse(0) { constantZero } + val isResultZero = result.isZero() + + when { + size == 0 && !isResultZero -> add(result) + size > 1 || !isResultZero -> this[0] = result + else -> clear() + } + } + ) + /** + * Returns difference between the integer represented as polynomial and the polynomial. + * + * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. + */ + public override operator fun Int.minus(other: ListPolynomial): ListPolynomial = + if (this == 0) other + else + ListPolynomial( + other.coefficients + .toMutableList() + .apply { + forEachIndexed { index, c -> if (index != 0) this[index] = -c } + + val result = this@minus - getOrElse(0) { constantZero } + val isResultZero = result.isZero() + + when { + size == 0 && !isResultZero -> add(result) + size > 1 || !isResultZero -> this[0] = result + else -> clear() + } + } + ) + /** + * Returns product of the integer represented as polynomial and the polynomial. + * + * The operation is equivalent to sum of [this] copies of [other]. + */ + public override operator fun Int.times(other: ListPolynomial): ListPolynomial = + if (this == 0) zero + else ListPolynomial( + other.coefficients + .applyAndRemoveZeros { + for (deg in indices) this[deg] = this@times * this[deg] + } + ) + + /** + * Returns sum of the constant represented as polynomial and the polynomial. + */ + public override operator fun C.plus(other: ListPolynomial): ListPolynomial = + if (this.isZero()) other + else with(other.coefficients) { + if (isEmpty()) ListPolynomial(listOf(this@plus)) + else ListPolynomial( + toMutableList() + .apply { + val result = if (size == 0) this@plus else this@plus + get(0) + val isResultZero = result.isZero() + + when { + size == 0 && !isResultZero -> add(result) + size > 1 || !isResultZero -> this[0] = result + else -> clear() + } + } + ) + } + /** + * Returns difference between the constant represented as polynomial and the polynomial. + */ + public override operator fun C.minus(other: ListPolynomial): ListPolynomial = + if (this.isZero()) other + else with(other.coefficients) { + if (isEmpty()) ListPolynomial(listOf(this@minus)) + else ListPolynomial( + toMutableList() + .apply { + forEachIndexed { index, c -> if (index != 0) this[index] = -c } + + val result = if (size == 0) this@minus else this@minus - get(0) + val isResultZero = result.isZero() + + when { + size == 0 && !isResultZero -> add(result) + size > 1 || !isResultZero -> this[0] = result + else -> clear() + } + } + ) + } + /** + * Returns product of the constant represented as polynomial and the polynomial. + */ + public override operator fun C.times(other: ListPolynomial): ListPolynomial = + if (this.isZero()) other + else ListPolynomial( + other.coefficients + .applyAndRemoveZeros { + for (deg in indices) this[deg] = this@times * this[deg] + } + ) + + /** + * Returns sum of the constant represented as polynomial and the polynomial. + */ + public override operator fun ListPolynomial.plus(other: C): ListPolynomial = + if (other.isZero()) this + else with(coefficients) { + if (isEmpty()) ListPolynomial(listOf(other)) + else ListPolynomial( + toMutableList() + .apply { + val result = if (size == 0) other else get(0) + other + val isResultZero = result.isZero() + + when { + size == 0 && !isResultZero -> add(result) + size > 1 || !isResultZero -> this[0] = result + else -> clear() + } + } + ) + } + /** + * Returns difference between the constant represented as polynomial and the polynomial. + */ + public override operator fun ListPolynomial.minus(other: C): ListPolynomial = + if (other.isZero()) this + else with(coefficients) { + if (isEmpty()) ListPolynomial(listOf(-other)) + else ListPolynomial( + toMutableList() + .apply { + val result = if (size == 0) other else get(0) - other + val isResultZero = result.isZero() + + when { + size == 0 && !isResultZero -> add(result) + size > 1 || !isResultZero -> this[0] = result + else -> clear() + } + } + ) + } + /** + * Returns product of the constant represented as polynomial and the polynomial. + */ + public override operator fun ListPolynomial.times(other: C): ListPolynomial = + if (other.isZero()) this + else ListPolynomial( + coefficients + .applyAndRemoveZeros { + for (deg in indices) this[deg] = this[deg] * other + } + ) + + /** + * Returns negation of the polynomial. + */ + public override operator fun ListPolynomial.unaryMinus(): ListPolynomial = + ListPolynomial(coefficients.map { -it }) + /** + * Returns sum of the polynomials. + */ + public override operator fun ListPolynomial.plus(other: ListPolynomial): ListPolynomial { + val thisDegree = degree + val otherDegree = other.degree + return ListPolynomial( + Coefficients(max(thisDegree, otherDegree) + 1) { + when { + it > thisDegree -> other.coefficients[it] + it > otherDegree -> coefficients[it] + else -> coefficients[it] + other.coefficients[it] + } + } + ) + } + /** + * Returns difference of the polynomials. + */ + public override operator fun ListPolynomial.minus(other: ListPolynomial): ListPolynomial { + val thisDegree = degree + val otherDegree = other.degree + return ListPolynomial( + Coefficients(max(thisDegree, otherDegree) + 1) { + when { + it > thisDegree -> -other.coefficients[it] + it > otherDegree -> coefficients[it] + else -> coefficients[it] - other.coefficients[it] + } + } + ) + } + /** + * Returns product of the polynomials. + */ + public override operator fun ListPolynomial.times(other: ListPolynomial): ListPolynomial { + val thisDegree = degree + val otherDegree = other.degree + return when { + thisDegree == -1 -> zero + otherDegree == -1 -> zero + else -> + ListPolynomial( + Coefficients(thisDegree + otherDegree + 1) { d -> + (max(0, d - otherDegree)..min(thisDegree, d)) + .map { coefficients[it] * other.coefficients[d - it] } + .reduce { acc, rational -> acc + rational } + } + ) + } + } + + /** + * Check if the instant is zero polynomial. + */ + public override fun ListPolynomial.isZero(): Boolean = coefficients.all { it.isZero() } + /** + * Check if the instant is unit polynomial. + */ + public override fun ListPolynomial.isOne(): Boolean = + with(coefficients) { + isNotEmpty() && withIndex().all { (index, c) -> if (index == 0) c.isOne() else c.isZero() } + } + /** + * Check if the instant is minus unit polynomial. + */ + public override fun ListPolynomial.isMinusOne(): Boolean = + with(coefficients) { + isNotEmpty() && withIndex().all { (index, c) -> if (index == 0) c.isMinusOne() else c.isZero() } + } + + /** + * Instance of zero polynomial (zero of the polynomial ring). + */ + override val zero: ListPolynomial = ListPolynomial(emptyList()) + /** + * Instance of unit constant (unit of the underlying ring). + */ + override val one: ListPolynomial = ListPolynomial(listOf(constantOne)) + + /** + * Checks equality of the polynomials. + */ + public override infix fun ListPolynomial.equalsTo(other: ListPolynomial): Boolean = + when { + this === other -> true + this.degree == other.degree -> (0..degree).all { coefficients[it] == other.coefficients[it] } + else -> false + } + + /** + * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is + * zero, degree is -1. + */ + public override val ListPolynomial.degree: Int get() = coefficients.indexOfLast { it != constantZero } + + /** + * If polynomial is a constant polynomial represents and returns it as constant. + * Otherwise, (when the polynomial is not constant polynomial) returns `null`. + */ + public override fun ListPolynomial.asConstantOrNull(): C? = + with(coefficients) { + when { + isEmpty() -> constantZero + withIndex().all { (index, c) -> index == 0 || c.isZero() } -> first() + else -> null + } + } + + @Suppress("NOTHING_TO_INLINE") + public inline fun ListPolynomial.substitute(argument: C): C = this.substitute(ring, argument) + @Suppress("NOTHING_TO_INLINE") + public inline fun ListPolynomial.substitute(argument: ListPolynomial): ListPolynomial = this.substitute(ring, argument) + + @Suppress("NOTHING_TO_INLINE") + public inline fun ListPolynomial.asFunction(): (C) -> C = { this.substitute(ring, it) } + @Suppress("NOTHING_TO_INLINE") + public inline fun ListPolynomial.asFunctionOnConstants(): (C) -> C = { this.substitute(ring, it) } + @Suppress("NOTHING_TO_INLINE") + public inline fun ListPolynomial.asFunctionOnPolynomials(): (ListPolynomial) -> ListPolynomial = { this.substitute(ring, it) } + + /** + * Evaluates the polynomial for the given value [argument]. + */ + @Suppress("NOTHING_TO_INLINE") + public inline operator fun ListPolynomial.invoke(argument: C): C = this.substitute(ring, argument) + @Suppress("NOTHING_TO_INLINE") + public inline operator fun ListPolynomial.invoke(argument: ListPolynomial): ListPolynomial = this.substitute(ring, argument) + + // TODO: Move to other internal utilities with context receiver + @JvmName("applyAndRemoveZerosInternal") + internal inline fun MutableList.applyAndRemoveZeros(block: MutableList.() -> Unit) : MutableList { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + block() + while (isNotEmpty() && elementAt(lastIndex).isZero()) removeAt(lastIndex) + return this + } + internal inline fun List.applyAndRemoveZeros(block: MutableList.() -> Unit) : List = + toMutableList().applyAndRemoveZeros(block) + @Suppress("FunctionName") + 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 (isNotEmpty() && elementAt(lastIndex).isZero()) removeAt(lastIndex) } + return list + } + @Suppress("FunctionName") + internal inline fun Coefficients(size: Int, init: (index: Int) -> C): List = MutableCoefficients(size, init) + @OptIn(ExperimentalTypeInference::class) + internal inline fun buildCoefficients(@BuilderInference builderAction: MutableList.() -> Unit): List { + contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) } + return buildList { + builderAction() + while (isNotEmpty() && elementAt(lastIndex).isZero()) removeAt(lastIndex) + } + } + @OptIn(ExperimentalTypeInference::class) + internal inline fun buildCoefficients(capacity: Int, @BuilderInference builderAction: MutableList.() -> Unit): List { + contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) } + return buildList(capacity) { + builderAction() + while (isNotEmpty() && elementAt(lastIndex).isZero()) removeAt(lastIndex) + } + } +} + +/** + * Space of polynomials constructed over ring. + * + * @param C the type of constants. Polynomials have them as a coefficients in their terms. + * @param A type of underlying ring of constants. It's [Ring] of [C]. + * @param ring underlying ring of constants of type [A]. + */ +public class ScalableListPolynomialSpace( + ring: A, +) : ListPolynomialSpace(ring), ScaleOperations> where A : Ring, A : ScaleOperations { + override fun scale(a: ListPolynomial, value: Double): ListPolynomial = + ring { ListPolynomial(a.coefficients.map { scale(it, value) }) } +} diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt new file mode 100644 index 000000000..50ddd3118 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt @@ -0,0 +1,154 @@ +/* + * 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.functions + +import space.kscience.kmath.operations.Ring + + +public data class ListRationalFunction internal constructor ( + public override val numerator: ListPolynomial, + public override val denominator: ListPolynomial +) : RationalFunction> { + override fun toString(): String = "RationalFunction${numerator.coefficients}/${denominator.coefficients}" +} + +// Waiting for context receivers :( TODO: Replace with context receivers when they will be available + +//context(RationalFunctionSpace) +//@Suppress("FunctionName") +//internal fun > RationalFunction(numerator: Polynomial, denominator: Polynomial): RationalFunction = +// if (denominator.isZero()) throw ArithmeticException("/ by zero") +// else RationalFunction(numerator, denominator) +//context(RationalFunctionSpace) +//@Suppress("FunctionName") +//public fun > RationalFunction(numeratorCoefficients: List, denominatorCoefficients: List, reverse: Boolean = false): RationalFunction = +// RationalFunction( +// Polynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), +// Polynomial( with(denominatorCoefficients) { if (reverse) reversed() else this } ).also { if (it.isZero()) } +// ) +//context(RationalFunctionSpace) +//@Suppress("FunctionName") +//public fun > RationalFunction(numerator: Polynomial): RationalFunction = +// RationalFunction(numerator, onePolynomial) +//context(RationalFunctionSpace) +//@Suppress("FunctionName") +//public fun > RationalFunction(numeratorCoefficients: List, reverse: Boolean = false): RationalFunction = +// RationalFunction( +// Polynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ) +// ) + +public class ListRationalFunctionSpace> ( + public val ring: A, +) : + RationalFunctionalSpaceOverPolynomialSpace< + C, + ListPolynomial, + ListRationalFunction, + ListPolynomialSpace, + >, + PolynomialSpaceOfFractions< + C, + ListPolynomial, + ListRationalFunction, + >() { + + override val polynomialRing : ListPolynomialSpace = ListPolynomialSpace(ring) + override fun constructRationalFunction(numerator: ListPolynomial, denominator: ListPolynomial): ListRationalFunction = + ListRationalFunction(numerator, denominator) + + /** + * Instance of zero rational function (zero of the rational functions ring). + */ + public override val zero: ListRationalFunction = ListRationalFunction(polynomialZero, polynomialOne) + /** + * Instance of unit polynomial (unit of the rational functions ring). + */ + public override val one: ListRationalFunction = ListRationalFunction(polynomialOne, polynomialOne) + + // TODO: Разобрать + + public operator fun ListRationalFunction.div(other: ListRationalFunction): ListRationalFunction = + ListRationalFunction( + numerator * other.denominator, + denominator * other.numerator + ) + + public operator fun ListRationalFunction.div(other: ListPolynomial): ListRationalFunction = + ListRationalFunction( + numerator, + denominator * other + ) + + public operator fun ListRationalFunction.div(other: C): ListRationalFunction = + ListRationalFunction( + numerator, + denominator * other + ) + + public operator fun ListRationalFunction.div(other: Int): ListRationalFunction = + ListRationalFunction( + numerator, + denominator * other + ) + +// operator fun invoke(arg: UnivariatePolynomial): RationalFunction = +// RationalFunction( +// numerator(arg), +// denominator(arg) +// ) +// +// operator fun invoke(arg: RationalFunction): RationalFunction { +// val num = numerator invokeRFTakeNumerator arg +// val den = denominator invokeRFTakeNumerator arg +// val degreeDif = numeratorDegree - denominatorDegree +// return if (degreeDif > 0) +// RationalFunction( +// num, +// multiplyByPower(den, arg.denominator, degreeDif) +// ) +// else +// RationalFunction( +// multiplyByPower(num, arg.denominator, -degreeDif), +// den +// ) +// } +// +// override fun toString(): String = toString(UnivariatePolynomial.variableName) +// +// fun toString(withVariableName: String = UnivariatePolynomial.variableName): String = +// when(true) { +// numerator.isZero() -> "0" +// denominator.isOne() -> numerator.toString(withVariableName) +// else -> "${numerator.toStringWithBrackets(withVariableName)}/${denominator.toStringWithBrackets(withVariableName)}" +// } +// +// fun toStringWithBrackets(withVariableName: String = UnivariatePolynomial.variableName): String = +// when(true) { +// numerator.isZero() -> "0" +// denominator.isOne() -> numerator.toStringWithBrackets(withVariableName) +// else -> "(${numerator.toStringWithBrackets(withVariableName)}/${denominator.toStringWithBrackets(withVariableName)})" +// } +// +// fun toReversedString(withVariableName: String = UnivariatePolynomial.variableName): String = +// when(true) { +// numerator.isZero() -> "0" +// denominator.isOne() -> numerator.toReversedString(withVariableName) +// else -> "${numerator.toReversedStringWithBrackets(withVariableName)}/${denominator.toReversedStringWithBrackets(withVariableName)}" +// } +// +// fun toReversedStringWithBrackets(withVariableName: String = UnivariatePolynomial.variableName): String = +// when(true) { +// numerator.isZero() -> "0" +// denominator.isOne() -> numerator.toReversedStringWithBrackets(withVariableName) +// else -> "(${numerator.toReversedStringWithBrackets(withVariableName)}/${denominator.toReversedStringWithBrackets(withVariableName)})" +// } +// +// fun removeZeros() = +// RationalFunction( +// numerator.removeZeros(), +// denominator.removeZeros() +// ) +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt index c05bc30ec..3b9b907b7 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -43,7 +43,7 @@ internal constructor( * contain any zeros on end, but can contain zeros on start or anywhere in middle. */ public val coefficients: Map, C> -) : AbstractPolynomial { +) : Polynomial { override fun toString(): String = "NumberedPolynomial$coefficients" } @@ -112,7 +112,7 @@ public fun C.asNumberedPolynomial() : NumberedPolynomial = NumberedPolyno */ public open class NumberedPolynomialSpace>( public final override val ring: A, -) : AbstractPolynomialSpaceOverRing, A> { +) : PolynomialSpaceOverRing, A> { /** * Returns sum of the polynomial and the integer represented as polynomial. * diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt index 4da715e3f..f3b90b5c5 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt @@ -12,7 +12,7 @@ import kotlin.math.max public class NumberedRationalFunction internal constructor( public override val numerator: NumberedPolynomial, public override val denominator: NumberedPolynomial -) : AbstractRationalFunction> { +) : RationalFunction> { override fun toString(): String = "NumberedRationalFunction${numerator.coefficients}/${denominator.coefficients}" } @@ -61,7 +61,7 @@ public class NumberedRationalFunction internal constructor( public class NumberedRationalFunctionSpace> ( public val ring: A, ) : - AbstractRationalFunctionalSpaceOverPolynomialSpace< + RationalFunctionalSpaceOverPolynomialSpace< C, NumberedPolynomial, NumberedRationalFunction, diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt index cfd21d552..612b00535 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt @@ -27,10 +27,10 @@ public fun interface Piecewise { * @property pieces An ordered list of range-polynomial pairs. The list does not in general guarantee that there are no * "holes" in it. */ -public interface PiecewisePolynomial> : Piecewise> { - public val pieces: Collection, Polynomial>> +public interface PiecewisePolynomial> : Piecewise> { + public val pieces: Collection, ListPolynomial>> - override fun findPiece(arg: T): Polynomial? + override fun findPiece(arg: T): ListPolynomial? } /** @@ -38,11 +38,11 @@ public interface PiecewisePolynomial> : Piecewise> PiecewisePolynomial( - pieces: Collection, Polynomial>>, + pieces: Collection, ListPolynomial>>, ): PiecewisePolynomial = object : PiecewisePolynomial { - override val pieces: Collection, Polynomial>> = pieces + override val pieces: Collection, ListPolynomial>> = pieces - override fun findPiece(arg: T): Polynomial? = pieces.firstOrNull { arg in it.first }?.second + override fun findPiece(arg: T): ListPolynomial? = pieces.firstOrNull { arg in it.first }?.second } /** @@ -50,10 +50,10 @@ public fun > PiecewisePolynomial( * The pieces search is logarithmic. */ private class OrderedPiecewisePolynomial>( - override val pieces: List, Polynomial>>, + override val pieces: List, ListPolynomial>>, ) : PiecewisePolynomial { - override fun findPiece(arg: T): Polynomial? { + override fun findPiece(arg: T): ListPolynomial? { val index = pieces.binarySearch { (range, _) -> when { arg >= range.endInclusive -> -1 @@ -74,7 +74,7 @@ private class OrderedPiecewisePolynomial>( */ public class PiecewiseBuilder>(delimiter: T) { private val delimiters: MutableList = arrayListOf(delimiter) - private val pieces: MutableList> = arrayListOf() + private val pieces: MutableList> = arrayListOf() /** * Dynamically adds a piece to the right side (beyond maximum argument value of previous piece) @@ -82,7 +82,7 @@ public class PiecewiseBuilder>(delimiter: T) { * @param right new rightmost position. If is less than current rightmost position, an error is thrown. * @param piece the sub-function. */ - public fun putRight(right: T, piece: Polynomial) { + public fun putRight(right: T, piece: ListPolynomial) { require(right > delimiters.last()) { "New delimiter should be to the right of old one" } delimiters += right pieces += piece @@ -94,7 +94,7 @@ public class PiecewiseBuilder>(delimiter: T) { * @param left the new leftmost position. If is less than current rightmost position, an error is thrown. * @param piece the sub-function. */ - public fun putLeft(left: T, piece: Polynomial) { + public fun putLeft(left: T, piece: ListPolynomial) { require(left < delimiters.first()) { "New delimiter should be to the left of old one" } delimiters.add(0, left) pieces.add(0, piece) 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 d6c959fd1..b26a57a34 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 @@ -6,486 +6,384 @@ package space.kscience.kmath.functions import space.kscience.kmath.operations.* -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract -import kotlin.experimental.ExperimentalTypeInference +import kotlin.js.JsName import kotlin.jvm.JvmName -import kotlin.math.max -import kotlin.math.min + /** - * Polynomial model without fixation on specific context they are applied to. - * - * @param coefficients constant is the leftmost coefficient. + * Abstraction of polynomials. */ -public data class Polynomial( +public interface Polynomial + +/** + * Abstraction of ring of polynomials of type [P] over ring of constants of type [C]. + * + * @param C the type of constants. Polynomials have them as coefficients in their terms. + * @param P the type of polynomials. + */ +@Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") +public interface PolynomialSpace> : Ring

{ /** - * List that collects coefficients of the polynomial. Every monomial `a x^d` is represented as a coefficients - * `a` placed into the list with index `d`. For example coefficients of polynomial `5 x^2 - 6` can be represented as - * ``` - * listOf( - * -6, // -6 + - * 0, // 0 x + - * 5, // 5 x^2 - * ) - * ``` - * and also as - * ``` - * listOf( - * -6, // -6 + - * 0, // 0 x + - * 5, // 5 x^2 - * 0, // 0 x^3 - * 0, // 0 x^4 - * ) - * ``` - * It is recommended not to put extra zeros at end of the list (as for `0x^3` and `0x^4` in the example), but is not - * prohibited. + * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * + * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. */ - public val coefficients: List -) : AbstractPolynomial { - override fun toString(): String = "Polynomial$coefficients" -} + public operator fun C.plus(other: Int): C + /** + * Returns difference between the constant and the integer represented as constant (member of underlying ring). + * + * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. + */ + public operator fun C.minus(other: Int): C + /** + * Returns product of the constant and the integer represented as constant (member of underlying ring). + * + * The operation is equivalent to sum of [other] copies of [this]. + */ + public operator fun C.times(other: Int): C -/** - * Returns a [Polynomial] instance with given [coefficients]. The collection of coefficients will be reversed if - * [reverse] parameter is true. - */ -@Suppress("FunctionName") -public fun Polynomial(coefficients: List, reverse: Boolean = false): Polynomial = - Polynomial(with(coefficients) { if (reverse) reversed() else this }) + /** + * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * + * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. + */ + public operator fun Int.plus(other: C): C + /** + * Returns difference between the integer represented as constant (member of underlying ring) and the constant. + * + * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. + */ + public operator fun Int.minus(other: C): C + /** + * Returns product of the integer represented as constant (member of underlying ring) and the constant. + * + * The operation is equivalent to sum of [this] copies of [other]. + */ + public operator fun Int.times(other: C): C -/** - * Returns a [Polynomial] instance with given [coefficients]. The collection of coefficients will be reversed if - * [reverse] parameter is true. - */ -@Suppress("FunctionName") -public fun Polynomial(vararg coefficients: C, reverse: Boolean = false): Polynomial = - Polynomial(with(coefficients) { if (reverse) reversed() else toList() }) - -public fun C.asPolynomial() : Polynomial = Polynomial(listOf(this)) - -/** - * Space of univariate polynomials constructed over ring. - * - * @param C the type of constants. Polynomials have them as a coefficients in their terms. - * @param A type of underlying ring of constants. It's [Ring] of [C]. - * @param ring underlying ring of constants of type [A]. - */ -public open class PolynomialSpace>( - public override val ring: A, -) : AbstractPolynomialSpaceOverRing, A> { /** * Returns sum of the polynomial and the integer represented as polynomial. * * The operation is equivalent to adding [other] copies of unit polynomial to [this]. */ - public override operator fun Polynomial.plus(other: Int): Polynomial = - if (other == 0) this - else - Polynomial( - coefficients - .toMutableList() - .apply { - val result = getOrElse(0) { constantZero } + other - val isResultZero = result.isZero() - - when { - size == 0 && !isResultZero -> add(result) - size > 1 || !isResultZero -> this[0] = result - else -> clear() - } - } - ) + public operator fun P.plus(other: Int): P = addMultipliedBySquaring(this, one, other) /** * Returns difference between the polynomial and the integer represented as polynomial. * * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. */ - public override operator fun Polynomial.minus(other: Int): Polynomial = - if (other == 0) this - else - Polynomial( - coefficients - .toMutableList() - .apply { - val result = getOrElse(0) { constantZero } - other - val isResultZero = result.isZero() - - when { - size == 0 && !isResultZero -> add(result) - size > 1 || !isResultZero -> this[0] = result - else -> clear() - } - } - ) + public operator fun P.minus(other: Int): P = addMultipliedBySquaring(this, one, -other) /** * Returns product of the polynomial and the integer represented as polynomial. * * The operation is equivalent to sum of [other] copies of [this]. */ - public override operator fun Polynomial.times(other: Int): Polynomial = - if (other == 0) zero - else Polynomial( - coefficients - .applyAndRemoveZeros { - for (deg in indices) this[deg] = this[deg] * other - } - ) + public operator fun P.times(other: Int): P = multiplyBySquaring(this, other) /** * Returns sum of the integer represented as polynomial and the polynomial. * * The operation is equivalent to adding [this] copies of unit polynomial to [other]. */ - public override operator fun Int.plus(other: Polynomial): Polynomial = - if (this == 0) other - else - Polynomial( - other.coefficients - .toMutableList() - .apply { - val result = this@plus + getOrElse(0) { constantZero } - val isResultZero = result.isZero() - - when { - size == 0 && !isResultZero -> add(result) - size > 1 || !isResultZero -> this[0] = result - else -> clear() - } - } - ) + public operator fun Int.plus(other: P): P = addMultipliedBySquaring(other, one, this) /** * Returns difference between the integer represented as polynomial and the polynomial. * * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. */ - public override operator fun Int.minus(other: Polynomial): Polynomial = - if (this == 0) other - else - Polynomial( - other.coefficients - .toMutableList() - .apply { - forEachIndexed { index, c -> if (index != 0) this[index] = -c } - - val result = this@minus - getOrElse(0) { constantZero } - val isResultZero = result.isZero() - - when { - size == 0 && !isResultZero -> add(result) - size > 1 || !isResultZero -> this[0] = result - else -> clear() - } - } - ) + public operator fun Int.minus(other: P): P = addMultipliedBySquaring(-other, one, this) /** * Returns product of the integer represented as polynomial and the polynomial. * * The operation is equivalent to sum of [this] copies of [other]. */ - public override operator fun Int.times(other: Polynomial): Polynomial = - if (this == 0) zero - else Polynomial( - other.coefficients - .applyAndRemoveZeros { - for (deg in indices) this[deg] = this@times * this[deg] - } - ) + public operator fun Int.times(other: P): P = multiplyBySquaring(other, this) + + /** + * Returns the same constant. + */ + @JvmName("constantUnaryPlus") + @JsName("constantUnaryPlus") + public operator fun C.unaryPlus(): C = this + /** + * Returns negation of the constant. + */ + @JvmName("constantUnaryMinus") + @JsName("constantUnaryMinus") + public operator fun C.unaryMinus(): C + /** + * Returns sum of the constants. + */ + @JvmName("constantPlus") + @JsName("constantPlus") + public operator fun C.plus(other: C): C + /** + * Returns difference of the constants. + */ + @JvmName("constantMinus") + @JsName("constantMinus") + public operator fun C.minus(other: C): C + /** + * Returns product of the constants. + */ + @JvmName("constantTimes") + @JsName("constantTimes") + public operator fun C.times(other: C): C + /** + * Raises [arg] to the integer power [exponent]. + */ + @JvmName("constantPower") + @JsName("constantPower") + public fun power(arg: C, exponent: UInt) : C + + /** + * Check if the instant is zero constant. + */ + public fun C.isZero(): Boolean = this == constantZero + /** + * Check if the instant is NOT zero constant. + */ + public fun C.isNotZero(): Boolean = !isZero() + /** + * Check if the instant is unit constant. + */ + public fun C.isOne(): Boolean = this == constantOne + /** + * Check if the instant is NOT unit constant. + */ + public fun C.isNotOne(): Boolean = !isOne() + /** + * Check if the instant is minus unit constant. + */ + public fun C.isMinusOne(): Boolean = this == -constantOne + /** + * Check if the instant is NOT minus unit constant. + */ + public fun C.isNotMinusOne(): Boolean = !isMinusOne() + + /** + * Instance of zero constant (zero of the underlying ring). + */ + public val constantZero: C + /** + * Instance of unit constant (unit of the underlying ring). + */ + public val constantOne: C /** * Returns sum of the constant represented as polynomial and the polynomial. */ - public override operator fun C.plus(other: Polynomial): Polynomial = - if (this.isZero()) other - else with(other.coefficients) { - if (isEmpty()) Polynomial(listOf(this@plus)) - else Polynomial( - toMutableList() - .apply { - val result = if (size == 0) this@plus else this@plus + get(0) - val isResultZero = result.isZero() - - when { - size == 0 && !isResultZero -> add(result) - size > 1 || !isResultZero -> this[0] = result - else -> clear() - } - } - ) - } + public operator fun C.plus(other: P): P /** * Returns difference between the constant represented as polynomial and the polynomial. */ - public override operator fun C.minus(other: Polynomial): Polynomial = - if (this.isZero()) other - else with(other.coefficients) { - if (isEmpty()) Polynomial(listOf(this@minus)) - else Polynomial( - toMutableList() - .apply { - forEachIndexed { index, c -> if (index != 0) this[index] = -c } - - val result = if (size == 0) this@minus else this@minus - get(0) - val isResultZero = result.isZero() - - when { - size == 0 && !isResultZero -> add(result) - size > 1 || !isResultZero -> this[0] = result - else -> clear() - } - } - ) - } + public operator fun C.minus(other: P): P /** * Returns product of the constant represented as polynomial and the polynomial. */ - public override operator fun C.times(other: Polynomial): Polynomial = - if (this.isZero()) other - else Polynomial( - other.coefficients - .applyAndRemoveZeros { - for (deg in indices) this[deg] = this@times * this[deg] - } - ) + public operator fun C.times(other: P): P /** * Returns sum of the constant represented as polynomial and the polynomial. */ - public override operator fun Polynomial.plus(other: C): Polynomial = - if (other.isZero()) this - else with(coefficients) { - if (isEmpty()) Polynomial(listOf(other)) - else Polynomial( - toMutableList() - .apply { - val result = if (size == 0) other else get(0) + other - val isResultZero = result.isZero() - - when { - size == 0 && !isResultZero -> add(result) - size > 1 || !isResultZero -> this[0] = result - else -> clear() - } - } - ) - } + public operator fun P.plus(other: C): P /** * Returns difference between the constant represented as polynomial and the polynomial. */ - public override operator fun Polynomial.minus(other: C): Polynomial = - if (other.isZero()) this - else with(coefficients) { - if (isEmpty()) Polynomial(listOf(-other)) - else Polynomial( - toMutableList() - .apply { - val result = if (size == 0) other else get(0) - other - val isResultZero = result.isZero() - - when { - size == 0 && !isResultZero -> add(result) - size > 1 || !isResultZero -> this[0] = result - else -> clear() - } - } - ) - } + public operator fun P.minus(other: C): P /** * Returns product of the constant represented as polynomial and the polynomial. */ - public override operator fun Polynomial.times(other: C): Polynomial = - if (other.isZero()) this - else Polynomial( - coefficients - .applyAndRemoveZeros { - for (deg in indices) this[deg] = this[deg] * other - } - ) + public operator fun P.times(other: C): P + /** + * Returns the same polynomial. + */ + public override operator fun P.unaryPlus(): P = this /** * Returns negation of the polynomial. */ - public override operator fun Polynomial.unaryMinus(): Polynomial = - Polynomial(coefficients.map { -it }) + public override operator fun P.unaryMinus(): P /** * Returns sum of the polynomials. */ - public override operator fun Polynomial.plus(other: Polynomial): Polynomial { - val thisDegree = degree - val otherDegree = other.degree - return Polynomial( - Coefficients(max(thisDegree, otherDegree) + 1) { - when { - it > thisDegree -> other.coefficients[it] - it > otherDegree -> coefficients[it] - else -> coefficients[it] + other.coefficients[it] - } - } - ) - } + public override operator fun P.plus(other: P): P /** * Returns difference of the polynomials. */ - public override operator fun Polynomial.minus(other: Polynomial): Polynomial { - val thisDegree = degree - val otherDegree = other.degree - return Polynomial( - Coefficients(max(thisDegree, otherDegree) + 1) { - when { - it > thisDegree -> -other.coefficients[it] - it > otherDegree -> coefficients[it] - else -> coefficients[it] - other.coefficients[it] - } - } - ) - } + public override operator fun P.minus(other: P): P /** * Returns product of the polynomials. */ - public override operator fun Polynomial.times(other: Polynomial): Polynomial { - val thisDegree = degree - val otherDegree = other.degree - return when { - thisDegree == -1 -> zero - otherDegree == -1 -> zero - else -> - Polynomial( - Coefficients(thisDegree + otherDegree + 1) { d -> - (max(0, d - otherDegree)..min(thisDegree, d)) - .map { coefficients[it] * other.coefficients[d - it] } - .reduce { acc, rational -> acc + rational } - } - ) - } - } + public override operator fun P.times(other: P): P + /** + * Raises [arg] to the integer power [exponent]. + */ + public override fun power(arg: P, exponent: UInt) : P = exponentiationBySquaring(arg, exponent) /** * Check if the instant is zero polynomial. */ - public override fun Polynomial.isZero(): Boolean = coefficients.all { it.isZero() } + public fun P.isZero(): Boolean = this equalsTo zero + /** + * Check if the instant is NOT zero polynomial. + */ + public fun P.isNotZero(): Boolean = !isZero() /** * Check if the instant is unit polynomial. */ - public override fun Polynomial.isOne(): Boolean = - with(coefficients) { - isNotEmpty() && withIndex().all { (index, c) -> if (index == 0) c.isOne() else c.isZero() } - } + public fun P.isOne(): Boolean = this equalsTo one + /** + * Check if the instant is NOT unit polynomial. + */ + public fun P.isNotOne(): Boolean = !isOne() /** * Check if the instant is minus unit polynomial. */ - public override fun Polynomial.isMinusOne(): Boolean = - with(coefficients) { - isNotEmpty() && withIndex().all { (index, c) -> if (index == 0) c.isMinusOne() else c.isZero() } - } + public fun P.isMinusOne(): Boolean = this equalsTo -one + /** + * Check if the instant is NOT minus unit polynomial. + */ + public fun P.isNotMinusOne(): Boolean = !isMinusOne() /** * Instance of zero polynomial (zero of the polynomial ring). */ - override val zero: Polynomial = Polynomial(emptyList()) + public override val zero: P /** - * Instance of unit constant (unit of the underlying ring). + * Instance of unit polynomial (unit of the polynomial ring). */ - override val one: Polynomial = Polynomial(listOf(constantOne)) + public override val one: P /** * Checks equality of the polynomials. */ - public override infix fun Polynomial.equalsTo(other: Polynomial): Boolean = - when { - this === other -> true - this.degree == other.degree -> (0..degree).all { coefficients[it] == other.coefficients[it] } - else -> false - } + public infix fun P.equalsTo(other: P): Boolean + /** + * Checks NOT equality of the polynomials. + */ + public infix fun P.notEqualsTo(other: P): Boolean = !(this equalsTo other) /** * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is * zero, degree is -1. */ - public override val Polynomial.degree: Int get() = coefficients.indexOfLast { it != constantZero } + public val P.degree: Int + /** + * Checks if the instant is constant polynomial (of degree no more than 0) over considered ring. + */ + public fun P.isConstant(): Boolean = degree <= 0 + /** + * Checks if the instant is **not** constant polynomial (of degree no more than 0) over considered ring. + */ + public fun P.isNotConstant(): Boolean = !isConstant() + /** + * Checks if the instant is constant non-zero polynomial (of degree no more than 0) over considered ring. + */ + public fun P.isNonZeroConstant(): Boolean = degree == 0 + /** + * Checks if the instant is **not** constant non-zero polynomial (of degree no more than 0) over considered ring. + */ + public fun P.isNotNonZeroConstant(): Boolean = !isNonZeroConstant() /** * If polynomial is a constant polynomial represents and returns it as constant. * Otherwise, (when the polynomial is not constant polynomial) returns `null`. */ - public override fun Polynomial.asConstantOrNull(): C? = - with(coefficients) { - when { - isEmpty() -> constantZero - withIndex().all { (index, c) -> index == 0 || c.isZero() } -> first() - else -> null - } - } - - @Suppress("NOTHING_TO_INLINE") - public inline fun Polynomial.substitute(argument: C): C = this.substitute(ring, argument) - @Suppress("NOTHING_TO_INLINE") - public inline fun Polynomial.substitute(argument: Polynomial): Polynomial = this.substitute(ring, argument) - - @Suppress("NOTHING_TO_INLINE") - public inline fun Polynomial.asFunction(): (C) -> C = { this.substitute(ring, it) } - @Suppress("NOTHING_TO_INLINE") - public inline fun Polynomial.asFunctionOnConstants(): (C) -> C = { this.substitute(ring, it) } - @Suppress("NOTHING_TO_INLINE") - public inline fun Polynomial.asFunctionOnPolynomials(): (Polynomial) -> Polynomial = { this.substitute(ring, it) } - + public fun P.asConstantOrNull(): C? /** - * Evaluates the polynomial for the given value [argument]. + * If polynomial is a constant polynomial represents and returns it as constant. + * Otherwise, (when the polynomial is not constant polynomial) raises corresponding exception. */ - @Suppress("NOTHING_TO_INLINE") - public inline operator fun Polynomial.invoke(argument: C): C = this.substitute(ring, argument) - @Suppress("NOTHING_TO_INLINE") - public inline operator fun Polynomial.invoke(argument: Polynomial): Polynomial = this.substitute(ring, argument) + public fun P.asConstant(): C = requireNotNull(asConstantOrNull()) { "Can not represent non-constant polynomial as a constant" } - // TODO: Move to other internal utilities with context receiver - @JvmName("applyAndRemoveZerosInternal") - internal inline fun MutableList.applyAndRemoveZeros(block: MutableList.() -> Unit) : MutableList { - contract { - callsInPlace(block, InvocationKind.EXACTLY_ONCE) - } - block() - while (isNotEmpty() && elementAt(lastIndex).isZero()) removeAt(lastIndex) - return this - } - internal inline fun List.applyAndRemoveZeros(block: MutableList.() -> Unit) : List = - toMutableList().applyAndRemoveZeros(block) - @Suppress("FunctionName") - 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 (isNotEmpty() && elementAt(lastIndex).isZero()) removeAt(lastIndex) } - return list - } - @Suppress("FunctionName") - internal inline fun Coefficients(size: Int, init: (index: Int) -> C): List = MutableCoefficients(size, init) - @OptIn(ExperimentalTypeInference::class) - internal inline fun buildCoefficients(@BuilderInference builderAction: MutableList.() -> Unit): List { - contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) } - return buildList { - builderAction() - while (isNotEmpty() && elementAt(lastIndex).isZero()) removeAt(lastIndex) - } - } - @OptIn(ExperimentalTypeInference::class) - internal inline fun buildCoefficients(capacity: Int, @BuilderInference builderAction: MutableList.() -> Unit): List { - contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) } - return buildList(capacity) { - builderAction() - while (isNotEmpty() && elementAt(lastIndex).isZero()) removeAt(lastIndex) - } - } + override fun add(left: P, right: P): P = left + right + override fun multiply(left: P, right: P): P = left * right } /** - * Space of polynomials constructed over ring. + * Abstraction of ring of polynomials of type [P] over ring of constants of type [C]. It also assumes that there is + * provided [ring] (of type [A]), that provides constant-wise operations. * - * @param C the type of constants. Polynomials have them as a coefficients in their terms. - * @param A type of underlying ring of constants. It's [Ring] of [C]. - * @param ring underlying ring of constants of type [A]. + * @param C the type of constants. Polynomials have them as coefficients in their terms. + * @param P the type of polynomials. + * @param A the type of algebraic structure (precisely, of ring) provided for constants. */ -public class ScalablePolynomialSpace( - ring: A, -) : PolynomialSpace(ring), ScaleOperations> where A : Ring, A : ScaleOperations { - override fun scale(a: Polynomial, value: Double): Polynomial = - ring { Polynomial(a.coefficients.map { scale(it, value) }) } -} +@Suppress("INAPPLICABLE_JVM_NAME") +public interface PolynomialSpaceOverRing, A: Ring> : PolynomialSpace { + + public val ring: A + + /** + * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * + * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. + */ + public override operator fun C.plus(other: Int): C = ring { addMultipliedBySquaring(this@plus, one, other) } + /** + * Returns difference between the constant and the integer represented as constant (member of underlying ring). + * + * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. + */ + public override operator fun C.minus(other: Int): C = ring { addMultipliedBySquaring(this@minus, one, -other) } + /** + * Returns product of the constant and the integer represented as constant (member of underlying ring). + * + * The operation is equivalent to sum of [other] copies of [this]. + */ + public override operator fun C.times(other: Int): C = ring { multiplyBySquaring(this@times, other) } + + /** + * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * + * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. + */ + public override operator fun Int.plus(other: C): C = ring { addMultipliedBySquaring(other, one, this@plus) } + /** + * Returns difference between the integer represented as constant (member of underlying ring) and the constant. + * + * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. + */ + public override operator fun Int.minus(other: C): C = ring { addMultipliedBySquaring(-other, one, this@minus) } + /** + * Returns product of the integer represented as constant (member of underlying ring) and the constant. + * + * The operation is equivalent to sum of [this] copies of [other]. + */ + public override operator fun Int.times(other: C): C = ring { multiplyBySquaring(other, this@times) } + + /** + * Returns negation of the constant. + */ + @JvmName("constantUnaryMinus") + public override operator fun C.unaryMinus(): C = ring { -this@unaryMinus } + /** + * Returns sum of the constants. + */ + @JvmName("constantPlus") + public override operator fun C.plus(other: C): C = ring { this@plus + other } + /** + * Returns difference of the constants. + */ + @JvmName("constantMinus") + public override operator fun C.minus(other: C): C = ring { this@minus - other } + /** + * Returns product of the constants. + */ + @JvmName("constantTimes") + public override operator fun C.times(other: C): C = ring { this@times * other } + /** + * Raises [arg] to the integer power [exponent]. + */ + @JvmName("constantPower") + override fun power(arg: C, exponent: UInt): C = ring { power(arg, exponent) } + + /** + * Instance of zero constant (zero of the underlying ring). + */ + public override val constantZero: C get() = ring.zero + /** + * Instance of unit constant (unit of the underlying ring). + */ + public override val constantOne: C get() = ring.one +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt index 51c1e2f80..635661b8a 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt @@ -5,150 +5,1081 @@ package space.kscience.kmath.functions -import space.kscience.kmath.operations.Ring +import space.kscience.kmath.operations.* +import kotlin.js.JsName +import kotlin.jvm.JvmName -public data class RationalFunction internal constructor ( - public override val numerator: Polynomial, - public override val denominator: Polynomial -) : AbstractRationalFunction> { - override fun toString(): String = "RationalFunction${numerator.coefficients}/${denominator.coefficients}" +/** + * Abstraction of rational function. + */ +public interface RationalFunction> { + public val numerator: P + public val denominator: P + public operator fun component1(): P = numerator + public operator fun component2(): P = denominator } -// Waiting for context receivers :( TODO: Replace with context receivers when they will be available +/** + * Abstraction of field of rational functions of type [R] with respect to polynomials of type [P] and constants of type + * [C]. + * + * @param C the type of constants. Polynomials have them as coefficients in their terms. + * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. + * @param R the type of rational functions. + */ // TODO: Add support of field +@Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") +public interface RationalFunctionalSpace, R: RationalFunction> : Ring { + /** + * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * + * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. + */ + public operator fun C.plus(other: Int): C + /** + * Returns difference between the constant and the integer represented as constant (member of underlying ring). + * + * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. + */ + public operator fun C.minus(other: Int): C + /** + * Returns product of the constant and the integer represented as constant (member of underlying ring). + * + * The operation is equivalent to sum of [other] copies of [this]. + */ + public operator fun C.times(other: Int): C -//context(RationalFunctionSpace) -//@Suppress("FunctionName") -//internal fun > RationalFunction(numerator: Polynomial, denominator: Polynomial): RationalFunction = -// if (denominator.isZero()) throw ArithmeticException("/ by zero") -// else RationalFunction(numerator, denominator) -//context(RationalFunctionSpace) -//@Suppress("FunctionName") -//public fun > RationalFunction(numeratorCoefficients: List, denominatorCoefficients: List, reverse: Boolean = false): RationalFunction = -// RationalFunction( -// Polynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), -// Polynomial( with(denominatorCoefficients) { if (reverse) reversed() else this } ).also { if (it.isZero()) } -// ) -//context(RationalFunctionSpace) -//@Suppress("FunctionName") -//public fun > RationalFunction(numerator: Polynomial): RationalFunction = -// RationalFunction(numerator, onePolynomial) -//context(RationalFunctionSpace) -//@Suppress("FunctionName") -//public fun > RationalFunction(numeratorCoefficients: List, reverse: Boolean = false): RationalFunction = -// RationalFunction( -// Polynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ) -// ) + /** + * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * + * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. + */ + public operator fun Int.plus(other: C): C + /** + * Returns difference between the integer represented as constant (member of underlying ring) and the constant. + * + * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. + */ + public operator fun Int.minus(other: C): C + /** + * Returns product of the integer represented as constant (member of underlying ring) and the constant. + * + * The operation is equivalent to sum of [this] copies of [other]. + */ + public operator fun Int.times(other: C): C -public class RationalFunctionSpace> ( - public val ring: A, -) : - AbstractRationalFunctionalSpaceOverPolynomialSpace< - C, - Polynomial, - RationalFunction, - PolynomialSpace, - >, - PolynomialSpaceOfFractions< - C, - Polynomial, - RationalFunction, - >() { + /** + * Returns sum of the constant and the integer represented as polynomial. + * + * The operation is equivalent to adding [other] copies of unit polynomial to [this]. + */ + public operator fun P.plus(other: Int): P + /** + * Returns difference between the constant and the integer represented as polynomial. + * + * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. + */ + public operator fun P.minus(other: Int): P + /** + * Returns product of the constant and the integer represented as polynomial. + * + * The operation is equivalent to sum of [other] copies of [this]. + */ + public operator fun P.times(other: Int): P - override val polynomialRing : PolynomialSpace = PolynomialSpace(ring) - override fun constructRationalFunction(numerator: Polynomial, denominator: Polynomial): RationalFunction = - RationalFunction(numerator, denominator) + /** + * Returns sum of the integer represented as polynomial and the constant. + * + * The operation is equivalent to adding [this] copies of unit polynomial to [other]. + */ + public operator fun Int.plus(other: P): P + /** + * Returns difference between the integer represented as polynomial and the constant. + * + * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. + */ + public operator fun Int.minus(other: P): P + /** + * Returns product of the integer represented as polynomial and the constant. + * + * The operation is equivalent to sum of [this] copies of [other]. + */ + public operator fun Int.times(other: P): P + + /** + * Returns sum of the rational function and the integer represented as rational function. + * + * The operation is equivalent to adding [other] copies of unit polynomial to [this]. + */ + public operator fun R.plus(other: Int): R = addMultipliedBySquaring(this, one, other) + /** + * Returns difference between the rational function and the integer represented as rational function. + * + * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. + */ + public operator fun R.minus(other: Int): R = addMultipliedBySquaring(this, one, -other) + /** + * Returns product of the rational function and the integer represented as rational function. + * + * The operation is equivalent to sum of [other] copies of [this]. + */ + public operator fun R.times(other: Int): R = multiplyBySquaring(this, other) + + /** + * Returns sum of the integer represented as rational function and the rational function. + * + * The operation is equivalent to adding [this] copies of unit polynomial to [other]. + */ + public operator fun Int.plus(other: R): R = addMultipliedBySquaring(other, one, this) + /** + * Returns difference between the integer represented as rational function and the rational function. + * + * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. + */ + public operator fun Int.minus(other: R): R = addMultipliedBySquaring(-other, one, this) + /** + * Returns product of the integer represented as rational function and the rational function. + * + * The operation is equivalent to sum of [this] copies of [other]. + */ + public operator fun Int.times(other: R): R = multiplyBySquaring(other, this) + + /** + * Returns the same constant. + */ + @JvmName("constantUnaryPlus") + @JsName("constantUnaryPlus") + public operator fun C.unaryPlus(): C = this + /** + * Returns negation of the constant. + */ + @JvmName("constantUnaryMinus") + @JsName("constantUnaryMinus") + public operator fun C.unaryMinus(): C + /** + * Returns sum of the constants. + */ + @JvmName("constantPlus") + @JsName("constantPlus") + public operator fun C.plus(other: C): C + /** + * Returns difference of the constants. + */ + @JvmName("constantMinus") + @JsName("constantMinus") + public operator fun C.minus(other: C): C + /** + * Returns product of the constants. + */ + @JvmName("constantTimes") + @JsName("constantTimes") + public operator fun C.times(other: C): C + /** + * Raises [arg] to the integer power [exponent]. + */ + @JvmName("constantPower") + @JsName("constantPower") + public fun power(arg: C, exponent: UInt) : C + + /** + * Check if the instant is zero constant. + */ + public fun C.isZero(): Boolean = this == constantZero + /** + * Check if the instant is NOT zero constant. + */ + public fun C.isNotZero(): Boolean = !isZero() + /** + * Check if the instant is unit constant. + */ + public fun C.isOne(): Boolean = this == constantOne + /** + * Check if the instant is NOT unit constant. + */ + public fun C.isNotOne(): Boolean = !isOne() + /** + * Check if the instant is minus unit constant. + */ + public fun C.isMinusOne(): Boolean = this == -constantOne + /** + * Check if the instant is NOT minus unit constant. + */ + public fun C.isNotMinusOne(): Boolean = !isMinusOne() + + /** + * Instance of zero constant (zero of the underlying ring). + */ + public val constantZero: C + /** + * Instance of unit constant (unit of the underlying ring). + */ + public val constantOne: C + + /** + * Returns sum of the constant represented as polynomial and the polynomial. + */ + public operator fun C.plus(other: P): P + /** + * Returns difference between the constant represented as polynomial and the polynomial. + */ + public operator fun C.minus(other: P): P + /** + * Returns product of the constant represented as polynomial and the polynomial. + */ + public operator fun C.times(other: P): P + + /** + * Returns sum of the constant represented as polynomial and the polynomial. + */ + public operator fun P.plus(other: C): P + /** + * Returns difference between the constant represented as polynomial and the polynomial. + */ + public operator fun P.minus(other: C): P + /** + * Returns product of the constant represented as polynomial and the polynomial. + */ + public operator fun P.times(other: C): P + + /** + * Returns the same polynomial. + */ + public operator fun P.unaryPlus(): P = this + /** + * Returns negation of the polynomial. + */ + public operator fun P.unaryMinus(): P + /** + * Returns sum of the polynomials. + */ + public operator fun P.plus(other: P): P + /** + * Returns difference of the polynomials. + */ + public operator fun P.minus(other: P): P + /** + * Returns product of the polynomials. + */ + public operator fun P.times(other: P): P + /** + * Raises [arg] to the integer power [exponent]. + */ + public fun power(arg: P, exponent: UInt) : P + + /** + * Check if the instant is zero polynomial. + */ + public fun P.isZero(): Boolean = this equalsTo polynomialZero + /** + * Check if the instant is NOT zero polynomial. + */ + public fun P.isNotZero(): Boolean = !isZero() + /** + * Check if the instant is unit polynomial. + */ + public fun P.isOne(): Boolean = this equalsTo polynomialOne + /** + * Check if the instant is NOT unit polynomial. + */ + public fun P.isNotOne(): Boolean = !isOne() + /** + * Check if the instant is minus unit polynomial. + */ + public fun P.isMinusOne(): Boolean = this equalsTo -polynomialOne + /** + * Check if the instant is NOT minus unit polynomial. + */ + public fun P.isNotMinusOne(): Boolean = !isMinusOne() + + /** + * Instance of zero polynomial (zero of the polynomial ring). + */ + public val polynomialZero: P + /** + * Instance of unit polynomial (unit of the polynomial ring). + */ + public val polynomialOne: P + + /** + * Checks equality of the polynomials. + */ + public infix fun P.equalsTo(other: P): Boolean + /** + * Checks NOT equality of the polynomials. + */ + public infix fun P.notEqualsTo(other: P): Boolean = !(this equalsTo other) + + /** + * Returns sum of the constant represented as rational function and the rational function. + */ + public operator fun C.plus(other: R): R + /** + * Returns difference between the constant represented as polynomial and the rational function. + */ + public operator fun C.minus(other: R): R + /** + * Returns product of the constant represented as polynomial and the rational function. + */ + public operator fun C.times(other: R): R + + /** + * Returns sum of the constant represented as rational function and the rational function. + */ + public operator fun R.plus(other: C): R + /** + * Returns difference between the constant represented as rational function and the rational function. + */ + public operator fun R.minus(other: C): R + /** + * Returns product of the constant represented as rational function and the rational function. + */ + public operator fun R.times(other: C): R + + /** + * Returns sum of the polynomial represented as rational function and the rational function. + */ + public operator fun P.plus(other: R): R + /** + * Returns difference between the polynomial represented as polynomial and the rational function. + */ + public operator fun P.minus(other: R): R + /** + * Returns product of the polynomial represented as polynomial and the rational function. + */ + public operator fun P.times(other: R): R + + /** + * Returns sum of the polynomial represented as rational function and the rational function. + */ + public operator fun R.plus(other: P): R + /** + * Returns difference between the polynomial represented as rational function and the rational function. + */ + public operator fun R.minus(other: P): R + /** + * Returns product of the polynomial represented as rational function and the rational function. + */ + public operator fun R.times(other: P): R + + /** + * Returns the same rational function. + */ + public override operator fun R.unaryPlus(): R = this + /** + * Returns negation of the rational function. + */ + public override operator fun R.unaryMinus(): R + /** + * Returns sum of the rational functions. + */ + public override operator fun R.plus(other: R): R + /** + * Returns difference of the rational functions. + */ + public override operator fun R.minus(other: R): R + /** + * Returns product of the rational functions. + */ + public override operator fun R.times(other: R): R + /** + * Raises [arg] to the integer power [exponent]. + */ + public override fun power(arg: R, exponent: UInt) : R = exponentiationBySquaring(arg, exponent) + + /** + * Check if the instant is zero rational function. + */ + public fun R.isZero(): Boolean = numerator equalsTo polynomialZero + /** + * Check if the instant is NOT zero rational function. + */ + public fun R.isNotZero(): Boolean = !isZero() + /** + * Check if the instant is unit rational function. + */ + public fun R.isOne(): Boolean = numerator equalsTo denominator + /** + * Check if the instant is NOT unit rational function. + */ + public fun R.isNotOne(): Boolean = !isOne() + /** + * Check if the instant is minus unit rational function. + */ + public fun R.isMinusOne(): Boolean = (numerator + denominator).isZero() + /** + * Check if the instant is NOT minus unit rational function. + */ + public fun R.isNotMinusOne(): Boolean = !isMinusOne() /** * Instance of zero rational function (zero of the rational functions ring). */ - public override val zero: RationalFunction = RationalFunction(polynomialZero, polynomialOne) + public override val zero: R /** * Instance of unit polynomial (unit of the rational functions ring). */ - public override val one: RationalFunction = RationalFunction(polynomialOne, polynomialOne) + public override val one: R - // TODO: Разобрать + /** + * Checks equality of the rational functions. + */ + public infix fun R.equalsTo(other: R): Boolean = + when { + this === other -> true + numerator.isZero() != other.numerator.isZero() -> false + numeratorDegree - denominatorDegree != with(other) { numeratorDegree - denominatorDegree } -> false + else -> numerator * other.denominator equalsTo other.numerator * denominator + } + /** + * Checks NOT equality of the polynomials. + */ + public infix fun R.notEqualsTo(other: R): Boolean = !(this equalsTo other) - public operator fun RationalFunction.div(other: RationalFunction): RationalFunction = - RationalFunction( - numerator * other.denominator, - denominator * other.numerator + /** + * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is + * zero, degree is -1. + */ + public val P.degree: Int + + /** + * Checks if the instant is constant polynomial (of degree no more than 0) over considered ring. + */ + public fun P.isConstant(): Boolean = degree <= 0 + /** + * Checks if the instant is **not** constant polynomial (of degree no more than 0) over considered ring. + */ + public fun P.isNotConstant(): Boolean = !isConstant() + /** + * Checks if the instant is constant non-zero polynomial (of degree no more than 0) over considered ring. + */ + public fun P.isNonZeroConstant(): Boolean = degree == 0 + /** + * Checks if the instant is **not** constant non-zero polynomial (of degree no more than 0) over considered ring. + */ + public fun P.isNotNonZeroConstant(): Boolean = !isNonZeroConstant() + /** + * If polynomial is a constant polynomial represents and returns it as constant. + * Otherwise, (when the polynomial is not constant polynomial) returns `null`. + */ + public fun P.asConstantOrNull(): C? + /** + * If polynomial is a constant polynomial represents and returns it as constant. + * Otherwise, (when the polynomial is not constant polynomial) raises corresponding exception. + */ + public fun P.asConstant(): C = requireNotNull(asConstantOrNull()) { "Can not represent non-constant polynomial as a constant" } + + /** + * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is + * zero, degree is -1. + */ + public val R.numeratorDegree: Int get() = numerator.degree + /** + * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is + * zero, degree is -1. + */ + public val R.denominatorDegree: Int get() = denominator.degree + + override fun add(left: R, right: R): R = left + right + override fun multiply(left: R, right: R): R = left * right +} + +/** + * Abstraction of field of rational functions of type [R] with respect to polynomials of type [P] and constants of type + * [C]. It also assumes that there is provided [ring] (of type [A]), that provides constant-wise operations. + * + * @param C the type of constants. Polynomials have them as coefficients in their terms. + * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. + * @param R the type of rational functions. + * @param A the type of algebraic structure (precisely, of ring) provided for constants. + */ // TODO: Add support of field +@Suppress("INAPPLICABLE_JVM_NAME") +public interface RationalFunctionalSpaceOverRing, R: RationalFunction, A: Ring> : RationalFunctionalSpace { + + public val ring: A + + /** + * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * + * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. + */ + public override operator fun C.plus(other: Int): C = ring { addMultipliedBySquaring(this@plus, one, other) } + /** + * Returns difference between the constant and the integer represented as constant (member of underlying ring). + * + * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. + */ + public override operator fun C.minus(other: Int): C = ring { addMultipliedBySquaring(this@minus, one, -other) } + /** + * Returns product of the constant and the integer represented as constant (member of underlying ring). + * + * The operation is equivalent to sum of [other] copies of [this]. + */ + public override operator fun C.times(other: Int): C = ring { multiplyBySquaring(this@times, other) } + + /** + * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * + * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. + */ + public override operator fun Int.plus(other: C): C = ring { addMultipliedBySquaring(other, one, this@plus) } + /** + * Returns difference between the integer represented as constant (member of underlying ring) and the constant. + * + * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. + */ + public override operator fun Int.minus(other: C): C = ring { addMultipliedBySquaring(-other, one, this@minus) } + /** + * Returns product of the integer represented as constant (member of underlying ring) and the constant. + * + * The operation is equivalent to sum of [this] copies of [other]. + */ + public override operator fun Int.times(other: C): C = ring { multiplyBySquaring(other, this@times) } + + /** + * Returns the same constant. + */ + @JvmName("constantUnaryPlus") + public override operator fun C.unaryPlus(): C = ring { +this@unaryPlus } + /** + * Returns negation of the constant. + */ + @JvmName("constantUnaryMinus") + public override operator fun C.unaryMinus(): C = ring { -this@unaryMinus } + /** + * Returns sum of the constants. + */ + @JvmName("constantPlus") + public override operator fun C.plus(other: C): C = ring { this@plus + other } + /** + * Returns difference of the constants. + */ + @JvmName("constantMinus") + public override operator fun C.minus(other: C): C = ring { this@minus - other } + /** + * Returns product of the constants. + */ + @JvmName("constantTimes") + public override operator fun C.times(other: C): C = ring { this@times * other } + /** + * Raises [arg] to the integer power [exponent]. + */ + @JvmName("constantPower") + public override fun power(arg: C, exponent: UInt) : C = ring { power(arg, exponent) } + + /** + * Instance of zero constant (zero of the underlying ring). + */ + public override val constantZero: C get() = ring.zero + /** + * Instance of unit constant (unit of the underlying ring). + */ + public override val constantOne: C get() = ring.one +} + +/** + * Abstraction of field of rational functions of type [R] with respect to polynomials of type [P] and constants of type + * [C]. It also assumes that there is provided [polynomialRing] (of type [AP]), that provides constant- and + * polynomial-wise operations. + * + * @param C the type of constants. Polynomials have them as coefficients in their terms. + * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. + * @param R the type of rational functions. + * @param AP the type of algebraic structure (precisely, of ring) provided for polynomials. + */ // TODO: Add support of field +@Suppress("INAPPLICABLE_JVM_NAME") +public interface RationalFunctionalSpaceOverPolynomialSpace< + C, + P: Polynomial, + R: RationalFunction, + AP: PolynomialSpace, + > : RationalFunctionalSpace { + + public val polynomialRing: AP + + /** + * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * + * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. + */ + public override operator fun C.plus(other: Int): C = polynomialRing { this@plus + other } + /** + * Returns difference between the constant and the integer represented as constant (member of underlying ring). + * + * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. + */ + public override operator fun C.minus(other: Int): C = polynomialRing { this@minus - other } + /** + * Returns product of the constant and the integer represented as constant (member of underlying ring). + * + * The operation is equivalent to sum of [other] copies of [this]. + */ + public override operator fun C.times(other: Int): C = polynomialRing { this@times * other } + + /** + * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * + * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. + */ + public override operator fun Int.plus(other: C): C = polynomialRing { this@plus + other } + /** + * Returns difference between the integer represented as constant (member of underlying ring) and the constant. + * + * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. + */ + public override operator fun Int.minus(other: C): C = polynomialRing { this@minus - other } + /** + * Returns product of the integer represented as constant (member of underlying ring) and the constant. + * + * The operation is equivalent to sum of [this] copies of [other]. + */ + public override operator fun Int.times(other: C): C = polynomialRing { this@times * other } + + /** + * Returns sum of the constant and the integer represented as polynomial. + * + * The operation is equivalent to adding [other] copies of unit polynomial to [this]. + */ + public override operator fun P.plus(other: Int): P = polynomialRing { this@plus + other } + /** + * Returns difference between the constant and the integer represented as polynomial. + * + * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. + */ + public override operator fun P.minus(other: Int): P = polynomialRing { this@minus - other } + /** + * Returns product of the constant and the integer represented as polynomial. + * + * The operation is equivalent to sum of [other] copies of [this]. + */ + public override operator fun P.times(other: Int): P = polynomialRing { this@times * other } + + /** + * Returns sum of the integer represented as polynomial and the constant. + * + * The operation is equivalent to adding [this] copies of unit polynomial to [other]. + */ + public override operator fun Int.plus(other: P): P = polynomialRing { this@plus + other } + /** + * Returns difference between the integer represented as polynomial and the constant. + * + * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. + */ + public override operator fun Int.minus(other: P): P = polynomialRing { this@minus - other } + /** + * Returns product of the integer represented as polynomial and the constant. + * + * The operation is equivalent to sum of [this] copies of [other]. + */ + public override operator fun Int.times(other: P): P = polynomialRing { this@times * other } + + /** + * Returns the same constant. + */ + @JvmName("constantUnaryPlus") + public override operator fun C.unaryPlus(): C = polynomialRing { +this@unaryPlus } + /** + * Returns negation of the constant. + */ + @JvmName("constantUnaryMinus") + public override operator fun C.unaryMinus(): C = polynomialRing { -this@unaryMinus } + /** + * Returns sum of the constants. + */ + @JvmName("constantPlus") + public override operator fun C.plus(other: C): C = polynomialRing { this@plus + other } + /** + * Returns difference of the constants. + */ + @JvmName("constantMinus") + public override operator fun C.minus(other: C): C = polynomialRing { this@minus - other } + /** + * Returns product of the constants. + */ + @JvmName("constantTimes") + public override operator fun C.times(other: C): C = polynomialRing { this@times * other } + /** + * Raises [arg] to the integer power [exponent]. + */ + @JvmName("constantPower") + public override fun power(arg: C, exponent: UInt) : C = polynomialRing { power(arg, exponent) } + + /** + * Check if the instant is zero constant. + */ + public override fun C.isZero(): Boolean = polynomialRing { this@isZero.isZero() } + /** + * Check if the instant is NOT zero constant. + */ + public override fun C.isNotZero(): Boolean = polynomialRing { this@isNotZero.isNotZero() } + /** + * Check if the instant is unit constant. + */ + public override fun C.isOne(): Boolean = polynomialRing { this@isOne.isOne() } + /** + * Check if the instant is NOT unit constant. + */ + public override fun C.isNotOne(): Boolean = polynomialRing { this@isNotOne.isNotOne() } + /** + * Check if the instant is minus unit constant. + */ + public override fun C.isMinusOne(): Boolean = polynomialRing { this@isMinusOne.isMinusOne() } + /** + * Check if the instant is NOT minus unit constant. + */ + public override fun C.isNotMinusOne(): Boolean = polynomialRing { this@isNotMinusOne.isNotMinusOne() } + + /** + * Instance of zero constant (zero of the underlying ring). + */ + public override val constantZero: C get() = polynomialRing.constantZero + /** + * Instance of unit constant (unit of the underlying ring). + */ + public override val constantOne: C get() = polynomialRing.constantOne + + /** + * Returns sum of the constant represented as polynomial and the polynomial. + */ + public override operator fun C.plus(other: P): P = polynomialRing { this@plus + other } + /** + * Returns difference between the constant represented as polynomial and the polynomial. + */ + public override operator fun C.minus(other: P): P = polynomialRing { this@minus - other } + /** + * Returns product of the constant represented as polynomial and the polynomial. + */ + public override operator fun C.times(other: P): P = polynomialRing { this@times * other } + + /** + * Returns sum of the constant represented as polynomial and the polynomial. + */ + public override operator fun P.plus(other: C): P = polynomialRing { this@plus + other } + /** + * Returns difference between the constant represented as polynomial and the polynomial. + */ + public override operator fun P.minus(other: C): P = polynomialRing { this@minus - other } + /** + * Returns product of the constant represented as polynomial and the polynomial. + */ + public override operator fun P.times(other: C): P = polynomialRing { this@times * other } + + /** + * Returns the same polynomial. + */ + public override operator fun P.unaryPlus(): P = polynomialRing { +this@unaryPlus } + /** + * Returns negation of the polynomial. + */ + public override operator fun P.unaryMinus(): P = polynomialRing { -this@unaryMinus } + /** + * Returns sum of the polynomials. + */ + public override operator fun P.plus(other: P): P = polynomialRing { this@plus + other } + /** + * Returns difference of the polynomials. + */ + public override operator fun P.minus(other: P): P = polynomialRing { this@minus - other } + /** + * Returns product of the polynomials. + */ + public override operator fun P.times(other: P): P = polynomialRing { this@times * other } + /** + * Raises [arg] to the integer power [exponent]. + */ + public override fun power(arg: P, exponent: UInt) : P = polynomialRing { power(arg, exponent) } + + /** + * Check if the instant is zero polynomial. + */ + public override fun P.isZero(): Boolean = polynomialRing { this@isZero.isZero() } + /** + * Check if the instant is NOT zero polynomial. + */ + public override fun P.isNotZero(): Boolean = polynomialRing { this@isNotZero.isNotZero() } + /** + * Check if the instant is unit polynomial. + */ + public override fun P.isOne(): Boolean = polynomialRing { this@isOne.isOne() } + /** + * Check if the instant is NOT unit polynomial. + */ + public override fun P.isNotOne(): Boolean = polynomialRing { this@isNotOne.isNotOne() } + /** + * Check if the instant is minus unit polynomial. + */ + public override fun P.isMinusOne(): Boolean = polynomialRing { this@isMinusOne.isMinusOne() } + /** + * Check if the instant is NOT minus unit polynomial. + */ + public override fun P.isNotMinusOne(): Boolean = polynomialRing { this@isNotMinusOne.isNotMinusOne() } + + /** + * Instance of zero polynomial (zero of the polynomial ring). + */ + public override val polynomialZero: P get() = polynomialRing.zero + /** + * Instance of unit polynomial (unit of the polynomial ring). + */ + public override val polynomialOne: P get() = polynomialRing.one + + /** + * Checks equality of the polynomials. + */ + public override infix fun P.equalsTo(other: P): Boolean = polynomialRing { this@equalsTo equalsTo other } + /** + * Checks NOT equality of the polynomials. + */ + public override infix fun P.notEqualsTo(other: P): Boolean = polynomialRing { this@notEqualsTo notEqualsTo other } + + /** + * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is + * zero, degree is -1. + */ + public override val P.degree: Int get() = polynomialRing { this@degree.degree } + + /** + * Checks if the instant is constant polynomial (of degree no more than 0) over considered ring. + */ + public override fun P.isConstant(): Boolean = polynomialRing { this@isConstant.isConstant() } + /** + * Checks if the instant is **not** constant polynomial (of degree no more than 0) over considered ring. + */ + public override fun P.isNotConstant(): Boolean = polynomialRing { this@isNotConstant.isNotConstant() } + /** + * Checks if the instant is constant non-zero polynomial (of degree no more than 0) over considered ring. + */ + public override fun P.isNonZeroConstant(): Boolean = polynomialRing { this@isNonZeroConstant.isNonZeroConstant() } + /** + * Checks if the instant is **not** constant non-zero polynomial (of degree no more than 0) over considered ring. + */ + public override fun P.isNotNonZeroConstant(): Boolean = polynomialRing { this@isNotNonZeroConstant.isNotNonZeroConstant() } + /** + * If polynomial is a constant polynomial represents and returns it as constant. + * Otherwise, (when the polynomial is not constant polynomial) returns `null`. + */ + public override fun P.asConstantOrNull(): C? = polynomialRing { this@asConstantOrNull.asConstantOrNull() } + /** + * If polynomial is a constant polynomial represents and returns it as constant. + * Otherwise, (when the polynomial is not constant polynomial) raises corresponding exception. + */ + public override fun P.asConstant(): C = polynomialRing { this@asConstant.asConstant() } +} + +/** + * Abstraction of field of rational functions of type [R] with respect to polynomials of type [P] and constants of type + * [C]. It also assumes that there is provided constructor + * + * @param C the type of constants. Polynomials have them as coefficients in their terms. + * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. + * @param R the type of rational functions. + * @param AP the type of algebraic structure (precisely, of ring) provided for polynomials. + */ // TODO: Add support of field +@Suppress("INAPPLICABLE_JVM_NAME") +public abstract class PolynomialSpaceOfFractions< + C, + P: Polynomial, + R: RationalFunction, + > : RationalFunctionalSpace { + protected abstract fun constructRationalFunction(numerator: P, denominator: P) : R + + /** + * Returns sum of the rational function and the integer represented as rational function. + * + * The operation is equivalent to adding [other] copies of unit polynomial to [this]. + */ + public override operator fun R.plus(other: Int): R = + constructRationalFunction( + numerator + denominator * other, + denominator + ) + /** + * Returns difference between the rational function and the integer represented as rational function. + * + * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. + */ + public override operator fun R.minus(other: Int): R = + constructRationalFunction( + numerator - denominator * other, + denominator + ) + /** + * Returns product of the rational function and the integer represented as rational function. + * + * The operation is equivalent to sum of [other] copies of [this]. + */ + public override operator fun R.times(other: Int): R = + constructRationalFunction( + numerator * other, + denominator ) - public operator fun RationalFunction.div(other: Polynomial): RationalFunction = - RationalFunction( - numerator, - denominator * other + /** + * Returns sum of the integer represented as rational function and the rational function. + * + * The operation is equivalent to adding [this] copies of unit polynomial to [other]. + */ + public override operator fun Int.plus(other: R): R = + constructRationalFunction( + other.denominator * this + other.numerator, + other.denominator + ) + /** + * Returns difference between the integer represented as rational function and the rational function. + * + * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. + */ + public override operator fun Int.minus(other: R): R = + constructRationalFunction( + other.denominator * this - other.numerator, + other.denominator + ) + /** + * Returns product of the integer represented as rational function and the rational function. + * + * The operation is equivalent to sum of [this] copies of [other]. + */ + public override operator fun Int.times(other: R): R = + constructRationalFunction( + this * other.numerator, + other.denominator ) - public operator fun RationalFunction.div(other: C): RationalFunction = - RationalFunction( - numerator, - denominator * other + /** + * Returns sum of the constant represented as rational function and the rational function. + */ + public override operator fun C.plus(other: R): R = + constructRationalFunction( + other.denominator * this + other.numerator, + other.denominator + ) + /** + * Returns difference between the constant represented as polynomial and the rational function. + */ + public override operator fun C.minus(other: R): R = + constructRationalFunction( + other.denominator * this - other.numerator, + other.denominator + ) + /** + * Returns product of the constant represented as polynomial and the rational function. + */ + public override operator fun C.times(other: R): R = + constructRationalFunction( + this * other.numerator, + other.denominator ) - public operator fun RationalFunction.div(other: Int): RationalFunction = - RationalFunction( - numerator, - denominator * other + /** + * Returns sum of the constant represented as rational function and the rational function. + */ + public override operator fun R.plus(other: C): R = + constructRationalFunction( + numerator + denominator * other, + denominator + ) + /** + * Returns difference between the constant represented as rational function and the rational function. + */ + public override operator fun R.minus(other: C): R = + constructRationalFunction( + numerator - denominator * other, + denominator + ) + /** + * Returns product of the constant represented as rational function and the rational function. + */ + public override operator fun R.times(other: C): R = + constructRationalFunction( + numerator * other, + denominator ) -// operator fun invoke(arg: UnivariatePolynomial): RationalFunction = -// RationalFunction( -// numerator(arg), -// denominator(arg) -// ) -// -// operator fun invoke(arg: RationalFunction): RationalFunction { -// val num = numerator invokeRFTakeNumerator arg -// val den = denominator invokeRFTakeNumerator arg -// val degreeDif = numeratorDegree - denominatorDegree -// return if (degreeDif > 0) -// RationalFunction( -// num, -// multiplyByPower(den, arg.denominator, degreeDif) -// ) -// else -// RationalFunction( -// multiplyByPower(num, arg.denominator, -degreeDif), -// den -// ) -// } -// -// override fun toString(): String = toString(UnivariatePolynomial.variableName) -// -// fun toString(withVariableName: String = UnivariatePolynomial.variableName): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toString(withVariableName) -// else -> "${numerator.toStringWithBrackets(withVariableName)}/${denominator.toStringWithBrackets(withVariableName)}" -// } -// -// fun toStringWithBrackets(withVariableName: String = UnivariatePolynomial.variableName): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toStringWithBrackets(withVariableName) -// else -> "(${numerator.toStringWithBrackets(withVariableName)}/${denominator.toStringWithBrackets(withVariableName)})" -// } -// -// fun toReversedString(withVariableName: String = UnivariatePolynomial.variableName): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedString(withVariableName) -// else -> "${numerator.toReversedStringWithBrackets(withVariableName)}/${denominator.toReversedStringWithBrackets(withVariableName)}" -// } -// -// fun toReversedStringWithBrackets(withVariableName: String = UnivariatePolynomial.variableName): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedStringWithBrackets(withVariableName) -// else -> "(${numerator.toReversedStringWithBrackets(withVariableName)}/${denominator.toReversedStringWithBrackets(withVariableName)})" -// } -// -// fun removeZeros() = -// RationalFunction( -// numerator.removeZeros(), -// denominator.removeZeros() -// ) + /** + * Returns sum of the polynomial represented as rational function and the rational function. + */ + public override operator fun P.plus(other: R): R = + constructRationalFunction( + other.denominator * this + other.numerator, + other.denominator + ) + /** + * Returns difference between the polynomial represented as polynomial and the rational function. + */ + public override operator fun P.minus(other: R): R = + constructRationalFunction( + other.denominator * this - other.numerator, + other.denominator + ) + /** + * Returns product of the polynomial represented as polynomial and the rational function. + */ + public override operator fun P.times(other: R): R = + constructRationalFunction( + this * other.numerator, + other.denominator + ) + + /** + * Returns sum of the polynomial represented as rational function and the rational function. + */ + public override operator fun R.plus(other: P): R = + constructRationalFunction( + numerator + denominator * other, + denominator + ) + /** + * Returns difference between the polynomial represented as rational function and the rational function. + */ + public override operator fun R.minus(other: P): R = + constructRationalFunction( + numerator - denominator * other, + denominator + ) + /** + * Returns product of the polynomial represented as rational function and the rational function. + */ + public override operator fun R.times(other: P): R = + constructRationalFunction( + numerator * other, + denominator + ) + + /** + * Returns negation of the rational function. + */ + public override operator fun R.unaryMinus(): R = constructRationalFunction(-numerator, denominator) + /** + * Returns sum of the rational functions. + */ + public override operator fun R.plus(other: R): R = + constructRationalFunction( + numerator * other.denominator + denominator * other.numerator, + denominator * other.denominator + ) + /** + * Returns difference of the rational functions. + */ + public override operator fun R.minus(other: R): R = + constructRationalFunction( + numerator * other.denominator - denominator * other.numerator, + denominator * other.denominator + ) + /** + * Returns product of the rational functions. + */ + public override operator fun R.times(other: R): R = + constructRationalFunction( + numerator * other.numerator, + denominator * other.denominator + ) + + /** + * Instance of zero rational function (zero of the rational functions ring). + */ + public override val zero: R get() = constructRationalFunction(polynomialZero, polynomialOne) + + /** + * Instance of unit polynomial (unit of the rational functions ring). + */ + public override val one: R get() = constructRationalFunction(polynomialOne, polynomialOne) } \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt index d79e8eda3..583160cf4 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt @@ -17,7 +17,7 @@ public fun > A.labeledRationalFunction(): LabeledRationalFunction LabeledRationalFunctionSpace(this) /** - * Creates a [RationalFunctionSpace]'s scope over a received ring. + * Creates a [LabeledRationalFunctionSpace]'s scope over a received ring. */ public inline fun , R> A.labeledRationalFunction(block: LabeledRationalFunctionSpace.() -> R): R { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listPolynomialUtil.kt similarity index 72% rename from kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt rename to kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listPolynomialUtil.kt index afaf27a52..df5ba593a 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listPolynomialUtil.kt @@ -22,31 +22,31 @@ import kotlin.math.pow // if (degree > -1) Polynomial(coefficients.subList(0, degree + 1)) else zero /** - * Creates a [PolynomialSpace] over a received ring. + * Creates a [ListPolynomialSpace] over a received ring. */ -public fun > A.polynomial(): PolynomialSpace = - PolynomialSpace(this) +public fun > A.listPolynomial(): ListPolynomialSpace = + ListPolynomialSpace(this) /** - * Creates a [PolynomialSpace]'s scope over a received ring. + * Creates a [ListPolynomialSpace]'s scope over a received ring. */ -public inline fun , R> A.polynomial(block: PolynomialSpace.() -> R): R { +public inline fun , R> A.listPolynomial(block: ListPolynomialSpace.() -> R): R { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return PolynomialSpace(this).block() + return ListPolynomialSpace(this).block() } /** - * Creates a [ScalablePolynomialSpace] over a received scalable ring. + * Creates a [ScalableListPolynomialSpace] over a received scalable ring. */ -public fun A.scalablePolynomial(): ScalablePolynomialSpace where A : Ring, A : ScaleOperations = - ScalablePolynomialSpace(this) +public fun A.scalableListPolynomial(): ScalableListPolynomialSpace where A : Ring, A : ScaleOperations = + ScalableListPolynomialSpace(this) /** - * Creates a [ScalablePolynomialSpace]'s scope over a received scalable ring. + * Creates a [ScalableListPolynomialSpace]'s scope over a received scalable ring. */ -public inline fun A.scalablePolynomial(block: ScalablePolynomialSpace.() -> R): R where A : Ring, A : ScaleOperations { +public inline fun A.scalableListPolynomial(block: ScalableListPolynomialSpace.() -> R): R where A : Ring, A : ScaleOperations { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return ScalablePolynomialSpace(this).block() + return ScalableListPolynomialSpace(this).block() } @Suppress("NOTHING_TO_INLINE") @@ -99,7 +99,7 @@ internal inline fun multiplyAddingTo( /** * Evaluates the value of the given double polynomial for given double argument. */ -public fun Polynomial.substitute(arg: Double): Double = +public fun ListPolynomial.substitute(arg: Double): Double = coefficients.reduceIndexedOrNull { index, acc, c -> acc + c * arg.pow(index) } ?: .0 @@ -109,7 +109,7 @@ public fun Polynomial.substitute(arg: Double): Double = * * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). */ -public fun Polynomial.substitute(ring: Ring, arg: C): C = ring { +public fun ListPolynomial.substitute(ring: Ring, arg: C): C = ring { if (coefficients.isEmpty()) return@ring zero var result: C = coefficients.last() for (j in coefficients.size - 2 downTo 0) { @@ -118,11 +118,11 @@ public fun Polynomial.substitute(ring: Ring, arg: C): C = ring { return result } -public fun Polynomial.substitute(ring: Ring, arg: Polynomial) : Polynomial = ring { - if (coefficients.isEmpty()) return Polynomial(emptyList()) +public fun ListPolynomial.substitute(ring: Ring, arg: ListPolynomial) : ListPolynomial = ring { + if (coefficients.isEmpty()) return ListPolynomial(emptyList()) val thisDegree = coefficients.indexOfLast { it != zero } - if (thisDegree == -1) return Polynomial(emptyList()) + if (thisDegree == -1) return ListPolynomial(emptyList()) val argDegree = arg.coefficients.indexOfLast { it != zero } if (argDegree == -1) return coefficients[0].asPolynomial() val constantZero = zero @@ -145,27 +145,27 @@ public fun Polynomial.substitute(ring: Ring, arg: Polynomial) : Pol } with(resultCoefs) { while (isNotEmpty() && elementAt(lastIndex) == constantZero) removeAt(lastIndex) } - return Polynomial(resultCoefs) + return ListPolynomial(resultCoefs) } /** * Represent the polynomial as a regular context-less function. */ -public fun > Polynomial.asFunction(ring: A): (C) -> C = { substitute(ring, it) } +public fun > ListPolynomial.asFunction(ring: A): (C) -> C = { substitute(ring, it) } /** * Represent the polynomial as a regular context-less function. */ -public fun > Polynomial.asPolynomialFunctionOver(ring: A): (Polynomial) -> Polynomial = { substitute(ring, it) } +public fun > ListPolynomial.asPolynomialFunctionOver(ring: A): (ListPolynomial) -> ListPolynomial = { substitute(ring, it) } /** * Returns algebraic derivative of received polynomial. */ @UnstableKMathAPI -public fun Polynomial.derivative( +public fun ListPolynomial.derivative( algebra: A, -): Polynomial where A : Ring, A : NumericAlgebra = algebra { - Polynomial( +): ListPolynomial where A : Ring, A : NumericAlgebra = algebra { + ListPolynomial( buildList(max(0, coefficients.size - 1)) { for (deg in 1 .. coefficients.lastIndex) add(number(deg) * coefficients[deg]) while (isNotEmpty() && elementAt(lastIndex) == algebra.zero) removeAt(lastIndex) @@ -177,12 +177,12 @@ public fun Polynomial.derivative( * Returns algebraic derivative of received polynomial. */ @UnstableKMathAPI -public fun Polynomial.nthDerivative( +public fun ListPolynomial.nthDerivative( algebra: A, order: Int, -): Polynomial where A : Ring, A : NumericAlgebra = algebra { +): ListPolynomial where A : Ring, A : NumericAlgebra = algebra { require(order >= 0) { "Order of derivative must be non-negative" } - Polynomial( + ListPolynomial( buildList(max(0, coefficients.size - order)) { for (deg in order.. coefficients.lastIndex) add((deg - order + 1 .. deg).fold(coefficients[deg]) { acc, d -> acc * number(d) }) @@ -195,10 +195,10 @@ public fun Polynomial.nthDerivative( * Returns algebraic antiderivative of received polynomial. */ @UnstableKMathAPI -public fun Polynomial.antiderivative( +public fun ListPolynomial.antiderivative( algebra: A, -): Polynomial where A : Field, A : NumericAlgebra = algebra { - Polynomial( +): ListPolynomial where A : Field, A : NumericAlgebra = algebra { + ListPolynomial( buildList(coefficients.size + 1) { add(zero) coefficients.mapIndexedTo(this) { index, t -> t / number(index + 1) } @@ -211,12 +211,12 @@ public fun Polynomial.antiderivative( * Returns algebraic antiderivative of received polynomial. */ @UnstableKMathAPI -public fun Polynomial.nthAntiderivative( +public fun ListPolynomial.nthAntiderivative( algebra: A, order: Int, -): Polynomial where A : Field, A : NumericAlgebra = algebra { +): ListPolynomial where A : Field, A : NumericAlgebra = algebra { require(order >= 0) { "Order of antiderivative must be non-negative" } - Polynomial( + ListPolynomial( buildList(coefficients.size + order) { repeat(order) { add(zero) } coefficients.mapIndexedTo(this) { index, c -> (1..order).fold(c) { acc, i -> acc / number(index + i) } } @@ -229,7 +229,7 @@ public fun Polynomial.nthAntiderivative( * Compute a definite integral of a given polynomial in a [range] */ @UnstableKMathAPI -public fun > Polynomial.integrate( +public fun > ListPolynomial.integrate( algebra: Field, range: ClosedRange, ): C = algebra { diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/rationalFunctionUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listRationalFunctionUtil.kt similarity index 88% rename from kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/rationalFunctionUtil.kt rename to kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listRationalFunctionUtil.kt index 8d2073834..151c7bb8d 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/rationalFunctionUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listRationalFunctionUtil.kt @@ -14,23 +14,23 @@ import kotlin.math.max /** - * Creates a [RationalFunctionSpace] over a received ring. + * Creates a [ListRationalFunctionSpace] over a received ring. */ -public fun > A.rationalFunction(): RationalFunctionSpace = - RationalFunctionSpace(this) +public fun > A.listRationalFunction(): ListRationalFunctionSpace = + ListRationalFunctionSpace(this) /** - * Creates a [RationalFunctionSpace]'s scope over a received ring. + * Creates a [ListRationalFunctionSpace]'s scope over a received ring. */ -public inline fun , R> A.rationalFunction(block: RationalFunctionSpace.() -> R): R { +public inline fun , R> A.listRationalFunction(block: ListRationalFunctionSpace.() -> R): R { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return RationalFunctionSpace(this).block() + return ListRationalFunctionSpace(this).block() } /** * Evaluates the value of the given double polynomial for given double argument. */ -public fun RationalFunction.substitute(arg: Double): Double = +public fun ListRationalFunction.substitute(arg: Double): Double = numerator.substitute(arg) / denominator.substitute(arg) /** @@ -38,7 +38,7 @@ public fun RationalFunction.substitute(arg: Double): Double = * * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). */ -public fun RationalFunction.substitute(ring: Field, arg: C): C = ring { +public fun ListRationalFunction.substitute(ring: Field, arg: C): C = ring { numerator.substitute(ring, arg) / denominator.substitute(ring, arg) } @@ -50,13 +50,13 @@ public fun RationalFunction.substitute(ring: Field, arg: C): C = ring * ``` * is returned. * - * Used in [Polynomial.substitute] and [RationalFunction.substitute] for performance optimisation. + * Used in [ListPolynomial.substitute] and [ListRationalFunction.substitute] for performance optimisation. */ // TODO: Дописать -internal fun Polynomial.substituteRationalFunctionTakeNumerator(ring: Ring, arg: RationalFunction): Polynomial = ring { - if (coefficients.isEmpty()) return Polynomial(emptyList()) +internal fun ListPolynomial.substituteRationalFunctionTakeNumerator(ring: Ring, arg: ListRationalFunction): ListPolynomial = ring { + if (coefficients.isEmpty()) return ListPolynomial(emptyList()) val thisDegree = coefficients.indexOfLast { it != zero } - if (thisDegree == -1) return Polynomial(emptyList()) + if (thisDegree == -1) return ListPolynomial(emptyList()) val thisDegreeLog2 = 31 - thisDegree.countLeadingZeroBits() val numeratorDegree = arg.numerator.coefficients.indexOfLast { it != zero } val denominatorDegree = arg.denominator.coefficients.indexOfLast { it != zero } @@ -189,7 +189,7 @@ internal fun Polynomial.substituteRationalFunctionTakeNumerator(ring: Rin return levelResultCoefs } - return Polynomial( + return ListPolynomial( processLevelEdged( level = thisDegreeLog2, start = 0, diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt index cc725f981..5cd0679ab 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt @@ -17,7 +17,7 @@ public fun > A.numberedRationalFunction(): NumberedRationalFuncti NumberedRationalFunctionSpace(this) /** - * Creates a [RationalFunctionSpace]'s scope over a received ring. + * Creates a [NumberedRationalFunctionSpace]'s scope over a received ring. */ public inline fun , R> A.numberedRationalFunction(block: NumberedRationalFunctionSpace.() -> R): R { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt index 34d7bcf41..b55f16cf2 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt @@ -7,7 +7,7 @@ package space.kscience.kmath.interpolation import space.kscience.kmath.data.XYColumnarData import space.kscience.kmath.functions.PiecewisePolynomial -import space.kscience.kmath.functions.Polynomial +import space.kscience.kmath.functions.ListPolynomial import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.Field import space.kscience.kmath.operations.invoke @@ -32,7 +32,7 @@ public class LinearInterpolator>(override val algebra: Field>( val x02 = x0 * x0 val x03 = x02 * x0 //Shift coefficients to represent absolute polynomial instead of one with an offset - val polynomial = Polynomial( + val polynomial = ListPolynomial( a - b * x0 + c * x02 - d * x03, b - 2 * c * x0 + 3 * d * x02, c - 3 * d * x0, diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt new file mode 100644 index 000000000..0d2c4b5fc --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt @@ -0,0 +1,705 @@ +/* + * 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.functions + +import space.kscience.kmath.test.misc.* +import kotlin.test.* + + +class ListPolynomialTest { + @Test + fun test_Polynomial_Int_plus() { + RationalField.listPolynomial { + assertEquals( + ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + -3, + "test 1" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + 2, + "test 2" + ) + assertEquals( + ListPolynomial(), + ListPolynomial(Rational(-2)) + 2, + "test 3" + ) + assertEquals( + ListPolynomial(), + ListPolynomial() + 0, + "test 4" + ) + assertEquals( + ListPolynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + 1, + "test 5" + ) + assertEquals( + ListPolynomial(Rational(-1)), + ListPolynomial(Rational(-2)) + 1, + "test 6" + ) + assertEquals( + ListPolynomial(Rational(2)), + ListPolynomial() + 2, + "test 7" + ) + } + } + @Test + fun test_Polynomial_Int_minus() { + RationalField.listPolynomial { + assertEquals( + ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - -3, + "test 1" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), + ListPolynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - 2, + "test 2" + ) + assertEquals( + ListPolynomial(), + ListPolynomial(Rational(2)) - 2, + "test 3" + ) + assertEquals( + ListPolynomial(), + ListPolynomial() - 0, + "test 4" + ) + assertEquals( + ListPolynomial(Rational(1), Rational(0), Rational(0), Rational(0)), + ListPolynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - 1, + "test 5" + ) + assertEquals( + ListPolynomial(Rational(1)), + ListPolynomial(Rational(2)) - 1, + "test 6" + ) + assertEquals( + ListPolynomial(Rational(-2)), + ListPolynomial() - 2, + "test 7" + ) + } + } + @Test + fun test_Polynomial_Int_times() { + IntModuloRing(35).listPolynomial { + assertEquals( + ListPolynomial(34, 2, 1, 20, 2), + ListPolynomial(22, 26, 13, 15, 26) * 27, + "test 1" + ) + assertEquals( + ListPolynomial(), + ListPolynomial(7, 0, 49, 21, 14) * 15, + "test 2" + ) + } + } + @Test + fun test_Int_Polynomial_plus() { + RationalField.listPolynomial { + assertEquals( + ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), + -3 + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)), + "test 1" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), + 2 + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), + "test 2" + ) + assertEquals( + ListPolynomial(), + 2 + ListPolynomial(Rational(-2)), + "test 3" + ) + assertEquals( + ListPolynomial(), + 0 + ListPolynomial(), + "test 4" + ) + assertEquals( + ListPolynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), + 1 + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), + "test 5" + ) + assertEquals( + ListPolynomial(Rational(-1)), + 1 + ListPolynomial(Rational(-2)), + "test 6" + ) + assertEquals( + ListPolynomial(Rational(2)), + 2 + ListPolynomial(), + "test 7" + ) + } + } + @Test + fun test_Int_Polynomial_minus() { + RationalField.listPolynomial { + assertEquals( + ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), + 3 - ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), + "test 1" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), + -2 - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), + "test 2" + ) + assertEquals( + ListPolynomial(), + -2 - ListPolynomial(Rational(-2)), + "test 3" + ) + assertEquals( + ListPolynomial(), + 0 - ListPolynomial(), + "test 4" + ) + assertEquals( + ListPolynomial(Rational(1), Rational(0), Rational(0), Rational(0)), + -1 - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), + "test 5" + ) + assertEquals( + ListPolynomial(Rational(1)), + -1 - ListPolynomial(Rational(-2)), + "test 6" + ) + assertEquals( + ListPolynomial(Rational(-2)), + -2 - ListPolynomial(), + "test 7" + ) + } + } + @Test + fun test_Int_Polynomial_times() { + IntModuloRing(35).listPolynomial { + assertEquals( + ListPolynomial(34, 2, 1, 20, 2), + 27 * ListPolynomial(22, 26, 13, 15, 26), + "test 1" + ) + assertEquals( + ListPolynomial(), + 15 * ListPolynomial(7, 0, 49, 21, 14), + "test 2" + ) + } + } + @Test + fun test_Polynomial_Constant_plus() { + RationalField.listPolynomial { + assertEquals( + ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + Rational(-3), + "test 1" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + Rational(2), + "test 2" + ) + assertEquals( + ListPolynomial(), + ListPolynomial(Rational(-2)) + Rational(2), + "test 3" + ) + assertEquals( + ListPolynomial(), + ListPolynomial() + Rational(0), + "test 4" + ) + assertEquals( + ListPolynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + Rational(1), + "test 5" + ) + assertEquals( + ListPolynomial(Rational(-1)), + ListPolynomial(Rational(-2)) + Rational(1), + "test 6" + ) + assertEquals( + ListPolynomial(Rational(2)), + ListPolynomial() + Rational(2), + "test 7" + ) + } + } + @Test + fun test_Polynomial_Constant_minus() { + RationalField.listPolynomial { + assertEquals( + ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - Rational(-3), + "test 1" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), + ListPolynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - Rational(2), + "test 2" + ) + assertEquals( + ListPolynomial(), + ListPolynomial(Rational(2)) - Rational(2), + "test 3" + ) + assertEquals( + ListPolynomial(), + ListPolynomial() - Rational(0), + "test 4" + ) + assertEquals( + ListPolynomial(Rational(1), Rational(0), Rational(0), Rational(0)), + ListPolynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - Rational(1), + "test 5" + ) + assertEquals( + ListPolynomial(Rational(1)), + ListPolynomial(Rational(2)) - Rational(1), + "test 6" + ) + assertEquals( + ListPolynomial(Rational(-2)), + ListPolynomial() - Rational(2), + "test 7" + ) + } + } + @Test + fun test_Polynomial_Constant_times() { + IntModuloRing(35).listPolynomial { + assertEquals( + ListPolynomial(34, 2, 1, 20, 2), + ListPolynomial(22, 26, 13, 15, 26) * number(27), + "test 1" + ) + assertEquals( + ListPolynomial(), + ListPolynomial(7, 0, 49, 21, 14) * number(15), + "test 2" + ) + } + } + @Test + fun test_Constant_Polynomial_plus() { + RationalField.listPolynomial { + assertEquals( + ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), + Rational(-3) + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)), + "test 1" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), + Rational(2) + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), + "test 2" + ) + assertEquals( + ListPolynomial(), + Rational(2) + ListPolynomial(Rational(-2)), + "test 3" + ) + assertEquals( + ListPolynomial(), + Rational(0) + ListPolynomial(), + "test 4" + ) + assertEquals( + ListPolynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), + Rational(1) + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), + "test 5" + ) + assertEquals( + ListPolynomial(Rational(-1)), + Rational(1) + ListPolynomial(Rational(-2)), + "test 6" + ) + assertEquals( + ListPolynomial(Rational(2)), + Rational(2) + ListPolynomial(), + "test 7" + ) + } + } + @Test + fun test_Constant_Polynomial_minus() { + RationalField.listPolynomial { + assertEquals( + ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), + Rational(3) - ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), + "test 1" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), + Rational(-2) - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), + "test 2" + ) + assertEquals( + ListPolynomial(), + Rational(-2) - ListPolynomial(Rational(-2)), + "test 3" + ) + assertEquals( + ListPolynomial(), + Rational(0) - ListPolynomial(), + "test 4" + ) + assertEquals( + ListPolynomial(Rational(1), Rational(0), Rational(0), Rational(0)), + Rational(-1) - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), + "test 5" + ) + assertEquals( + ListPolynomial(Rational(1)), + Rational(-1) - ListPolynomial(Rational(-2)), + "test 6" + ) + assertEquals( + ListPolynomial(Rational(-2)), + Rational(-2) - ListPolynomial(), + "test 7" + ) + } + } + @Test + fun test_Constant_Polynomial_times() { + IntModuloRing(35).listPolynomial { + assertEquals( + ListPolynomial(34, 2, 1, 20, 2), + 27 * ListPolynomial(22, 26, 13, 15, 26), + "test 1" + ) + assertEquals( + ListPolynomial(), + 15 * ListPolynomial(7, 0, 49, 21, 14), + "test 2" + ) + } + } + @Test + fun test_Polynomial_unaryMinus() { + RationalField.listPolynomial { + assertEquals( + ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), + -ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)), + "test 1" + ) + assertEquals( + ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7), Rational(0), Rational(0)), + -ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7), Rational(0), Rational(0)), + "test 2" + ) + } + } + @Test + fun test_Polynomial_Polynomial_plus() { + RationalField.listPolynomial { + // (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( + ListPolynomial(Rational(-10, 63), Rational(37, 9), Rational(-29, 56)), + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + + ListPolynomial(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( + ListPolynomial(Rational(-2, 9), Rational(-5, 12), Rational(2, 4)), + ListPolynomial(Rational(-2, 9), Rational(-8, 3)) + + ListPolynomial(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( + ListPolynomial(Rational(-18, 7), Rational(-23, 6), Rational(2, 3)), + ListPolynomial(Rational(-4, 7), Rational(-2, 6), Rational(0), Rational(0)) + + ListPolynomial(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( + ListPolynomial(), + ListPolynomial(Rational(-2, 4), Rational(-6, 9), Rational(-4, 9)) + + ListPolynomial(Rational(2, 4), Rational(6, 9), Rational(4, 9)), + "test 4" + ) + } + } + @Test + fun test_Polynomial_Polynomial_minus() { + RationalField.listPolynomial { + // (5/9 - 8/9 x - 8/7 x^2) - (-5/7 + 5/1 x + 5/8 x^2) ?= 80/63 - 53/9 x - 99/56 x^2 + assertEquals( + ListPolynomial(Rational(80, 63), Rational(-53, 9), Rational(-99, 56)), + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - + ListPolynomial(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 - 59/12 x - 2/4 x^2 + assertEquals( + ListPolynomial(Rational(-2, 9), Rational(-59, 12), Rational(-2, 4)), + ListPolynomial(Rational(-2, 9), Rational(-8, 3)) - + ListPolynomial(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) ?= 10/7 + 19/6 x - 2/3 x^2 + assertEquals( + ListPolynomial(Rational(10, 7), Rational(19, 6), Rational(-2, 3)), + ListPolynomial(Rational(-4, 7), Rational(-2, 6), Rational(0), Rational(0)) - + ListPolynomial(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( + ListPolynomial(), + ListPolynomial(Rational(-2, 4), Rational(-6, 9), Rational(-4, 9)) - + ListPolynomial(Rational(-2, 4), Rational(-6, 9), Rational(-4, 9)), + "test 4" + ) + } + } + @Test + fun test_Polynomial_Polynomial_times() { + IntModuloRing(35).listPolynomial { + // (1 + x + x^2) * (1 - x + x^2) ?= 1 + x^2 + x^4 + assertEquals( + ListPolynomial(1, 0, 1, 0, 1), + ListPolynomial(1, -1, 1) * ListPolynomial(1, 1, 1), + "test 1" + ) + // Spoiler: 5 * 7 = 0 + assertEquals( + ListPolynomial(), + ListPolynomial(5, -25, 10) * ListPolynomial(21, 14, -7), + "test 2" + ) + } + } + @Test + fun test_Polynomial_isZero() { + RationalField.listPolynomial { + assertTrue("test 1") { ListPolynomial().isZero() } + assertTrue("test 2") { ListPolynomial(Rational(0)).isZero() } + assertTrue("test 3") { ListPolynomial(Rational(0), Rational(0)).isZero() } + assertTrue("test 4") { ListPolynomial(Rational(0), Rational(0), Rational(0)) + .isZero() } + assertFalse("test 5") { ListPolynomial(Rational(3, 5)).isZero() } + assertFalse("test 6") { ListPolynomial(Rational(3, 5), Rational(0)) + .isZero() } + assertFalse("test 7") { ListPolynomial(Rational(0), Rational(3, 5), Rational(0)) + .isZero() } + } + } + @Test + fun test_Polynomial_isOne() { + RationalField.listPolynomial { + assertFalse("test 1") { ListPolynomial().isOne() } + assertFalse("test 2") { ListPolynomial(Rational(0)).isOne() } + assertFalse("test 3") { ListPolynomial(Rational(0), Rational(0)).isOne() } + assertFalse("test 4") { ListPolynomial(Rational(0), Rational(0), Rational(0)) + .isOne() } + assertFalse("test 5") { ListPolynomial(Rational(3, 5)).isOne() } + assertTrue("test 6") { ListPolynomial(Rational(5, 5)).isOne() } + assertFalse("test 7") { ListPolynomial(Rational(3, 5), Rational(0)).isOne() } + assertTrue("test 8") { ListPolynomial(Rational(3, 3), Rational(0)).isOne() } + assertFalse("test 9") { ListPolynomial(Rational(0), Rational(3, 5), Rational(0)) + .isOne() } + assertFalse("test 10") { ListPolynomial(Rational(0), Rational(5, 5), Rational(0)) + .isOne() } + assertFalse("test 11") { ListPolynomial(Rational(1), Rational(3, 5), Rational(0)) + .isOne() } + assertFalse("test 12") { ListPolynomial(Rational(1), Rational(5, 5), Rational(0)) + .isOne() } + } + } + @Test + fun test_Polynomial_isMinusOne() { + RationalField.listPolynomial { + assertFalse("test 1") { ListPolynomial().isMinusOne() } + assertFalse("test 2") { ListPolynomial(Rational(0)).isMinusOne() } + assertFalse("test 3") { ListPolynomial(Rational(0), Rational(0)).isMinusOne() } + assertFalse("test 4") { ListPolynomial(Rational(0), Rational(0), Rational(0)) + .isMinusOne() } + assertFalse("test 5") { ListPolynomial(Rational(3, 5)).isMinusOne() } + assertTrue("test 6") { ListPolynomial(Rational(-5, 5)).isMinusOne() } + assertFalse("test 7") { ListPolynomial(Rational(3, 5), Rational(0)).isMinusOne() } + assertTrue("test 8") { ListPolynomial(Rational(-3, 3), Rational(0)).isMinusOne() } + assertFalse("test 9") { ListPolynomial(Rational(0), Rational(3, 5), Rational(0)) + .isMinusOne() } + assertFalse("test 10") { ListPolynomial(Rational(0), Rational(5, -5), Rational(0)) + .isMinusOne() } + assertFalse("test 11") { ListPolynomial(Rational(-1), Rational(3, 5), Rational(0)) + .isMinusOne() } + assertFalse("test 12") { ListPolynomial(Rational(-1), Rational(5, -5), Rational(0)) + .isMinusOne() } + } + } + @Test + fun test_Polynomial_Polynomial_equalsTo() { + RationalField.listPolynomial { + assertTrue("test 1") { + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) equalsTo + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + } + assertTrue("test 2") { + ListPolynomial(Rational(5, 9), Rational(0), Rational(-8, 7)) equalsTo + ListPolynomial(Rational(5, 9), Rational(0), Rational(-8, 7)) + } + assertTrue("test 3") { + ListPolynomial(Rational(0), Rational(0), Rational(-8, 7), Rational(0), Rational(0)) equalsTo + ListPolynomial(Rational(0), Rational(0), Rational(-8, 7)) + } + assertFalse("test 4") { + ListPolynomial(Rational(5, 9), Rational(5, 7), Rational(-8, 7)) equalsTo + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + } + assertFalse("test 5") { + ListPolynomial(Rational(8, 3), Rational(0), Rational(-8, 7)) equalsTo + ListPolynomial(Rational(5, 9), Rational(0), Rational(-8, 7)) + } + assertFalse("test 6") { + ListPolynomial(Rational(0), Rational(0), Rational(-8, 7), Rational(0), Rational(0)) equalsTo + ListPolynomial(Rational(0), Rational(0), Rational(8, 7)) + } + } + } + @Test + fun test_Polynomial_degree() { + RationalField.listPolynomial { + assertEquals( + 2, + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)).degree, + "test 1" + ) + assertEquals( + -1, + ListPolynomial().degree, + "test 2" + ) + assertEquals( + -1, + ListPolynomial(Rational(0)).degree, + "test 3" + ) + assertEquals( + -1, + ListPolynomial(Rational(0), Rational(0)).degree, + "test 4" + ) + assertEquals( + -1, + ListPolynomial(Rational(0), Rational(0), Rational(0)).degree, + "test 5" + ) + assertEquals( + 0, + ListPolynomial(Rational(5, 9)).degree, + "test 6" + ) + assertEquals( + 0, + ListPolynomial(Rational(5, 9), Rational(0)).degree, + "test 7" + ) + assertEquals( + 0, + ListPolynomial(Rational(5, 9), Rational(0), Rational(0)).degree, + "test 8" + ) + assertEquals( + 2, + ListPolynomial(Rational(0), Rational(0), Rational(-8, 7)).degree, + "test 9" + ) + assertEquals( + 2, + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7), Rational(0), Rational(0)).degree, + "test 10" + ) + assertEquals( + 2, + ListPolynomial(Rational(0), Rational(0), Rational(-8, 7), Rational(0), Rational(0)).degree, + "test 11" + ) + } + } + @Test + fun test_Polynomial_asConstantOrNull() { + RationalField.listPolynomial { + assertEquals( + Rational(0), + ListPolynomial().asConstantOrNull(), + "test 1" + ) + assertEquals( + Rational(0), + ListPolynomial(Rational(0)).asConstantOrNull(), + "test 2" + ) + assertEquals( + Rational(0), + ListPolynomial(Rational(0), Rational(0)).asConstantOrNull(), + "test 3" + ) + assertEquals( + Rational(0), + ListPolynomial(Rational(0), Rational(0), Rational(0)).asConstantOrNull(), + "test 4" + ) + assertEquals( + Rational(-7, 9), + ListPolynomial(Rational(-7, 9)).asConstantOrNull(), + "test 5" + ) + assertEquals( + Rational(-7, 9), + ListPolynomial(Rational(-7, 9), Rational(0)).asConstantOrNull(), + "test 6" + ) + assertEquals( + Rational(-7, 9), + ListPolynomial(Rational(-7, 9), Rational(0), Rational(0)).asConstantOrNull(), + "test 7" + ) + assertEquals( + null, + ListPolynomial(Rational(0), Rational(-7, 9)).asConstantOrNull(), + "test 8" + ) + assertEquals( + null, + ListPolynomial(Rational(0), Rational(-7, 9), Rational(0)).asConstantOrNull(), + "test 9" + ) + assertEquals( + null, + ListPolynomial(Rational(0), Rational(0), Rational(-7, 9)).asConstantOrNull(), + "test 10" + ) + assertEquals( + null, + ListPolynomial(Rational(4, 15), Rational(0), Rational(-7, 9)).asConstantOrNull(), + "test 11" + ) + assertEquals( + null, + ListPolynomial(Rational(4, 15), Rational(0), Rational(-7, 9), Rational(0)) + .asConstantOrNull(), + "test 12" + ) + } + } +} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt new file mode 100644 index 000000000..bec46c034 --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt @@ -0,0 +1,229 @@ +/* + * 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.functions + +import space.kscience.kmath.test.misc.Rational +import space.kscience.kmath.test.misc.RationalField +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertFailsWith + + +class ListPolynomialUtilTest { + @Test + fun test_substitute_Double() { + val polynomial = ListPolynomial(1.0, -2.0, 1.0) + assertEquals(0.0, polynomial.substitute(1.0), 0.001) + } + @Test + fun test_substitute_Constant() { + assertEquals( + Rational(0), + ListPolynomial(Rational(1), Rational(-2), Rational(1)).substitute(RationalField, Rational(1)), + "test 1" + ) + assertEquals( + Rational(25057, 21000), + ListPolynomial(Rational(5,8), Rational(8, 3), Rational(4, 7), Rational(3, 2)) + .substitute(RationalField, Rational(1, 5)), + "test 2" + ) + assertEquals( + Rational(2983, 5250), + ListPolynomial(Rational(0), Rational(8, 3), Rational(4, 7), Rational(3, 2)) + .substitute(RationalField, Rational(1, 5)), + "test 3" + ) + assertEquals( + Rational(4961, 4200), + ListPolynomial(Rational(5,8), Rational(8, 3), Rational(4, 7), Rational(0)) + .substitute(RationalField, Rational(1, 5)), + "test 4" + ) + assertEquals( + Rational(3511, 3000), + ListPolynomial(Rational(5,8), Rational(8, 3), Rational(0), Rational(3, 2)) + .substitute(RationalField, Rational(1, 5)), + "test 5" + ) + } + @Test + fun test_substitute_Polynomial() { + assertEquals( + ListPolynomial(), + ListPolynomial(Rational(1), Rational(-2), Rational(1)).substitute(RationalField, ListPolynomial(Rational(1))), + "test 1" + ) + assertEquals( + ListPolynomial(Rational(709, 378), Rational(155, 252), Rational(19, 525), Rational(2, 875)), + ListPolynomial(Rational(1, 7), Rational(9, 4), Rational(1, 3), Rational(2, 7)) + .substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(1, 5))), + "test 2" + ) + assertEquals( + ListPolynomial(Rational(655, 378), Rational(155, 252), Rational(19, 525), Rational(2, 875)), + ListPolynomial(Rational(0), Rational(9, 4), Rational(1, 3), Rational(2, 7)) + .substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(1, 5))), + "test 3" + ) + assertEquals( + ListPolynomial(Rational(677, 378), Rational(97, 180), Rational(1, 75)), + ListPolynomial(Rational(1, 7), Rational(9, 4), Rational(1, 3), Rational(0)) + .substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(1, 5))), + "test 4" + ) + assertEquals( + ListPolynomial(Rational(653, 378), Rational(221, 420), Rational(4, 175), Rational(2, 875)), + ListPolynomial(Rational(1, 7), Rational(9, 4), Rational(0), Rational(2, 7)) + .substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(1, 5))), + "test 5" + ) + assertEquals( + ListPolynomial(Rational(89, 54)), + ListPolynomial(Rational(0), Rational(9, 4), Rational(1, 3), Rational(0)) + .substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(0))), + "test 6" + ) + } + @Test + fun test_derivative() { + assertEquals( + ListPolynomial(Rational(-2), Rational(2)), + ListPolynomial(Rational(1), Rational(-2), Rational(1)).derivative(RationalField), + "test 1" + ) + assertEquals( + ListPolynomial(Rational(-8, 3), Rational(8, 9), Rational(15, 7), Rational(-20, 9)), + ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).derivative(RationalField), + "test 2" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(8, 9), Rational(15, 7), Rational(-20, 9)), + ListPolynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).derivative(RationalField), + "test 3" + ) + assertEquals( + ListPolynomial(Rational(-8, 3), Rational(8, 9), Rational(15, 7)), + ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).derivative(RationalField), + "test 4" + ) + } + @Test + fun test_nthDerivative() { + assertEquals( + ListPolynomial(Rational(-2), Rational(2)), + ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 1), + "test 1" + ) + assertFailsWith("test2") { + ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, -1) + } + assertEquals( + ListPolynomial(Rational(1), Rational(-2), Rational(1)), + ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 0), + "test 3" + ) + assertEquals( + ListPolynomial(Rational(2)), + ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 2), + "test 4" + ) + assertEquals( + ListPolynomial(), + ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 3), + "test 5" + ) + assertEquals( + ListPolynomial(), + ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 4), + "test 6" + ) + assertEquals( + ListPolynomial(Rational(8, 9), Rational(30, 7), Rational(-20, 3)), + ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthDerivative(RationalField, 2), + "test 7" + ) + assertEquals( + ListPolynomial(Rational(8, 9), Rational(30, 7), Rational(-20, 3)), + ListPolynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthDerivative(RationalField, 2), + "test 8" + ) + assertEquals( + ListPolynomial(Rational(8, 9), Rational(30, 7)), + ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).nthDerivative(RationalField, 2), + "test 9" + ) + } + @Test + fun test_antiderivative() { + assertEquals( + ListPolynomial(Rational(0), Rational(1), Rational(-1), Rational(1, 3)), + ListPolynomial(Rational(1), Rational(-2), Rational(1)).antiderivative(RationalField), + "test 1" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(1, 5), Rational(-4, 3), Rational(4, 27), Rational(5, 28), Rational(-1, 9)), + ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).antiderivative(RationalField), + "test 2" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(4, 27), Rational(5, 28), Rational(-1, 9)), + ListPolynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).antiderivative(RationalField), + "test 3" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(1, 5), Rational(-4, 3), Rational(4, 27), Rational(5, 28)), + ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).antiderivative(RationalField), + "test 4" + ) + } + @Test + fun test_nthAntiderivative() { + assertEquals( + ListPolynomial(Rational(0), Rational(1), Rational(-1), Rational(1, 3)), + ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 1), + "test 1" + ) + assertFailsWith("test2") { + ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, -1) + } + assertEquals( + ListPolynomial(Rational(1), Rational(-2), Rational(1)), + ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 0), + "test 3" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(1, 2), Rational(-1, 3), Rational(1, 12)), + ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 2), + "test 4" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(1, 6), Rational(-1, 12), Rational(1, 60)), + ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 3), + "test 5" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0), Rational(1, 24), Rational(-1, 60), Rational(1, 360)), + ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 4), + "test 6" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(1, 10), Rational(-4, 9), Rational(1, 27), Rational(1, 28), Rational(-1, 54)), + ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthAntiderivative(RationalField, 2), + "test 7" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0), Rational(1, 27), Rational(1, 28), Rational(-1, 54)), + ListPolynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthAntiderivative(RationalField, 2), + "test 8" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(1, 10), Rational(-4, 9), Rational(1, 27), Rational(1, 28)), + ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).nthAntiderivative(RationalField, 2), + "test 9" + ) + } +} \ No newline at end of file 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 deleted file mode 100644 index 141bdd436..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt +++ /dev/null @@ -1,691 +0,0 @@ -/* - * 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.functions - -import space.kscience.kmath.test.misc.* -import kotlin.test.* - - -class PolynomialTest { - @Test - fun test_Polynomial_Int_plus() { - RationalField.polynomial { - assertEquals( - Polynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), - Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + -3, - "test 1" - ) - assertEquals( - Polynomial(Rational(0), Rational(0), Rational(0), Rational(0)), - Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + 2, - "test 2" - ) - assertEquals( - Polynomial(), - Polynomial(Rational(-2)) + 2, - "test 3" - ) - assertEquals( - Polynomial(), - Polynomial() + 0, - "test 4" - ) - assertEquals( - Polynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), - Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + 1, - "test 5" - ) - assertEquals( - Polynomial(Rational(-1)), - Polynomial(Rational(-2)) + 1, - "test 6" - ) - assertEquals( - Polynomial(Rational(2)), - Polynomial() + 2, - "test 7" - ) - } - } - @Test - fun test_Polynomial_Int_minus() { - RationalField.polynomial { - assertEquals( - Polynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), - Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - -3, - "test 1" - ) - assertEquals( - Polynomial(Rational(0), Rational(0), Rational(0), Rational(0)), - Polynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - 2, - "test 2" - ) - assertEquals( - Polynomial(), - Polynomial(Rational(2)) - 2, - "test 3" - ) - assertEquals( - Polynomial(), - Polynomial() - 0, - "test 4" - ) - assertEquals( - Polynomial(Rational(1), Rational(0), Rational(0), Rational(0)), - Polynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - 1, - "test 5" - ) - assertEquals( - Polynomial(Rational(1)), - Polynomial(Rational(2)) - 1, - "test 6" - ) - assertEquals( - Polynomial(Rational(-2)), - Polynomial() - 2, - "test 7" - ) - } - } - @Test - fun test_Polynomial_Int_times() { - IntModuloRing(35).polynomial { - assertEquals( - Polynomial(34, 2, 1, 20, 2), - Polynomial(22, 26, 13, 15, 26) * 27, - "test 1" - ) - assertEquals( - Polynomial(), - Polynomial(7, 0, 49, 21, 14) * 15, - "test 2" - ) - } - } - @Test - fun test_Int_Polynomial_plus() { - RationalField.polynomial { - assertEquals( - Polynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), - -3 + Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)), - "test 1" - ) - assertEquals( - Polynomial(Rational(0), Rational(0), Rational(0), Rational(0)), - 2 + Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 2" - ) - assertEquals( - Polynomial(), - 2 + Polynomial(Rational(-2)), - "test 3" - ) - assertEquals( - Polynomial(), - 0 + Polynomial(), - "test 4" - ) - assertEquals( - Polynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), - 1 + Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 5" - ) - assertEquals( - Polynomial(Rational(-1)), - 1 + Polynomial(Rational(-2)), - "test 6" - ) - assertEquals( - Polynomial(Rational(2)), - 2 + Polynomial(), - "test 7" - ) - } - } - @Test - fun test_Int_Polynomial_minus() { - RationalField.polynomial { - assertEquals( - Polynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), - 3 - Polynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), - "test 1" - ) - assertEquals( - Polynomial(Rational(0), Rational(0), Rational(0), Rational(0)), - -2 - Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 2" - ) - assertEquals( - Polynomial(), - -2 - Polynomial(Rational(-2)), - "test 3" - ) - assertEquals( - Polynomial(), - 0 - Polynomial(), - "test 4" - ) - assertEquals( - Polynomial(Rational(1), Rational(0), Rational(0), Rational(0)), - -1 - Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 5" - ) - assertEquals( - Polynomial(Rational(1)), - -1 - Polynomial(Rational(-2)), - "test 6" - ) - assertEquals( - Polynomial(Rational(-2)), - -2 - Polynomial(), - "test 7" - ) - } - } - @Test - fun test_Int_Polynomial_times() { - IntModuloRing(35).polynomial { - assertEquals( - Polynomial(34, 2, 1, 20, 2), - 27 * Polynomial(22, 26, 13, 15, 26), - "test 1" - ) - assertEquals( - Polynomial(), - 15 * Polynomial(7, 0, 49, 21, 14), - "test 2" - ) - } - } - @Test - fun test_Polynomial_Constant_plus() { - RationalField.polynomial { - assertEquals( - Polynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), - Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + Rational(-3), - "test 1" - ) - assertEquals( - Polynomial(Rational(0), Rational(0), Rational(0), Rational(0)), - Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + Rational(2), - "test 2" - ) - assertEquals( - Polynomial(), - Polynomial(Rational(-2)) + Rational(2), - "test 3" - ) - assertEquals( - Polynomial(), - Polynomial() + Rational(0), - "test 4" - ) - assertEquals( - Polynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), - Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + Rational(1), - "test 5" - ) - assertEquals( - Polynomial(Rational(-1)), - Polynomial(Rational(-2)) + Rational(1), - "test 6" - ) - assertEquals( - Polynomial(Rational(2)), - Polynomial() + Rational(2), - "test 7" - ) - } - } - @Test - fun test_Polynomial_Constant_minus() { - RationalField.polynomial { - assertEquals( - Polynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), - Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - Rational(-3), - "test 1" - ) - assertEquals( - Polynomial(Rational(0), Rational(0), Rational(0), Rational(0)), - Polynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - Rational(2), - "test 2" - ) - assertEquals( - Polynomial(), - Polynomial(Rational(2)) - Rational(2), - "test 3" - ) - assertEquals( - Polynomial(), - Polynomial() - Rational(0), - "test 4" - ) - assertEquals( - Polynomial(Rational(1), Rational(0), Rational(0), Rational(0)), - Polynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - Rational(1), - "test 5" - ) - assertEquals( - Polynomial(Rational(1)), - Polynomial(Rational(2)) - Rational(1), - "test 6" - ) - assertEquals( - Polynomial(Rational(-2)), - Polynomial() - Rational(2), - "test 7" - ) - } - } - @Test - fun test_Polynomial_Constant_times() { - IntModuloRing(35).polynomial { - assertEquals( - Polynomial(34, 2, 1, 20, 2), - Polynomial(22, 26, 13, 15, 26) * number(27), - "test 1" - ) - assertEquals( - Polynomial(), - Polynomial(7, 0, 49, 21, 14) * number(15), - "test 2" - ) - } - } - @Test - fun test_Constant_Polynomial_plus() { - RationalField.polynomial { - assertEquals( - Polynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), - Rational(-3) + Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)), - "test 1" - ) - assertEquals( - Polynomial(Rational(0), Rational(0), Rational(0), Rational(0)), - Rational(2) + Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 2" - ) - assertEquals( - Polynomial(), - Rational(2) + Polynomial(Rational(-2)), - "test 3" - ) - assertEquals( - Polynomial(), - Rational(0) + Polynomial(), - "test 4" - ) - assertEquals( - Polynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), - Rational(1) + Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 5" - ) - assertEquals( - Polynomial(Rational(-1)), - Rational(1) + Polynomial(Rational(-2)), - "test 6" - ) - assertEquals( - Polynomial(Rational(2)), - Rational(2) + Polynomial(), - "test 7" - ) - } - } - @Test - fun test_Constant_Polynomial_minus() { - RationalField.polynomial { - assertEquals( - Polynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), - Rational(3) - Polynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), - "test 1" - ) - assertEquals( - Polynomial(Rational(0), Rational(0), Rational(0), Rational(0)), - Rational(-2) - Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 2" - ) - assertEquals( - Polynomial(), - Rational(-2) - Polynomial(Rational(-2)), - "test 3" - ) - assertEquals( - Polynomial(), - Rational(0) - Polynomial(), - "test 4" - ) - assertEquals( - Polynomial(Rational(1), Rational(0), Rational(0), Rational(0)), - Rational(-1) - Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 5" - ) - assertEquals( - Polynomial(Rational(1)), - Rational(-1) - Polynomial(Rational(-2)), - "test 6" - ) - assertEquals( - Polynomial(Rational(-2)), - Rational(-2) - Polynomial(), - "test 7" - ) - } - } - @Test - fun test_Constant_Polynomial_times() { - IntModuloRing(35).polynomial { - assertEquals( - Polynomial(34, 2, 1, 20, 2), - 27 * Polynomial(22, 26, 13, 15, 26), - "test 1" - ) - assertEquals( - Polynomial(), - 15 * Polynomial(7, 0, 49, 21, 14), - "test 2" - ) - } - } - @Test - fun test_Polynomial_unaryMinus() { - RationalField.polynomial { - assertEquals( - Polynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), - -Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)), - "test 1" - ) - assertEquals( - Polynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7), Rational(0), Rational(0)), - -Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7), Rational(0), Rational(0)), - "test 2" - ) - } - } - @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 { - // (5/9 - 8/9 x - 8/7 x^2) - (-5/7 + 5/1 x + 5/8 x^2) ?= 80/63 - 53/9 x - 99/56 x^2 - assertEquals( - Polynomial(Rational(80, 63), Rational(-53, 9), Rational(-99, 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 - 59/12 x - 2/4 x^2 - assertEquals( - Polynomial(Rational(-2, 9), Rational(-59, 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) ?= 10/7 + 19/6 x - 2/3 x^2 - assertEquals( - Polynomial(Rational(10, 7), Rational(19, 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_times() { - IntModuloRing(35).polynomial { - // (1 + x + x^2) * (1 - x + x^2) ?= 1 + x^2 + x^4 - assertEquals( - Polynomial(1, 0, 1, 0, 1), - Polynomial(1, -1, 1) * Polynomial(1, 1, 1), - "test 1" - ) - // Spoiler: 5 * 7 = 0 - assertEquals( - Polynomial(), - Polynomial(5, -25, 10) * Polynomial(21, 14, -7), - "test 2" - ) - } - } - @Test - fun test_Polynomial_isZero() { - RationalField.polynomial { - assertTrue("test 1") { Polynomial().isZero() } - assertTrue("test 2") { Polynomial(Rational(0)).isZero() } - assertTrue("test 3") { Polynomial(Rational(0), Rational(0)).isZero() } - assertTrue("test 4") { Polynomial(Rational(0), Rational(0), Rational(0)).isZero() } - assertFalse("test 5") { Polynomial(Rational(3, 5)).isZero() } - assertFalse("test 6") { Polynomial(Rational(3, 5), Rational(0)).isZero() } - assertFalse("test 7") { Polynomial(Rational(0), Rational(3, 5), Rational(0)).isZero() } - } - } - @Test - fun test_Polynomial_isOne() { - RationalField.polynomial { - assertFalse("test 1") { Polynomial().isOne() } - assertFalse("test 2") { Polynomial(Rational(0)).isOne() } - assertFalse("test 3") { Polynomial(Rational(0), Rational(0)).isOne() } - assertFalse("test 4") { Polynomial(Rational(0), Rational(0), Rational(0)).isOne() } - assertFalse("test 5") { Polynomial(Rational(3, 5)).isOne() } - assertTrue("test 6") { Polynomial(Rational(5, 5)).isOne() } - assertFalse("test 7") { Polynomial(Rational(3, 5), Rational(0)).isOne() } - assertTrue("test 8") { Polynomial(Rational(3, 3), Rational(0)).isOne() } - assertFalse("test 9") { Polynomial(Rational(0), Rational(3, 5), Rational(0)).isOne() } - assertFalse("test 10") { Polynomial(Rational(0), Rational(5, 5), Rational(0)).isOne() } - assertFalse("test 11") { Polynomial(Rational(1), Rational(3, 5), Rational(0)).isOne() } - assertFalse("test 12") { Polynomial(Rational(1), Rational(5, 5), Rational(0)).isOne() } - } - } - @Test - fun test_Polynomial_isMinusOne() { - RationalField.polynomial { - assertFalse("test 1") { Polynomial().isMinusOne() } - assertFalse("test 2") { Polynomial(Rational(0)).isMinusOne() } - assertFalse("test 3") { Polynomial(Rational(0), Rational(0)).isMinusOne() } - assertFalse("test 4") { Polynomial(Rational(0), Rational(0), Rational(0)).isMinusOne() } - assertFalse("test 5") { Polynomial(Rational(3, 5)).isMinusOne() } - assertTrue("test 6") { Polynomial(Rational(-5, 5)).isMinusOne() } - assertFalse("test 7") { Polynomial(Rational(3, 5), Rational(0)).isMinusOne() } - assertTrue("test 8") { Polynomial(Rational(-3, 3), Rational(0)).isMinusOne() } - assertFalse("test 9") { Polynomial(Rational(0), Rational(3, 5), Rational(0)).isMinusOne() } - assertFalse("test 10") { Polynomial(Rational(0), Rational(5, -5), Rational(0)).isMinusOne() } - assertFalse("test 11") { Polynomial(Rational(-1), Rational(3, 5), Rational(0)).isMinusOne() } - assertFalse("test 12") { Polynomial(Rational(-1), Rational(5, -5), Rational(0)).isMinusOne() } - } - } - @Test - fun test_Polynomial_equalsTo() { - RationalField.polynomial { - assertTrue("test 1") { - Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) equalsTo - Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - } - assertTrue("test 2") { - Polynomial(Rational(5, 9), Rational(0), Rational(-8, 7)) equalsTo - Polynomial(Rational(5, 9), Rational(0), Rational(-8, 7)) - } - assertTrue("test 3") { - Polynomial(Rational(0), Rational(0), Rational(-8, 7), Rational(0), Rational(0)) equalsTo - Polynomial(Rational(0), Rational(0), Rational(-8, 7)) - } - assertFalse("test 4") { - Polynomial(Rational(5, 9), Rational(5, 7), Rational(-8, 7)) equalsTo - Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - } - assertFalse("test 5") { - Polynomial(Rational(8, 3), Rational(0), Rational(-8, 7)) equalsTo - Polynomial(Rational(5, 9), Rational(0), Rational(-8, 7)) - } - assertFalse("test 6") { - Polynomial(Rational(0), Rational(0), Rational(-8, 7), Rational(0), Rational(0)) equalsTo - Polynomial(Rational(0), Rational(0), Rational(8, 7)) - } - } - } - @Test - fun test_Polynomial_degree() { - RationalField.polynomial { - assertEquals( - 2, - Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)).degree, - "test 1" - ) - assertEquals( - -1, - Polynomial().degree, - "test 2" - ) - assertEquals( - -1, - Polynomial(Rational(0)).degree, - "test 3" - ) - assertEquals( - -1, - Polynomial(Rational(0), Rational(0)).degree, - "test 4" - ) - assertEquals( - -1, - Polynomial(Rational(0), Rational(0), Rational(0)).degree, - "test 5" - ) - assertEquals( - 0, - Polynomial(Rational(5, 9)).degree, - "test 6" - ) - assertEquals( - 0, - Polynomial(Rational(5, 9), Rational(0)).degree, - "test 7" - ) - assertEquals( - 0, - Polynomial(Rational(5, 9), Rational(0), Rational(0)).degree, - "test 8" - ) - assertEquals( - 2, - Polynomial(Rational(0), Rational(0), Rational(-8, 7)).degree, - "test 9" - ) - assertEquals( - 2, - Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7), Rational(0), Rational(0)).degree, - "test 10" - ) - assertEquals( - 2, - Polynomial(Rational(0), Rational(0), Rational(-8, 7), Rational(0), Rational(0)).degree, - "test 11" - ) - } - } - @Test - fun test_Polynomial_asConstantOrNull() { - RationalField.polynomial { - assertEquals( - Rational(0), - Polynomial().asConstantOrNull(), - "test 1" - ) - assertEquals( - Rational(0), - Polynomial(Rational(0)).asConstantOrNull(), - "test 2" - ) - assertEquals( - Rational(0), - Polynomial(Rational(0), Rational(0)).asConstantOrNull(), - "test 3" - ) - assertEquals( - Rational(0), - Polynomial(Rational(0), Rational(0), Rational(0)).asConstantOrNull(), - "test 4" - ) - assertEquals( - Rational(-7, 9), - Polynomial(Rational(-7, 9)).asConstantOrNull(), - "test 5" - ) - assertEquals( - Rational(-7, 9), - Polynomial(Rational(-7, 9), Rational(0)).asConstantOrNull(), - "test 6" - ) - assertEquals( - Rational(-7, 9), - Polynomial(Rational(-7, 9), Rational(0), Rational(0)).asConstantOrNull(), - "test 7" - ) - assertEquals( - null, - Polynomial(Rational(0), Rational(-7, 9)).asConstantOrNull(), - "test 8" - ) - assertEquals( - null, - Polynomial(Rational(0), Rational(-7, 9), Rational(0)).asConstantOrNull(), - "test 9" - ) - assertEquals( - null, - Polynomial(Rational(0), Rational(0), Rational(-7, 9)).asConstantOrNull(), - "test 10" - ) - assertEquals( - null, - Polynomial(Rational(4, 15), Rational(0), Rational(-7, 9)).asConstantOrNull(), - "test 11" - ) - assertEquals( - null, - Polynomial(Rational(4, 15), Rational(0), Rational(-7, 9), Rational(0)).asConstantOrNull(), - "test 12" - ) - } - } -} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt deleted file mode 100644 index 21c5436d3..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt +++ /dev/null @@ -1,229 +0,0 @@ -/* - * 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.functions - -import space.kscience.kmath.test.misc.Rational -import space.kscience.kmath.test.misc.RationalField -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertFailsWith - - -class PolynomialUtilTest { - @Test - fun test_substitute_Double() { - val polynomial = Polynomial(1.0, -2.0, 1.0) - assertEquals(0.0, polynomial.substitute(1.0), 0.001) - } - @Test - fun test_substitute_Constant() { - assertEquals( - Rational(0), - Polynomial(Rational(1), Rational(-2), Rational(1)).substitute(RationalField, Rational(1)), - "test 1" - ) - assertEquals( - Rational(25057, 21000), - Polynomial(Rational(5,8), Rational(8, 3), Rational(4, 7), Rational(3, 2)) - .substitute(RationalField, Rational(1, 5)), - "test 2" - ) - assertEquals( - Rational(2983, 5250), - Polynomial(Rational(0), Rational(8, 3), Rational(4, 7), Rational(3, 2)) - .substitute(RationalField, Rational(1, 5)), - "test 3" - ) - assertEquals( - Rational(4961, 4200), - Polynomial(Rational(5,8), Rational(8, 3), Rational(4, 7), Rational(0)) - .substitute(RationalField, Rational(1, 5)), - "test 4" - ) - assertEquals( - Rational(3511, 3000), - Polynomial(Rational(5,8), Rational(8, 3), Rational(0), Rational(3, 2)) - .substitute(RationalField, Rational(1, 5)), - "test 5" - ) - } - @Test - fun test_substitute_Polynomial() { - assertEquals( - Polynomial(), - Polynomial(Rational(1), Rational(-2), Rational(1)).substitute(RationalField, Polynomial(Rational(1))), - "test 1" - ) - assertEquals( - Polynomial(Rational(709, 378), Rational(155, 252), Rational(19, 525), Rational(2, 875)), - Polynomial(Rational(1, 7), Rational(9, 4), Rational(1, 3), Rational(2, 7)) - .substitute(RationalField, Polynomial(Rational(6, 9), Rational(1, 5))), - "test 2" - ) - assertEquals( - Polynomial(Rational(655, 378), Rational(155, 252), Rational(19, 525), Rational(2, 875)), - Polynomial(Rational(0), Rational(9, 4), Rational(1, 3), Rational(2, 7)) - .substitute(RationalField, Polynomial(Rational(6, 9), Rational(1, 5))), - "test 3" - ) - assertEquals( - Polynomial(Rational(677, 378), Rational(97, 180), Rational(1, 75)), - Polynomial(Rational(1, 7), Rational(9, 4), Rational(1, 3), Rational(0)) - .substitute(RationalField, Polynomial(Rational(6, 9), Rational(1, 5))), - "test 4" - ) - assertEquals( - Polynomial(Rational(653, 378), Rational(221, 420), Rational(4, 175), Rational(2, 875)), - Polynomial(Rational(1, 7), Rational(9, 4), Rational(0), Rational(2, 7)) - .substitute(RationalField, Polynomial(Rational(6, 9), Rational(1, 5))), - "test 5" - ) - assertEquals( - Polynomial(Rational(89, 54)), - Polynomial(Rational(0), Rational(9, 4), Rational(1, 3), Rational(0)) - .substitute(RationalField, Polynomial(Rational(6, 9), Rational(0))), - "test 6" - ) - } - @Test - fun test_derivative() { - assertEquals( - Polynomial(Rational(-2), Rational(2)), - Polynomial(Rational(1), Rational(-2), Rational(1)).derivative(RationalField), - "test 1" - ) - assertEquals( - Polynomial(Rational(-8, 3), Rational(8, 9), Rational(15, 7), Rational(-20, 9)), - Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).derivative(RationalField), - "test 2" - ) - assertEquals( - Polynomial(Rational(0), Rational(8, 9), Rational(15, 7), Rational(-20, 9)), - Polynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).derivative(RationalField), - "test 3" - ) - assertEquals( - Polynomial(Rational(-8, 3), Rational(8, 9), Rational(15, 7)), - Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).derivative(RationalField), - "test 4" - ) - } - @Test - fun test_nthDerivative() { - assertEquals( - Polynomial(Rational(-2), Rational(2)), - Polynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 1), - "test 1" - ) - assertFailsWith("test2") { - Polynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, -1) - } - assertEquals( - Polynomial(Rational(1), Rational(-2), Rational(1)), - Polynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 0), - "test 3" - ) - assertEquals( - Polynomial(Rational(2)), - Polynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 2), - "test 4" - ) - assertEquals( - Polynomial(), - Polynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 3), - "test 5" - ) - assertEquals( - Polynomial(), - Polynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 4), - "test 6" - ) - assertEquals( - Polynomial(Rational(8, 9), Rational(30, 7), Rational(-20, 3)), - Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthDerivative(RationalField, 2), - "test 7" - ) - assertEquals( - Polynomial(Rational(8, 9), Rational(30, 7), Rational(-20, 3)), - Polynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthDerivative(RationalField, 2), - "test 8" - ) - assertEquals( - Polynomial(Rational(8, 9), Rational(30, 7)), - Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).nthDerivative(RationalField, 2), - "test 9" - ) - } - @Test - fun test_antiderivative() { - assertEquals( - Polynomial(Rational(0), Rational(1), Rational(-1), Rational(1, 3)), - Polynomial(Rational(1), Rational(-2), Rational(1)).antiderivative(RationalField), - "test 1" - ) - assertEquals( - Polynomial(Rational(0), Rational(1, 5), Rational(-4, 3), Rational(4, 27), Rational(5, 28), Rational(-1, 9)), - Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).antiderivative(RationalField), - "test 2" - ) - assertEquals( - Polynomial(Rational(0), Rational(0), Rational(0), Rational(4, 27), Rational(5, 28), Rational(-1, 9)), - Polynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).antiderivative(RationalField), - "test 3" - ) - assertEquals( - Polynomial(Rational(0), Rational(1, 5), Rational(-4, 3), Rational(4, 27), Rational(5, 28)), - Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).antiderivative(RationalField), - "test 4" - ) - } - @Test - fun test_nthAntiderivative() { - assertEquals( - Polynomial(Rational(0), Rational(1), Rational(-1), Rational(1, 3)), - Polynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 1), - "test 1" - ) - assertFailsWith("test2") { - Polynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, -1) - } - assertEquals( - Polynomial(Rational(1), Rational(-2), Rational(1)), - Polynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 0), - "test 3" - ) - assertEquals( - Polynomial(Rational(0), Rational(0), Rational(1, 2), Rational(-1, 3), Rational(1, 12)), - Polynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 2), - "test 4" - ) - assertEquals( - Polynomial(Rational(0), Rational(0), Rational(0), Rational(1, 6), Rational(-1, 12), Rational(1, 60)), - Polynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 3), - "test 5" - ) - assertEquals( - Polynomial(Rational(0), Rational(0), Rational(0), Rational(0), Rational(1, 24), Rational(-1, 60), Rational(1, 360)), - Polynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 4), - "test 6" - ) - assertEquals( - Polynomial(Rational(0), Rational(0), Rational(1, 10), Rational(-4, 9), Rational(1, 27), Rational(1, 28), Rational(-1, 54)), - Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthAntiderivative(RationalField, 2), - "test 7" - ) - assertEquals( - Polynomial(Rational(0), Rational(0), Rational(0), Rational(0), Rational(1, 27), Rational(1, 28), Rational(-1, 54)), - Polynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthAntiderivative(RationalField, 2), - "test 8" - ) - assertEquals( - Polynomial(Rational(0), Rational(0), Rational(1, 10), Rational(-4, 9), Rational(1, 27), Rational(1, 28)), - Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).nthAntiderivative(RationalField, 2), - "test 9" - ) - } -} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt index afeba0be4..aae0ad017 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt @@ -5,7 +5,7 @@ package space.kscience.kmath.integration -import space.kscience.kmath.functions.Polynomial +import space.kscience.kmath.functions.ListPolynomial import space.kscience.kmath.functions.integrate import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.DoubleField @@ -19,7 +19,7 @@ class SplineIntegralTest { @Test fun integratePolynomial(){ - val polynomial = Polynomial(1.0, 2.0, 3.0) + val polynomial = ListPolynomial(1.0, 2.0, 3.0) val integral = polynomial.integrate(DoubleField,1.0..2.0) assertEquals(11.0, integral, 0.001) } diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt index a8a8a09bc..535a42846 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt @@ -5,8 +5,8 @@ package space.kscience.kmath.test.misc -import space.kscience.kmath.functions.Polynomial -import space.kscience.kmath.functions.PolynomialSpace +import space.kscience.kmath.functions.ListPolynomial +import space.kscience.kmath.functions.ListPolynomialSpace import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.Ring @@ -134,9 +134,9 @@ class IntModuloRing : Ring { inline fun IntModulo.div(arg: IntModulo): IntModulo = this / arg } -fun PolynomialSpace.number(arg: Int) = IntModulo(arg, ring.modulus, toCheckInput = false) +fun ListPolynomialSpace.number(arg: Int) = IntModulo(arg, ring.modulus, toCheckInput = false) -fun PolynomialSpace.Polynomial(vararg coefs: Int): Polynomial = - Polynomial(coefs.map { IntModulo(it, ring.modulus) }) -fun IntModuloRing.Polynomial(vararg coefs: Int): Polynomial = - Polynomial(coefs.map { IntModulo(it, modulus) }) \ No newline at end of file +fun ListPolynomialSpace.ListPolynomial(vararg coefs: Int): ListPolynomial = + ListPolynomial(coefs.map { IntModulo(it, ring.modulus) }) +fun IntModuloRing.ListPolynomial(vararg coefs: Int): ListPolynomial = + ListPolynomial(coefs.map { IntModulo(it, modulus) }) \ No newline at end of file -- 2.34.1 From 98b9a708937213eda5160805638e9d851869c7cc Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Tue, 22 Mar 2022 02:37:26 +0300 Subject: [PATCH 046/123] Enhanced tests of Double substitution. --- .../kmath/functions/ListPolynomialUtilTest.kt | 32 +++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt index bec46c034..50ae18260 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt @@ -15,8 +15,36 @@ import kotlin.test.assertFailsWith class ListPolynomialUtilTest { @Test fun test_substitute_Double() { - val polynomial = ListPolynomial(1.0, -2.0, 1.0) - assertEquals(0.0, polynomial.substitute(1.0), 0.001) + assertEquals( + 0.0, + ListPolynomial(1.0, -2.0, 1.0).substitute(1.0), + 0.001, + "test 1" + ) + assertEquals( + 1.1931904761904761, + ListPolynomial(0.625, 2.6666666666666665, 0.5714285714285714, 1.5).substitute(0.2), + 0.001, + "test 2" + ) + assertEquals( + 0.5681904761904762, + ListPolynomial(0.0, 2.6666666666666665, 0.5714285714285714, 1.5).substitute(0.2), + 0.001, + "test 3" + ) + assertEquals( + 1.1811904761904761, + ListPolynomial(0.625, 2.6666666666666665, 0.5714285714285714, 0.0).substitute(0.2), + 0.001, + "test 4" + ) + assertEquals( + 1.1703333333333332, + ListPolynomial(0.625, 2.6666666666666665, 0.0, 1.5).substitute(0.2), + 0.001, + "test 5" + ) } @Test fun test_substitute_Constant() { -- 2.34.1 From 09868f090b7507ae9ecb8ad17cc5dad75899c5b3 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Tue, 22 Mar 2022 02:39:43 +0300 Subject: [PATCH 047/123] Enhanced tests of Double substitution. --- .../kmath/functions/LabeledPolynomial.kt | 10 +++++- .../kmath/functions/ListPolynomial.kt | 12 ++++++- .../kmath/functions/NumberedPolynomial.kt | 10 +++++- .../kscience/kmath/functions/Polynomial.kt | 10 ++++++ .../kmath/functions/RationalFunction.kt | 31 +++++++++++++++++-- 5 files changed, 67 insertions(+), 6 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt index 968f77b20..3b4971d9c 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt @@ -6,7 +6,8 @@ package space.kscience.kmath.functions import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.operations.* +import space.kscience.kmath.operations.Ring +import space.kscience.kmath.operations.ScaleOperations import kotlin.contracts.InvocationKind import kotlin.contracts.contract import kotlin.experimental.ExperimentalTypeInference @@ -269,6 +270,13 @@ public class LabeledPolynomialSpace>( } ) + /** + * Converts the integer [value] to polynomial. + */ + public override fun number(value: Int): LabeledPolynomial = + if (value == 0) zero + else LabeledPolynomial(mapOf(emptyMap() to constantNumber(value))) + public operator fun C.plus(other: Symbol): LabeledPolynomial = if (isZero()) LabeledPolynomial(mapOf( mapOf(other to 1U) to constantOne, diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt index b97c1e0b4..f886ca19f 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt @@ -5,7 +5,9 @@ package space.kscience.kmath.functions -import space.kscience.kmath.operations.* +import space.kscience.kmath.operations.Ring +import space.kscience.kmath.operations.ScaleOperations +import space.kscience.kmath.operations.invoke import kotlin.contracts.InvocationKind import kotlin.contracts.contract import kotlin.experimental.ExperimentalTypeInference @@ -13,6 +15,7 @@ import kotlin.jvm.JvmName import kotlin.math.max import kotlin.math.min + /** * Polynomial model without fixation on specific context they are applied to. * @@ -193,6 +196,13 @@ public open class ListPolynomialSpace>( } ) + /** + * Converts the integer [value] to polynomial. + */ + public override fun number(value: Int): ListPolynomial = + if (value == 0) zero + else ListPolynomial(constantNumber(value)) + /** * Returns sum of the constant represented as polynomial and the polynomial. */ diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt index 3b9b907b7..387b6841d 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -5,7 +5,8 @@ package space.kscience.kmath.functions -import space.kscience.kmath.operations.* +import space.kscience.kmath.operations.Ring +import space.kscience.kmath.operations.ScaleOperations import kotlin.contracts.InvocationKind import kotlin.contracts.contract import kotlin.experimental.ExperimentalTypeInference @@ -221,6 +222,13 @@ public open class NumberedPolynomialSpace>( } ) + /** + * Converts the integer [value] to polynomial. + */ + public override fun number(value: Int): NumberedPolynomial = + if (value == 0) zero + else NumberedPolynomial(mapOf(emptyList() to constantNumber(value))) + /** * Returns sum of the constant represented as polynomial and the polynomial. */ 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 b26a57a34..dc46c868a 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 @@ -61,6 +61,11 @@ public interface PolynomialSpace> : Ring

{ */ public operator fun Int.times(other: C): C + /** + * Converts the integer [value] to constant. + */ + public fun constantNumber(value: Int): C = constantOne * value + /** * Returns sum of the polynomial and the integer represented as polynomial. * @@ -99,6 +104,11 @@ public interface PolynomialSpace> : Ring

{ */ public operator fun Int.times(other: P): P = multiplyBySquaring(other, this) + /** + * Converts the integer [value] to polynomial. + */ + public fun number(value: Int): P = one * value + /** * Returns the same constant. */ diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt index 635661b8a..724d88963 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt @@ -68,6 +68,11 @@ public interface RationalFunctionalSpace, R: RationalFunctio */ public operator fun Int.times(other: C): C + /** + * Converts the integer [value] to constant. + */ + public fun constantNumber(value: Int): C = constantOne * value + /** * Returns sum of the constant and the integer represented as polynomial. * @@ -106,6 +111,11 @@ public interface RationalFunctionalSpace, R: RationalFunctio */ public operator fun Int.times(other: P): P + /** + * Converts the integer [value] to polynomial. + */ + public fun polynomialNumber(value: Int): P = polynomialOne * value + /** * Returns sum of the rational function and the integer represented as rational function. * @@ -144,6 +154,11 @@ public interface RationalFunctionalSpace, R: RationalFunctio */ public operator fun Int.times(other: R): R = multiplyBySquaring(other, this) + /** + * Converts the integer [value] to rational function. + */ + public fun number(value: Int): R = one * value + /** * Returns the same constant. */ @@ -672,6 +687,11 @@ public interface RationalFunctionalSpaceOverPolynomialSpace< */ public override operator fun Int.times(other: P): P = polynomialRing { this@times * other } + /** + * Converts the integer [value] to polynomial. + */ + public override fun polynomialNumber(value: Int): P = polynomialRing { number(value) } + /** * Returns the same constant. */ @@ -880,7 +900,7 @@ public abstract class PolynomialSpaceOfFractions< P: Polynomial, R: RationalFunction, > : RationalFunctionalSpace { - protected abstract fun constructRationalFunction(numerator: P, denominator: P) : R + protected abstract fun constructRationalFunction(numerator: P, denominator: P = polynomialOne) : R /** * Returns sum of the rational function and the integer represented as rational function. @@ -944,6 +964,11 @@ public abstract class PolynomialSpaceOfFractions< other.denominator ) + /** + * Converts the integer [value] to rational function. + */ + public override fun number(value: Int): R = constructRationalFunction(polynomialNumber(value)) + /** * Returns sum of the constant represented as rational function and the rational function. */ @@ -1076,10 +1101,10 @@ public abstract class PolynomialSpaceOfFractions< /** * Instance of zero rational function (zero of the rational functions ring). */ - public override val zero: R get() = constructRationalFunction(polynomialZero, polynomialOne) + public override val zero: R get() = constructRationalFunction(polynomialZero) /** * Instance of unit polynomial (unit of the rational functions ring). */ - public override val one: R get() = constructRationalFunction(polynomialOne, polynomialOne) + public override val one: R get() = constructRationalFunction(polynomialOne) } \ No newline at end of file -- 2.34.1 From 2f9e5043577d798f1330c20da497bb44eb66c617 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Tue, 22 Mar 2022 13:58:29 +0300 Subject: [PATCH 048/123] Added division to RFs' Spaces. Added conversion to polynomial and RFs' spaces. Added requirements for RFs' denominators' changes for case of non-integral domain. Added requirements for non-zero divisor to RFs' divisions. --- .../kmath/functions/LabeledPolynomial.kt | 11 +- .../functions/LabeledRationalFunction.kt | 18 -- .../kmath/functions/ListPolynomial.kt | 13 +- .../kmath/functions/ListRationalFunction.kt | 24 -- .../kmath/functions/NumberedPolynomial.kt | 11 +- .../kscience/kmath/functions/Polynomial.kt | 17 ++ .../kmath/functions/RationalFunction.kt | 217 +++++++++++++++++- 7 files changed, 250 insertions(+), 61 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt index 3b4971d9c..e0b92a712 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt @@ -273,9 +273,7 @@ public class LabeledPolynomialSpace>( /** * Converts the integer [value] to polynomial. */ - public override fun number(value: Int): LabeledPolynomial = - if (value == 0) zero - else LabeledPolynomial(mapOf(emptyMap() to constantNumber(value))) + public override fun number(value: Int): LabeledPolynomial = number(constantNumber(value)) public operator fun C.plus(other: Symbol): LabeledPolynomial = if (isZero()) LabeledPolynomial(mapOf( @@ -425,6 +423,13 @@ public class LabeledPolynomialSpace>( } ) + /** + * Converts the constant [value] to polynomial. + */ + public override fun number(value: C): LabeledPolynomial = + if (value == 0) zero + else LabeledPolynomial(mapOf(emptyMap() to value)) + public operator fun Symbol.plus(other: Symbol): LabeledPolynomial = if (this == other) LabeledPolynomial(mapOf( mapOf(this to 1U) to constantOne * 2 diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt index f347f9191..735e04a48 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt @@ -144,24 +144,6 @@ public class LabeledRationalFunctionSpace>( // TODO: Разобрать - public operator fun LabeledRationalFunction.div(other: LabeledRationalFunction): LabeledRationalFunction = - LabeledRationalFunction( - numerator * other.denominator, - denominator * other.numerator - ) - - public operator fun LabeledRationalFunction.div(other: LabeledPolynomial): LabeledRationalFunction = - LabeledRationalFunction( - numerator, - denominator * other - ) - - public operator fun LabeledRationalFunction.div(other: C): LabeledRationalFunction = - LabeledRationalFunction( - numerator, - denominator * other - ) - // operator fun invoke(arg: Map): LabeledRationalFunction = // LabeledRationalFunction( // numerator(arg), diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt index f886ca19f..90e9cde69 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt @@ -66,7 +66,7 @@ public fun ListPolynomial(coefficients: List, reverse: Boolean = false): public fun ListPolynomial(vararg coefficients: C, reverse: Boolean = false): ListPolynomial = ListPolynomial(with(coefficients) { if (reverse) reversed() else toList() }) -public fun C.asPolynomial() : ListPolynomial = ListPolynomial(listOf(this)) +public fun C.asListPolynomial() : ListPolynomial = ListPolynomial(listOf(this)) /** * Space of univariate polynomials constructed over ring. @@ -199,9 +199,7 @@ public open class ListPolynomialSpace>( /** * Converts the integer [value] to polynomial. */ - public override fun number(value: Int): ListPolynomial = - if (value == 0) zero - else ListPolynomial(constantNumber(value)) + public override fun number(value: Int): ListPolynomial = number(constantNumber(value)) /** * Returns sum of the constant represented as polynomial and the polynomial. @@ -313,6 +311,13 @@ public open class ListPolynomialSpace>( } ) + /** + * Converts the constant [value] to polynomial. + */ + public override fun number(value: C): ListPolynomial = + if (value.isZero()) zero + else ListPolynomial(value) + /** * Returns negation of the polynomial. */ diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt index 50ddd3118..8bd925c46 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt @@ -70,30 +70,6 @@ public class ListRationalFunctionSpace> ( // TODO: Разобрать - public operator fun ListRationalFunction.div(other: ListRationalFunction): ListRationalFunction = - ListRationalFunction( - numerator * other.denominator, - denominator * other.numerator - ) - - public operator fun ListRationalFunction.div(other: ListPolynomial): ListRationalFunction = - ListRationalFunction( - numerator, - denominator * other - ) - - public operator fun ListRationalFunction.div(other: C): ListRationalFunction = - ListRationalFunction( - numerator, - denominator * other - ) - - public operator fun ListRationalFunction.div(other: Int): ListRationalFunction = - ListRationalFunction( - numerator, - denominator * other - ) - // operator fun invoke(arg: UnivariatePolynomial): RationalFunction = // RationalFunction( // numerator(arg), diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt index 387b6841d..1f37a1c2b 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -225,9 +225,7 @@ public open class NumberedPolynomialSpace>( /** * Converts the integer [value] to polynomial. */ - public override fun number(value: Int): NumberedPolynomial = - if (value == 0) zero - else NumberedPolynomial(mapOf(emptyList() to constantNumber(value))) + public override fun number(value: Int): NumberedPolynomial = number(constantNumber(value)) /** * Returns sum of the constant represented as polynomial and the polynomial. @@ -331,6 +329,13 @@ public open class NumberedPolynomialSpace>( } ) + /** + * Converts the constant [value] to polynomial. + */ + public override fun number(value: C): NumberedPolynomial = + if (value == 0) zero + else NumberedPolynomial(mapOf(emptyList() to value)) + /** * Returns negation of the polynomial. */ 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 dc46c868a..f8d7d5a36 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 @@ -65,6 +65,10 @@ public interface PolynomialSpace> : Ring

{ * Converts the integer [value] to constant. */ public fun constantNumber(value: Int): C = constantOne * value + /** + * Converts the integer to constant. + */ + public fun Int.asConstant(): C = constantNumber(this) /** * Returns sum of the polynomial and the integer represented as polynomial. @@ -108,6 +112,10 @@ public interface PolynomialSpace> : Ring

{ * Converts the integer [value] to polynomial. */ public fun number(value: Int): P = one * value + /** + * Converts the integer to polynomial. + */ + public fun Int.asPolynomial(): P = number(this) /** * Returns the same constant. @@ -206,6 +214,15 @@ public interface PolynomialSpace> : Ring

{ */ public operator fun P.times(other: C): P + /** + * Converts the constant [value] to polynomial. + */ + public fun number(value: C): P = one * value + /** + * Converts the constant to polynomial. + */ + public fun C.asPolynomial(): P = number(this) + /** * Returns the same polynomial. */ diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt index 724d88963..90e3bdbb1 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt @@ -72,6 +72,10 @@ public interface RationalFunctionalSpace, R: RationalFunctio * Converts the integer [value] to constant. */ public fun constantNumber(value: Int): C = constantOne * value + /** + * Converts the integer to constant. + */ + public fun Int.asConstant(): C = constantNumber(this) /** * Returns sum of the constant and the integer represented as polynomial. @@ -115,6 +119,10 @@ public interface RationalFunctionalSpace, R: RationalFunctio * Converts the integer [value] to polynomial. */ public fun polynomialNumber(value: Int): P = polynomialOne * value + /** + * Converts the integer to polynomial. + */ + public fun Int.asPolynomial(): P = polynomialNumber(this) /** * Returns sum of the rational function and the integer represented as rational function. @@ -134,6 +142,13 @@ public interface RationalFunctionalSpace, R: RationalFunctio * The operation is equivalent to sum of [other] copies of [this]. */ public operator fun R.times(other: Int): R = multiplyBySquaring(this, other) + /** + * Returns quotient of the rational function and the integer represented as rational function. + * + * The operation is equivalent to creating a new rational function by preserving numerator of [this] and + * multiplication denominator of [this] to [other]. + */ + public operator fun R.div(other: Int): R = this / multiplyBySquaring(one, other) /** * Returns sum of the integer represented as rational function and the rational function. @@ -153,11 +168,22 @@ public interface RationalFunctionalSpace, R: RationalFunctio * The operation is equivalent to sum of [this] copies of [other]. */ public operator fun Int.times(other: R): R = multiplyBySquaring(other, this) + /** + * Returns quotient of the integer represented as rational function and the rational function. + * + * The operation is equivalent to creating a new rational function which numerator is [this] times denominator of + * [other] and which denominator is [other]'s numerator. + */ + public operator fun Int.div(other: R): R = multiplyBySquaring(one / other, this) /** * Converts the integer [value] to rational function. */ public fun number(value: Int): R = one * value + /** + * Converts the integer to rational function. + */ + public fun Int.asRationalFunction(): R = number(this) /** * Returns the same constant. @@ -256,6 +282,15 @@ public interface RationalFunctionalSpace, R: RationalFunctio */ public operator fun P.times(other: C): P + /** + * Converts the constant [value] to polynomial. + */ + public fun polynomialNumber(value: C): P = polynomialOne * value + /** + * Converts the constant to polynomial. + */ + public fun C.asPolynomial(): P = polynomialNumber(this) + /** * Returns the same polynomial. */ @@ -276,6 +311,10 @@ public interface RationalFunctionalSpace, R: RationalFunctio * Returns product of the polynomials. */ public operator fun P.times(other: P): P + /** + * Returns quotient of the polynomials as rational function. + */ + public operator fun P.div(other: P): R /** * Raises [arg] to the integer power [exponent]. */ @@ -336,19 +375,36 @@ public interface RationalFunctionalSpace, R: RationalFunctio * Returns product of the constant represented as polynomial and the rational function. */ public operator fun C.times(other: R): R + /** + * Returns quotient of the constant represented as polynomial and the rational function. + */ + public operator fun C.div(other: R): R /** - * Returns sum of the constant represented as rational function and the rational function. + * Returns sum of the rational function and the constant represented as rational function. */ public operator fun R.plus(other: C): R /** - * Returns difference between the constant represented as rational function and the rational function. + * Returns difference between the rational function and the constant represented as rational function. */ public operator fun R.minus(other: C): R /** - * Returns product of the constant represented as rational function and the rational function. + * Returns product of the rational function and the constant represented as rational function. */ public operator fun R.times(other: C): R + /** + * Returns quotient of the rational function and the constant represented as rational function. + */ + public operator fun R.div(other: C): R + + /** + * Converts the constant [value] to rational function. + */ + public fun number(value: C): R = one * value + /** + * Converts the constant to rational function. + */ + public fun C.asRationalFunction(): R = number(this) /** * Returns sum of the polynomial represented as rational function and the rational function. @@ -362,19 +418,36 @@ public interface RationalFunctionalSpace, R: RationalFunctio * Returns product of the polynomial represented as polynomial and the rational function. */ public operator fun P.times(other: R): R + /** + * Returns quotient of the polynomial represented as polynomial and the rational function. + */ + public operator fun P.div(other: R): R /** - * Returns sum of the polynomial represented as rational function and the rational function. + * Returns sum of the rational function and the polynomial represented as rational function. */ public operator fun R.plus(other: P): R /** - * Returns difference between the polynomial represented as rational function and the rational function. + * Returns difference between the rational function and the polynomial represented as rational function. */ public operator fun R.minus(other: P): R /** - * Returns product of the polynomial represented as rational function and the rational function. + * Returns product of the rational function and the polynomial represented as rational function. */ public operator fun R.times(other: P): R + /** + * Returns quotient of the rational function and the polynomial represented as rational function. + */ + public operator fun R.div(other: P): R + + /** + * Converts the polynomial [value] to rational function. + */ + public fun number(value: P): R = one * value + /** + * Converts the polynomial to rational function. + */ + public fun P.asRationalFunction(): R = number(this) /** * Returns the same rational function. @@ -396,6 +469,10 @@ public interface RationalFunctionalSpace, R: RationalFunctio * Returns product of the rational functions. */ public override operator fun R.times(other: R): R + /** + * Returns quotient of the rational functions. + */ + public operator fun R.div(other: R): R /** * Raises [arg] to the integer power [exponent]. */ @@ -649,6 +726,15 @@ public interface RationalFunctionalSpaceOverPolynomialSpace< */ public override operator fun Int.times(other: C): C = polynomialRing { this@times * other } + /** + * Converts the integer [value] to constant. + */ + public override fun constantNumber(value: Int): C = polynomialRing { constantNumber(value) } + /** + * Converts the integer to constant. + */ + override fun Int.asConstant(): C = polynomialRing { asConstant() } + /** * Returns sum of the constant and the integer represented as polynomial. * @@ -691,6 +777,10 @@ public interface RationalFunctionalSpaceOverPolynomialSpace< * Converts the integer [value] to polynomial. */ public override fun polynomialNumber(value: Int): P = polynomialRing { number(value) } + /** + * Converts the integer to polynomial. + */ + public override fun Int.asPolynomial(): P = polynomialRing { asPolynomial() } /** * Returns the same constant. @@ -783,6 +873,15 @@ public interface RationalFunctionalSpaceOverPolynomialSpace< */ public override operator fun P.times(other: C): P = polynomialRing { this@times * other } + /** + * Converts the constant [value] to polynomial. + */ + public override fun polynomialNumber(value: C): P = polynomialRing { number(value) } + /** + * Converts the constant to polynomial. + */ + public override fun C.asPolynomial(): P = polynomialRing { asPolynomial() } + /** * Returns the same polynomial. */ @@ -933,6 +1032,19 @@ public abstract class PolynomialSpaceOfFractions< denominator ) + public override operator fun R.div(other: Int): R { + val otherAsConstant = constantNumber(other) + require(otherAsConstant.isNotZero()) { "/ by zero." } + return constructRationalFunction( + numerator, + (denominator * other).also { + check(it.isNotZero()) { + "Got zero denominator during division of rational functions to constant. It means underlying ring of polynomials is not integral domain." + } + } + ) + } + /** * Returns sum of the integer represented as rational function and the rational function. * @@ -964,11 +1076,24 @@ public abstract class PolynomialSpaceOfFractions< other.denominator ) + public override operator fun Int.div(other: R): R { + require(other.numerator.isNotZero()) { "/ by zero." } + return constructRationalFunction( + this * other.denominator, + other.numerator + ) + } + /** * Converts the integer [value] to rational function. */ public override fun number(value: Int): R = constructRationalFunction(polynomialNumber(value)) + /** + * Returns quotient of the polynomials as rational function. + */ + public override operator fun P.div(other: P): R = constructRationalFunction(this, other) + /** * Returns sum of the constant represented as rational function and the rational function. */ @@ -994,6 +1119,14 @@ public abstract class PolynomialSpaceOfFractions< other.denominator ) + public override operator fun C.div(other: R): R { + require(other.numerator.isNotZero()) { "/ by zero." } + return constructRationalFunction( + this * other.denominator, + other.numerator + ) + } + /** * Returns sum of the constant represented as rational function and the rational function. */ @@ -1019,6 +1152,23 @@ public abstract class PolynomialSpaceOfFractions< denominator ) + public override operator fun R.div(other: C): R { + require(other.isNotZero()) { "/ by zero." } + return constructRationalFunction( + numerator, + (denominator * other).also { + check(it.isNotZero()) { + "Got zero denominator during division of rational functions to constant. It means underlying ring of polynomials is not integral domain." + } + } + ) + } + + /** + * Converts the constant [value] to rational function. + */ + public override fun number(value: C): R = constructRationalFunction(polynomialNumber(value)) + /** * Returns sum of the polynomial represented as rational function and the rational function. */ @@ -1044,6 +1194,14 @@ public abstract class PolynomialSpaceOfFractions< other.denominator ) + public override operator fun P.div(other: R): R { + require(other.numerator.isNotZero()) { "/ by zero." } + return constructRationalFunction( + this * other.denominator, + other.numerator + ) + } + /** * Returns sum of the polynomial represented as rational function and the rational function. */ @@ -1069,6 +1227,23 @@ public abstract class PolynomialSpaceOfFractions< denominator ) + public override operator fun R.div(other: P): R { + require(other.isNotZero()) { "/ by zero." } + return constructRationalFunction( + numerator, + (denominator * other).also { + require(it.isNotZero()) { + "Got zero denominator during division of rational functions to polynomial. It means underlying ring of polynomials is not integral domain." + } + } + ) + } + + /** + * Converts the polynomial [value] to rational function. + */ + public override fun number(value: P): R = constructRationalFunction(value) + /** * Returns negation of the rational function. */ @@ -1079,7 +1254,11 @@ public abstract class PolynomialSpaceOfFractions< public override operator fun R.plus(other: R): R = constructRationalFunction( numerator * other.denominator + denominator * other.numerator, - denominator * other.denominator + (denominator * other.denominator).also { + check(it.isNotZero()) { + "Got zero denominator during addition of rational functions. It means underlying ring of polynomials is not integral domain." + } + } ) /** * Returns difference of the rational functions. @@ -1087,7 +1266,11 @@ public abstract class PolynomialSpaceOfFractions< public override operator fun R.minus(other: R): R = constructRationalFunction( numerator * other.denominator - denominator * other.numerator, - denominator * other.denominator + (denominator * other.denominator).also { + check(it.isNotZero()) { + "Got zero denominator during subtraction of rational functions. It means underlying ring of polynomials is not integral domain." + } + } ) /** * Returns product of the rational functions. @@ -1095,9 +1278,25 @@ public abstract class PolynomialSpaceOfFractions< public override operator fun R.times(other: R): R = constructRationalFunction( numerator * other.numerator, - denominator * other.denominator + (denominator * other.denominator).also { + check(it.isNotZero()) { + "Got zero denominator during multiplication of rational functions. It means underlying ring of polynomials is not integral domain." + } + } ) + public override operator fun R.div(other: R): R { + require(other.isNotZero()) { "/ by zero." } + return constructRationalFunction( + numerator * other.denominator, + (denominator * other.numerator).also { + check(it.isNotZero()) { + "Got zero denominator during division of rational functions. It means underlying ring of polynomials is not integral domain." + } + } + ) + } + /** * Instance of zero rational function (zero of the rational functions ring). */ -- 2.34.1 From 39ce855075662461892ff70f2c52c630d9e70d66 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Tue, 22 Mar 2022 14:25:09 +0300 Subject: [PATCH 049/123] Added constructors for RFs' spaces --- .../functions/LabeledRationalFunction.kt | 82 +++++++------- .../kmath/functions/ListRationalFunction.kt | 62 +++++++---- .../functions/NumberedRationalFunction.kt | 100 ++++++++---------- 3 files changed, 122 insertions(+), 122 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt index 735e04a48..599660b52 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt @@ -19,48 +19,46 @@ public class LabeledRationalFunction( // Waiting for context receivers :( TODO: Replace with context receivers when they will be available -//context(RationalFunctionSpace) -//@Suppress("FunctionName") -//internal fun > RationalFunction(numerator: Polynomial, denominator: Polynomial): RationalFunction = -// if (denominator.isZero()) throw ArithmeticException("/ by zero") -// else RationalFunction(numerator, denominator) -//context(RationalFunctionSpace) -//@Suppress("FunctionName") -//public fun > RationalFunction(numeratorCoefficients: List, denominatorCoefficients: List, reverse: Boolean = false): RationalFunction = -// RationalFunction( -// Polynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), -// Polynomial( with(denominatorCoefficients) { if (reverse) reversed() else this } ).also { if (it.isZero()) } -// ) -//context(RationalFunctionSpace) -//@Suppress("FunctionName") -//public fun > RationalFunction(numerator: Polynomial): RationalFunction = -// RationalFunction(numerator, onePolynomial) -//context(RationalFunctionSpace) -//@Suppress("FunctionName") -//public fun > RationalFunction(numeratorCoefficients: List, reverse: Boolean = false): RationalFunction = -// RationalFunction( -// Polynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ) -// ) - -// TODO: Rewrite former constructors as fabrics -//constructor(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>) : this( -//LabeledPolynomial(numeratorCoefficients), -//LabeledPolynomial(denominatorCoefficients) -//) -// -//constructor(numeratorCoefficients: Collection, C>>, denominatorCoefficients: Collection, C>>) : this( -//LabeledPolynomial(numeratorCoefficients), -//LabeledPolynomial(denominatorCoefficients) -//) -// -//constructor(numerator: LabeledPolynomial) : this(numerator, numerator.getOne()) -//constructor(numeratorCoefficients: Map, C>) : this( -//LabeledPolynomial(numeratorCoefficients) -//) -// -//constructor(numeratorCoefficients: Collection, C>>) : this( -//LabeledPolynomial(numeratorCoefficients) -//) +@Suppress("FunctionName") +internal fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numerator: LabeledPolynomial, denominator: LabeledPolynomial): LabeledRationalFunction = + if (denominator.isZero()) throw ArithmeticException("/ by zero") + else LabeledRationalFunction(numerator, denominator) +@Suppress("FunctionName") +internal fun > A.LabeledRationalFunction(numerator: LabeledPolynomial, denominator: LabeledPolynomial): LabeledRationalFunction = + if (denominator.coefficients.values.all { it == zero }) throw ArithmeticException("/ by zero") + else LabeledRationalFunction(numerator, denominator) +@Suppress("FunctionName") +public fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): LabeledRationalFunction = + if (denominatorCoefficients.values.all { it == zero }) throw ArithmeticException("/ by zero") + else LabeledRationalFunction( + LabeledPolynomial(numeratorCoefficients), + LabeledPolynomial(denominatorCoefficients) + ) +@Suppress("FunctionName") +public fun > A.LabeledRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): LabeledRationalFunction = + if (denominatorCoefficients.values.all { it == zero }) throw ArithmeticException("/ by zero") + else LabeledRationalFunction( + LabeledPolynomial(numeratorCoefficients), + LabeledPolynomial(denominatorCoefficients) + ) +@Suppress("FunctionName") +public fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numerator: LabeledPolynomial): LabeledRationalFunction = + LabeledRationalFunction(numerator, polynomialOne) +@Suppress("FunctionName") +public fun > A.LabeledRationalFunction(numerator: LabeledPolynomial): LabeledRationalFunction = + LabeledRationalFunction(numerator, LabeledPolynomial(mapOf(emptyMap() to one))) +@Suppress("FunctionName") +public fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numeratorCoefficients: Map, C>): LabeledRationalFunction = + LabeledRationalFunction( + LabeledPolynomial(numeratorCoefficients), + polynomialOne + ) +@Suppress("FunctionName") +public fun > A.LabeledRationalFunction(numeratorCoefficients: Map, C>): LabeledRationalFunction = + LabeledRationalFunction( + LabeledPolynomial(numeratorCoefficients), + LabeledPolynomial(mapOf(emptyMap() to one)) + ) public class LabeledRationalFunctionSpace>( public val ring: A, diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt index 8bd925c46..67c7e9fa2 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt @@ -17,28 +17,46 @@ public data class ListRationalFunction internal constructor ( // Waiting for context receivers :( TODO: Replace with context receivers when they will be available -//context(RationalFunctionSpace) -//@Suppress("FunctionName") -//internal fun > RationalFunction(numerator: Polynomial, denominator: Polynomial): RationalFunction = -// if (denominator.isZero()) throw ArithmeticException("/ by zero") -// else RationalFunction(numerator, denominator) -//context(RationalFunctionSpace) -//@Suppress("FunctionName") -//public fun > RationalFunction(numeratorCoefficients: List, denominatorCoefficients: List, reverse: Boolean = false): RationalFunction = -// RationalFunction( -// Polynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), -// Polynomial( with(denominatorCoefficients) { if (reverse) reversed() else this } ).also { if (it.isZero()) } -// ) -//context(RationalFunctionSpace) -//@Suppress("FunctionName") -//public fun > RationalFunction(numerator: Polynomial): RationalFunction = -// RationalFunction(numerator, onePolynomial) -//context(RationalFunctionSpace) -//@Suppress("FunctionName") -//public fun > RationalFunction(numeratorCoefficients: List, reverse: Boolean = false): RationalFunction = -// RationalFunction( -// Polynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ) -// ) +@Suppress("FunctionName") +internal fun > ListRationalFunctionSpace.ListRationalFunction(numerator: ListPolynomial, denominator: ListPolynomial): ListRationalFunction = + if (denominator.isZero()) throw ArithmeticException("/ by zero") + else ListRationalFunction(numerator, denominator) +@Suppress("FunctionName") +internal fun > A.ListRationalFunction(numerator: ListPolynomial, denominator: ListPolynomial): ListRationalFunction = + if (denominator.coefficients.all { it == zero }) throw ArithmeticException("/ by zero") + else ListRationalFunction(numerator, denominator) +@Suppress("FunctionName") +public fun > ListRationalFunctionSpace.ListRationalFunction(numeratorCoefficients: List, denominatorCoefficients: List, reverse: Boolean = false): ListRationalFunction = + if (denominatorCoefficients.all { it == zero }) throw ArithmeticException("/ by zero") + else ListRationalFunction( + ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), + ListPolynomial( with(denominatorCoefficients) { if (reverse) reversed() else this } ) + ) +@Suppress("FunctionName") +public fun > A.ListRationalFunction(numeratorCoefficients: List, denominatorCoefficients: List, reverse: Boolean = false): ListRationalFunction = + if (denominatorCoefficients.all { it == zero }) throw ArithmeticException("/ by zero") + else ListRationalFunction( + ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), + ListPolynomial( with(denominatorCoefficients) { if (reverse) reversed() else this } ) + ) +@Suppress("FunctionName") +public fun > ListRationalFunctionSpace.ListRationalFunction(numerator: ListPolynomial): ListRationalFunction = + ListRationalFunction(numerator, polynomialOne) +@Suppress("FunctionName") +public fun > A.ListRationalFunction(numerator: ListPolynomial): ListRationalFunction = + ListRationalFunction(numerator, ListPolynomial(listOf(one))) +@Suppress("FunctionName") +public fun > ListRationalFunctionSpace.ListRationalFunction(numeratorCoefficients: List, reverse: Boolean = false): ListRationalFunction = + ListRationalFunction( + ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), + polynomialOne + ) +@Suppress("FunctionName") +public fun > A.ListRationalFunction(numeratorCoefficients: List, reverse: Boolean = false): ListRationalFunction = + ListRationalFunction( + ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), + ListPolynomial(listOf(one)) + ) public class ListRationalFunctionSpace> ( public val ring: A, diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt index f3b90b5c5..b32f01f2a 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt @@ -5,7 +5,8 @@ package space.kscience.kmath.functions -import space.kscience.kmath.operations.* +import space.kscience.kmath.operations.Ring +import space.kscience.kmath.operations.invoke import kotlin.math.max @@ -18,45 +19,46 @@ public class NumberedRationalFunction internal constructor( // Waiting for context receivers :( TODO: Replace with context receivers when they will be available -//context(RationalFunctionSpace) -//@Suppress("FunctionName") -//internal fun > RationalFunction(numerator: Polynomial, denominator: Polynomial): RationalFunction = -// if (denominator.isZero()) throw ArithmeticException("/ by zero") -// else RationalFunction(numerator, denominator) -//context(RationalFunctionSpace) -//@Suppress("FunctionName") -//public fun > RationalFunction(numeratorCoefficients: List, denominatorCoefficients: List, reverse: Boolean = false): RationalFunction = -// RationalFunction( -// Polynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), -// Polynomial( with(denominatorCoefficients) { if (reverse) reversed() else this } ).also { if (it.isZero()) } -// ) -//context(RationalFunctionSpace) -//@Suppress("FunctionName") -//public fun > RationalFunction(numerator: Polynomial): RationalFunction = -// RationalFunction(numerator, onePolynomial) -//context(RationalFunctionSpace) -//@Suppress("FunctionName") -//public fun > RationalFunction(numeratorCoefficients: List, reverse: Boolean = false): RationalFunction = -// RationalFunction( -// Polynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ) -// ) - -// TODO: Rewrite former constructors as fabrics -//constructor(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>) : this( -//Polynomial(numeratorCoefficients), -//Polynomial(denominatorCoefficients) -//) -//constructor(numeratorCoefficients: Collection, C>>, denominatorCoefficients: Collection, C>>) : this( -//Polynomial(numeratorCoefficients), -//Polynomial(denominatorCoefficients) -//) -//constructor(numerator: Polynomial) : this(numerator, numerator.getOne()) -//constructor(numeratorCoefficients: Map, C>) : this( -//Polynomial(numeratorCoefficients) -//) -//constructor(numeratorCoefficients: Collection, C>>) : this( -//Polynomial(numeratorCoefficients) -//) +@Suppress("FunctionName") +internal fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numerator: NumberedPolynomial, denominator: NumberedPolynomial): NumberedRationalFunction = + if (denominator.isZero()) throw ArithmeticException("/ by zero") + else NumberedRationalFunction(numerator, denominator) +@Suppress("FunctionName") +internal fun > A.NumberedRationalFunction(numerator: NumberedPolynomial, denominator: NumberedPolynomial): NumberedRationalFunction = + if (denominator.coefficients.values.all { it == zero }) throw ArithmeticException("/ by zero") + else NumberedRationalFunction(numerator, denominator) +@Suppress("FunctionName") +public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): NumberedRationalFunction = + if (denominatorCoefficients.values.all { it == zero }) throw ArithmeticException("/ by zero") + else NumberedRationalFunction( + NumberedPolynomial(numeratorCoefficients), + NumberedPolynomial(denominatorCoefficients) + ) +@Suppress("FunctionName") +public fun > A.NumberedRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): NumberedRationalFunction = + if (denominatorCoefficients.values.all { it == zero }) throw ArithmeticException("/ by zero") + else NumberedRationalFunction( + NumberedPolynomial(numeratorCoefficients), + NumberedPolynomial(denominatorCoefficients) + ) +@Suppress("FunctionName") +public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numerator: NumberedPolynomial): NumberedRationalFunction = + NumberedRationalFunction(numerator, polynomialOne) +@Suppress("FunctionName") +public fun > A.NumberedRationalFunction(numerator: NumberedPolynomial): NumberedRationalFunction = + NumberedRationalFunction(numerator, NumberedPolynomial(mapOf(emptyList() to one))) +@Suppress("FunctionName") +public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numeratorCoefficients: Map, C>): NumberedRationalFunction = + NumberedRationalFunction( + NumberedPolynomial(numeratorCoefficients), + polynomialOne + ) +@Suppress("FunctionName") +public fun > A.NumberedRationalFunction(numeratorCoefficients: Map, C>): NumberedRationalFunction = + NumberedRationalFunction( + NumberedPolynomial(numeratorCoefficients), + NumberedPolynomial(mapOf(emptyList() to one)) + ) public class NumberedRationalFunctionSpace> ( public val ring: A, @@ -156,24 +158,6 @@ public class NumberedRationalFunctionSpace> ( // TODO: Разобрать - public operator fun NumberedRationalFunction.div(other: NumberedRationalFunction): NumberedRationalFunction = - NumberedRationalFunction( - numerator * other.denominator, - denominator * other.numerator - ) - - public operator fun NumberedRationalFunction.div(other: NumberedPolynomial): NumberedRationalFunction = - NumberedRationalFunction( - numerator, - denominator * other - ) - - public operator fun NumberedRationalFunction.div(other: C): NumberedRationalFunction = - NumberedRationalFunction( - numerator, - denominator * other - ) - // operator fun invoke(arg: Map): NumberedRationalFunction = // NumberedRationalFunction( // numerator(arg), -- 2.34.1 From b44c99c265d0d8a43679c694135585047a489813 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Tue, 22 Mar 2022 15:28:34 +0300 Subject: [PATCH 050/123] Added multivariate abstractions. --- .../kmath/functions/LabeledPolynomial.kt | 68 +++--- .../functions/LabeledRationalFunction.kt | 33 +-- .../kscience/kmath/functions/Polynomial.kt | 60 +++++- .../kmath/functions/RationalFunction.kt | 197 ++++++++++++++++++ 4 files changed, 303 insertions(+), 55 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt index e0b92a712..29aeb6bb0 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt @@ -117,8 +117,8 @@ public fun C.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomia */ public class LabeledPolynomialSpace>( public override val ring: A, -) : PolynomialSpaceOverRing, A> { - public operator fun Symbol.plus(other: Int): LabeledPolynomial = +) : MultivariatePolynomialSpace>, PolynomialSpaceOverRing, A> { + public override operator fun Symbol.plus(other: Int): LabeledPolynomial = if (other == 0) LabeledPolynomial(mapOf( mapOf(this@plus to 1U) to constantOne, )) @@ -126,7 +126,7 @@ public class LabeledPolynomialSpace>( mapOf(this@plus to 1U) to constantOne, emptyMap() to constantOne * other, )) - public operator fun Symbol.minus(other: Int): LabeledPolynomial = + public override operator fun Symbol.minus(other: Int): LabeledPolynomial = if (other == 0) LabeledPolynomial(mapOf( mapOf(this@minus to 1U) to -constantOne, )) @@ -134,13 +134,13 @@ public class LabeledPolynomialSpace>( mapOf(this@minus to 1U) to -constantOne, emptyMap() to constantOne * other, )) - public operator fun Symbol.times(other: Int): LabeledPolynomial = + public override operator fun Symbol.times(other: Int): LabeledPolynomial = if (other == 0) zero else LabeledPolynomial(mapOf( mapOf(this to 1U) to constantOne * other, )) - public operator fun Int.plus(other: Symbol): LabeledPolynomial = + public override operator fun Int.plus(other: Symbol): LabeledPolynomial = if (this == 0) LabeledPolynomial(mapOf( mapOf(other to 1U) to constantOne, )) @@ -148,7 +148,7 @@ public class LabeledPolynomialSpace>( mapOf(other to 1U) to constantOne, emptyMap() to constantOne * this@plus, )) - public operator fun Int.minus(other: Symbol): LabeledPolynomial = + public override operator fun Int.minus(other: Symbol): LabeledPolynomial = if (this == 0) LabeledPolynomial(mapOf( mapOf(other to 1U) to -constantOne, )) @@ -156,7 +156,7 @@ public class LabeledPolynomialSpace>( mapOf(other to 1U) to -constantOne, emptyMap() to constantOne * this@minus, )) - public operator fun Int.times(other: Symbol): LabeledPolynomial = + public override operator fun Int.times(other: Symbol): LabeledPolynomial = if (this == 0) zero else LabeledPolynomial(mapOf( mapOf(other to 1U) to constantOne * this@times, @@ -275,7 +275,7 @@ public class LabeledPolynomialSpace>( */ public override fun number(value: Int): LabeledPolynomial = number(constantNumber(value)) - public operator fun C.plus(other: Symbol): LabeledPolynomial = + public override operator fun C.plus(other: Symbol): LabeledPolynomial = if (isZero()) LabeledPolynomial(mapOf( mapOf(other to 1U) to constantOne, )) @@ -283,7 +283,7 @@ public class LabeledPolynomialSpace>( mapOf(other to 1U) to constantOne, emptyMap() to this@plus, )) - public operator fun C.minus(other: Symbol): LabeledPolynomial = + public override operator fun C.minus(other: Symbol): LabeledPolynomial = if (isZero()) LabeledPolynomial(mapOf( mapOf(other to 1U) to -constantOne, )) @@ -291,13 +291,13 @@ public class LabeledPolynomialSpace>( mapOf(other to 1U) to -constantOne, emptyMap() to this@minus, )) - public operator fun C.times(other: Symbol): LabeledPolynomial = + public override operator fun C.times(other: Symbol): LabeledPolynomial = if (isZero()) zero else LabeledPolynomial(mapOf( mapOf(other to 1U) to this@times, )) - public operator fun Symbol.plus(other: C): LabeledPolynomial = + public override operator fun Symbol.plus(other: C): LabeledPolynomial = if (other.isZero()) LabeledPolynomial(mapOf( mapOf(this@plus to 1U) to constantOne, )) @@ -305,7 +305,7 @@ public class LabeledPolynomialSpace>( mapOf(this@plus to 1U) to constantOne, emptyMap() to other, )) - public operator fun Symbol.minus(other: C): LabeledPolynomial = + public override operator fun Symbol.minus(other: C): LabeledPolynomial = if (other.isZero()) LabeledPolynomial(mapOf( mapOf(this@minus to 1U) to -constantOne, )) @@ -313,7 +313,7 @@ public class LabeledPolynomialSpace>( mapOf(this@minus to 1U) to -constantOne, emptyMap() to other, )) - public operator fun Symbol.times(other: C): LabeledPolynomial = + public override operator fun Symbol.times(other: C): LabeledPolynomial = if (other.isZero()) zero else LabeledPolynomial(mapOf( mapOf(this@times to 1U) to other, @@ -430,7 +430,15 @@ public class LabeledPolynomialSpace>( if (value == 0) zero else LabeledPolynomial(mapOf(emptyMap() to value)) - public operator fun Symbol.plus(other: Symbol): LabeledPolynomial = + public override operator fun Symbol.unaryPlus(): LabeledPolynomial = + LabeledPolynomial(mapOf( + mapOf(this to 1U) to constantOne, + )) + public override operator fun Symbol.unaryMinus(): LabeledPolynomial = + LabeledPolynomial(mapOf( + mapOf(this to 1U) to -constantOne, + )) + public override operator fun Symbol.plus(other: Symbol): LabeledPolynomial = if (this == other) LabeledPolynomial(mapOf( mapOf(this to 1U) to constantOne * 2 )) @@ -438,13 +446,13 @@ public class LabeledPolynomialSpace>( mapOf(this to 1U) to constantOne, mapOf(other to 1U) to constantOne, )) - public operator fun Symbol.minus(other: Symbol): LabeledPolynomial = + public override operator fun Symbol.minus(other: Symbol): LabeledPolynomial = if (this == other) zero else LabeledPolynomial(mapOf( mapOf(this to 1U) to constantOne, mapOf(other to 1U) to -constantOne, )) - public operator fun Symbol.times(other: Symbol): LabeledPolynomial = + public override operator fun Symbol.times(other: Symbol): LabeledPolynomial = if (this == other) LabeledPolynomial(mapOf( mapOf(this to 2U) to constantOne )) @@ -452,7 +460,7 @@ public class LabeledPolynomialSpace>( mapOf(this to 1U, other to 1U) to constantOne, )) - public operator fun Symbol.plus(other: LabeledPolynomial): LabeledPolynomial = + public override operator fun Symbol.plus(other: LabeledPolynomial): LabeledPolynomial = with(other.coefficients) { if (isEmpty()) LabeledPolynomial(mapOf(mapOf(this@plus to 1u) to constantOne)) else LabeledPolynomial( @@ -467,7 +475,7 @@ public class LabeledPolynomialSpace>( } ) } - public operator fun Symbol.minus(other: LabeledPolynomial): LabeledPolynomial = + public override operator fun Symbol.minus(other: LabeledPolynomial): LabeledPolynomial = with(other.coefficients) { if (isEmpty()) LabeledPolynomial(mapOf(mapOf(this@minus to 1u) to constantOne)) else LabeledPolynomial( @@ -484,13 +492,13 @@ public class LabeledPolynomialSpace>( } ) } - public operator fun Symbol.times(other: LabeledPolynomial): LabeledPolynomial = + public override operator fun Symbol.times(other: LabeledPolynomial): LabeledPolynomial = LabeledPolynomial( other.coefficients .mapKeys { (degs, _) -> degs.toMutableMap().also{ it[this] = if (this in it) it[this]!! + 1U else 1U } } ) - public operator fun LabeledPolynomial.plus(other: Symbol): LabeledPolynomial = + public override operator fun LabeledPolynomial.plus(other: Symbol): LabeledPolynomial = with(coefficients) { if (isEmpty()) LabeledPolynomial(mapOf(mapOf(other to 1u) to constantOne)) else LabeledPolynomial( @@ -505,7 +513,7 @@ public class LabeledPolynomialSpace>( } ) } - public operator fun LabeledPolynomial.minus(other: Symbol): LabeledPolynomial = + public override operator fun LabeledPolynomial.minus(other: Symbol): LabeledPolynomial = with(coefficients) { if (isEmpty()) LabeledPolynomial(mapOf(mapOf(other to 1u) to constantOne)) else LabeledPolynomial( @@ -520,7 +528,7 @@ public class LabeledPolynomialSpace>( } ) } - public operator fun LabeledPolynomial.times(other: Symbol): LabeledPolynomial = + public override operator fun LabeledPolynomial.times(other: Symbol): LabeledPolynomial = LabeledPolynomial( coefficients .mapKeys { (degs, _) -> degs.toMutableMap().also{ it[other] = if (other in it) it[other]!! + 1U else 1U } } @@ -604,7 +612,7 @@ public class LabeledPolynomialSpace>( * As consequence all values in the map are positive integers. Also, if the polynomial is constant, the map is empty. * And keys of the map is the same as in [variables]. */ - public val LabeledPolynomial.degrees: Map + public override val LabeledPolynomial.degrees: Map get() = buildMap { coefficients.entries.forEach { (degs, c) -> @@ -613,10 +621,20 @@ public class LabeledPolynomialSpace>( } } } + /** + * Counts degree of the polynomial by the specified [variable]. + */ + public override fun LabeledPolynomial.degreeBy(variable: Symbol): UInt = + coefficients.entries.maxOfOrNull { (degs, c) -> if (c.isZero()) 0u else degs.getOrElse(variable) { 0u } } ?: 0u + /** + * Counts degree of the polynomial by the specified [variables]. + */ + public override fun LabeledPolynomial.degreeBy(variables: Collection): UInt = + coefficients.entries.maxOfOrNull { (degs, c) -> if (c.isZero()) 0u else degs.filterKeys { it in variables }.values.sum() } ?: 0u /** * Set of all variables that appear in the polynomial in positive exponents. */ - public val LabeledPolynomial.variables: Set + public override val LabeledPolynomial.variables: Set get() = buildSet { coefficients.entries.forEach { (degs, c) -> if (c.isNotZero()) addAll(degs.keys) } @@ -624,7 +642,7 @@ public class LabeledPolynomialSpace>( /** * Count of all variables that appear in the polynomial in positive exponents. */ - public val LabeledPolynomial.countOfVariables: Int get() = variables.size + public override val LabeledPolynomial.countOfVariables: Int get() = variables.size /** * Checks if the instant is constant polynomial (of degree no more than 0) over considered ring. diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt index 599660b52..00dd3bb47 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt @@ -63,14 +63,16 @@ public fun > A.LabeledRationalFunction(numeratorCoefficients: Map< public class LabeledRationalFunctionSpace>( public val ring: A, ) : - RationalFunctionalSpaceOverPolynomialSpace< + MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSpace< C, + Symbol, LabeledPolynomial, LabeledRationalFunction, LabeledPolynomialSpace, >, - PolynomialSpaceOfFractions< + MultivariatePolynomialSpaceOfFractions< C, + Symbol, LabeledPolynomial, LabeledRationalFunction, >() { @@ -113,33 +115,6 @@ public class LabeledRationalFunctionSpace>( return numerator * other.denominator equalsTo other.numerator * denominator } - /** - * Map that associates variables (that appear in the polynomial in positive exponents) with their most exponents - * in which they are appeared in the polynomial. - * - * As consequence all values in the map are positive integers. Also, if the polynomial is constant, the map is empty. - * And keys of the map is the same as in [variables]. - */ - public val LabeledPolynomial.degrees: Map get() = polynomialRing { degrees } - /** - * Set of all variables that appear in the polynomial in positive exponents. - */ - public val LabeledPolynomial.variables: Set get() = polynomialRing { variables } - /** - * Count of all variables that appear in the polynomial in positive exponents. - */ - public val LabeledPolynomial.countOfVariables: Int get() = polynomialRing { countOfVariables } - - /** - * Count of all variables that appear in the polynomial in positive exponents. - */ - public val LabeledRationalFunction.variables: Set - get() = numerator.variables union denominator.variables - /** - * Count of all variables that appear in the polynomial in positive exponents. - */ - public val LabeledRationalFunction.countOfVariables: Int get() = variables.size - // TODO: Разобрать // operator fun invoke(arg: Map): LabeledRationalFunction = 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 f8d7d5a36..224e18832 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 @@ -5,7 +5,8 @@ package space.kscience.kmath.functions -import space.kscience.kmath.operations.* +import space.kscience.kmath.operations.Ring +import space.kscience.kmath.operations.invoke import kotlin.js.JsName import kotlin.jvm.JvmName @@ -413,4 +414,61 @@ public interface PolynomialSpaceOverRing, A: Ring> : Poly * Instance of unit constant (unit of the underlying ring). */ public override val constantOne: C get() = ring.one +} + +public interface MultivariatePolynomialSpace>: PolynomialSpace { + public operator fun V.plus(other: Int): P + public operator fun V.minus(other: Int): P + public operator fun V.times(other: Int): P + + public operator fun Int.plus(other: V): P + public operator fun Int.minus(other: V): P + public operator fun Int.times(other: V): P + + public operator fun C.plus(other: V): P + public operator fun C.minus(other: V): P + public operator fun C.times(other: V): P + + public operator fun V.plus(other: C): P + public operator fun V.minus(other: C): P + public operator fun V.times(other: C): P + + public operator fun V.unaryPlus(): P + public operator fun V.unaryMinus(): P + public operator fun V.plus(other: V): P + public operator fun V.minus(other: V): P + public operator fun V.times(other: V): P + + public operator fun V.plus(other: P): P + public operator fun V.minus(other: P): P + public operator fun V.times(other: P): P + + public operator fun P.plus(other: V): P + public operator fun P.minus(other: V): P + public operator fun P.times(other: V): P + + /** + * Map that associates variables (that appear in the polynomial in positive exponents) with their most exponents + * in which they are appeared in the polynomial. + * + * As consequence all values in the map are positive integers. Also, if the polynomial is constant, the map is empty. + * And keys of the map is the same as in [variables]. + */ + public val P.degrees: Map + /** + * Counts degree of the polynomial by the specified [variable]. + */ + public fun P.degreeBy(variable: V): UInt = degrees.getOrElse(variable) { 0u } + /** + * Counts degree of the polynomial by the specified [variables]. + */ + public fun P.degreeBy(variables: Collection): UInt + /** + * Set of all variables that appear in the polynomial in positive exponents. + */ + public val P.variables: Set get() = degrees.keys + /** + * Count of all variables that appear in the polynomial in positive exponents. + */ + public val P.countOfVariables: Int get() = variables.size } \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt index 90e3bdbb1..c5fcde8ed 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt @@ -1306,4 +1306,201 @@ public abstract class PolynomialSpaceOfFractions< * Instance of unit polynomial (unit of the rational functions ring). */ public override val one: R get() = constructRationalFunction(polynomialOne) +} + +public interface MultivariateRationalFunctionalSpace< + C, + V, + P: Polynomial, + R: RationalFunction + >: RationalFunctionalSpace { + public operator fun V.plus(other: Int): P + public operator fun V.minus(other: Int): P + public operator fun V.times(other: Int): P + + public operator fun Int.plus(other: V): P + public operator fun Int.minus(other: V): P + public operator fun Int.times(other: V): P + + public operator fun C.plus(other: V): P + public operator fun C.minus(other: V): P + public operator fun C.times(other: V): P + + public operator fun V.plus(other: C): P + public operator fun V.minus(other: C): P + public operator fun V.times(other: C): P + + public operator fun V.unaryPlus(): P + public operator fun V.unaryMinus(): P + public operator fun V.plus(other: V): P + public operator fun V.minus(other: V): P + public operator fun V.times(other: V): P + + public operator fun V.plus(other: P): P + public operator fun V.minus(other: P): P + public operator fun V.times(other: P): P + + public operator fun P.plus(other: V): P + public operator fun P.minus(other: V): P + public operator fun P.times(other: V): P + + public operator fun V.plus(other: R): R + public operator fun V.minus(other: R): R + public operator fun V.times(other: R): R + + public operator fun R.plus(other: V): R + public operator fun R.minus(other: V): R + public operator fun R.times(other: V): R + + /** + * Map that associates variables (that appear in the polynomial in positive exponents) with their most exponents + * in which they are appeared in the polynomial. + * + * As consequence all values in the map are positive integers. Also, if the polynomial is constant, the map is empty. + * And keys of the map is the same as in [variables]. + */ + public val P.degrees: Map + /** + * Counts degree of the polynomial by the specified [variable]. + */ + public fun P.degreeBy(variable: V): UInt = degrees.getOrElse(variable) { 0u } + /** + * Counts degree of the polynomial by the specified [variables]. + */ + public fun P.degreeBy(variables: Collection): UInt + /** + * Set of all variables that appear in the polynomial in positive exponents. + */ + public val P.variables: Set get() = degrees.keys + /** + * Count of all variables that appear in the polynomial in positive exponents. + */ + public val P.countOfVariables: Int get() = variables.size + + /** + * Set of all variables that appear in the polynomial in positive exponents. + */ + public val R.variables: Set get() = numerator.variables union denominator.variables + /** + * Count of all variables that appear in the polynomial in positive exponents. + */ + public val R.countOfVariables: Int get() = variables.size +} + +public interface MultivariateRationalFunctionalSpaceOverRing< + C, + V, + P: Polynomial, + R: RationalFunction, + A: Ring + > : RationalFunctionalSpaceOverRing, MultivariateRationalFunctionalSpace + +public interface MultivariateRationalFunctionalSpaceOverPolynomialSpace< + C, + V, + P: Polynomial, + R: RationalFunction, + AP: PolynomialSpace, + > : RationalFunctionalSpaceOverPolynomialSpace, MultivariateRationalFunctionalSpace + +public interface MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSpace< + C, + V, + P: Polynomial, + R: RationalFunction, + AP: MultivariatePolynomialSpace, + > : MultivariateRationalFunctionalSpaceOverPolynomialSpace { + public override operator fun V.plus(other: Int): P = polynomialRing { this@plus + other } + public override operator fun V.minus(other: Int): P = polynomialRing { this@minus - other } + public override operator fun V.times(other: Int): P = polynomialRing { this@times * other } + + public override operator fun Int.plus(other: V): P = polynomialRing { this@plus + other } + public override operator fun Int.minus(other: V): P = polynomialRing { this@minus - other } + public override operator fun Int.times(other: V): P = polynomialRing { this@times * other } + + public override operator fun C.plus(other: V): P = polynomialRing { this@plus + other } + public override operator fun C.minus(other: V): P = polynomialRing { this@minus - other } + public override operator fun C.times(other: V): P = polynomialRing { this@times * other } + + public override operator fun V.plus(other: C): P = polynomialRing { this@plus + other } + public override operator fun V.minus(other: C): P = polynomialRing { this@minus - other } + public override operator fun V.times(other: C): P = polynomialRing { this@times * other } + + public override operator fun V.unaryPlus(): P = polynomialRing { +this@unaryPlus } + public override operator fun V.unaryMinus(): P = polynomialRing { -this@unaryMinus } + public override operator fun V.plus(other: V): P = polynomialRing { this@plus + other } + public override operator fun V.minus(other: V): P = polynomialRing { this@minus - other } + public override operator fun V.times(other: V): P = polynomialRing { this@times * other } + + public override operator fun V.plus(other: P): P = polynomialRing { this@plus + other } + public override operator fun V.minus(other: P): P = polynomialRing { this@minus - other } + public override operator fun V.times(other: P): P = polynomialRing { this@times * other } + + public override operator fun P.plus(other: V): P = polynomialRing { this@plus + other } + public override operator fun P.minus(other: V): P = polynomialRing { this@minus - other } + public override operator fun P.times(other: V): P = polynomialRing { this@times * other } + + /** + * Map that associates variables (that appear in the polynomial in positive exponents) with their most exponents + * in which they are appeared in the polynomial. + * + * As consequence all values in the map are positive integers. Also, if the polynomial is constant, the map is empty. + * And keys of the map is the same as in [variables]. + */ + public override val P.degrees: Map get() = polynomialRing { degrees } + /** + * Counts degree of the polynomial by the specified [variable]. + */ + public override fun P.degreeBy(variable: V): UInt = polynomialRing { degreeBy(variable) } + /** + * Counts degree of the polynomial by the specified [variables]. + */ + public override fun P.degreeBy(variables: Collection): UInt = polynomialRing { degreeBy(variables) } + /** + * Set of all variables that appear in the polynomial in positive exponents. + */ + public override val P.variables: Set get() = polynomialRing { variables } + /** + * Count of all variables that appear in the polynomial in positive exponents. + */ + public override val P.countOfVariables: Int get() = polynomialRing { countOfVariables } +} + +public abstract class MultivariatePolynomialSpaceOfFractions< + C, + V, + P: Polynomial, + R: RationalFunction, + > : MultivariateRationalFunctionalSpace, PolynomialSpaceOfFractions() { + public override operator fun V.plus(other: R): R = + constructRationalFunction( + this * other.denominator + other.numerator, + other.denominator + ) + public override operator fun V.minus(other: R): R = + constructRationalFunction( + this * other.denominator - other.numerator, + other.denominator + ) + public override operator fun V.times(other: R): R = + constructRationalFunction( + this * other.numerator, + other.denominator + ) + + public override operator fun R.plus(other: V): R = + constructRationalFunction( + numerator + denominator * other, + denominator + ) + public override operator fun R.minus(other: V): R = + constructRationalFunction( + numerator - denominator * other, + denominator + ) + public override operator fun R.times(other: V): R = + constructRationalFunction( + numerator * other, + denominator + ) } \ No newline at end of file -- 2.34.1 From 5b8d6b601e54526c0148bd391e380d305ad4496a Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Tue, 22 Mar 2022 15:37:19 +0300 Subject: [PATCH 051/123] Added `degreeBy` to `Numbered...`. --- .../kscience/kmath/functions/NumberedPolynomial.kt | 12 ++++++++++++ .../kmath/functions/NumberedRationalFunction.kt | 8 ++++++++ 2 files changed, 20 insertions(+) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt index 1f37a1c2b..570ccce8e 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -471,6 +471,18 @@ public open class NumberedPolynomialSpace>( } } } + /** + * Counts degree of the polynomial by the specified [variable]. + */ + public fun NumberedPolynomial.degreeBy(variable: Int): UInt = + coefficients.entries.maxOfOrNull { (degs, c) -> if (c.isZero()) 0u else degs.getOrElse(variable) { 0u } } ?: 0u + /** + * Counts degree of the polynomial by the specified [variables]. + */ + public fun NumberedPolynomial.degreeBy(variables: Collection): UInt = + coefficients.entries.maxOfOrNull { (degs, c) -> + if (c.isZero()) 0u else degs.withIndex().filter { (index, _) -> index in variables }.sumOf { it.value } + } ?: 0u /** * Count of variables occurring in the polynomial with positive power. If there is no such variable, * the result is `0`. diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt index b32f01f2a..2a4d942a6 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt @@ -126,6 +126,14 @@ public class NumberedRationalFunctionSpace> ( * And last index of the list is [lastVariable]. */ public val NumberedPolynomial.degrees: List get() = polynomialRing { degrees } + /** + * Counts degree of the polynomial by the specified [variable]. + */ + public fun NumberedPolynomial.degreeBy(variable: Int): UInt = polynomialRing { degreeBy(variable) } + /** + * Counts degree of the polynomial by the specified [variables]. + */ + public fun NumberedPolynomial.degreeBy(variables: Collection): UInt = polynomialRing { degreeBy(variables) } /** * Count of variables occurring in the polynomial with positive power. If there is no such variable, * the result is `0`. -- 2.34.1 From d75a41482d09a7b97c049924df60b370ee14497c Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Tue, 22 Mar 2022 17:09:33 +0300 Subject: [PATCH 052/123] Added fabrics for `LabeledPolynomial` and `NumberedPolynomial`. --- .../kmath/functions/LabeledPolynomial.kt | 131 ++++++++------ .../kmath/functions/NumberedPolynomial.kt | 171 ++++++++---------- 2 files changed, 158 insertions(+), 144 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt index 29aeb6bb0..3d1b91f7b 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt @@ -54,59 +54,86 @@ internal constructor( */ internal fun Map.cleanUp() = filterValues { it > 0U } -//context(LabeledPolynomialSpace>) -//@Suppress("FunctionName") -//internal fun LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = false) : LabeledPolynomial { -// if (!toCheckInput) return LabeledPolynomial(coefs) -// -// val fixedCoefs = mutableMapOf, C>() -// -// for (entry in coefs) { -// val key = entry.key.cleanUp() -// val value = entry.value -// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value -// } -// -// return LabeledPolynomial( -// fixedCoefs.filterValues { it.isNotZero() } -// ) -//} -// -//context(LabeledPolynomialSpace>) -//@Suppress("FunctionName") -//internal fun LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = false) : LabeledPolynomial { -// if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) -// -// val fixedCoefs = mutableMapOf, C>() -// -// for (entry in pairs) { -// val key = entry.first.cleanUp() -// val value = entry.second -// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value -// } -// -// return LabeledPolynomial( -// fixedCoefs.filterValues { it.isNotZero() } -// ) -//} -// -//// TODO: Do not know how to make it without context receivers -//context(LabeledPolynomialSpace>) -//@Suppress("FunctionName") -//public fun LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) -// -//context(LabeledPolynomialSpace>) -//@Suppress("FunctionName") -//public fun LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) -// -//context(LabeledPolynomialSpace>) -//@Suppress("FunctionName") -//public fun LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(pairs.toList(), toCheckInput = true) -// -//context(LabeledPolynomialSpace>) -//public fun Symbol.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1u) to constantOne)) +// Waiting for context receivers :( TODO: Replace with context receivers when they will be available -public fun C.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to this)) +@Suppress("FunctionName", "NOTHING_TO_INLINE") +internal inline fun > LabeledPolynomialSpace.LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(coefs, toCheckInput) +@Suppress("FunctionName") +internal fun > A.LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : LabeledPolynomial { + if (!toCheckInput) return LabeledPolynomial(coefs) + + val fixedCoefs = mutableMapOf, C>() + + for (entry in coefs) { + val key = entry.key.cleanUp() + val value = entry.value + fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value + } + + return LabeledPolynomial( + fixedCoefs.filterValues { it != zero } + ) +} + +@Suppress("FunctionName", "NOTHING_TO_INLINE") +internal inline fun > LabeledPolynomialSpace.LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(pairs, toCheckInput) +@Suppress("FunctionName") +internal fun > A.LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : LabeledPolynomial { + if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) + + val fixedCoefs = mutableMapOf, C>() + + for (entry in pairs) { + val key = entry.first.cleanUp() + val value = entry.second + fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value + } + + return LabeledPolynomial( + fixedCoefs.filterValues { it != zero } + ) +} + +@Suppress("FunctionName", "NOTHING_TO_INLINE") +internal inline fun > LabeledPolynomialSpace.LabeledPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(pairs = pairs, toCheckInput = toCheckInput) +@Suppress("FunctionName") +internal fun > A.LabeledPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : LabeledPolynomial { + if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) + + val fixedCoefs = mutableMapOf, C>() + + for (entry in pairs) { + val key = entry.first.cleanUp() + val value = entry.second + fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value + } + + return LabeledPolynomial( + fixedCoefs.filterValues { it != zero } + ) +} + +@Suppress("FunctionName") +public fun > A.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) +@Suppress("FunctionName") +public fun > LabeledPolynomialSpace.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) + +@Suppress("FunctionName") +public fun > A.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) +@Suppress("FunctionName") +public fun > LabeledPolynomialSpace.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) + +@Suppress("FunctionName") +public fun > A.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs, toCheckInput = true) +@Suppress("FunctionName") +public fun > LabeledPolynomialSpace.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs, toCheckInput = true) + +//context(A) +//public fun > Symbol.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1u) to one)) +//context(LabeledPolynomialSpace) +//public fun > Symbol.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1u) to constantOne)) + +public fun C.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to this)) /** * Space of polynomials. diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt index 570ccce8e..411409e39 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -53,56 +53,86 @@ internal constructor( */ internal fun List.cleanUp() = subList(0, indexOfLast { it != 0U } + 1) -//context(NumberedPolynomialSpace>) -//@Suppress("FunctionName") -//internal fun NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean = false) : NumberedPolynomial { -// if (!toCheckInput) return NumberedPolynomial(coefs) -// -// val fixedCoefs = mutableMapOf, C>() -// -// for (entry in coefs) { -// val key = entry.key.cleanUp() -// val value = entry.value -// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value -// } -// -// return NumberedPolynomial( -// fixedCoefs.filterValues { it.isNotZero() } -// ) -//} -// -//context(NumberedPolynomialSpace>) -//@Suppress("FunctionName") -//internal fun NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = false) : NumberedPolynomial { -// if (!toCheckInput) return NumberedPolynomial(pairs.toMap()) -// -// val fixedCoefs = mutableMapOf, C>() -// -// for (entry in pairs) { -// val key = entry.first.cleanUp() -// val value = entry.second -// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value -// } -// -// return NumberedPolynomial( -// fixedCoefs.filterValues { it.isNotZero() } -// ) -//} -// -//// TODO: Do not know how to make it without context receivers -//context(NumberedPolynomialSpace>) -//@Suppress("FunctionName") -//public fun NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, toCheckInput = true) -// -//context(NumberedPolynomialSpace>) -//@Suppress("FunctionName") -//public fun NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, toCheckInput = true) -// -//context(NumberedPolynomialSpace>) -//@Suppress("FunctionName") -//public fun NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(pairs.toList(), toCheckInput = true) +// Waiting for context receivers :( TODO: Replace with context receivers when they will be available -public fun C.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomial(mapOf(emptyList() to this)) +@Suppress("FunctionName", "NOTHING_TO_INLINE") +internal inline fun > NumberedPolynomialSpace.NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(coefs, toCheckInput) +@Suppress("FunctionName") +internal fun > A.NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : NumberedPolynomial { + if (!toCheckInput) return NumberedPolynomial(coefs) + + val fixedCoefs = mutableMapOf, C>() + + for (entry in coefs) { + val key = entry.key.cleanUp() + val value = entry.value + fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value + } + + return NumberedPolynomial( + fixedCoefs.filterValues { it != zero } + ) +} + +@Suppress("FunctionName", "NOTHING_TO_INLINE") +internal inline fun > NumberedPolynomialSpace.NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(pairs, toCheckInput) +@Suppress("FunctionName") +internal fun > A.NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : NumberedPolynomial { + if (!toCheckInput) return NumberedPolynomial(pairs.toMap()) + + val fixedCoefs = mutableMapOf, C>() + + for (entry in pairs) { + val key = entry.first.cleanUp() + val value = entry.second + fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value + } + + return NumberedPolynomial( + fixedCoefs.filterValues { it != zero } + ) +} + +@Suppress("FunctionName", "NOTHING_TO_INLINE") +internal inline fun > NumberedPolynomialSpace.NumberedPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(pairs = pairs, toCheckInput = toCheckInput) +@Suppress("FunctionName") +internal fun > A.NumberedPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : NumberedPolynomial { + if (!toCheckInput) return NumberedPolynomial(pairs.toMap()) + + val fixedCoefs = mutableMapOf, C>() + + for (entry in pairs) { + val key = entry.first.cleanUp() + val value = entry.second + fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value + } + + return NumberedPolynomial( + fixedCoefs.filterValues { it != zero } + ) +} + +@Suppress("FunctionName") +public fun > A.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, toCheckInput = true) +@Suppress("FunctionName") +public fun > NumberedPolynomialSpace.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, toCheckInput = true) + +@Suppress("FunctionName") +public fun > A.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, toCheckInput = true) +@Suppress("FunctionName") +public fun > NumberedPolynomialSpace.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, toCheckInput = true) + +@Suppress("FunctionName") +public fun > A.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs, toCheckInput = true) +@Suppress("FunctionName") +public fun > NumberedPolynomialSpace.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs, toCheckInput = true) + +//context(A) +//public fun > Symbol.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomial(mapOf(mapOf(this to 1u) to one)) +//context(NumberedPolynomialSpace) +//public fun > Symbol.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomial(mapOf(mapOf(this to 1u) to constantOne)) + +public fun C.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomial(mapOf(emptyList() to this)) /** * Space of polynomials. @@ -574,47 +604,4 @@ public open class NumberedPolynomialSpace>( for ((degs, c) in this) if (c.isZero()) this.remove(degs) } } - - @Suppress("FunctionName") - internal fun NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean = false) : NumberedPolynomial { - if (!toCheckInput) return NumberedPolynomial(coefs) - - val fixedCoefs = mutableMapOf, C>() - - for (entry in coefs) { - val key = entry.key.cleanUp() - val value = entry.value - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return NumberedPolynomial( - fixedCoefs.filterValues { it.isNotZero() } - ) - } - - @Suppress("FunctionName") - internal fun NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = false) : NumberedPolynomial { - if (!toCheckInput) return NumberedPolynomial(pairs.toMap()) - - val fixedCoefs = mutableMapOf, C>() - - for (entry in pairs) { - val key = entry.first.cleanUp() - val value = entry.second - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return NumberedPolynomial( - fixedCoefs.filterValues { it.isNotZero() } - ) - } - - @Suppress("FunctionName") - public fun NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, toCheckInput = true) - - @Suppress("FunctionName") - public fun NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, toCheckInput = true) - - @Suppress("FunctionName") - public fun NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(pairs.toList(), toCheckInput = true) } \ No newline at end of file -- 2.34.1 From 0a5122a974b1e6a6d888115e36bbe3118db931f3 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Tue, 22 Mar 2022 19:40:55 +0300 Subject: [PATCH 053/123] Prototyped DSL-like constructor for `NumberedPolynomial`. --- .../kmath/functions/NumberedPolynomial.kt | 58 ++++++++++++++++++- .../kmath/functions/labeledPolynomialUtil.kt | 47 --------------- .../kmath/functions/listPolynomialUtil.kt | 2 +- 3 files changed, 58 insertions(+), 49 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt index 411409e39..80998d6bf 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -5,6 +5,7 @@ package space.kscience.kmath.functions +import space.kscience.kmath.operations.invoke import space.kscience.kmath.operations.Ring import space.kscience.kmath.operations.ScaleOperations import kotlin.contracts.InvocationKind @@ -132,7 +133,59 @@ public fun > NumberedPolynomialSpace.NumberedPolynomial(vara //context(NumberedPolynomialSpace) //public fun > Symbol.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomial(mapOf(mapOf(this to 1u) to constantOne)) -public fun C.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomial(mapOf(emptyList() to this)) +//context(A) +//public fun C.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomial(mapOf(emptyList() to this)) + +@DslMarker +internal annotation class NumberedPolynomialConstructorDSL + +@NumberedPolynomialConstructorDSL +public class NumberedPolynomialTermSignatureBuilder { + private val signature: MutableList = ArrayList() + public fun build(): List = signature + public infix fun Int.inPowerOf(deg: UInt) { + if (this > signature.lastIndex) { + signature.addAll(List(this - signature.lastIndex - 1) { 0u }) + signature.add(deg) + } else { + signature[this] = deg + } + } + public infix fun Int.to(deg: UInt): Unit = this inPowerOf deg +} + +@NumberedPolynomialConstructorDSL +public class NumberedPolynomialBuilderOverRing internal constructor(internal val context: Ring, capacity: Int = 0) { + private val coefficients: MutableMap, C> = LinkedHashMap(capacity) + public fun build(): NumberedPolynomial = NumberedPolynomial(coefficients) + public operator fun C.invoke(block: NumberedPolynomialTermSignatureBuilder.() -> Unit) { + val signature = NumberedPolynomialTermSignatureBuilder().apply(block).build() + coefficients[signature] = context { coefficients.getOrElse(signature) { zero } + this@invoke } + } +} + +@NumberedPolynomialConstructorDSL +public class NumberedPolynomialBuilderOverPolynomialSpace internal constructor(internal val context: NumberedPolynomialSpace, capacity: Int = 0) { + private val coefficients: MutableMap, C> = LinkedHashMap(capacity) + public fun build(): NumberedPolynomial = NumberedPolynomial(coefficients) + public operator fun C.invoke(block: NumberedPolynomialTermSignatureBuilder.() -> Unit) { + val signature = NumberedPolynomialTermSignatureBuilder().apply(block).build() + coefficients[signature] = context { coefficients.getOrElse(signature) { constantZero } + this@invoke } + } +} + +@NumberedPolynomialConstructorDSL +@Suppress("FunctionName") +public fun > A.NumberedPolynomial(block: NumberedPolynomialBuilderOverRing.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilderOverRing(this).apply(block).build() +@NumberedPolynomialConstructorDSL +@Suppress("FunctionName") +public fun > A.NumberedPolynomial(capacity: Int, block: NumberedPolynomialBuilderOverRing.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilderOverRing(this, capacity).apply(block).build() +@NumberedPolynomialConstructorDSL +@Suppress("FunctionName") +public fun > NumberedPolynomialSpace.NumberedPolynomial(block: NumberedPolynomialBuilderOverPolynomialSpace.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilderOverPolynomialSpace(this).apply(block).build() +@NumberedPolynomialConstructorDSL +@Suppress("FunctionName") +public fun > NumberedPolynomialSpace.NumberedPolynomial(capacity: Int, block: NumberedPolynomialBuilderOverPolynomialSpace.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilderOverPolynomialSpace(this, capacity).apply(block).build() /** * Space of polynomials. @@ -604,4 +657,7 @@ public open class NumberedPolynomialSpace>( for ((degs, c) in this) if (c.isZero()) this.remove(degs) } } + + // TODO: Move to other constructors with context receiver + public fun C.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomial(mapOf(emptyList() to this)) } \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt index 27fdd7d7b..88d357413 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt @@ -17,53 +17,6 @@ import kotlin.contracts.contract // TODO: Docs -//// TODO: Reuse underlying ring extensions -// -//context(LabeledPolynomialSpace) -//@Suppress("NOTHING_TO_INLINE") -//fun > numberConstant(value: Int): C = ring { number(value) } -// -//context(LabeledPolynomialSpace) -//fun > power(arg: C, pow: UInt): C = ring { power(arg, pow) } -// -//context(LabeledPolynomialSpace) -//fun > multiplyWithPower(base: C, arg: C, pow: UInt): C = ring { multiplyWithPower(base, arg, pow) } -// - -// -//context(LabeledPolynomialSpace) -//fun > power(arg: Symbol, pow: UInt): LabeledPolynomial = -// if (pow == 0U) one -// else LabeledPolynomial(mapOf( -// mapOf(arg to pow) to constantOne -// )) -// - -// -//context(LabeledPolynomialSpace) -//fun > number(value: Int): LabeledPolynomial = ring { LabeledPolynomial(mapOf(emptyMap() to number(value))) } -// -//context(LabeledPolynomialSpace) -//fun > multiplyWithPower(base: LabeledPolynomial, arg: LabeledPolynomial, pow: UInt): LabeledPolynomial = -// when { -// arg.isZero() && pow > 0U -> base -// arg.isOne() -> base -// arg.isMinusOne() -> if (pow % 2U == 0U) base else -base -// else -> multiplyWithPowerInternalLogic(base, arg, pow) -// } -// -//// Trivial but very slow -//context(LabeledPolynomialSpace) -//internal tailrec fun > multiplyWithPowerInternalLogic(base: LabeledPolynomial, arg: LabeledPolynomial, exponent: UInt): LabeledPolynomial = -// when { -// exponent == 0U -> base -// exponent == 1U -> base * arg -// exponent % 2U == 0U -> multiplyWithPowerInternalLogic(base, arg * arg, exponent / 2U) -// exponent % 2U == 1U -> multiplyWithPowerInternalLogic(base * arg, arg * arg, exponent / 2U) -// else -> error("Error in raising ring instant by unsigned integer: got reminder by division by 2 different from 0 and 1") -// } -// - /** * Creates a [LabeledPolynomialSpace] over a received ring. */ diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listPolynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listPolynomialUtil.kt index df5ba593a..35155d09d 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listPolynomialUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listPolynomialUtil.kt @@ -124,7 +124,7 @@ public fun ListPolynomial.substitute(ring: Ring, arg: ListPolynomial = MutableList(thisDegree * argDegree + 1) { constantZero } resultCoefs[0] = coefficients[thisDegree] -- 2.34.1 From 420bf05b22fa107ad33cf2bb5b05795c8b22b96e Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Tue, 22 Mar 2022 19:42:59 +0300 Subject: [PATCH 054/123] Fixed annoying JVM clashes :expressionless: --- .../kscience/kmath/functions/Polynomial.kt | 24 ++++++++ .../kmath/functions/RationalFunction.kt | 61 +++++++++++++++++++ 2 files changed, 85 insertions(+) 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 224e18832..d44c47dd6 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 @@ -416,35 +416,59 @@ public interface PolynomialSpaceOverRing, A: Ring> : Poly public override val constantOne: C get() = ring.one } +@Suppress("INAPPLICABLE_JVM_NAME") public interface MultivariatePolynomialSpace>: PolynomialSpace { + @JvmName("VariableIntPlus") public operator fun V.plus(other: Int): P + @JvmName("VariableIntMinus") public operator fun V.minus(other: Int): P + @JvmName("VariableIntMinusTimes") public operator fun V.times(other: Int): P + @JvmName("IntVariablePlus") public operator fun Int.plus(other: V): P + @JvmName("IntVariableMinus") public operator fun Int.minus(other: V): P + @JvmName("IntVariableTimes") public operator fun Int.times(other: V): P + @JvmName("ConstantVariablePlus") public operator fun C.plus(other: V): P + @JvmName("ConstantVariableMinus") public operator fun C.minus(other: V): P + @JvmName("ConstantVariableTimes") public operator fun C.times(other: V): P + @JvmName("VariableConstantPlus") public operator fun V.plus(other: C): P + @JvmName("VariableConstantMinus") public operator fun V.minus(other: C): P + @JvmName("VariableConstantTimes") public operator fun V.times(other: C): P + @JvmName("VariableUnaryPlus") public operator fun V.unaryPlus(): P + @JvmName("VariableUnaryMinus") public operator fun V.unaryMinus(): P + @JvmName("VariablePlus") public operator fun V.plus(other: V): P + @JvmName("VariableMinus") public operator fun V.minus(other: V): P + @JvmName("VariableTimes") public operator fun V.times(other: V): P + @JvmName("VariablePolynomialPlus") public operator fun V.plus(other: P): P + @JvmName("VariablePolynomialMinus") public operator fun V.minus(other: P): P + @JvmName("VariablePolynomialTimes") public operator fun V.times(other: P): P + @JvmName("PolynomialVariablePlus") public operator fun P.plus(other: V): P + @JvmName("PolynomialVariableMinus") public operator fun P.minus(other: V): P + @JvmName("PolynomialVariableTimes") public operator fun P.times(other: V): P /** diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt index c5fcde8ed..9c0263c4c 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt @@ -1308,48 +1308,78 @@ public abstract class PolynomialSpaceOfFractions< public override val one: R get() = constructRationalFunction(polynomialOne) } +@Suppress("INAPPLICABLE_JVM_NAME") public interface MultivariateRationalFunctionalSpace< C, V, P: Polynomial, R: RationalFunction >: RationalFunctionalSpace { + @JvmName("VariableIntPlus") public operator fun V.plus(other: Int): P + @JvmName("VariableIntMinus") public operator fun V.minus(other: Int): P + @JvmName("VariableIntMinusTimes") public operator fun V.times(other: Int): P + @JvmName("IntVariablePlus") public operator fun Int.plus(other: V): P + @JvmName("IntVariableMinus") public operator fun Int.minus(other: V): P + @JvmName("IntVariableTimes") public operator fun Int.times(other: V): P + @JvmName("ConstantVariablePlus") public operator fun C.plus(other: V): P + @JvmName("ConstantVariableMinus") public operator fun C.minus(other: V): P + @JvmName("ConstantVariableTimes") public operator fun C.times(other: V): P + @JvmName("VariableConstantPlus") public operator fun V.plus(other: C): P + @JvmName("VariableConstantMinus") public operator fun V.minus(other: C): P + @JvmName("VariableConstantTimes") public operator fun V.times(other: C): P + @JvmName("VariableUnaryPlus") public operator fun V.unaryPlus(): P + @JvmName("VariableUnaryMinus") public operator fun V.unaryMinus(): P + @JvmName("VariablePlus") public operator fun V.plus(other: V): P + @JvmName("VariableMinus") public operator fun V.minus(other: V): P + @JvmName("VariableTimes") public operator fun V.times(other: V): P + @JvmName("VariablePolynomialPlus") public operator fun V.plus(other: P): P + @JvmName("VariablePolynomialMinus") public operator fun V.minus(other: P): P + @JvmName("VariablePolynomialTimes") public operator fun V.times(other: P): P + @JvmName("PolynomialVariablePlus") public operator fun P.plus(other: V): P + @JvmName("PolynomialVariableMinus") public operator fun P.minus(other: V): P + @JvmName("PolynomialVariableTimes") public operator fun P.times(other: V): P + @JvmName("VariableRationalFunctionPlus") public operator fun V.plus(other: R): R + @JvmName("VariableRationalFunctionMinus") public operator fun V.minus(other: R): R + @JvmName("VariableRationalFunctionTimes") public operator fun V.times(other: R): R + @JvmName("RationalFunctionVariablePlus") public operator fun R.plus(other: V): R + @JvmName("RationalFunctionVariableMinus") public operator fun R.minus(other: V): R + @JvmName("RationalFunctionVariableTimes") public operator fun R.times(other: V): R /** @@ -1403,6 +1433,7 @@ public interface MultivariateRationalFunctionalSpaceOverPolynomialSpace< AP: PolynomialSpace, > : RationalFunctionalSpaceOverPolynomialSpace, MultivariateRationalFunctionalSpace +@Suppress("INAPPLICABLE_JVM_NAME") public interface MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSpace< C, V, @@ -1410,34 +1441,57 @@ public interface MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSp R: RationalFunction, AP: MultivariatePolynomialSpace, > : MultivariateRationalFunctionalSpaceOverPolynomialSpace { + @JvmName("VariableIntPlus") public override operator fun V.plus(other: Int): P = polynomialRing { this@plus + other } + @JvmName("VariableIntMinus") public override operator fun V.minus(other: Int): P = polynomialRing { this@minus - other } + @JvmName("VariableIntMinusTimes") public override operator fun V.times(other: Int): P = polynomialRing { this@times * other } + @JvmName("IntVariablePlus") public override operator fun Int.plus(other: V): P = polynomialRing { this@plus + other } + @JvmName("IntVariableMinus") public override operator fun Int.minus(other: V): P = polynomialRing { this@minus - other } + @JvmName("IntVariableTimes") public override operator fun Int.times(other: V): P = polynomialRing { this@times * other } + @JvmName("ConstantVariablePlus") public override operator fun C.plus(other: V): P = polynomialRing { this@plus + other } + @JvmName("ConstantVariableMinus") public override operator fun C.minus(other: V): P = polynomialRing { this@minus - other } + @JvmName("ConstantVariableTimes") public override operator fun C.times(other: V): P = polynomialRing { this@times * other } + @JvmName("VariableConstantPlus") public override operator fun V.plus(other: C): P = polynomialRing { this@plus + other } + @JvmName("VariableConstantMinus") public override operator fun V.minus(other: C): P = polynomialRing { this@minus - other } + @JvmName("VariableConstantTimes") public override operator fun V.times(other: C): P = polynomialRing { this@times * other } + @JvmName("VariableUnaryPlus") public override operator fun V.unaryPlus(): P = polynomialRing { +this@unaryPlus } + @JvmName("VariableUnaryMinus") public override operator fun V.unaryMinus(): P = polynomialRing { -this@unaryMinus } + @JvmName("VariablePlus") public override operator fun V.plus(other: V): P = polynomialRing { this@plus + other } + @JvmName("VariableMinus") public override operator fun V.minus(other: V): P = polynomialRing { this@minus - other } + @JvmName("VariableTimes") public override operator fun V.times(other: V): P = polynomialRing { this@times * other } + @JvmName("VariablePolynomialPlus") public override operator fun V.plus(other: P): P = polynomialRing { this@plus + other } + @JvmName("VariablePolynomialMinus") public override operator fun V.minus(other: P): P = polynomialRing { this@minus - other } + @JvmName("VariablePolynomialTimes") public override operator fun V.times(other: P): P = polynomialRing { this@times * other } + @JvmName("PolynomialVariablePlus") public override operator fun P.plus(other: V): P = polynomialRing { this@plus + other } + @JvmName("PolynomialVariableMinus") public override operator fun P.minus(other: V): P = polynomialRing { this@minus - other } + @JvmName("PolynomialVariableTimes") public override operator fun P.times(other: V): P = polynomialRing { this@times * other } /** @@ -1466,38 +1520,45 @@ public interface MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSp public override val P.countOfVariables: Int get() = polynomialRing { countOfVariables } } +@Suppress("INAPPLICABLE_JVM_NAME") public abstract class MultivariatePolynomialSpaceOfFractions< C, V, P: Polynomial, R: RationalFunction, > : MultivariateRationalFunctionalSpace, PolynomialSpaceOfFractions() { + @JvmName("VariableRationalFunctionPlus") public override operator fun V.plus(other: R): R = constructRationalFunction( this * other.denominator + other.numerator, other.denominator ) + @JvmName("VariableRationalFunctionMinus") public override operator fun V.minus(other: R): R = constructRationalFunction( this * other.denominator - other.numerator, other.denominator ) + @JvmName("VariableRationalFunctionTimes") public override operator fun V.times(other: R): R = constructRationalFunction( this * other.numerator, other.denominator ) + @JvmName("RationalFunctionVariablePlus") public override operator fun R.plus(other: V): R = constructRationalFunction( numerator + denominator * other, denominator ) + @JvmName("RationalFunctionVariableMinus") public override operator fun R.minus(other: V): R = constructRationalFunction( numerator - denominator * other, denominator ) + @JvmName("RationalFunctionVariableTimes") public override operator fun R.times(other: V): R = constructRationalFunction( numerator * other, -- 2.34.1 From 060f0ee35dfdfe510b70c55550a379f47d6106d7 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Fri, 25 Mar 2022 00:57:32 +0300 Subject: [PATCH 055/123] Removed comparability feature. --- .../kmath/functions/LabeledPolynomial.kt | 286 +++++------------ .../functions/LabeledRationalFunction.kt | 58 +--- .../kmath/functions/ListPolynomial.kt | 203 +++--------- .../kmath/functions/ListRationalFunction.kt | 16 +- .../kmath/functions/NumberedPolynomial.kt | 246 ++++----------- .../functions/NumberedRationalFunction.kt | 60 +--- .../kscience/kmath/functions/Polynomial.kt | 86 ----- .../kmath/functions/RationalFunction.kt | 297 ++---------------- .../kmath/functions/listPolynomialUtil.kt | 9 +- .../functions/listRationalFunctionUtil.kt | 6 +- .../kmath/functions/ListPolynomialTest.kt | 156 +-------- .../kmath/functions/ListPolynomialUtilTest.kt | 2 +- 12 files changed, 242 insertions(+), 1183 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt index 3d1b91f7b..908e89534 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt @@ -58,6 +58,8 @@ internal fun Map.cleanUp() = filterValues { it > 0U } @Suppress("FunctionName", "NOTHING_TO_INLINE") internal inline fun > LabeledPolynomialSpace.LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(coefs, toCheckInput) +@Suppress("FunctionName", "NOTHING_TO_INLINE") +internal inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(coefs, toCheckInput) @Suppress("FunctionName") internal fun > A.LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : LabeledPolynomial { if (!toCheckInput) return LabeledPolynomial(coefs) @@ -70,13 +72,13 @@ internal fun > A.LabeledPolynomial(coefs: Map, C fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value } - return LabeledPolynomial( - fixedCoefs.filterValues { it != zero } - ) + return LabeledPolynomial(fixedCoefs) } @Suppress("FunctionName", "NOTHING_TO_INLINE") internal inline fun > LabeledPolynomialSpace.LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(pairs, toCheckInput) +@Suppress("FunctionName", "NOTHING_TO_INLINE") +internal inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(pairs, toCheckInput) @Suppress("FunctionName") internal fun > A.LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : LabeledPolynomial { if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) @@ -89,13 +91,13 @@ internal fun > A.LabeledPolynomial(pairs: Collection( - fixedCoefs.filterValues { it != zero } - ) + return LabeledPolynomial(fixedCoefs) } @Suppress("FunctionName", "NOTHING_TO_INLINE") internal inline fun > LabeledPolynomialSpace.LabeledPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(pairs = pairs, toCheckInput = toCheckInput) +@Suppress("FunctionName", "NOTHING_TO_INLINE") +internal inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(pairs = pairs, toCheckInput = toCheckInput) @Suppress("FunctionName") internal fun > A.LabeledPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : LabeledPolynomial { if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) @@ -108,25 +110,29 @@ internal fun > A.LabeledPolynomial(vararg pairs: Pair( - fixedCoefs.filterValues { it != zero } - ) + return LabeledPolynomial(fixedCoefs) } @Suppress("FunctionName") public fun > A.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) @Suppress("FunctionName") public fun > LabeledPolynomialSpace.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) +@Suppress("FunctionName") +public fun > LabeledRationalFunctionSpace.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) @Suppress("FunctionName") public fun > A.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) @Suppress("FunctionName") public fun > LabeledPolynomialSpace.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) +@Suppress("FunctionName") +public fun > LabeledRationalFunctionSpace.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) @Suppress("FunctionName") public fun > A.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs, toCheckInput = true) @Suppress("FunctionName") public fun > LabeledPolynomialSpace.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs, toCheckInput = true) +@Suppress("FunctionName") +public fun > LabeledRationalFunctionSpace.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs, toCheckInput = true) //context(A) //public fun > Symbol.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1u) to one)) @@ -196,19 +202,17 @@ public class LabeledPolynomialSpace>( */ public override operator fun LabeledPolynomial.plus(other: Int): LabeledPolynomial = if (other == 0) this - else - LabeledPolynomial( - coefficients - .toMutableMap() + else with(coefficients) { + if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to other.asConstant())) + else LabeledPolynomial( + toMutableMap() .apply { val degs = emptyMap() - val result = getOrElse(degs) { constantZero } + other - - if (result.isZero()) remove(degs) - else this[degs] = result + this[degs] = getOrElse(degs) { constantZero } + other } ) + } /** * Returns difference between the polynomial and the integer represented as polynomial. * @@ -216,19 +220,17 @@ public class LabeledPolynomialSpace>( */ public override operator fun LabeledPolynomial.minus(other: Int): LabeledPolynomial = if (other == 0) this - else - LabeledPolynomial( - coefficients - .toMutableMap() + else with(coefficients) { + if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to (-other).asConstant())) + else LabeledPolynomial( + toMutableMap() .apply { val degs = emptyMap() - val result = getOrElse(degs) { constantZero } - other - - if (result.isZero()) remove(degs) - else this[degs] = result + this[degs] = getOrElse(degs) { constantZero } - other } ) + } /** * Returns product of the polynomial and the integer represented as polynomial. * @@ -238,7 +240,8 @@ public class LabeledPolynomialSpace>( if (other == 0) zero else LabeledPolynomial( coefficients - .applyAndRemoveZeros { + .toMutableMap() + .apply { for (degs in keys) this[degs] = this[degs]!! * other } ) @@ -250,19 +253,17 @@ public class LabeledPolynomialSpace>( */ public override operator fun Int.plus(other: LabeledPolynomial): LabeledPolynomial = if (this == 0) other - else - LabeledPolynomial( - other.coefficients - .toMutableMap() + else with(other.coefficients) { + if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to this@plus.asConstant())) + else LabeledPolynomial( + toMutableMap() .apply { val degs = emptyMap() - val result = this@plus + getOrElse(degs) { constantZero } - - if (result.isZero()) remove(degs) - else this[degs] = result + this[degs] = this@plus + getOrElse(degs) { constantZero } } ) + } /** * Returns difference between the integer represented as polynomial and the polynomial. * @@ -270,19 +271,17 @@ public class LabeledPolynomialSpace>( */ public override operator fun Int.minus(other: LabeledPolynomial): LabeledPolynomial = if (this == 0) other - else - LabeledPolynomial( - other.coefficients - .toMutableMap() + else with(other.coefficients) { + if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to this@minus.asConstant())) + else LabeledPolynomial( + toMutableMap() .apply { val degs = emptyMap() - val result = this@minus - getOrElse(degs) { constantZero } - - if (result.isZero()) remove(degs) - else this[degs] = result + this[degs] = this@minus - getOrElse(degs) { constantZero } } ) + } /** * Returns product of the integer represented as polynomial and the polynomial. * @@ -292,7 +291,8 @@ public class LabeledPolynomialSpace>( if (this == 0) zero else LabeledPolynomial( other.coefficients - .applyAndRemoveZeros { + .toMutableMap() + .apply { for (degs in keys) this[degs] = this@times * this[degs]!! } ) @@ -303,46 +303,32 @@ public class LabeledPolynomialSpace>( public override fun number(value: Int): LabeledPolynomial = number(constantNumber(value)) public override operator fun C.plus(other: Symbol): LabeledPolynomial = - if (isZero()) LabeledPolynomial(mapOf( - mapOf(other to 1U) to constantOne, - )) - else LabeledPolynomial(mapOf( + LabeledPolynomial(mapOf( mapOf(other to 1U) to constantOne, emptyMap() to this@plus, )) public override operator fun C.minus(other: Symbol): LabeledPolynomial = - if (isZero()) LabeledPolynomial(mapOf( - mapOf(other to 1U) to -constantOne, - )) - else LabeledPolynomial(mapOf( + LabeledPolynomial(mapOf( mapOf(other to 1U) to -constantOne, emptyMap() to this@minus, )) public override operator fun C.times(other: Symbol): LabeledPolynomial = - if (isZero()) zero - else LabeledPolynomial(mapOf( + LabeledPolynomial(mapOf( mapOf(other to 1U) to this@times, )) public override operator fun Symbol.plus(other: C): LabeledPolynomial = - if (other.isZero()) LabeledPolynomial(mapOf( - mapOf(this@plus to 1U) to constantOne, - )) - else LabeledPolynomial(mapOf( + LabeledPolynomial(mapOf( mapOf(this@plus to 1U) to constantOne, emptyMap() to other, )) public override operator fun Symbol.minus(other: C): LabeledPolynomial = - if (other.isZero()) LabeledPolynomial(mapOf( - mapOf(this@minus to 1U) to -constantOne, - )) - else LabeledPolynomial(mapOf( + LabeledPolynomial(mapOf( mapOf(this@minus to 1U) to -constantOne, emptyMap() to other, )) public override operator fun Symbol.times(other: C): LabeledPolynomial = - if (other.isZero()) zero - else LabeledPolynomial(mapOf( + LabeledPolynomial(mapOf( mapOf(this@times to 1U) to other, )) @@ -350,18 +336,14 @@ public class LabeledPolynomialSpace>( * Returns sum of the constant represented as polynomial and the polynomial. */ override operator fun C.plus(other: LabeledPolynomial): LabeledPolynomial = - if (this.isZero()) other - else with(other.coefficients) { + with(other.coefficients) { if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to this@plus)) else LabeledPolynomial( toMutableMap() .apply { val degs = emptyMap() - val result = this@plus + getOrElse(degs) { constantZero } - - if (result.isZero()) remove(degs) - else this[degs] = result + this[degs] = this@plus + getOrElse(degs) { constantZero } } ) } @@ -369,8 +351,7 @@ public class LabeledPolynomialSpace>( * Returns difference between the constant represented as polynomial and the polynomial. */ override operator fun C.minus(other: LabeledPolynomial): LabeledPolynomial = - if (this.isZero()) other - else with(other.coefficients) { + with(other.coefficients) { if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to this@minus)) else LabeledPolynomial( toMutableMap() @@ -379,10 +360,7 @@ public class LabeledPolynomialSpace>( val degs = emptyMap() - val result = this@minus - getOrElse(degs) { constantZero } - - if (result.isZero()) remove(degs) - else this[degs] = result + this[degs] = this@minus - getOrElse(degs) { constantZero } } ) } @@ -390,10 +368,10 @@ public class LabeledPolynomialSpace>( * Returns product of the constant represented as polynomial and the polynomial. */ override operator fun C.times(other: LabeledPolynomial): LabeledPolynomial = - if (this.isZero()) zero - else LabeledPolynomial( + LabeledPolynomial( other.coefficients - .applyAndRemoveZeros { + .toMutableMap() + .apply { for (degs in keys) this[degs] = this@times * this[degs]!! } ) @@ -402,18 +380,14 @@ public class LabeledPolynomialSpace>( * Returns sum of the constant represented as polynomial and the polynomial. */ override operator fun LabeledPolynomial.plus(other: C): LabeledPolynomial = - if (other.isZero()) this - else with(coefficients) { + with(coefficients) { if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to other)) else LabeledPolynomial( toMutableMap() .apply { val degs = emptyMap() - val result = getOrElse(degs) { constantZero } + other - - if (result.isZero()) remove(degs) - else this[degs] = result + this[degs] = getOrElse(degs) { constantZero } + other } ) } @@ -421,8 +395,7 @@ public class LabeledPolynomialSpace>( * Returns difference between the constant represented as polynomial and the polynomial. */ override operator fun LabeledPolynomial.minus(other: C): LabeledPolynomial = - if (other.isZero()) this - else with(coefficients) { + with(coefficients) { if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to other)) else LabeledPolynomial( toMutableMap() @@ -431,10 +404,7 @@ public class LabeledPolynomialSpace>( val degs = emptyMap() - val result = getOrElse(degs) { constantZero } - other - - if (result.isZero()) remove(degs) - else this[degs] = result + this[degs] = getOrElse(degs) { constantZero } - other } ) } @@ -442,10 +412,10 @@ public class LabeledPolynomialSpace>( * Returns product of the constant represented as polynomial and the polynomial. */ override operator fun LabeledPolynomial.times(other: C): LabeledPolynomial = - if (other.isZero()) zero - else LabeledPolynomial( + LabeledPolynomial( coefficients - .applyAndRemoveZeros { + .toMutableMap() + .apply { for (degs in keys) this[degs] = this[degs]!! * other } ) @@ -454,8 +424,7 @@ public class LabeledPolynomialSpace>( * Converts the constant [value] to polynomial. */ public override fun number(value: C): LabeledPolynomial = - if (value == 0) zero - else LabeledPolynomial(mapOf(emptyMap() to value)) + LabeledPolynomial(mapOf(emptyMap() to value)) public override operator fun Symbol.unaryPlus(): LabeledPolynomial = LabeledPolynomial(mapOf( @@ -495,10 +464,7 @@ public class LabeledPolynomialSpace>( .apply { val degs = mapOf(this@plus to 1U) - val result = constantOne + getOrElse(degs) { constantZero } - - if (result.isZero()) remove(degs) - else this[degs] = result + this[degs] = constantOne + getOrElse(degs) { constantZero } } ) } @@ -512,10 +478,7 @@ public class LabeledPolynomialSpace>( val degs = mapOf(this@minus to 1U) - val result = constantOne - getOrElse(degs) { constantZero } - - if (result.isZero()) remove(degs) - else this[degs] = result + this[degs] = constantOne - getOrElse(degs) { constantZero } } ) } @@ -533,10 +496,7 @@ public class LabeledPolynomialSpace>( .apply { val degs = mapOf(other to 1U) - val result = constantOne + getOrElse(degs) { constantZero } - - if (result.isZero()) remove(degs) - else this[degs] = result + this[degs] = constantOne + getOrElse(degs) { constantZero } } ) } @@ -548,10 +508,7 @@ public class LabeledPolynomialSpace>( .apply { val degs = mapOf(other to 1U) - val result = constantOne - getOrElse(degs) { constantZero } - - if (result.isZero()) remove(degs) - else this[degs] = result + this[degs] = constantOne - getOrElse(degs) { constantZero } } ) } @@ -573,7 +530,7 @@ public class LabeledPolynomialSpace>( */ override operator fun LabeledPolynomial.plus(other: LabeledPolynomial): LabeledPolynomial = LabeledPolynomial( - buildCoefficients(coefficients.size + other.coefficients.size) { + buildMap(coefficients.size + other.coefficients.size) { other.coefficients.mapValuesTo(this) { it.value } other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! + value else value } } @@ -583,7 +540,7 @@ public class LabeledPolynomialSpace>( */ override operator fun LabeledPolynomial.minus(other: LabeledPolynomial): LabeledPolynomial = LabeledPolynomial( - buildCoefficients(coefficients.size + other.coefficients.size) { + buildMap(coefficients.size + other.coefficients.size) { other.coefficients.mapValuesTo(this) { it.value } other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! - value else -value } } @@ -592,20 +549,16 @@ public class LabeledPolynomialSpace>( * Returns product of the polynomials. */ override operator fun LabeledPolynomial.times(other: LabeledPolynomial): LabeledPolynomial = - when { - isZero() -> zero - other.isZero() -> zero - else -> LabeledPolynomial( - buildCoefficients(coefficients.size * other.coefficients.size) { - for ((degs1, c1) in coefficients) for ((degs2, c2) in other.coefficients) { - val degs = degs1.toMutableMap() - degs2.mapValuesTo(degs) { (variable, deg) -> degs.getOrElse(variable) { 0u } + deg } - val c = c1 * c2 - this[degs] = if (degs in this) this[degs]!! + c else c - } + LabeledPolynomial( + buildMap(coefficients.size * other.coefficients.size) { + for ((degs1, c1) in coefficients) for ((degs2, c2) in other.coefficients) { + val degs = degs1.toMutableMap() + degs2.mapValuesTo(degs) { (variable, deg) -> degs.getOrElse(variable) { 0u } + deg } + val c = c1 * c2 + this[degs] = if (degs in this) this[degs]!! + c else c } - ) - } + } + ) /** * Instance of zero polynomial (zero of the polynomial ring). @@ -616,22 +569,12 @@ public class LabeledPolynomialSpace>( */ override val one: LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to constantOne)) - /** - * Checks equality of the polynomials. - */ - override infix fun LabeledPolynomial.equalsTo(other: LabeledPolynomial): Boolean = - when { - this === other -> true - else -> coefficients.size == other.coefficients.size && - coefficients.all { (key, value) -> with(other.coefficients) { key in this && this[key] == value } } - } - /** * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is * zero, degree is -1. */ override val LabeledPolynomial.degree: Int - get() = coefficients.entries.maxOfOrNull { (degs, c) -> if (c.isZero()) -1 else degs.values.sum().toInt() } ?: -1 + get() = coefficients.entries.maxOfOrNull { (degs, c) -> degs.values.sum().toInt() } ?: -1 /** * Map that associates variables (that appear in the polynomial in positive exponents) with their most exponents * in which they are appeared in the polynomial. @@ -642,8 +585,8 @@ public class LabeledPolynomialSpace>( public override val LabeledPolynomial.degrees: Map get() = buildMap { - coefficients.entries.forEach { (degs, c) -> - if (c.isNotZero()) degs.mapValuesTo(this) { (variable, deg) -> + coefficients.entries.forEach { (degs, _) -> + degs.mapValuesTo(this) { (variable, deg) -> max(getOrElse(variable) { 0u }, deg) } } @@ -652,55 +595,25 @@ public class LabeledPolynomialSpace>( * Counts degree of the polynomial by the specified [variable]. */ public override fun LabeledPolynomial.degreeBy(variable: Symbol): UInt = - coefficients.entries.maxOfOrNull { (degs, c) -> if (c.isZero()) 0u else degs.getOrElse(variable) { 0u } } ?: 0u + coefficients.entries.maxOfOrNull { (degs, _) -> degs.getOrElse(variable) { 0u } } ?: 0u /** * Counts degree of the polynomial by the specified [variables]. */ public override fun LabeledPolynomial.degreeBy(variables: Collection): UInt = - coefficients.entries.maxOfOrNull { (degs, c) -> if (c.isZero()) 0u else degs.filterKeys { it in variables }.values.sum() } ?: 0u + coefficients.entries.maxOfOrNull { (degs, _) -> degs.filterKeys { it in variables }.values.sum() } ?: 0u /** * Set of all variables that appear in the polynomial in positive exponents. */ public override val LabeledPolynomial.variables: Set get() = buildSet { - coefficients.entries.forEach { (degs, c) -> if (c.isNotZero()) addAll(degs.keys) } + coefficients.entries.forEach { (degs, _) -> addAll(degs.keys) } } /** * Count of all variables that appear in the polynomial in positive exponents. */ public override val LabeledPolynomial.countOfVariables: Int get() = variables.size - /** - * Checks if the instant is constant polynomial (of degree no more than 0) over considered ring. - */ - override fun LabeledPolynomial.isConstant(): Boolean = - coefficients.all { (degs, c) -> degs.isEmpty() || c.isZero() } - /** - * Checks if the instant is constant non-zero polynomial (of degree no more than 0) over considered ring. - */ - override fun LabeledPolynomial.isNonZeroConstant(): Boolean = - with(coefficients) { - var foundAbsoluteTermAndItIsNotZero = false - for ((degs, c) in this) { - if (degs.isNotEmpty()) if (c.isNotZero()) return@with false - else { - if (c.isZero()) return@with false - else foundAbsoluteTermAndItIsNotZero = true - } - } - foundAbsoluteTermAndItIsNotZero - } - /** - * If polynomial is a constant polynomial represents and returns it as constant. - * Otherwise, (when the polynomial is not constant polynomial) returns `null`. - */ - override fun LabeledPolynomial.asConstantOrNull(): C? = - with(coefficients) { - if(isConstant()) getOrElse(emptyMap()) { constantZero } - else null - } - // @Suppress("NOTHING_TO_INLINE") // public inline fun LabeledPolynomial.substitute(argument: Map): LabeledPolynomial = this.substitute(ring, argument) // @Suppress("NOTHING_TO_INLINE") @@ -719,33 +632,4 @@ public class LabeledPolynomialSpace>( // @Suppress("NOTHING_TO_INLINE") // @JvmName("invokePolynomial") // public inline operator fun LabeledPolynomial.invoke(argument: Map>): LabeledPolynomial = this.substitute(ring, argument) - - // TODO: Move to other internal utilities with context receiver - @JvmName("applyAndRemoveZerosInternal") - internal fun MutableMap, C>.applyAndRemoveZeros(block: MutableMap, C>.() -> Unit) : MutableMap, C> { - contract { - callsInPlace(block, InvocationKind.EXACTLY_ONCE) - } - block() - for ((degs, c) in this) if (c.isZero()) this.remove(degs) - return this - } - internal fun Map, C>.applyAndRemoveZeros(block: MutableMap, C>.() -> Unit) : Map, C> = - toMutableMap().applyAndRemoveZeros(block) - @OptIn(ExperimentalTypeInference::class) - internal inline fun buildCoefficients(@BuilderInference builderAction: MutableMap, C>.() -> Unit): Map, C> { - contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) } - return buildMap { - builderAction() - for ((degs, c) in this) if (c.isZero()) this.remove(degs) - } - } - @OptIn(ExperimentalTypeInference::class) - internal inline fun buildCoefficients(capacity: Int, @BuilderInference builderAction: MutableMap, C>.() -> Unit): Map, C> { - contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) } - return buildMap(capacity) { - builderAction() - for ((degs, c) in this) if (c.isZero()) this.remove(degs) - } - } } \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt index 00dd3bb47..0f46520dc 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt @@ -19,45 +19,35 @@ public class LabeledRationalFunction( // Waiting for context receivers :( TODO: Replace with context receivers when they will be available -@Suppress("FunctionName") -internal fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numerator: LabeledPolynomial, denominator: LabeledPolynomial): LabeledRationalFunction = - if (denominator.isZero()) throw ArithmeticException("/ by zero") - else LabeledRationalFunction(numerator, denominator) -@Suppress("FunctionName") -internal fun > A.LabeledRationalFunction(numerator: LabeledPolynomial, denominator: LabeledPolynomial): LabeledRationalFunction = - if (denominator.coefficients.values.all { it == zero }) throw ArithmeticException("/ by zero") - else LabeledRationalFunction(numerator, denominator) @Suppress("FunctionName") public fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): LabeledRationalFunction = - if (denominatorCoefficients.values.all { it == zero }) throw ArithmeticException("/ by zero") - else LabeledRationalFunction( - LabeledPolynomial(numeratorCoefficients), - LabeledPolynomial(denominatorCoefficients) + LabeledRationalFunction( + LabeledPolynomial(numeratorCoefficients, toCheckInput = true), + LabeledPolynomial(denominatorCoefficients, toCheckInput = true) ) @Suppress("FunctionName") public fun > A.LabeledRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): LabeledRationalFunction = - if (denominatorCoefficients.values.all { it == zero }) throw ArithmeticException("/ by zero") - else LabeledRationalFunction( - LabeledPolynomial(numeratorCoefficients), - LabeledPolynomial(denominatorCoefficients) + LabeledRationalFunction( + LabeledPolynomial(numeratorCoefficients, toCheckInput = true), + LabeledPolynomial(denominatorCoefficients, toCheckInput = true) ) @Suppress("FunctionName") public fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numerator: LabeledPolynomial): LabeledRationalFunction = LabeledRationalFunction(numerator, polynomialOne) @Suppress("FunctionName") public fun > A.LabeledRationalFunction(numerator: LabeledPolynomial): LabeledRationalFunction = - LabeledRationalFunction(numerator, LabeledPolynomial(mapOf(emptyMap() to one))) + LabeledRationalFunction(numerator, LabeledPolynomial(mapOf(emptyMap() to one), toCheckInput = false)) @Suppress("FunctionName") public fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numeratorCoefficients: Map, C>): LabeledRationalFunction = LabeledRationalFunction( - LabeledPolynomial(numeratorCoefficients), + LabeledPolynomial(numeratorCoefficients, toCheckInput = true), polynomialOne ) @Suppress("FunctionName") public fun > A.LabeledRationalFunction(numeratorCoefficients: Map, C>): LabeledRationalFunction = LabeledRationalFunction( - LabeledPolynomial(numeratorCoefficients), - LabeledPolynomial(mapOf(emptyMap() to one)) + LabeledPolynomial(numeratorCoefficients, toCheckInput = true), + LabeledPolynomial(mapOf(emptyMap() to one), toCheckInput = false) ) public class LabeledRationalFunctionSpace>( @@ -82,38 +72,16 @@ public class LabeledRationalFunctionSpace>( numerator: LabeledPolynomial, denominator: LabeledPolynomial ): LabeledRationalFunction = - LabeledRationalFunction(numerator, denominator) + LabeledRationalFunction(numerator, denominator) /** * Instance of zero rational function (zero of the rational functions ring). */ - public override val zero: LabeledRationalFunction = LabeledRationalFunction(polynomialZero, polynomialOne) + public override val zero: LabeledRationalFunction = LabeledRationalFunction(polynomialZero, polynomialOne) /** * Instance of unit polynomial (unit of the rational functions ring). */ - public override val one: LabeledRationalFunction = LabeledRationalFunction(polynomialOne, polynomialOne) - - /** - * Checks equality of the rational functions. - */ - public override infix fun LabeledRationalFunction.equalsTo(other: LabeledRationalFunction): Boolean { - if (this === other) return true - - if (numerator.isZero() != other.numerator.isZero()) return false - - val variables = this.variables union other.variables - val thisNumeratorDegrees = this.numerator.degrees - val thisDenominatorDegrees = this.denominator.degrees - val otherNumeratorDegrees = other.numerator.degrees - val otherDenominatorDegrees = other.denominator.degrees - for (variable in variables) - if ( - thisNumeratorDegrees.getOrElse(variable) { 0u } + otherDenominatorDegrees.getOrElse(variable) { 0u } - != thisDenominatorDegrees.getOrElse(variable) { 0u } + otherNumeratorDegrees.getOrElse(variable) { 0u } - ) return false - - return numerator * other.denominator equalsTo other.numerator * denominator - } + public override val one: LabeledRationalFunction = LabeledRationalFunction(polynomialOne, polynomialOne) // TODO: Разобрать diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt index 90e9cde69..711d2bb49 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt @@ -91,13 +91,9 @@ public open class ListPolynomialSpace>( .toMutableList() .apply { val result = getOrElse(0) { constantZero } + other - val isResultZero = result.isZero() - when { - size == 0 && !isResultZero -> add(result) - size > 1 || !isResultZero -> this[0] = result - else -> clear() - } + if(size == 0) add(result) + else this[0] = result } ) /** @@ -113,13 +109,9 @@ public open class ListPolynomialSpace>( .toMutableList() .apply { val result = getOrElse(0) { constantZero } - other - val isResultZero = result.isZero() - when { - size == 0 && !isResultZero -> add(result) - size > 1 || !isResultZero -> this[0] = result - else -> clear() - } + if(size == 0) add(result) + else this[0] = result } ) /** @@ -131,7 +123,8 @@ public open class ListPolynomialSpace>( if (other == 0) zero else ListPolynomial( coefficients - .applyAndRemoveZeros { + .toMutableList() + .apply { for (deg in indices) this[deg] = this[deg] * other } ) @@ -149,13 +142,9 @@ public open class ListPolynomialSpace>( .toMutableList() .apply { val result = this@plus + getOrElse(0) { constantZero } - val isResultZero = result.isZero() - when { - size == 0 && !isResultZero -> add(result) - size > 1 || !isResultZero -> this[0] = result - else -> clear() - } + if(size == 0) add(result) + else this[0] = result } ) /** @@ -173,13 +162,9 @@ public open class ListPolynomialSpace>( forEachIndexed { index, c -> if (index != 0) this[index] = -c } val result = this@minus - getOrElse(0) { constantZero } - val isResultZero = result.isZero() - when { - size == 0 && !isResultZero -> add(result) - size > 1 || !isResultZero -> this[0] = result - else -> clear() - } + if(size == 0) add(result) + else this[0] = result } ) /** @@ -191,7 +176,8 @@ public open class ListPolynomialSpace>( if (this == 0) zero else ListPolynomial( other.coefficients - .applyAndRemoveZeros { + .toMutableList() + .apply { for (deg in indices) this[deg] = this@times * this[deg] } ) @@ -205,20 +191,15 @@ public open class ListPolynomialSpace>( * Returns sum of the constant represented as polynomial and the polynomial. */ public override operator fun C.plus(other: ListPolynomial): ListPolynomial = - if (this.isZero()) other - else with(other.coefficients) { + with(other.coefficients) { if (isEmpty()) ListPolynomial(listOf(this@plus)) else ListPolynomial( toMutableList() .apply { val result = if (size == 0) this@plus else this@plus + get(0) - val isResultZero = result.isZero() - when { - size == 0 && !isResultZero -> add(result) - size > 1 || !isResultZero -> this[0] = result - else -> clear() - } + if(size == 0) add(result) + else this[0] = result } ) } @@ -226,8 +207,7 @@ public open class ListPolynomialSpace>( * Returns difference between the constant represented as polynomial and the polynomial. */ public override operator fun C.minus(other: ListPolynomial): ListPolynomial = - if (this.isZero()) other - else with(other.coefficients) { + with(other.coefficients) { if (isEmpty()) ListPolynomial(listOf(this@minus)) else ListPolynomial( toMutableList() @@ -235,13 +215,9 @@ public open class ListPolynomialSpace>( forEachIndexed { index, c -> if (index != 0) this[index] = -c } val result = if (size == 0) this@minus else this@minus - get(0) - val isResultZero = result.isZero() - when { - size == 0 && !isResultZero -> add(result) - size > 1 || !isResultZero -> this[0] = result - else -> clear() - } + if(size == 0) add(result) + else this[0] = result } ) } @@ -249,10 +225,10 @@ public open class ListPolynomialSpace>( * Returns product of the constant represented as polynomial and the polynomial. */ public override operator fun C.times(other: ListPolynomial): ListPolynomial = - if (this.isZero()) other - else ListPolynomial( + ListPolynomial( other.coefficients - .applyAndRemoveZeros { + .toMutableList() + .apply { for (deg in indices) this[deg] = this@times * this[deg] } ) @@ -261,20 +237,15 @@ public open class ListPolynomialSpace>( * Returns sum of the constant represented as polynomial and the polynomial. */ public override operator fun ListPolynomial.plus(other: C): ListPolynomial = - if (other.isZero()) this - else with(coefficients) { + with(coefficients) { if (isEmpty()) ListPolynomial(listOf(other)) else ListPolynomial( toMutableList() .apply { val result = if (size == 0) other else get(0) + other - val isResultZero = result.isZero() - when { - size == 0 && !isResultZero -> add(result) - size > 1 || !isResultZero -> this[0] = result - else -> clear() - } + if(size == 0) add(result) + else this[0] = result } ) } @@ -282,20 +253,15 @@ public open class ListPolynomialSpace>( * Returns difference between the constant represented as polynomial and the polynomial. */ public override operator fun ListPolynomial.minus(other: C): ListPolynomial = - if (other.isZero()) this - else with(coefficients) { + with(coefficients) { if (isEmpty()) ListPolynomial(listOf(-other)) else ListPolynomial( toMutableList() .apply { val result = if (size == 0) other else get(0) - other - val isResultZero = result.isZero() - when { - size == 0 && !isResultZero -> add(result) - size > 1 || !isResultZero -> this[0] = result - else -> clear() - } + if(size == 0) add(result) + else this[0] = result } ) } @@ -303,10 +269,10 @@ public open class ListPolynomialSpace>( * Returns product of the constant represented as polynomial and the polynomial. */ public override operator fun ListPolynomial.times(other: C): ListPolynomial = - if (other.isZero()) this - else ListPolynomial( + ListPolynomial( coefficients - .applyAndRemoveZeros { + .toMutableList() + .apply { for (deg in indices) this[deg] = this[deg] * other } ) @@ -314,9 +280,7 @@ public open class ListPolynomialSpace>( /** * Converts the constant [value] to polynomial. */ - public override fun number(value: C): ListPolynomial = - if (value.isZero()) zero - else ListPolynomial(value) + public override fun number(value: C): ListPolynomial = ListPolynomial(value) /** * Returns negation of the polynomial. @@ -330,7 +294,7 @@ public open class ListPolynomialSpace>( val thisDegree = degree val otherDegree = other.degree return ListPolynomial( - Coefficients(max(thisDegree, otherDegree) + 1) { + List(max(thisDegree, otherDegree) + 1) { when { it > thisDegree -> other.coefficients[it] it > otherDegree -> coefficients[it] @@ -346,7 +310,7 @@ public open class ListPolynomialSpace>( val thisDegree = degree val otherDegree = other.degree return ListPolynomial( - Coefficients(max(thisDegree, otherDegree) + 1) { + List(max(thisDegree, otherDegree) + 1) { when { it > thisDegree -> -other.coefficients[it] it > otherDegree -> coefficients[it] @@ -361,39 +325,15 @@ public open class ListPolynomialSpace>( public override operator fun ListPolynomial.times(other: ListPolynomial): ListPolynomial { val thisDegree = degree val otherDegree = other.degree - return when { - thisDegree == -1 -> zero - otherDegree == -1 -> zero - else -> - ListPolynomial( - Coefficients(thisDegree + otherDegree + 1) { d -> - (max(0, d - otherDegree)..min(thisDegree, d)) - .map { coefficients[it] * other.coefficients[d - it] } - .reduce { acc, rational -> acc + rational } - } - ) - } + return ListPolynomial( + List(thisDegree + otherDegree + 1) { d -> + (max(0, d - otherDegree)..min(thisDegree, d)) + .map { coefficients[it] * other.coefficients[d - it] } + .reduce { acc, rational -> acc + rational } + } + ) } - /** - * Check if the instant is zero polynomial. - */ - public override fun ListPolynomial.isZero(): Boolean = coefficients.all { it.isZero() } - /** - * Check if the instant is unit polynomial. - */ - public override fun ListPolynomial.isOne(): Boolean = - with(coefficients) { - isNotEmpty() && withIndex().all { (index, c) -> if (index == 0) c.isOne() else c.isZero() } - } - /** - * Check if the instant is minus unit polynomial. - */ - public override fun ListPolynomial.isMinusOne(): Boolean = - with(coefficients) { - isNotEmpty() && withIndex().all { (index, c) -> if (index == 0) c.isMinusOne() else c.isZero() } - } - /** * Instance of zero polynomial (zero of the polynomial ring). */ @@ -403,34 +343,11 @@ public open class ListPolynomialSpace>( */ override val one: ListPolynomial = ListPolynomial(listOf(constantOne)) - /** - * Checks equality of the polynomials. - */ - public override infix fun ListPolynomial.equalsTo(other: ListPolynomial): Boolean = - when { - this === other -> true - this.degree == other.degree -> (0..degree).all { coefficients[it] == other.coefficients[it] } - else -> false - } - /** * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is * zero, degree is -1. */ - public override val ListPolynomial.degree: Int get() = coefficients.indexOfLast { it != constantZero } - - /** - * If polynomial is a constant polynomial represents and returns it as constant. - * Otherwise, (when the polynomial is not constant polynomial) returns `null`. - */ - public override fun ListPolynomial.asConstantOrNull(): C? = - with(coefficients) { - when { - isEmpty() -> constantZero - withIndex().all { (index, c) -> index == 0 || c.isZero() } -> first() - else -> null - } - } + public override val ListPolynomial.degree: Int get() = coefficients.lastIndex @Suppress("NOTHING_TO_INLINE") public inline fun ListPolynomial.substitute(argument: C): C = this.substitute(ring, argument) @@ -451,44 +368,6 @@ public open class ListPolynomialSpace>( public inline operator fun ListPolynomial.invoke(argument: C): C = this.substitute(ring, argument) @Suppress("NOTHING_TO_INLINE") public inline operator fun ListPolynomial.invoke(argument: ListPolynomial): ListPolynomial = this.substitute(ring, argument) - - // TODO: Move to other internal utilities with context receiver - @JvmName("applyAndRemoveZerosInternal") - internal inline fun MutableList.applyAndRemoveZeros(block: MutableList.() -> Unit) : MutableList { - contract { - callsInPlace(block, InvocationKind.EXACTLY_ONCE) - } - block() - while (isNotEmpty() && elementAt(lastIndex).isZero()) removeAt(lastIndex) - return this - } - internal inline fun List.applyAndRemoveZeros(block: MutableList.() -> Unit) : List = - toMutableList().applyAndRemoveZeros(block) - @Suppress("FunctionName") - 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 (isNotEmpty() && elementAt(lastIndex).isZero()) removeAt(lastIndex) } - return list - } - @Suppress("FunctionName") - internal inline fun Coefficients(size: Int, init: (index: Int) -> C): List = MutableCoefficients(size, init) - @OptIn(ExperimentalTypeInference::class) - internal inline fun buildCoefficients(@BuilderInference builderAction: MutableList.() -> Unit): List { - contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) } - return buildList { - builderAction() - while (isNotEmpty() && elementAt(lastIndex).isZero()) removeAt(lastIndex) - } - } - @OptIn(ExperimentalTypeInference::class) - internal inline fun buildCoefficients(capacity: Int, @BuilderInference builderAction: MutableList.() -> Unit): List { - contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) } - return buildList(capacity) { - builderAction() - while (isNotEmpty() && elementAt(lastIndex).isZero()) removeAt(lastIndex) - } - } } /** diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt index 67c7e9fa2..f62d1857f 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt @@ -8,7 +8,7 @@ package space.kscience.kmath.functions import space.kscience.kmath.operations.Ring -public data class ListRationalFunction internal constructor ( +public data class ListRationalFunction( public override val numerator: ListPolynomial, public override val denominator: ListPolynomial ) : RationalFunction> { @@ -17,25 +17,15 @@ public data class ListRationalFunction internal constructor ( // Waiting for context receivers :( TODO: Replace with context receivers when they will be available -@Suppress("FunctionName") -internal fun > ListRationalFunctionSpace.ListRationalFunction(numerator: ListPolynomial, denominator: ListPolynomial): ListRationalFunction = - if (denominator.isZero()) throw ArithmeticException("/ by zero") - else ListRationalFunction(numerator, denominator) -@Suppress("FunctionName") -internal fun > A.ListRationalFunction(numerator: ListPolynomial, denominator: ListPolynomial): ListRationalFunction = - if (denominator.coefficients.all { it == zero }) throw ArithmeticException("/ by zero") - else ListRationalFunction(numerator, denominator) @Suppress("FunctionName") public fun > ListRationalFunctionSpace.ListRationalFunction(numeratorCoefficients: List, denominatorCoefficients: List, reverse: Boolean = false): ListRationalFunction = - if (denominatorCoefficients.all { it == zero }) throw ArithmeticException("/ by zero") - else ListRationalFunction( + ListRationalFunction( ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), ListPolynomial( with(denominatorCoefficients) { if (reverse) reversed() else this } ) ) @Suppress("FunctionName") public fun > A.ListRationalFunction(numeratorCoefficients: List, denominatorCoefficients: List, reverse: Boolean = false): ListRationalFunction = - if (denominatorCoefficients.all { it == zero }) throw ArithmeticException("/ by zero") - else ListRationalFunction( + ListRationalFunction( ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), ListPolynomial( with(denominatorCoefficients) { if (reverse) reversed() else this } ) ) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt index 80998d6bf..51f316c5d 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -58,6 +58,8 @@ internal fun List.cleanUp() = subList(0, indexOfLast { it != 0U } + 1) @Suppress("FunctionName", "NOTHING_TO_INLINE") internal inline fun > NumberedPolynomialSpace.NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(coefs, toCheckInput) +@Suppress("FunctionName", "NOTHING_TO_INLINE") +internal inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(coefs, toCheckInput) @Suppress("FunctionName") internal fun > A.NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : NumberedPolynomial { if (!toCheckInput) return NumberedPolynomial(coefs) @@ -70,13 +72,13 @@ internal fun > A.NumberedPolynomial(coefs: Map, C>, toC fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value } - return NumberedPolynomial( - fixedCoefs.filterValues { it != zero } - ) + return NumberedPolynomial(fixedCoefs) } @Suppress("FunctionName", "NOTHING_TO_INLINE") internal inline fun > NumberedPolynomialSpace.NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(pairs, toCheckInput) +@Suppress("FunctionName", "NOTHING_TO_INLINE") +internal inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(pairs, toCheckInput) @Suppress("FunctionName") internal fun > A.NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : NumberedPolynomial { if (!toCheckInput) return NumberedPolynomial(pairs.toMap()) @@ -89,13 +91,13 @@ internal fun > A.NumberedPolynomial(pairs: Collection( - fixedCoefs.filterValues { it != zero } - ) + return NumberedPolynomial(fixedCoefs) } @Suppress("FunctionName", "NOTHING_TO_INLINE") internal inline fun > NumberedPolynomialSpace.NumberedPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(pairs = pairs, toCheckInput = toCheckInput) +@Suppress("FunctionName", "NOTHING_TO_INLINE") +internal inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(pairs = pairs, toCheckInput = toCheckInput) @Suppress("FunctionName") internal fun > A.NumberedPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : NumberedPolynomial { if (!toCheckInput) return NumberedPolynomial(pairs.toMap()) @@ -108,25 +110,29 @@ internal fun > A.NumberedPolynomial(vararg pairs: Pair, fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value } - return NumberedPolynomial( - fixedCoefs.filterValues { it != zero } - ) + return NumberedPolynomial(fixedCoefs) } @Suppress("FunctionName") public fun > A.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, toCheckInput = true) @Suppress("FunctionName") public fun > NumberedPolynomialSpace.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, toCheckInput = true) +@Suppress("FunctionName") +public fun > NumberedRationalFunctionSpace.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, toCheckInput = true) @Suppress("FunctionName") public fun > A.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, toCheckInput = true) @Suppress("FunctionName") public fun > NumberedPolynomialSpace.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, toCheckInput = true) +@Suppress("FunctionName") +public fun > NumberedRationalFunctionSpace.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, toCheckInput = true) @Suppress("FunctionName") public fun > A.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs, toCheckInput = true) @Suppress("FunctionName") public fun > NumberedPolynomialSpace.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs, toCheckInput = true) +@Suppress("FunctionName") +public fun > NumberedRationalFunctionSpace.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs, toCheckInput = true) //context(A) //public fun > Symbol.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomial(mapOf(mapOf(this to 1u) to one)) @@ -211,10 +217,7 @@ public open class NumberedPolynomialSpace>( .apply { val degs = emptyList() - val result = getOrElse(degs) { constantZero } + other - - if (result.isZero()) remove(degs) - else this[degs] = result + this[degs] = getOrElse(degs) { constantZero } + other } ) /** @@ -231,10 +234,7 @@ public open class NumberedPolynomialSpace>( .apply { val degs = emptyList() - val result = getOrElse(degs) { constantZero } - other - - if (result.isZero()) remove(degs) - else this[degs] = result + this[degs] = getOrElse(degs) { constantZero } - other } ) /** @@ -246,7 +246,8 @@ public open class NumberedPolynomialSpace>( if (other == 0) zero else NumberedPolynomial( coefficients - .applyAndRemoveZeros { + .toMutableMap() + .apply { for (degs in keys) this[degs] = this[degs]!! * other } ) @@ -265,10 +266,7 @@ public open class NumberedPolynomialSpace>( .apply { val degs = emptyList() - val result = this@plus + getOrElse(degs) { constantZero } - - if (result.isZero()) remove(degs) - else this[degs] = result + this[degs] = this@plus + getOrElse(degs) { constantZero } } ) /** @@ -285,10 +283,7 @@ public open class NumberedPolynomialSpace>( .apply { val degs = emptyList() - val result = this@minus - getOrElse(degs) { constantZero } - - if (result.isZero()) remove(degs) - else this[degs] = result + this[degs] = this@minus - getOrElse(degs) { constantZero } } ) /** @@ -300,7 +295,8 @@ public open class NumberedPolynomialSpace>( if (this == 0) zero else NumberedPolynomial( other.coefficients - .applyAndRemoveZeros { + .toMutableMap() + .apply { for (degs in keys) this[degs] = this@times * this[degs]!! } ) @@ -314,18 +310,14 @@ public open class NumberedPolynomialSpace>( * Returns sum of the constant represented as polynomial and the polynomial. */ override operator fun C.plus(other: NumberedPolynomial): NumberedPolynomial = - if (this.isZero()) other - else with(other.coefficients) { + with(other.coefficients) { if (isEmpty()) NumberedPolynomial(mapOf(emptyList() to this@plus)) else NumberedPolynomial( toMutableMap() .apply { val degs = emptyList() - val result = this@plus + getOrElse(degs) { constantZero } - - if (result.isZero()) remove(degs) - else this[degs] = result + this[degs] = this@plus + getOrElse(degs) { constantZero } } ) } @@ -333,8 +325,7 @@ public open class NumberedPolynomialSpace>( * Returns difference between the constant represented as polynomial and the polynomial. */ override operator fun C.minus(other: NumberedPolynomial): NumberedPolynomial = - if (this.isZero()) -other - else with(other.coefficients) { + with(other.coefficients) { if (isEmpty()) NumberedPolynomial(mapOf(emptyList() to this@minus)) else NumberedPolynomial( toMutableMap() @@ -343,10 +334,7 @@ public open class NumberedPolynomialSpace>( val degs = emptyList() - val result = this@minus - getOrElse(degs) { constantZero } - - if (result.isZero()) remove(degs) - else this[degs] = result + this[degs] = this@minus - getOrElse(degs) { constantZero } } ) } @@ -354,10 +342,10 @@ public open class NumberedPolynomialSpace>( * Returns product of the constant represented as polynomial and the polynomial. */ override operator fun C.times(other: NumberedPolynomial): NumberedPolynomial = - if (this.isZero()) zero - else NumberedPolynomial( + NumberedPolynomial( other.coefficients - .applyAndRemoveZeros { + .toMutableMap() + .apply { for (degs in keys) this[degs] = this@times * this[degs]!! } ) @@ -366,18 +354,14 @@ public open class NumberedPolynomialSpace>( * Returns sum of the constant represented as polynomial and the polynomial. */ override operator fun NumberedPolynomial.plus(other: C): NumberedPolynomial = - if (other.isZero()) this - else with(coefficients) { + with(coefficients) { if (isEmpty()) NumberedPolynomial(mapOf(emptyList() to other)) else NumberedPolynomial( toMutableMap() .apply { val degs = emptyList() - val result = getOrElse(degs) { constantZero } + other - - if (result.isZero()) remove(degs) - else this[degs] = result + this[degs] = getOrElse(degs) { constantZero } + other } ) } @@ -385,18 +369,14 @@ public open class NumberedPolynomialSpace>( * Returns difference between the constant represented as polynomial and the polynomial. */ override operator fun NumberedPolynomial.minus(other: C): NumberedPolynomial = - if (other.isZero()) this - else with(coefficients) { + with(coefficients) { if (isEmpty()) NumberedPolynomial(mapOf(emptyList() to other)) else NumberedPolynomial( toMutableMap() .apply { val degs = emptyList() - val result = getOrElse(degs) { constantZero } - other - - if (result.isZero()) remove(degs) - else this[degs] = result + this[degs] = getOrElse(degs) { constantZero } - other } ) } @@ -404,10 +384,10 @@ public open class NumberedPolynomialSpace>( * Returns product of the constant represented as polynomial and the polynomial. */ override operator fun NumberedPolynomial.times(other: C): NumberedPolynomial = - if (other.isZero()) zero - else NumberedPolynomial( + NumberedPolynomial( coefficients - .applyAndRemoveZeros { + .toMutableMap() + .apply { for (degs in keys) this[degs] = this[degs]!! * other } ) @@ -416,8 +396,7 @@ public open class NumberedPolynomialSpace>( * Converts the constant [value] to polynomial. */ public override fun number(value: C): NumberedPolynomial = - if (value == 0) zero - else NumberedPolynomial(mapOf(emptyList() to value)) + NumberedPolynomial(mapOf(emptyList() to value)) /** * Returns negation of the polynomial. @@ -431,7 +410,7 @@ public open class NumberedPolynomialSpace>( */ override operator fun NumberedPolynomial.plus(other: NumberedPolynomial): NumberedPolynomial = NumberedPolynomial( - buildCoefficients(coefficients.size + other.coefficients.size) { + buildMap(coefficients.size + other.coefficients.size) { other.coefficients.mapValuesTo(this) { it.value } other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! + value else value } } @@ -441,7 +420,7 @@ public open class NumberedPolynomialSpace>( */ override operator fun NumberedPolynomial.minus(other: NumberedPolynomial): NumberedPolynomial = NumberedPolynomial( - buildCoefficients(coefficients.size + other.coefficients.size) { + buildMap(coefficients.size + other.coefficients.size) { other.coefficients.mapValuesTo(this) { it.value } other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! - value else -value } } @@ -450,57 +429,17 @@ public open class NumberedPolynomialSpace>( * Returns product of the polynomials. */ override operator fun NumberedPolynomial.times(other: NumberedPolynomial): NumberedPolynomial = - when { - isZero() -> zero - other.isZero() -> zero - else -> - NumberedPolynomial( - buildCoefficients(coefficients.size * other.coefficients.size) { - for ((degs1, c1) in coefficients) for ((degs2, c2) in other.coefficients) { - val degs = - (0..max(degs1.lastIndex, degs2.lastIndex)) - .map { degs1.getOrElse(it) { 0U } + degs2.getOrElse(it) { 0U } } - val c = c1 * c2 - this[degs] = if (degs in this) this[degs]!! + c else c - } - } - ) - } - - /** - * Check if the instant is zero polynomial. - */ - public override fun NumberedPolynomial.isZero(): Boolean = coefficients.values.all { it.isZero() } - /** - * Check if the instant is unit polynomial. - */ - public override fun NumberedPolynomial.isOne(): Boolean = - with(coefficients) { - var foundAbsoluteTermAndItIsOne = false - for ((degs, c) in this) { - if (degs.isNotEmpty()) if (c.isNotZero()) return@with false - else { - if (c.isNotOne()) return@with false - else foundAbsoluteTermAndItIsOne = true + NumberedPolynomial( + buildMap(coefficients.size * other.coefficients.size) { + for ((degs1, c1) in coefficients) for ((degs2, c2) in other.coefficients) { + val degs = + (0..max(degs1.lastIndex, degs2.lastIndex)) + .map { degs1.getOrElse(it) { 0U } + degs2.getOrElse(it) { 0U } } + val c = c1 * c2 + this[degs] = if (degs in this) this[degs]!! + c else c } } - foundAbsoluteTermAndItIsOne - } - /** - * Check if the instant is minus unit polynomial. - */ - public override fun NumberedPolynomial.isMinusOne(): Boolean = - with(coefficients) { - var foundAbsoluteTermAndItIsMinusOne = false - for ((degs, c) in this) { - if (degs.isNotEmpty()) if (c.isNotZero()) return@with false - else { - if (c.isNotMinusOne()) return@with false - else foundAbsoluteTermAndItIsMinusOne = true - } - } - foundAbsoluteTermAndItIsMinusOne - } + ) /** * Instance of zero polynomial (zero of the polynomial ring). @@ -516,28 +455,18 @@ public open class NumberedPolynomialSpace>( ) ) - /** - * Checks equality of the polynomials. - */ - override infix fun NumberedPolynomial.equalsTo(other: NumberedPolynomial): Boolean = - when { - this === other -> true - else -> coefficients.size == other.coefficients.size && - coefficients.all { (key, value) -> with(other.coefficients) { key in this && this[key] == value } } - } - /** * Maximal index (ID) of variable occurring in the polynomial with positive power. If there is no such variable, * the result is `-1`. */ public val NumberedPolynomial.lastVariable: Int - get() = coefficients.entries.maxOfOrNull { (degs, c) -> if (c.isZero()) -1 else degs.lastIndex } ?: -1 + get() = coefficients.entries.maxOfOrNull { (degs, _) -> degs.lastIndex } ?: -1 /** * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is * zero, degree is -1. */ override val NumberedPolynomial.degree: Int - get() = coefficients.entries.maxOfOrNull { (degs, c) -> if (c.isZero()) -1 else degs.sum().toInt() } ?: -1 + get() = coefficients.entries.maxOfOrNull { (degs, _) -> degs.sum().toInt() } ?: -1 /** * List that associates indices of variables (that appear in the polynomial in positive exponents) with their most * exponents in which the variables are appeared in the polynomial. @@ -548,8 +477,8 @@ public open class NumberedPolynomialSpace>( public val NumberedPolynomial.degrees: List get() = MutableList(lastVariable + 1) { 0u }.apply { - coefficients.entries.forEach { (degs, c) -> - if (c.isNotZero()) degs.forEachIndexed { index, deg -> + coefficients.entries.forEach { (degs, _) -> + degs.forEachIndexed { index, deg -> this[index] = max(this[index], deg) } } @@ -558,13 +487,13 @@ public open class NumberedPolynomialSpace>( * Counts degree of the polynomial by the specified [variable]. */ public fun NumberedPolynomial.degreeBy(variable: Int): UInt = - coefficients.entries.maxOfOrNull { (degs, c) -> if (c.isZero()) 0u else degs.getOrElse(variable) { 0u } } ?: 0u + coefficients.entries.maxOfOrNull { (degs, _) -> degs.getOrElse(variable) { 0u } } ?: 0u /** * Counts degree of the polynomial by the specified [variables]. */ public fun NumberedPolynomial.degreeBy(variables: Collection): UInt = - coefficients.entries.maxOfOrNull { (degs, c) -> - if (c.isZero()) 0u else degs.withIndex().filter { (index, _) -> index in variables }.sumOf { it.value } + coefficients.entries.maxOfOrNull { (degs, _) -> + degs.withIndex().filter { (index, _) -> index in variables }.sumOf { it.value } } ?: 0u /** * Count of variables occurring in the polynomial with positive power. If there is no such variable, @@ -573,43 +502,13 @@ public open class NumberedPolynomialSpace>( public val NumberedPolynomial.countOfVariables: Int get() = MutableList(lastVariable + 1) { false }.apply { - coefficients.entries.forEach { (degs, c) -> - if (c.isNotZero()) degs.forEachIndexed { index, deg -> + coefficients.entries.forEach { (degs, _) -> + degs.forEachIndexed { index, deg -> if (deg != 0u) this[index] = true } } }.count { it } - /** - * Checks if the instant is constant polynomial (of degree no more than 0) over considered ring. - */ - override fun NumberedPolynomial.isConstant(): Boolean = - coefficients.all { (degs, c) -> degs.isEmpty() || c.isZero() } - /** - * Checks if the instant is constant non-zero polynomial (of degree no more than 0) over considered ring. - */ - override fun NumberedPolynomial.isNonZeroConstant(): Boolean = - with(coefficients) { - var foundAbsoluteTermAndItIsNotZero = false - for ((degs, c) in this) { - if (degs.isNotEmpty()) if (c.isNotZero()) return@with false - else { - if (c.isZero()) return@with false - else foundAbsoluteTermAndItIsNotZero = true - } - } - foundAbsoluteTermAndItIsNotZero - } - /** - * If polynomial is a constant polynomial represents and returns it as constant. - * Otherwise, (when the polynomial is not constant polynomial) returns `null`. - */ - override fun NumberedPolynomial.asConstantOrNull(): C? = - with(coefficients) { - if(isConstant()) getOrElse(emptyList()) { constantZero } - else null - } - @Suppress("NOTHING_TO_INLINE") public inline fun NumberedPolynomial.substitute(argument: Map): NumberedPolynomial = this.substitute(ring, argument) @Suppress("NOTHING_TO_INLINE") @@ -629,35 +528,6 @@ public open class NumberedPolynomialSpace>( @JvmName("invokePolynomial") public inline operator fun NumberedPolynomial.invoke(argument: Map>): NumberedPolynomial = this.substitute(ring, argument) - // TODO: Move to other internal utilities with context receiver - @JvmName("applyAndRemoveZerosInternal") - internal fun MutableMap, C>.applyAndRemoveZeros(block: MutableMap, C>.() -> Unit) : MutableMap, C> { - contract { - callsInPlace(block, InvocationKind.EXACTLY_ONCE) - } - block() - for ((degs, c) in this) if (c.isZero()) this.remove(degs) - return this - } - internal fun Map, C>.applyAndRemoveZeros(block: MutableMap, C>.() -> Unit) : Map, C> = - toMutableMap().applyAndRemoveZeros(block) - @OptIn(ExperimentalTypeInference::class) - internal inline fun buildCoefficients(@BuilderInference builderAction: MutableMap, C>.() -> Unit): Map, C> { - contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) } - return buildMap { - builderAction() - for ((degs, c) in this) if (c.isZero()) this.remove(degs) - } - } - @OptIn(ExperimentalTypeInference::class) - internal inline fun buildCoefficients(capacity: Int, @BuilderInference builderAction: MutableMap, C>.() -> Unit): Map, C> { - contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) } - return buildMap(capacity) { - builderAction() - for ((degs, c) in this) if (c.isZero()) this.remove(degs) - } - } - // TODO: Move to other constructors with context receiver public fun C.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomial(mapOf(emptyList() to this)) } \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt index 2a4d942a6..b4d9f1d91 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt @@ -19,45 +19,35 @@ public class NumberedRationalFunction internal constructor( // Waiting for context receivers :( TODO: Replace with context receivers when they will be available -@Suppress("FunctionName") -internal fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numerator: NumberedPolynomial, denominator: NumberedPolynomial): NumberedRationalFunction = - if (denominator.isZero()) throw ArithmeticException("/ by zero") - else NumberedRationalFunction(numerator, denominator) -@Suppress("FunctionName") -internal fun > A.NumberedRationalFunction(numerator: NumberedPolynomial, denominator: NumberedPolynomial): NumberedRationalFunction = - if (denominator.coefficients.values.all { it == zero }) throw ArithmeticException("/ by zero") - else NumberedRationalFunction(numerator, denominator) @Suppress("FunctionName") public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): NumberedRationalFunction = - if (denominatorCoefficients.values.all { it == zero }) throw ArithmeticException("/ by zero") - else NumberedRationalFunction( - NumberedPolynomial(numeratorCoefficients), - NumberedPolynomial(denominatorCoefficients) + NumberedRationalFunction( + NumberedPolynomial(numeratorCoefficients, toCheckInput = true), + NumberedPolynomial(denominatorCoefficients, toCheckInput = true) ) @Suppress("FunctionName") public fun > A.NumberedRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): NumberedRationalFunction = - if (denominatorCoefficients.values.all { it == zero }) throw ArithmeticException("/ by zero") - else NumberedRationalFunction( - NumberedPolynomial(numeratorCoefficients), - NumberedPolynomial(denominatorCoefficients) + NumberedRationalFunction( + NumberedPolynomial(numeratorCoefficients, toCheckInput = true), + NumberedPolynomial(denominatorCoefficients, toCheckInput = true) ) @Suppress("FunctionName") public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numerator: NumberedPolynomial): NumberedRationalFunction = NumberedRationalFunction(numerator, polynomialOne) @Suppress("FunctionName") public fun > A.NumberedRationalFunction(numerator: NumberedPolynomial): NumberedRationalFunction = - NumberedRationalFunction(numerator, NumberedPolynomial(mapOf(emptyList() to one))) + NumberedRationalFunction(numerator, NumberedPolynomial(mapOf(emptyList() to one), toCheckInput = false)) @Suppress("FunctionName") public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numeratorCoefficients: Map, C>): NumberedRationalFunction = NumberedRationalFunction( - NumberedPolynomial(numeratorCoefficients), + NumberedPolynomial(numeratorCoefficients, toCheckInput = true), polynomialOne ) @Suppress("FunctionName") public fun > A.NumberedRationalFunction(numeratorCoefficients: Map, C>): NumberedRationalFunction = NumberedRationalFunction( - NumberedPolynomial(numeratorCoefficients), - NumberedPolynomial(mapOf(emptyList() to one)) + NumberedPolynomial(numeratorCoefficients, toCheckInput = true), + NumberedPolynomial(mapOf(emptyList() to one), toCheckInput = false) ) public class NumberedRationalFunctionSpace> ( @@ -91,28 +81,6 @@ public class NumberedRationalFunctionSpace> ( */ public override val one: NumberedRationalFunction = NumberedRationalFunction(polynomialOne, polynomialOne) - /** - * Checks equality of the rational functions. - */ - public override infix fun NumberedRationalFunction.equalsTo(other: NumberedRationalFunction): Boolean { - if (this === other) return true - - if (numerator.isZero() != other.numerator.isZero()) return false - - val countOfVariables = max(this.lastVariable, other.lastVariable) - val thisNumeratorDegrees = this.numerator.degrees - val thisDenominatorDegrees = this.denominator.degrees - val otherNumeratorDegrees = other.numerator.degrees - val otherDenominatorDegrees = other.denominator.degrees - for (variable in 0 .. countOfVariables) - if ( - thisNumeratorDegrees.getOrElse(variable) { 0u } + otherDenominatorDegrees.getOrElse(variable) { 0u } - != thisDenominatorDegrees.getOrElse(variable) { 0u } + otherNumeratorDegrees.getOrElse(variable) { 0u } - ) return false - - return numerator * other.denominator equalsTo other.numerator * denominator - } - /** * Maximal index (ID) of variable occurring in the polynomial with positive power. If there is no such variable, * the result is `-1`. @@ -152,13 +120,13 @@ public class NumberedRationalFunctionSpace> ( public val NumberedRationalFunction.countOfVariables: Int get() = MutableList(lastVariable + 1) { false }.apply { - numerator.coefficients.entries.forEach { (degs, c) -> - if (c.isNotZero()) degs.forEachIndexed { index, deg -> + numerator.coefficients.entries.forEach { (degs, _) -> + degs.forEachIndexed { index, deg -> if (deg != 0u) this[index] = true } } - denominator.coefficients.entries.forEach { (degs, c) -> - if (c.isNotZero()) degs.forEachIndexed { index, deg -> + denominator.coefficients.entries.forEach { (degs, _) -> + degs.forEachIndexed { index, deg -> if (deg != 0u) this[index] = true } } 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 d44c47dd6..96e860550 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 @@ -155,31 +155,6 @@ public interface PolynomialSpace> : Ring

{ @JsName("constantPower") public fun power(arg: C, exponent: UInt) : C - /** - * Check if the instant is zero constant. - */ - public fun C.isZero(): Boolean = this == constantZero - /** - * Check if the instant is NOT zero constant. - */ - public fun C.isNotZero(): Boolean = !isZero() - /** - * Check if the instant is unit constant. - */ - public fun C.isOne(): Boolean = this == constantOne - /** - * Check if the instant is NOT unit constant. - */ - public fun C.isNotOne(): Boolean = !isOne() - /** - * Check if the instant is minus unit constant. - */ - public fun C.isMinusOne(): Boolean = this == -constantOne - /** - * Check if the instant is NOT minus unit constant. - */ - public fun C.isNotMinusOne(): Boolean = !isMinusOne() - /** * Instance of zero constant (zero of the underlying ring). */ @@ -249,31 +224,6 @@ public interface PolynomialSpace> : Ring

{ */ public override fun power(arg: P, exponent: UInt) : P = exponentiationBySquaring(arg, exponent) - /** - * Check if the instant is zero polynomial. - */ - public fun P.isZero(): Boolean = this equalsTo zero - /** - * Check if the instant is NOT zero polynomial. - */ - public fun P.isNotZero(): Boolean = !isZero() - /** - * Check if the instant is unit polynomial. - */ - public fun P.isOne(): Boolean = this equalsTo one - /** - * Check if the instant is NOT unit polynomial. - */ - public fun P.isNotOne(): Boolean = !isOne() - /** - * Check if the instant is minus unit polynomial. - */ - public fun P.isMinusOne(): Boolean = this equalsTo -one - /** - * Check if the instant is NOT minus unit polynomial. - */ - public fun P.isNotMinusOne(): Boolean = !isMinusOne() - /** * Instance of zero polynomial (zero of the polynomial ring). */ @@ -283,48 +233,12 @@ public interface PolynomialSpace> : Ring

{ */ public override val one: P - /** - * Checks equality of the polynomials. - */ - public infix fun P.equalsTo(other: P): Boolean - /** - * Checks NOT equality of the polynomials. - */ - public infix fun P.notEqualsTo(other: P): Boolean = !(this equalsTo other) - /** * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is * zero, degree is -1. */ public val P.degree: Int - /** - * Checks if the instant is constant polynomial (of degree no more than 0) over considered ring. - */ - public fun P.isConstant(): Boolean = degree <= 0 - /** - * Checks if the instant is **not** constant polynomial (of degree no more than 0) over considered ring. - */ - public fun P.isNotConstant(): Boolean = !isConstant() - /** - * Checks if the instant is constant non-zero polynomial (of degree no more than 0) over considered ring. - */ - public fun P.isNonZeroConstant(): Boolean = degree == 0 - /** - * Checks if the instant is **not** constant non-zero polynomial (of degree no more than 0) over considered ring. - */ - public fun P.isNotNonZeroConstant(): Boolean = !isNonZeroConstant() - /** - * If polynomial is a constant polynomial represents and returns it as constant. - * Otherwise, (when the polynomial is not constant polynomial) returns `null`. - */ - public fun P.asConstantOrNull(): C? - /** - * If polynomial is a constant polynomial represents and returns it as constant. - * Otherwise, (when the polynomial is not constant polynomial) raises corresponding exception. - */ - public fun P.asConstant(): C = requireNotNull(asConstantOrNull()) { "Can not represent non-constant polynomial as a constant" } - override fun add(left: P, right: P): P = left + right override fun multiply(left: P, right: P): P = left * right } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt index 9c0263c4c..374f4a936 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt @@ -222,31 +222,6 @@ public interface RationalFunctionalSpace, R: RationalFunctio @JsName("constantPower") public fun power(arg: C, exponent: UInt) : C - /** - * Check if the instant is zero constant. - */ - public fun C.isZero(): Boolean = this == constantZero - /** - * Check if the instant is NOT zero constant. - */ - public fun C.isNotZero(): Boolean = !isZero() - /** - * Check if the instant is unit constant. - */ - public fun C.isOne(): Boolean = this == constantOne - /** - * Check if the instant is NOT unit constant. - */ - public fun C.isNotOne(): Boolean = !isOne() - /** - * Check if the instant is minus unit constant. - */ - public fun C.isMinusOne(): Boolean = this == -constantOne - /** - * Check if the instant is NOT minus unit constant. - */ - public fun C.isNotMinusOne(): Boolean = !isMinusOne() - /** * Instance of zero constant (zero of the underlying ring). */ @@ -320,31 +295,6 @@ public interface RationalFunctionalSpace, R: RationalFunctio */ public fun power(arg: P, exponent: UInt) : P - /** - * Check if the instant is zero polynomial. - */ - public fun P.isZero(): Boolean = this equalsTo polynomialZero - /** - * Check if the instant is NOT zero polynomial. - */ - public fun P.isNotZero(): Boolean = !isZero() - /** - * Check if the instant is unit polynomial. - */ - public fun P.isOne(): Boolean = this equalsTo polynomialOne - /** - * Check if the instant is NOT unit polynomial. - */ - public fun P.isNotOne(): Boolean = !isOne() - /** - * Check if the instant is minus unit polynomial. - */ - public fun P.isMinusOne(): Boolean = this equalsTo -polynomialOne - /** - * Check if the instant is NOT minus unit polynomial. - */ - public fun P.isNotMinusOne(): Boolean = !isMinusOne() - /** * Instance of zero polynomial (zero of the polynomial ring). */ @@ -354,15 +304,6 @@ public interface RationalFunctionalSpace, R: RationalFunctio */ public val polynomialOne: P - /** - * Checks equality of the polynomials. - */ - public infix fun P.equalsTo(other: P): Boolean - /** - * Checks NOT equality of the polynomials. - */ - public infix fun P.notEqualsTo(other: P): Boolean = !(this equalsTo other) - /** * Returns sum of the constant represented as rational function and the rational function. */ @@ -478,31 +419,6 @@ public interface RationalFunctionalSpace, R: RationalFunctio */ public override fun power(arg: R, exponent: UInt) : R = exponentiationBySquaring(arg, exponent) - /** - * Check if the instant is zero rational function. - */ - public fun R.isZero(): Boolean = numerator equalsTo polynomialZero - /** - * Check if the instant is NOT zero rational function. - */ - public fun R.isNotZero(): Boolean = !isZero() - /** - * Check if the instant is unit rational function. - */ - public fun R.isOne(): Boolean = numerator equalsTo denominator - /** - * Check if the instant is NOT unit rational function. - */ - public fun R.isNotOne(): Boolean = !isOne() - /** - * Check if the instant is minus unit rational function. - */ - public fun R.isMinusOne(): Boolean = (numerator + denominator).isZero() - /** - * Check if the instant is NOT minus unit rational function. - */ - public fun R.isNotMinusOne(): Boolean = !isMinusOne() - /** * Instance of zero rational function (zero of the rational functions ring). */ @@ -512,54 +428,12 @@ public interface RationalFunctionalSpace, R: RationalFunctio */ public override val one: R - /** - * Checks equality of the rational functions. - */ - public infix fun R.equalsTo(other: R): Boolean = - when { - this === other -> true - numerator.isZero() != other.numerator.isZero() -> false - numeratorDegree - denominatorDegree != with(other) { numeratorDegree - denominatorDegree } -> false - else -> numerator * other.denominator equalsTo other.numerator * denominator - } - /** - * Checks NOT equality of the polynomials. - */ - public infix fun R.notEqualsTo(other: R): Boolean = !(this equalsTo other) - /** * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is * zero, degree is -1. */ public val P.degree: Int - /** - * Checks if the instant is constant polynomial (of degree no more than 0) over considered ring. - */ - public fun P.isConstant(): Boolean = degree <= 0 - /** - * Checks if the instant is **not** constant polynomial (of degree no more than 0) over considered ring. - */ - public fun P.isNotConstant(): Boolean = !isConstant() - /** - * Checks if the instant is constant non-zero polynomial (of degree no more than 0) over considered ring. - */ - public fun P.isNonZeroConstant(): Boolean = degree == 0 - /** - * Checks if the instant is **not** constant non-zero polynomial (of degree no more than 0) over considered ring. - */ - public fun P.isNotNonZeroConstant(): Boolean = !isNonZeroConstant() - /** - * If polynomial is a constant polynomial represents and returns it as constant. - * Otherwise, (when the polynomial is not constant polynomial) returns `null`. - */ - public fun P.asConstantOrNull(): C? - /** - * If polynomial is a constant polynomial represents and returns it as constant. - * Otherwise, (when the polynomial is not constant polynomial) raises corresponding exception. - */ - public fun P.asConstant(): C = requireNotNull(asConstantOrNull()) { "Can not represent non-constant polynomial as a constant" } - /** * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is * zero, degree is -1. @@ -813,31 +687,6 @@ public interface RationalFunctionalSpaceOverPolynomialSpace< @JvmName("constantPower") public override fun power(arg: C, exponent: UInt) : C = polynomialRing { power(arg, exponent) } - /** - * Check if the instant is zero constant. - */ - public override fun C.isZero(): Boolean = polynomialRing { this@isZero.isZero() } - /** - * Check if the instant is NOT zero constant. - */ - public override fun C.isNotZero(): Boolean = polynomialRing { this@isNotZero.isNotZero() } - /** - * Check if the instant is unit constant. - */ - public override fun C.isOne(): Boolean = polynomialRing { this@isOne.isOne() } - /** - * Check if the instant is NOT unit constant. - */ - public override fun C.isNotOne(): Boolean = polynomialRing { this@isNotOne.isNotOne() } - /** - * Check if the instant is minus unit constant. - */ - public override fun C.isMinusOne(): Boolean = polynomialRing { this@isMinusOne.isMinusOne() } - /** - * Check if the instant is NOT minus unit constant. - */ - public override fun C.isNotMinusOne(): Boolean = polynomialRing { this@isNotMinusOne.isNotMinusOne() } - /** * Instance of zero constant (zero of the underlying ring). */ @@ -907,31 +756,6 @@ public interface RationalFunctionalSpaceOverPolynomialSpace< */ public override fun power(arg: P, exponent: UInt) : P = polynomialRing { power(arg, exponent) } - /** - * Check if the instant is zero polynomial. - */ - public override fun P.isZero(): Boolean = polynomialRing { this@isZero.isZero() } - /** - * Check if the instant is NOT zero polynomial. - */ - public override fun P.isNotZero(): Boolean = polynomialRing { this@isNotZero.isNotZero() } - /** - * Check if the instant is unit polynomial. - */ - public override fun P.isOne(): Boolean = polynomialRing { this@isOne.isOne() } - /** - * Check if the instant is NOT unit polynomial. - */ - public override fun P.isNotOne(): Boolean = polynomialRing { this@isNotOne.isNotOne() } - /** - * Check if the instant is minus unit polynomial. - */ - public override fun P.isMinusOne(): Boolean = polynomialRing { this@isMinusOne.isMinusOne() } - /** - * Check if the instant is NOT minus unit polynomial. - */ - public override fun P.isNotMinusOne(): Boolean = polynomialRing { this@isNotMinusOne.isNotMinusOne() } - /** * Instance of zero polynomial (zero of the polynomial ring). */ @@ -941,47 +765,11 @@ public interface RationalFunctionalSpaceOverPolynomialSpace< */ public override val polynomialOne: P get() = polynomialRing.one - /** - * Checks equality of the polynomials. - */ - public override infix fun P.equalsTo(other: P): Boolean = polynomialRing { this@equalsTo equalsTo other } - /** - * Checks NOT equality of the polynomials. - */ - public override infix fun P.notEqualsTo(other: P): Boolean = polynomialRing { this@notEqualsTo notEqualsTo other } - /** * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is * zero, degree is -1. */ public override val P.degree: Int get() = polynomialRing { this@degree.degree } - - /** - * Checks if the instant is constant polynomial (of degree no more than 0) over considered ring. - */ - public override fun P.isConstant(): Boolean = polynomialRing { this@isConstant.isConstant() } - /** - * Checks if the instant is **not** constant polynomial (of degree no more than 0) over considered ring. - */ - public override fun P.isNotConstant(): Boolean = polynomialRing { this@isNotConstant.isNotConstant() } - /** - * Checks if the instant is constant non-zero polynomial (of degree no more than 0) over considered ring. - */ - public override fun P.isNonZeroConstant(): Boolean = polynomialRing { this@isNonZeroConstant.isNonZeroConstant() } - /** - * Checks if the instant is **not** constant non-zero polynomial (of degree no more than 0) over considered ring. - */ - public override fun P.isNotNonZeroConstant(): Boolean = polynomialRing { this@isNotNonZeroConstant.isNotNonZeroConstant() } - /** - * If polynomial is a constant polynomial represents and returns it as constant. - * Otherwise, (when the polynomial is not constant polynomial) returns `null`. - */ - public override fun P.asConstantOrNull(): C? = polynomialRing { this@asConstantOrNull.asConstantOrNull() } - /** - * If polynomial is a constant polynomial represents and returns it as constant. - * Otherwise, (when the polynomial is not constant polynomial) raises corresponding exception. - */ - public override fun P.asConstant(): C = polynomialRing { this@asConstant.asConstant() } } /** @@ -1032,18 +820,11 @@ public abstract class PolynomialSpaceOfFractions< denominator ) - public override operator fun R.div(other: Int): R { - val otherAsConstant = constantNumber(other) - require(otherAsConstant.isNotZero()) { "/ by zero." } - return constructRationalFunction( + public override operator fun R.div(other: Int): R = + constructRationalFunction( numerator, - (denominator * other).also { - check(it.isNotZero()) { - "Got zero denominator during division of rational functions to constant. It means underlying ring of polynomials is not integral domain." - } - } + denominator * other ) - } /** * Returns sum of the integer represented as rational function and the rational function. @@ -1076,13 +857,11 @@ public abstract class PolynomialSpaceOfFractions< other.denominator ) - public override operator fun Int.div(other: R): R { - require(other.numerator.isNotZero()) { "/ by zero." } - return constructRationalFunction( + public override operator fun Int.div(other: R): R = + constructRationalFunction( this * other.denominator, other.numerator ) - } /** * Converts the integer [value] to rational function. @@ -1119,13 +898,11 @@ public abstract class PolynomialSpaceOfFractions< other.denominator ) - public override operator fun C.div(other: R): R { - require(other.numerator.isNotZero()) { "/ by zero." } - return constructRationalFunction( + public override operator fun C.div(other: R): R = + constructRationalFunction( this * other.denominator, other.numerator ) - } /** * Returns sum of the constant represented as rational function and the rational function. @@ -1152,17 +929,11 @@ public abstract class PolynomialSpaceOfFractions< denominator ) - public override operator fun R.div(other: C): R { - require(other.isNotZero()) { "/ by zero." } - return constructRationalFunction( + public override operator fun R.div(other: C): R = + constructRationalFunction( numerator, - (denominator * other).also { - check(it.isNotZero()) { - "Got zero denominator during division of rational functions to constant. It means underlying ring of polynomials is not integral domain." - } - } + denominator * other ) - } /** * Converts the constant [value] to rational function. @@ -1194,13 +965,11 @@ public abstract class PolynomialSpaceOfFractions< other.denominator ) - public override operator fun P.div(other: R): R { - require(other.numerator.isNotZero()) { "/ by zero." } - return constructRationalFunction( + public override operator fun P.div(other: R): R = + constructRationalFunction( this * other.denominator, other.numerator ) - } /** * Returns sum of the polynomial represented as rational function and the rational function. @@ -1227,17 +996,11 @@ public abstract class PolynomialSpaceOfFractions< denominator ) - public override operator fun R.div(other: P): R { - require(other.isNotZero()) { "/ by zero." } - return constructRationalFunction( + public override operator fun R.div(other: P): R = + constructRationalFunction( numerator, - (denominator * other).also { - require(it.isNotZero()) { - "Got zero denominator during division of rational functions to polynomial. It means underlying ring of polynomials is not integral domain." - } - } + denominator * other ) - } /** * Converts the polynomial [value] to rational function. @@ -1254,11 +1017,7 @@ public abstract class PolynomialSpaceOfFractions< public override operator fun R.plus(other: R): R = constructRationalFunction( numerator * other.denominator + denominator * other.numerator, - (denominator * other.denominator).also { - check(it.isNotZero()) { - "Got zero denominator during addition of rational functions. It means underlying ring of polynomials is not integral domain." - } - } + denominator * other.denominator ) /** * Returns difference of the rational functions. @@ -1266,11 +1025,7 @@ public abstract class PolynomialSpaceOfFractions< public override operator fun R.minus(other: R): R = constructRationalFunction( numerator * other.denominator - denominator * other.numerator, - (denominator * other.denominator).also { - check(it.isNotZero()) { - "Got zero denominator during subtraction of rational functions. It means underlying ring of polynomials is not integral domain." - } - } + denominator * other.denominator ) /** * Returns product of the rational functions. @@ -1278,24 +1033,14 @@ public abstract class PolynomialSpaceOfFractions< public override operator fun R.times(other: R): R = constructRationalFunction( numerator * other.numerator, - (denominator * other.denominator).also { - check(it.isNotZero()) { - "Got zero denominator during multiplication of rational functions. It means underlying ring of polynomials is not integral domain." - } - } + denominator * other.denominator ) - public override operator fun R.div(other: R): R { - require(other.isNotZero()) { "/ by zero." } - return constructRationalFunction( + public override operator fun R.div(other: R): R = + constructRationalFunction( numerator * other.denominator, - (denominator * other.numerator).also { - check(it.isNotZero()) { - "Got zero denominator during division of rational functions. It means underlying ring of polynomials is not integral domain." - } - } + denominator * other.numerator ) - } /** * Instance of zero rational function (zero of the rational functions ring). diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listPolynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listPolynomialUtil.kt index 35155d09d..50313cab9 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listPolynomialUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listPolynomialUtil.kt @@ -121,9 +121,9 @@ public fun ListPolynomial.substitute(ring: Ring, arg: C): C = ring { public fun ListPolynomial.substitute(ring: Ring, arg: ListPolynomial) : ListPolynomial = ring { if (coefficients.isEmpty()) return ListPolynomial(emptyList()) - val thisDegree = coefficients.indexOfLast { it != zero } + val thisDegree = coefficients.lastIndex if (thisDegree == -1) return ListPolynomial(emptyList()) - val argDegree = arg.coefficients.indexOfLast { it != zero } + val argDegree = arg.coefficients.lastIndex if (argDegree == -1) return coefficients[0].asListPolynomial() val constantZero = zero val resultCoefs: MutableList = MutableList(thisDegree * argDegree + 1) { constantZero } @@ -144,7 +144,6 @@ public fun ListPolynomial.substitute(ring: Ring, arg: ListPolynomial(resultCoefs) } @@ -168,7 +167,6 @@ public fun ListPolynomial.derivative( ListPolynomial( buildList(max(0, coefficients.size - 1)) { for (deg in 1 .. coefficients.lastIndex) add(number(deg) * coefficients[deg]) - while (isNotEmpty() && elementAt(lastIndex) == algebra.zero) removeAt(lastIndex) } ) } @@ -186,7 +184,6 @@ public fun ListPolynomial.nthDerivative( buildList(max(0, coefficients.size - order)) { for (deg in order.. coefficients.lastIndex) add((deg - order + 1 .. deg).fold(coefficients[deg]) { acc, d -> acc * number(d) }) - while (isNotEmpty() && elementAt(lastIndex) == algebra.zero) removeAt(lastIndex) } ) } @@ -202,7 +199,6 @@ public fun ListPolynomial.antiderivative( buildList(coefficients.size + 1) { add(zero) coefficients.mapIndexedTo(this) { index, t -> t / number(index + 1) } - while (isNotEmpty() && elementAt(lastIndex) == algebra.zero) removeAt(lastIndex) } ) } @@ -220,7 +216,6 @@ public fun ListPolynomial.nthAntiderivative( buildList(coefficients.size + order) { repeat(order) { add(zero) } coefficients.mapIndexedTo(this) { index, c -> (1..order).fold(c) { acc, i -> acc / number(index + i) } } - while (isNotEmpty() && elementAt(lastIndex) == algebra.zero) removeAt(lastIndex) } ) } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listRationalFunctionUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listRationalFunctionUtil.kt index 151c7bb8d..367212588 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listRationalFunctionUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listRationalFunctionUtil.kt @@ -55,11 +55,11 @@ public fun ListRationalFunction.substitute(ring: Field, arg: C): C = r internal fun ListPolynomial.substituteRationalFunctionTakeNumerator(ring: Ring, arg: ListRationalFunction): ListPolynomial = ring { if (coefficients.isEmpty()) return ListPolynomial(emptyList()) - val thisDegree = coefficients.indexOfLast { it != zero } + val thisDegree = coefficients.lastIndex if (thisDegree == -1) return ListPolynomial(emptyList()) val thisDegreeLog2 = 31 - thisDegree.countLeadingZeroBits() - val numeratorDegree = arg.numerator.coefficients.indexOfLast { it != zero } - val denominatorDegree = arg.denominator.coefficients.indexOfLast { it != zero } + val numeratorDegree = arg.numerator.coefficients.lastIndex + val denominatorDegree = arg.denominator.coefficients.lastIndex val argDegree = max(numeratorDegree, denominatorDegree) val constantZero = zero val powersOf2 = buildList(thisDegreeLog2 + 1) { diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt index 0d2c4b5fc..ac2647592 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt @@ -9,7 +9,7 @@ import space.kscience.kmath.test.misc.* import kotlin.test.* -class ListPolynomialTest { +class ListPolynomialTest { // TODO: Adapt tests to changes @Test fun test_Polynomial_Int_plus() { RationalField.listPolynomial { @@ -489,94 +489,6 @@ class ListPolynomialTest { } } @Test - fun test_Polynomial_isZero() { - RationalField.listPolynomial { - assertTrue("test 1") { ListPolynomial().isZero() } - assertTrue("test 2") { ListPolynomial(Rational(0)).isZero() } - assertTrue("test 3") { ListPolynomial(Rational(0), Rational(0)).isZero() } - assertTrue("test 4") { ListPolynomial(Rational(0), Rational(0), Rational(0)) - .isZero() } - assertFalse("test 5") { ListPolynomial(Rational(3, 5)).isZero() } - assertFalse("test 6") { ListPolynomial(Rational(3, 5), Rational(0)) - .isZero() } - assertFalse("test 7") { ListPolynomial(Rational(0), Rational(3, 5), Rational(0)) - .isZero() } - } - } - @Test - fun test_Polynomial_isOne() { - RationalField.listPolynomial { - assertFalse("test 1") { ListPolynomial().isOne() } - assertFalse("test 2") { ListPolynomial(Rational(0)).isOne() } - assertFalse("test 3") { ListPolynomial(Rational(0), Rational(0)).isOne() } - assertFalse("test 4") { ListPolynomial(Rational(0), Rational(0), Rational(0)) - .isOne() } - assertFalse("test 5") { ListPolynomial(Rational(3, 5)).isOne() } - assertTrue("test 6") { ListPolynomial(Rational(5, 5)).isOne() } - assertFalse("test 7") { ListPolynomial(Rational(3, 5), Rational(0)).isOne() } - assertTrue("test 8") { ListPolynomial(Rational(3, 3), Rational(0)).isOne() } - assertFalse("test 9") { ListPolynomial(Rational(0), Rational(3, 5), Rational(0)) - .isOne() } - assertFalse("test 10") { ListPolynomial(Rational(0), Rational(5, 5), Rational(0)) - .isOne() } - assertFalse("test 11") { ListPolynomial(Rational(1), Rational(3, 5), Rational(0)) - .isOne() } - assertFalse("test 12") { ListPolynomial(Rational(1), Rational(5, 5), Rational(0)) - .isOne() } - } - } - @Test - fun test_Polynomial_isMinusOne() { - RationalField.listPolynomial { - assertFalse("test 1") { ListPolynomial().isMinusOne() } - assertFalse("test 2") { ListPolynomial(Rational(0)).isMinusOne() } - assertFalse("test 3") { ListPolynomial(Rational(0), Rational(0)).isMinusOne() } - assertFalse("test 4") { ListPolynomial(Rational(0), Rational(0), Rational(0)) - .isMinusOne() } - assertFalse("test 5") { ListPolynomial(Rational(3, 5)).isMinusOne() } - assertTrue("test 6") { ListPolynomial(Rational(-5, 5)).isMinusOne() } - assertFalse("test 7") { ListPolynomial(Rational(3, 5), Rational(0)).isMinusOne() } - assertTrue("test 8") { ListPolynomial(Rational(-3, 3), Rational(0)).isMinusOne() } - assertFalse("test 9") { ListPolynomial(Rational(0), Rational(3, 5), Rational(0)) - .isMinusOne() } - assertFalse("test 10") { ListPolynomial(Rational(0), Rational(5, -5), Rational(0)) - .isMinusOne() } - assertFalse("test 11") { ListPolynomial(Rational(-1), Rational(3, 5), Rational(0)) - .isMinusOne() } - assertFalse("test 12") { ListPolynomial(Rational(-1), Rational(5, -5), Rational(0)) - .isMinusOne() } - } - } - @Test - fun test_Polynomial_Polynomial_equalsTo() { - RationalField.listPolynomial { - assertTrue("test 1") { - ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) equalsTo - ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - } - assertTrue("test 2") { - ListPolynomial(Rational(5, 9), Rational(0), Rational(-8, 7)) equalsTo - ListPolynomial(Rational(5, 9), Rational(0), Rational(-8, 7)) - } - assertTrue("test 3") { - ListPolynomial(Rational(0), Rational(0), Rational(-8, 7), Rational(0), Rational(0)) equalsTo - ListPolynomial(Rational(0), Rational(0), Rational(-8, 7)) - } - assertFalse("test 4") { - ListPolynomial(Rational(5, 9), Rational(5, 7), Rational(-8, 7)) equalsTo - ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - } - assertFalse("test 5") { - ListPolynomial(Rational(8, 3), Rational(0), Rational(-8, 7)) equalsTo - ListPolynomial(Rational(5, 9), Rational(0), Rational(-8, 7)) - } - assertFalse("test 6") { - ListPolynomial(Rational(0), Rational(0), Rational(-8, 7), Rational(0), Rational(0)) equalsTo - ListPolynomial(Rational(0), Rational(0), Rational(8, 7)) - } - } - } - @Test fun test_Polynomial_degree() { RationalField.listPolynomial { assertEquals( @@ -636,70 +548,4 @@ class ListPolynomialTest { ) } } - @Test - fun test_Polynomial_asConstantOrNull() { - RationalField.listPolynomial { - assertEquals( - Rational(0), - ListPolynomial().asConstantOrNull(), - "test 1" - ) - assertEquals( - Rational(0), - ListPolynomial(Rational(0)).asConstantOrNull(), - "test 2" - ) - assertEquals( - Rational(0), - ListPolynomial(Rational(0), Rational(0)).asConstantOrNull(), - "test 3" - ) - assertEquals( - Rational(0), - ListPolynomial(Rational(0), Rational(0), Rational(0)).asConstantOrNull(), - "test 4" - ) - assertEquals( - Rational(-7, 9), - ListPolynomial(Rational(-7, 9)).asConstantOrNull(), - "test 5" - ) - assertEquals( - Rational(-7, 9), - ListPolynomial(Rational(-7, 9), Rational(0)).asConstantOrNull(), - "test 6" - ) - assertEquals( - Rational(-7, 9), - ListPolynomial(Rational(-7, 9), Rational(0), Rational(0)).asConstantOrNull(), - "test 7" - ) - assertEquals( - null, - ListPolynomial(Rational(0), Rational(-7, 9)).asConstantOrNull(), - "test 8" - ) - assertEquals( - null, - ListPolynomial(Rational(0), Rational(-7, 9), Rational(0)).asConstantOrNull(), - "test 9" - ) - assertEquals( - null, - ListPolynomial(Rational(0), Rational(0), Rational(-7, 9)).asConstantOrNull(), - "test 10" - ) - assertEquals( - null, - ListPolynomial(Rational(4, 15), Rational(0), Rational(-7, 9)).asConstantOrNull(), - "test 11" - ) - assertEquals( - null, - ListPolynomial(Rational(4, 15), Rational(0), Rational(-7, 9), Rational(0)) - .asConstantOrNull(), - "test 12" - ) - } - } } \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt index 50ae18260..c4f07d957 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt @@ -12,7 +12,7 @@ import kotlin.test.assertEquals import kotlin.test.assertFailsWith -class ListPolynomialUtilTest { +class ListPolynomialUtilTest { // TODO: Adapt tests to changes @Test fun test_substitute_Double() { assertEquals( -- 2.34.1 From 7e328a5dbf936256a4612f582b5802b3d8e5a9aa Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Fri, 25 Mar 2022 00:59:48 +0300 Subject: [PATCH 056/123] Enhanced DSL constructor a bit. --- .../space/kscience/kmath/functions/NumberedPolynomial.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt index 51f316c5d..f931e8e7e 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -157,7 +157,8 @@ public class NumberedPolynomialTermSignatureBuilder { signature[this] = deg } } - public infix fun Int.to(deg: UInt): Unit = this inPowerOf deg + public infix fun Int.pow(deg: UInt): Unit = this inPowerOf deg + public infix fun Int.of(deg: UInt): Unit = this inPowerOf deg } @NumberedPolynomialConstructorDSL @@ -168,6 +169,7 @@ public class NumberedPolynomialBuilderOverRing internal constructor(internal val signature = NumberedPolynomialTermSignatureBuilder().apply(block).build() coefficients[signature] = context { coefficients.getOrElse(signature) { zero } + this@invoke } } + public infix fun C.with(block: NumberedPolynomialTermSignatureBuilder.() -> Unit): Unit = this.invoke(block) } @NumberedPolynomialConstructorDSL -- 2.34.1 From f7286d33d27f9312f163106ef7f137cf594f1ff0 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Fri, 25 Mar 2022 17:18:56 +0300 Subject: [PATCH 057/123] Moved constructors to separate files. Replaced some TODOs with FIXMEs. --- .../kmath/functions/LabeledPolynomial.kt | 96 --------- .../functions/LabeledRationalFunction.kt | 33 --- .../kmath/functions/ListPolynomial.kt | 18 -- .../kmath/functions/ListRationalFunction.kt | 33 --- .../kmath/functions/NumberedPolynomial.kt | 148 +------------- .../functions/NumberedRationalFunction.kt | 33 --- .../kmath/functions/RationalFunction.kt | 9 +- .../kscience/kmath/functions/algebraicStub.kt | 16 +- .../kmath/functions/labeledConstructors.kt | 147 ++++++++++++++ .../kmath/functions/listConstructors.kt | 60 ++++++ .../kmath/functions/numberedConstructors.kt | 188 ++++++++++++++++++ .../kmath/functions/numberedPolynomialUtil.kt | 33 --- 12 files changed, 408 insertions(+), 406 deletions(-) create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt index 908e89534..b904f7331 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt @@ -8,10 +8,6 @@ package space.kscience.kmath.functions import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.operations.Ring import space.kscience.kmath.operations.ScaleOperations -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract -import kotlin.experimental.ExperimentalTypeInference -import kotlin.jvm.JvmName import kotlin.math.max @@ -49,98 +45,6 @@ internal constructor( override fun toString(): String = "LabeledPolynomial$coefficients" } -/** - * Returns the same degrees' description of the monomial, but without zero degrees. - */ -internal fun Map.cleanUp() = filterValues { it > 0U } - -// Waiting for context receivers :( TODO: Replace with context receivers when they will be available - -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > LabeledPolynomialSpace.LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(coefs, toCheckInput) -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(coefs, toCheckInput) -@Suppress("FunctionName") -internal fun > A.LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : LabeledPolynomial { - if (!toCheckInput) return LabeledPolynomial(coefs) - - val fixedCoefs = mutableMapOf, C>() - - for (entry in coefs) { - val key = entry.key.cleanUp() - val value = entry.value - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return LabeledPolynomial(fixedCoefs) -} - -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > LabeledPolynomialSpace.LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(pairs, toCheckInput) -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(pairs, toCheckInput) -@Suppress("FunctionName") -internal fun > A.LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : LabeledPolynomial { - if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) - - val fixedCoefs = mutableMapOf, C>() - - for (entry in pairs) { - val key = entry.first.cleanUp() - val value = entry.second - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return LabeledPolynomial(fixedCoefs) -} - -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > LabeledPolynomialSpace.LabeledPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(pairs = pairs, toCheckInput = toCheckInput) -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(pairs = pairs, toCheckInput = toCheckInput) -@Suppress("FunctionName") -internal fun > A.LabeledPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : LabeledPolynomial { - if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) - - val fixedCoefs = mutableMapOf, C>() - - for (entry in pairs) { - val key = entry.first.cleanUp() - val value = entry.second - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return LabeledPolynomial(fixedCoefs) -} - -@Suppress("FunctionName") -public fun > A.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) -@Suppress("FunctionName") -public fun > LabeledPolynomialSpace.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) -@Suppress("FunctionName") -public fun > LabeledRationalFunctionSpace.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) - -@Suppress("FunctionName") -public fun > A.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > LabeledPolynomialSpace.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > LabeledRationalFunctionSpace.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) - -@Suppress("FunctionName") -public fun > A.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > LabeledPolynomialSpace.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > LabeledRationalFunctionSpace.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs, toCheckInput = true) - -//context(A) -//public fun > Symbol.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1u) to one)) -//context(LabeledPolynomialSpace) -//public fun > Symbol.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1u) to constantOne)) - -public fun C.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to this)) - /** * Space of polynomials. * diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt index 0f46520dc..76c6874f5 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt @@ -17,39 +17,6 @@ public class LabeledRationalFunction( override fun toString(): String = "LabeledRationalFunction${numerator.coefficients}/${denominator.coefficients}" } -// Waiting for context receivers :( TODO: Replace with context receivers when they will be available - -@Suppress("FunctionName") -public fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): LabeledRationalFunction = - LabeledRationalFunction( - LabeledPolynomial(numeratorCoefficients, toCheckInput = true), - LabeledPolynomial(denominatorCoefficients, toCheckInput = true) - ) -@Suppress("FunctionName") -public fun > A.LabeledRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): LabeledRationalFunction = - LabeledRationalFunction( - LabeledPolynomial(numeratorCoefficients, toCheckInput = true), - LabeledPolynomial(denominatorCoefficients, toCheckInput = true) - ) -@Suppress("FunctionName") -public fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numerator: LabeledPolynomial): LabeledRationalFunction = - LabeledRationalFunction(numerator, polynomialOne) -@Suppress("FunctionName") -public fun > A.LabeledRationalFunction(numerator: LabeledPolynomial): LabeledRationalFunction = - LabeledRationalFunction(numerator, LabeledPolynomial(mapOf(emptyMap() to one), toCheckInput = false)) -@Suppress("FunctionName") -public fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numeratorCoefficients: Map, C>): LabeledRationalFunction = - LabeledRationalFunction( - LabeledPolynomial(numeratorCoefficients, toCheckInput = true), - polynomialOne - ) -@Suppress("FunctionName") -public fun > A.LabeledRationalFunction(numeratorCoefficients: Map, C>): LabeledRationalFunction = - LabeledRationalFunction( - LabeledPolynomial(numeratorCoefficients, toCheckInput = true), - LabeledPolynomial(mapOf(emptyMap() to one), toCheckInput = false) - ) - public class LabeledRationalFunctionSpace>( public val ring: A, ) : diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt index 711d2bb49..585da95ea 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt @@ -50,24 +50,6 @@ public data class ListPolynomial( override fun toString(): String = "Polynomial$coefficients" } -/** - * Returns a [ListPolynomial] instance with given [coefficients]. The collection of coefficients will be reversed if - * [reverse] parameter is true. - */ -@Suppress("FunctionName") -public fun ListPolynomial(coefficients: List, reverse: Boolean = false): ListPolynomial = - ListPolynomial(with(coefficients) { if (reverse) reversed() else this }) - -/** - * Returns a [ListPolynomial] instance with given [coefficients]. The collection of coefficients will be reversed if - * [reverse] parameter is true. - */ -@Suppress("FunctionName") -public fun ListPolynomial(vararg coefficients: C, reverse: Boolean = false): ListPolynomial = - ListPolynomial(with(coefficients) { if (reverse) reversed() else toList() }) - -public fun C.asListPolynomial() : ListPolynomial = ListPolynomial(listOf(this)) - /** * Space of univariate polynomials constructed over ring. * diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt index f62d1857f..7b6c23ac3 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt @@ -15,39 +15,6 @@ public data class ListRationalFunction( override fun toString(): String = "RationalFunction${numerator.coefficients}/${denominator.coefficients}" } -// Waiting for context receivers :( TODO: Replace with context receivers when they will be available - -@Suppress("FunctionName") -public fun > ListRationalFunctionSpace.ListRationalFunction(numeratorCoefficients: List, denominatorCoefficients: List, reverse: Boolean = false): ListRationalFunction = - ListRationalFunction( - ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), - ListPolynomial( with(denominatorCoefficients) { if (reverse) reversed() else this } ) - ) -@Suppress("FunctionName") -public fun > A.ListRationalFunction(numeratorCoefficients: List, denominatorCoefficients: List, reverse: Boolean = false): ListRationalFunction = - ListRationalFunction( - ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), - ListPolynomial( with(denominatorCoefficients) { if (reverse) reversed() else this } ) - ) -@Suppress("FunctionName") -public fun > ListRationalFunctionSpace.ListRationalFunction(numerator: ListPolynomial): ListRationalFunction = - ListRationalFunction(numerator, polynomialOne) -@Suppress("FunctionName") -public fun > A.ListRationalFunction(numerator: ListPolynomial): ListRationalFunction = - ListRationalFunction(numerator, ListPolynomial(listOf(one))) -@Suppress("FunctionName") -public fun > ListRationalFunctionSpace.ListRationalFunction(numeratorCoefficients: List, reverse: Boolean = false): ListRationalFunction = - ListRationalFunction( - ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), - polynomialOne - ) -@Suppress("FunctionName") -public fun > A.ListRationalFunction(numeratorCoefficients: List, reverse: Boolean = false): ListRationalFunction = - ListRationalFunction( - ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), - ListPolynomial(listOf(one)) - ) - public class ListRationalFunctionSpace> ( public val ring: A, ) : diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt index f931e8e7e..e75373819 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -49,152 +49,6 @@ internal constructor( override fun toString(): String = "NumberedPolynomial$coefficients" } -/** - * Returns the same degrees' description of the monomial, but without extra zero degrees on the end. - */ -internal fun List.cleanUp() = subList(0, indexOfLast { it != 0U } + 1) - -// Waiting for context receivers :( TODO: Replace with context receivers when they will be available - -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > NumberedPolynomialSpace.NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(coefs, toCheckInput) -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(coefs, toCheckInput) -@Suppress("FunctionName") -internal fun > A.NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : NumberedPolynomial { - if (!toCheckInput) return NumberedPolynomial(coefs) - - val fixedCoefs = mutableMapOf, C>() - - for (entry in coefs) { - val key = entry.key.cleanUp() - val value = entry.value - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return NumberedPolynomial(fixedCoefs) -} - -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > NumberedPolynomialSpace.NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(pairs, toCheckInput) -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(pairs, toCheckInput) -@Suppress("FunctionName") -internal fun > A.NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : NumberedPolynomial { - if (!toCheckInput) return NumberedPolynomial(pairs.toMap()) - - val fixedCoefs = mutableMapOf, C>() - - for (entry in pairs) { - val key = entry.first.cleanUp() - val value = entry.second - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return NumberedPolynomial(fixedCoefs) -} - -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > NumberedPolynomialSpace.NumberedPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(pairs = pairs, toCheckInput = toCheckInput) -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(pairs = pairs, toCheckInput = toCheckInput) -@Suppress("FunctionName") -internal fun > A.NumberedPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : NumberedPolynomial { - if (!toCheckInput) return NumberedPolynomial(pairs.toMap()) - - val fixedCoefs = mutableMapOf, C>() - - for (entry in pairs) { - val key = entry.first.cleanUp() - val value = entry.second - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return NumberedPolynomial(fixedCoefs) -} - -@Suppress("FunctionName") -public fun > A.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, toCheckInput = true) -@Suppress("FunctionName") -public fun > NumberedPolynomialSpace.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, toCheckInput = true) -@Suppress("FunctionName") -public fun > NumberedRationalFunctionSpace.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, toCheckInput = true) - -@Suppress("FunctionName") -public fun > A.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > NumberedPolynomialSpace.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > NumberedRationalFunctionSpace.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, toCheckInput = true) - -@Suppress("FunctionName") -public fun > A.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > NumberedPolynomialSpace.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > NumberedRationalFunctionSpace.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs, toCheckInput = true) - -//context(A) -//public fun > Symbol.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomial(mapOf(mapOf(this to 1u) to one)) -//context(NumberedPolynomialSpace) -//public fun > Symbol.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomial(mapOf(mapOf(this to 1u) to constantOne)) - -//context(A) -//public fun C.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomial(mapOf(emptyList() to this)) - -@DslMarker -internal annotation class NumberedPolynomialConstructorDSL - -@NumberedPolynomialConstructorDSL -public class NumberedPolynomialTermSignatureBuilder { - private val signature: MutableList = ArrayList() - public fun build(): List = signature - public infix fun Int.inPowerOf(deg: UInt) { - if (this > signature.lastIndex) { - signature.addAll(List(this - signature.lastIndex - 1) { 0u }) - signature.add(deg) - } else { - signature[this] = deg - } - } - public infix fun Int.pow(deg: UInt): Unit = this inPowerOf deg - public infix fun Int.of(deg: UInt): Unit = this inPowerOf deg -} - -@NumberedPolynomialConstructorDSL -public class NumberedPolynomialBuilderOverRing internal constructor(internal val context: Ring, capacity: Int = 0) { - private val coefficients: MutableMap, C> = LinkedHashMap(capacity) - public fun build(): NumberedPolynomial = NumberedPolynomial(coefficients) - public operator fun C.invoke(block: NumberedPolynomialTermSignatureBuilder.() -> Unit) { - val signature = NumberedPolynomialTermSignatureBuilder().apply(block).build() - coefficients[signature] = context { coefficients.getOrElse(signature) { zero } + this@invoke } - } - public infix fun C.with(block: NumberedPolynomialTermSignatureBuilder.() -> Unit): Unit = this.invoke(block) -} - -@NumberedPolynomialConstructorDSL -public class NumberedPolynomialBuilderOverPolynomialSpace internal constructor(internal val context: NumberedPolynomialSpace, capacity: Int = 0) { - private val coefficients: MutableMap, C> = LinkedHashMap(capacity) - public fun build(): NumberedPolynomial = NumberedPolynomial(coefficients) - public operator fun C.invoke(block: NumberedPolynomialTermSignatureBuilder.() -> Unit) { - val signature = NumberedPolynomialTermSignatureBuilder().apply(block).build() - coefficients[signature] = context { coefficients.getOrElse(signature) { constantZero } + this@invoke } - } -} - -@NumberedPolynomialConstructorDSL -@Suppress("FunctionName") -public fun > A.NumberedPolynomial(block: NumberedPolynomialBuilderOverRing.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilderOverRing(this).apply(block).build() -@NumberedPolynomialConstructorDSL -@Suppress("FunctionName") -public fun > A.NumberedPolynomial(capacity: Int, block: NumberedPolynomialBuilderOverRing.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilderOverRing(this, capacity).apply(block).build() -@NumberedPolynomialConstructorDSL -@Suppress("FunctionName") -public fun > NumberedPolynomialSpace.NumberedPolynomial(block: NumberedPolynomialBuilderOverPolynomialSpace.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilderOverPolynomialSpace(this).apply(block).build() -@NumberedPolynomialConstructorDSL -@Suppress("FunctionName") -public fun > NumberedPolynomialSpace.NumberedPolynomial(capacity: Int, block: NumberedPolynomialBuilderOverPolynomialSpace.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilderOverPolynomialSpace(this, capacity).apply(block).build() - /** * Space of polynomials. * @@ -530,6 +384,6 @@ public open class NumberedPolynomialSpace>( @JvmName("invokePolynomial") public inline operator fun NumberedPolynomial.invoke(argument: Map>): NumberedPolynomial = this.substitute(ring, argument) - // TODO: Move to other constructors with context receiver + // FIXME: Move to other constructors with context receiver public fun C.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomial(mapOf(emptyList() to this)) } \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt index b4d9f1d91..30c7f0188 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt @@ -17,39 +17,6 @@ public class NumberedRationalFunction internal constructor( override fun toString(): String = "NumberedRationalFunction${numerator.coefficients}/${denominator.coefficients}" } -// Waiting for context receivers :( TODO: Replace with context receivers when they will be available - -@Suppress("FunctionName") -public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): NumberedRationalFunction = - NumberedRationalFunction( - NumberedPolynomial(numeratorCoefficients, toCheckInput = true), - NumberedPolynomial(denominatorCoefficients, toCheckInput = true) - ) -@Suppress("FunctionName") -public fun > A.NumberedRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): NumberedRationalFunction = - NumberedRationalFunction( - NumberedPolynomial(numeratorCoefficients, toCheckInput = true), - NumberedPolynomial(denominatorCoefficients, toCheckInput = true) - ) -@Suppress("FunctionName") -public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numerator: NumberedPolynomial): NumberedRationalFunction = - NumberedRationalFunction(numerator, polynomialOne) -@Suppress("FunctionName") -public fun > A.NumberedRationalFunction(numerator: NumberedPolynomial): NumberedRationalFunction = - NumberedRationalFunction(numerator, NumberedPolynomial(mapOf(emptyList() to one), toCheckInput = false)) -@Suppress("FunctionName") -public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numeratorCoefficients: Map, C>): NumberedRationalFunction = - NumberedRationalFunction( - NumberedPolynomial(numeratorCoefficients, toCheckInput = true), - polynomialOne - ) -@Suppress("FunctionName") -public fun > A.NumberedRationalFunction(numeratorCoefficients: Map, C>): NumberedRationalFunction = - NumberedRationalFunction( - NumberedPolynomial(numeratorCoefficients, toCheckInput = true), - NumberedPolynomial(mapOf(emptyList() to one), toCheckInput = false) - ) - public class NumberedRationalFunctionSpace> ( public val ring: A, ) : diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt index 374f4a936..eede543ee 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt @@ -27,7 +27,7 @@ public interface RationalFunction> { * @param C the type of constants. Polynomials have them as coefficients in their terms. * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. * @param R the type of rational functions. - */ // TODO: Add support of field + */ @Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") public interface RationalFunctionalSpace, R: RationalFunction> : Ring { /** @@ -457,7 +457,7 @@ public interface RationalFunctionalSpace, R: RationalFunctio * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. * @param R the type of rational functions. * @param A the type of algebraic structure (precisely, of ring) provided for constants. - */ // TODO: Add support of field + */ @Suppress("INAPPLICABLE_JVM_NAME") public interface RationalFunctionalSpaceOverRing, R: RationalFunction, A: Ring> : RationalFunctionalSpace { @@ -551,7 +551,7 @@ public interface RationalFunctionalSpaceOverRing, R: Rationa * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. * @param R the type of rational functions. * @param AP the type of algebraic structure (precisely, of ring) provided for polynomials. - */ // TODO: Add support of field + */ @Suppress("INAPPLICABLE_JVM_NAME") public interface RationalFunctionalSpaceOverPolynomialSpace< C, @@ -779,8 +779,7 @@ public interface RationalFunctionalSpaceOverPolynomialSpace< * @param C the type of constants. Polynomials have them as coefficients in their terms. * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. * @param R the type of rational functions. - * @param AP the type of algebraic structure (precisely, of ring) provided for polynomials. - */ // TODO: Add support of field + */ @Suppress("INAPPLICABLE_JVM_NAME") public abstract class PolynomialSpaceOfFractions< C, diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt index ca93e4259..fa97d6a6c 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt @@ -9,7 +9,7 @@ import space.kscience.kmath.operations.* // TODO: All of this should be moved to algebraic structures' place for utilities -// TODO: Move receiver to context receiver +// FIXME: Move receiver to context receiver /** * Returns product of [arg] and integer [multiplier]. * @@ -22,7 +22,7 @@ internal fun Group.multiplyBySquaring(arg: C, multiplier: Int): C = if (multiplier >= 0) multiplyBySquaring(arg, multiplier.toUInt()) else multiplyBySquaring(-arg, (-multiplier).toUInt()) -// TODO: Move receiver to context receiver +// FIXME: Move receiver to context receiver /** * Adds product of [arg] and [multiplier] to [base]. * @@ -36,7 +36,7 @@ internal fun GroupOps.addMultipliedBySquaring(base: C, arg: C, multiplier if (multiplier >= 0) addMultipliedBySquaring(base, arg, multiplier.toUInt()) else addMultipliedBySquaring(base, -arg, (-multiplier).toUInt()) -// TODO: Move receiver to context receiver +// FIXME: Move receiver to context receiver /** * Returns product of [arg] and integer [multiplier]. * @@ -56,7 +56,7 @@ internal tailrec fun Group.multiplyBySquaring(arg: C, multiplier: UInt): else -> error("Error in multiplication group instant by unsigned integer: got reminder by division by 2 different from 0 and 1") } -// TODO: Move receiver to context receiver +// FIXME: Move receiver to context receiver /** * Adds product of [arg] and [multiplier] to [base]. * @@ -77,7 +77,7 @@ internal tailrec fun GroupOps.addMultipliedBySquaring(base: C, arg: C, mu else -> error("Error in multiplication group instant by unsigned integer: got reminder by division by 2 different from 0 and 1") } -// TODO: Move receiver to context receiver +// FIXME: Move receiver to context receiver /** * Raises [arg] to the integer power [exponent]. * @@ -90,7 +90,7 @@ internal fun Field.exponentiationBySquaring(arg: C, exponent: Int): C = if (exponent >= 0) exponentiationBySquaring(arg, exponent.toUInt()) else exponentiationBySquaring(one / arg, (-exponent).toUInt()) -// TODO: Move receiver to context receiver +// FIXME: Move receiver to context receiver /** * Multiplies [base] and [arg] raised to the integer power [exponent]. * @@ -104,7 +104,7 @@ internal fun Field.multiplyExponentiationBySquaring(base: C, arg: C, expo if (exponent >= 0) multiplyExponentiationBySquaring(base, arg, exponent.toUInt()) else multiplyExponentiationBySquaring(base, one / arg, (-exponent).toUInt()) -// TODO: Move receiver to context receiver +// FIXME: Move receiver to context receiver /** * Raises [arg] to the integer power [exponent]. * @@ -124,7 +124,7 @@ internal tailrec fun Ring.exponentiationBySquaring(arg: C, exponent: UInt else -> error("Error in multiplication group instant by unsigned integer: got reminder by division by 2 different from 0 and 1") } -// TODO: Move receiver to context receiver +// FIXME: Move receiver to context receiver /** * Multiplies [base] and [arg] raised to the integer power [exponent]. * diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt new file mode 100644 index 000000000..12688a865 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt @@ -0,0 +1,147 @@ +/* + * 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.functions + +import space.kscience.kmath.expressions.Symbol +import space.kscience.kmath.operations.Ring + + +/** + * Returns the same degrees' description of the monomial, but without zero degrees. + */ +internal fun Map.cleanUp() = filterValues { it > 0U } + +// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available + +@Suppress("FunctionName", "NOTHING_TO_INLINE") +internal inline fun > LabeledPolynomialSpace.LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(coefs, toCheckInput) +@Suppress("FunctionName", "NOTHING_TO_INLINE") +internal inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(coefs, toCheckInput) +@Suppress("FunctionName") +internal fun > A.LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : LabeledPolynomial { + if (!toCheckInput) return LabeledPolynomial(coefs) + + val fixedCoefs = LinkedHashMap, C>(coefs.size) + + for (entry in coefs) { + val key = entry.key.cleanUp() + val value = entry.value + fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value + } + + return LabeledPolynomial(fixedCoefs) +} + +@Suppress("FunctionName", "NOTHING_TO_INLINE") +internal inline fun > LabeledPolynomialSpace.LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(pairs, toCheckInput) +@Suppress("FunctionName", "NOTHING_TO_INLINE") +internal inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(pairs, toCheckInput) +@Suppress("FunctionName") +internal fun > A.LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : LabeledPolynomial { + if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) + + val fixedCoefs = LinkedHashMap, C>(pairs.size) + + for (entry in pairs) { + val key = entry.first.cleanUp() + val value = entry.second + fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value + } + + return LabeledPolynomial(fixedCoefs) +} + +@Suppress("FunctionName", "NOTHING_TO_INLINE") +internal inline fun > LabeledPolynomialSpace.LabeledPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(pairs = pairs, toCheckInput = toCheckInput) +@Suppress("FunctionName", "NOTHING_TO_INLINE") +internal inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(pairs = pairs, toCheckInput = toCheckInput) +@Suppress("FunctionName") +internal fun > A.LabeledPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : LabeledPolynomial { + if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) + + val fixedCoefs = LinkedHashMap, C>(pairs.size) + + for (entry in pairs) { + val key = entry.first.cleanUp() + val value = entry.second + fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value + } + + return LabeledPolynomial(fixedCoefs) +} + +@Suppress("FunctionName") +public fun > A.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) +@Suppress("FunctionName") +public fun > LabeledPolynomialSpace.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) +@Suppress("FunctionName") +public fun > LabeledRationalFunctionSpace.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) + +@Suppress("FunctionName") +public fun > A.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) +@Suppress("FunctionName") +public fun > LabeledPolynomialSpace.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) +@Suppress("FunctionName") +public fun > LabeledRationalFunctionSpace.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) + +@Suppress("FunctionName") +public fun > A.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs, toCheckInput = true) +@Suppress("FunctionName") +public fun > LabeledPolynomialSpace.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs, toCheckInput = true) +@Suppress("FunctionName") +public fun > LabeledRationalFunctionSpace.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs, toCheckInput = true) + +//context(A) +//public fun > Symbol.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1u) to one)) +//context(LabeledPolynomialSpace) +//public fun > Symbol.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1u) to constantOne)) +//context(LabeledRationalFunctionSpace) +//public fun > Symbol.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1u) to constantOne)) + +public fun C.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to this)) + +// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available + +@Suppress("FunctionName") +public fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): LabeledRationalFunction = + LabeledRationalFunction( + LabeledPolynomial(numeratorCoefficients, toCheckInput = true), + LabeledPolynomial(denominatorCoefficients, toCheckInput = true) + ) +@Suppress("FunctionName") +public fun > A.LabeledRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): LabeledRationalFunction = + LabeledRationalFunction( + LabeledPolynomial(numeratorCoefficients, toCheckInput = true), + LabeledPolynomial(denominatorCoefficients, toCheckInput = true) + ) +@Suppress("FunctionName") +public fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numerator: LabeledPolynomial): LabeledRationalFunction = + LabeledRationalFunction(numerator, polynomialOne) +@Suppress("FunctionName") +public fun > A.LabeledRationalFunction(numerator: LabeledPolynomial): LabeledRationalFunction = + LabeledRationalFunction(numerator, LabeledPolynomial(mapOf(emptyMap() to one), toCheckInput = false)) +@Suppress("FunctionName") +public fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numeratorCoefficients: Map, C>): LabeledRationalFunction = + LabeledRationalFunction( + LabeledPolynomial(numeratorCoefficients, toCheckInput = true), + polynomialOne + ) +@Suppress("FunctionName") +public fun > A.LabeledRationalFunction(numeratorCoefficients: Map, C>): LabeledRationalFunction = + LabeledRationalFunction( + LabeledPolynomial(numeratorCoefficients, toCheckInput = true), + LabeledPolynomial(mapOf(emptyMap() to one), toCheckInput = false) + ) + +//context(A) +//public fun > Symbol.asLabeledRationalFunction() : LabeledRationalFunction = LabeledRationalFunction(asLabeledPolynomial()) +//context(LabeledRationalFunctionSpace) +//public fun > Symbol.asLabeledRationalFunction() : LabeledRationalFunction = LabeledRationalFunction(asLabeledPolynomial()) + +//context(A) +//public fun > C.asLabeledRationalFunction() : LabeledRationalFunction = LabeledRationalFunction(asLabeledPolynomial()) +//context(LabeledRationalFunctionSpace) +//public fun > C.asLabeledRationalFunction() : LabeledRationalFunction = LabeledRationalFunction(asLabeledPolynomial()) \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt new file mode 100644 index 000000000..9498c77ca --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt @@ -0,0 +1,60 @@ +/* + * 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.functions + +import space.kscience.kmath.operations.Ring + + +/** + * Returns a [ListPolynomial] instance with given [coefficients]. The collection of coefficients will be reversed if + * [reverse] parameter is true. + */ +@Suppress("FunctionName") +public fun ListPolynomial(coefficients: List, reverse: Boolean = false): ListPolynomial = + ListPolynomial(with(coefficients) { if (reverse) reversed() else this }) + +/** + * Returns a [ListPolynomial] instance with given [coefficients]. The collection of coefficients will be reversed if + * [reverse] parameter is true. + */ +@Suppress("FunctionName") +public fun ListPolynomial(vararg coefficients: C, reverse: Boolean = false): ListPolynomial = + ListPolynomial(with(coefficients) { if (reverse) reversed() else toList() }) + +public fun C.asListPolynomial() : ListPolynomial = ListPolynomial(listOf(this)) + + +// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available + +@Suppress("FunctionName") +public fun ListRationalFunction(numeratorCoefficients: List, denominatorCoefficients: List, reverse: Boolean = false): ListRationalFunction = + ListRationalFunction( + ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), + ListPolynomial( with(denominatorCoefficients) { if (reverse) reversed() else this } ) + ) +@Suppress("FunctionName") +public fun > ListRationalFunctionSpace.ListRationalFunction(numerator: ListPolynomial): ListRationalFunction = + ListRationalFunction(numerator, polynomialOne) +@Suppress("FunctionName") +public fun > A.ListRationalFunction(numerator: ListPolynomial): ListRationalFunction = + ListRationalFunction(numerator, ListPolynomial(listOf(one))) +@Suppress("FunctionName") +public fun > ListRationalFunctionSpace.ListRationalFunction(numeratorCoefficients: List, reverse: Boolean = false): ListRationalFunction = + ListRationalFunction( + ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), + polynomialOne + ) +@Suppress("FunctionName") +public fun > A.ListRationalFunction(numeratorCoefficients: List, reverse: Boolean = false): ListRationalFunction = + ListRationalFunction( + ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), + ListPolynomial(listOf(one)) + ) + +//context(A) +//public fun > C.asListRationalFunction() : ListRationalFunction = ListRationalFunction(asListPolynomial()) +//context(ListRationalFunctionSpace) +//public fun > C.asListRationalFunction() : ListRationalFunction = ListRationalFunction(asListPolynomial()) \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt new file mode 100644 index 000000000..e4b79b0b2 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt @@ -0,0 +1,188 @@ +/* + * 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.functions + +import space.kscience.kmath.operations.Ring +import space.kscience.kmath.operations.invoke + + +/** + * Returns the same degrees' description of the monomial, but without extra zero degrees on the end. + */ +internal fun List.cleanUp() = subList(0, indexOfLast { it != 0U } + 1) + +// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available + +@Suppress("FunctionName", "NOTHING_TO_INLINE") +internal inline fun > NumberedPolynomialSpace.NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(coefs, toCheckInput) +@Suppress("FunctionName", "NOTHING_TO_INLINE") +internal inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(coefs, toCheckInput) +@Suppress("FunctionName") +internal fun > A.NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : NumberedPolynomial { + if (!toCheckInput) return NumberedPolynomial(coefs) + + val fixedCoefs = mutableMapOf, C>() + + for (entry in coefs) { + val key = entry.key.cleanUp() + val value = entry.value + fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value + } + + return NumberedPolynomial(fixedCoefs) +} + +@Suppress("FunctionName", "NOTHING_TO_INLINE") +internal inline fun > NumberedPolynomialSpace.NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(pairs, toCheckInput) +@Suppress("FunctionName", "NOTHING_TO_INLINE") +internal inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(pairs, toCheckInput) +@Suppress("FunctionName") +internal fun > A.NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : NumberedPolynomial { + if (!toCheckInput) return NumberedPolynomial(pairs.toMap()) + + val fixedCoefs = mutableMapOf, C>() + + for (entry in pairs) { + val key = entry.first.cleanUp() + val value = entry.second + fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value + } + + return NumberedPolynomial(fixedCoefs) +} + +@Suppress("FunctionName", "NOTHING_TO_INLINE") +internal inline fun > NumberedPolynomialSpace.NumberedPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(pairs = pairs, toCheckInput = toCheckInput) +@Suppress("FunctionName", "NOTHING_TO_INLINE") +internal inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(pairs = pairs, toCheckInput = toCheckInput) +@Suppress("FunctionName") +internal fun > A.NumberedPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : NumberedPolynomial { + if (!toCheckInput) return NumberedPolynomial(pairs.toMap()) + + val fixedCoefs = mutableMapOf, C>() + + for (entry in pairs) { + val key = entry.first.cleanUp() + val value = entry.second + fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value + } + + return NumberedPolynomial(fixedCoefs) +} + +@Suppress("FunctionName") +public fun > A.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, toCheckInput = true) +@Suppress("FunctionName") +public fun > NumberedPolynomialSpace.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, toCheckInput = true) +@Suppress("FunctionName") +public fun > NumberedRationalFunctionSpace.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, toCheckInput = true) + +@Suppress("FunctionName") +public fun > A.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, toCheckInput = true) +@Suppress("FunctionName") +public fun > NumberedPolynomialSpace.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, toCheckInput = true) +@Suppress("FunctionName") +public fun > NumberedRationalFunctionSpace.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, toCheckInput = true) + +@Suppress("FunctionName") +public fun > A.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs, toCheckInput = true) +@Suppress("FunctionName") +public fun > NumberedPolynomialSpace.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs, toCheckInput = true) +@Suppress("FunctionName") +public fun > NumberedRationalFunctionSpace.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs, toCheckInput = true) + +public fun C.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomial(mapOf(emptyList() to this)) + +@DslMarker +internal annotation class NumberedPolynomialConstructorDSL + +@NumberedPolynomialConstructorDSL +public class NumberedPolynomialTermSignatureBuilder { + private val signature: MutableList = ArrayList() + public fun build(): List = signature + public infix fun Int.inPowerOf(deg: UInt) { + if (this > signature.lastIndex) { + signature.addAll(List(this - signature.lastIndex - 1) { 0u }) + signature.add(deg) + } else { + signature[this] = deg + } + } + public infix fun Int.pow(deg: UInt): Unit = this inPowerOf deg + public infix fun Int.of(deg: UInt): Unit = this inPowerOf deg +} + +@NumberedPolynomialConstructorDSL +public class NumberedPolynomialBuilderOverRing internal constructor(internal val context: Ring, capacity: Int = 0) { + private val coefficients: MutableMap, C> = LinkedHashMap(capacity) + public fun build(): NumberedPolynomial = NumberedPolynomial(coefficients) + public operator fun C.invoke(block: NumberedPolynomialTermSignatureBuilder.() -> Unit) { + val signature = NumberedPolynomialTermSignatureBuilder().apply(block).build() + coefficients[signature] = context { coefficients.getOrElse(signature) { zero } + this@invoke } + } + public infix fun C.with(block: NumberedPolynomialTermSignatureBuilder.() -> Unit): Unit = this.invoke(block) +} + +@NumberedPolynomialConstructorDSL +public class NumberedPolynomialBuilderOverPolynomialSpace internal constructor(internal val context: NumberedPolynomialSpace, capacity: Int = 0) { + private val coefficients: MutableMap, C> = LinkedHashMap(capacity) + public fun build(): NumberedPolynomial = NumberedPolynomial(coefficients) + public operator fun C.invoke(block: NumberedPolynomialTermSignatureBuilder.() -> Unit) { + val signature = NumberedPolynomialTermSignatureBuilder().apply(block).build() + coefficients[signature] = context { coefficients.getOrElse(signature) { constantZero } + this@invoke } + } +} + +@NumberedPolynomialConstructorDSL +@Suppress("FunctionName") +public fun > A.NumberedPolynomial(block: NumberedPolynomialBuilderOverRing.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilderOverRing(this).apply(block).build() +@NumberedPolynomialConstructorDSL +@Suppress("FunctionName") +public fun > A.NumberedPolynomial(capacity: Int, block: NumberedPolynomialBuilderOverRing.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilderOverRing(this, capacity).apply(block).build() +@NumberedPolynomialConstructorDSL +@Suppress("FunctionName") +public fun > NumberedPolynomialSpace.NumberedPolynomial(block: NumberedPolynomialBuilderOverPolynomialSpace.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilderOverPolynomialSpace(this).apply(block).build() +@NumberedPolynomialConstructorDSL +@Suppress("FunctionName") +public fun > NumberedPolynomialSpace.NumberedPolynomial(capacity: Int, block: NumberedPolynomialBuilderOverPolynomialSpace.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilderOverPolynomialSpace(this, capacity).apply(block).build() + +// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available + +@Suppress("FunctionName") +public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): NumberedRationalFunction = + NumberedRationalFunction( + NumberedPolynomial(numeratorCoefficients, toCheckInput = true), + NumberedPolynomial(denominatorCoefficients, toCheckInput = true) + ) +@Suppress("FunctionName") +public fun > A.NumberedRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): NumberedRationalFunction = + NumberedRationalFunction( + NumberedPolynomial(numeratorCoefficients, toCheckInput = true), + NumberedPolynomial(denominatorCoefficients, toCheckInput = true) + ) +@Suppress("FunctionName") +public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numerator: NumberedPolynomial): NumberedRationalFunction = + NumberedRationalFunction(numerator, polynomialOne) +@Suppress("FunctionName") +public fun > A.NumberedRationalFunction(numerator: NumberedPolynomial): NumberedRationalFunction = + NumberedRationalFunction(numerator, NumberedPolynomial(mapOf(emptyList() to one), toCheckInput = false)) +@Suppress("FunctionName") +public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numeratorCoefficients: Map, C>): NumberedRationalFunction = + NumberedRationalFunction( + NumberedPolynomial(numeratorCoefficients, toCheckInput = true), + polynomialOne + ) +@Suppress("FunctionName") +public fun > A.NumberedRationalFunction(numeratorCoefficients: Map, C>): NumberedRationalFunction = + NumberedRationalFunction( + NumberedPolynomial(numeratorCoefficients, toCheckInput = true), + NumberedPolynomial(mapOf(emptyList() to one), toCheckInput = false) + ) + +//context(A) +//public fun > C.asNumberedRationalFunction() : NumberedRationalFunction = NumberedRationalFunction(asLabeledPolynomial()) +//context(NumberedRationalFunctionSpace) +//public fun > C.asNumberedRationalFunction() : NumberedRationalFunction = NumberedRationalFunction(asLabeledPolynomial()) \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt index d544ca93c..ee85b0f56 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt @@ -9,38 +9,6 @@ import kotlin.math.max // TODO: Docs -//// TODO: Reuse underlying ring extensions -// -//context(NumberedPolynomialSpace) -//@Suppress("NOTHING_TO_INLINE") -//public fun > numberConstant(value: Int): C = ring { number(value) } -// -//context(NumberedPolynomialSpace) -//public fun > multiplyWithPower(base: C, arg: C, pow: UInt): C = ring { multiplyWithPower(base, arg, pow) } - -//context(NumberedPolynomialSpace) -//public fun > number(value: Int): NumberedPolynomial = ring { NumberedPolynomial(mapOf(emptyList() to number(value))) } -// -//context(NumberedPolynomialSpace) -//public fun > multiplyWithPower(base: NumberedPolynomial, arg: NumberedPolynomial, pow: UInt): NumberedPolynomial = -// when { -// arg.isZero() && pow > 0U -> base -// arg.isOne() -> base -// arg.isMinusOne() -> if (pow % 2U == 0U) base else -base -// else -> multiplyWithPowerInternalLogic(base, arg, pow) -// } -// -//// Trivial but very slow -//context(NumberedPolynomialSpace) -//internal tailrec fun > multiplyWithPowerInternalLogic(base: NumberedPolynomial, arg: NumberedPolynomial, exponent: UInt): NumberedPolynomial = -// when { -// exponent == 0U -> base -// exponent == 1U -> base * arg -// exponent % 2U == 0U -> multiplyWithPowerInternalLogic(base, arg * arg, exponent / 2U) -// exponent % 2U == 1U -> multiplyWithPowerInternalLogic(base * arg, arg * arg, exponent / 2U) -// else -> error("Error in raising ring instant by unsigned integer: got reminder by division by 2 different from 0 and 1") -// } - /** * Creates a [NumberedPolynomialSpace] over a received ring. */ @@ -271,7 +239,6 @@ public inline fun , R> A.numberedPolynomial(block: NumberedPolyno // toCheckInput = false // ) -// TODO: May be apply Horner's method too? /** * Evaluates the value of the given double polynomial for given double argument. */ -- 2.34.1 From b3087c245fc0da2631e9e53211e97dd47e1d1983 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Fri, 25 Mar 2022 17:46:13 +0300 Subject: [PATCH 058/123] Fixed tests. --- .../kmath/functions/ListPolynomialTest.kt | 108 ++++-------------- .../kmath/functions/ListPolynomialUtilTest.kt | 16 +-- .../kscience/kmath/test/misc/IntModulo.kt | 2 +- 3 files changed, 33 insertions(+), 93 deletions(-) diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt index ac2647592..5401be707 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt @@ -9,7 +9,7 @@ import space.kscience.kmath.test.misc.* import kotlin.test.* -class ListPolynomialTest { // TODO: Adapt tests to changes +class ListPolynomialTest { @Test fun test_Polynomial_Int_plus() { RationalField.listPolynomial { @@ -24,7 +24,7 @@ class ListPolynomialTest { // TODO: Adapt tests to changes "test 2" ) assertEquals( - ListPolynomial(), + ListPolynomial(Rational(0)), ListPolynomial(Rational(-2)) + 2, "test 3" ) @@ -64,7 +64,7 @@ class ListPolynomialTest { // TODO: Adapt tests to changes "test 2" ) assertEquals( - ListPolynomial(), + ListPolynomial(Rational(0)), ListPolynomial(Rational(2)) - 2, "test 3" ) @@ -99,7 +99,7 @@ class ListPolynomialTest { // TODO: Adapt tests to changes "test 1" ) assertEquals( - ListPolynomial(), + ListPolynomial(0, 0, 0, 0, 0), ListPolynomial(7, 0, 49, 21, 14) * 15, "test 2" ) @@ -119,7 +119,7 @@ class ListPolynomialTest { // TODO: Adapt tests to changes "test 2" ) assertEquals( - ListPolynomial(), + ListPolynomial(Rational(0)), 2 + ListPolynomial(Rational(-2)), "test 3" ) @@ -159,7 +159,7 @@ class ListPolynomialTest { // TODO: Adapt tests to changes "test 2" ) assertEquals( - ListPolynomial(), + ListPolynomial(Rational(0)), -2 - ListPolynomial(Rational(-2)), "test 3" ) @@ -194,7 +194,7 @@ class ListPolynomialTest { // TODO: Adapt tests to changes "test 1" ) assertEquals( - ListPolynomial(), + ListPolynomial(0, 0, 0, 0, 0), 15 * ListPolynomial(7, 0, 49, 21, 14), "test 2" ) @@ -214,12 +214,12 @@ class ListPolynomialTest { // TODO: Adapt tests to changes "test 2" ) assertEquals( - ListPolynomial(), + ListPolynomial(Rational(0)), ListPolynomial(Rational(-2)) + Rational(2), "test 3" ) assertEquals( - ListPolynomial(), + ListPolynomial(Rational(0)), ListPolynomial() + Rational(0), "test 4" ) @@ -254,12 +254,12 @@ class ListPolynomialTest { // TODO: Adapt tests to changes "test 2" ) assertEquals( - ListPolynomial(), + ListPolynomial(Rational(0)), ListPolynomial(Rational(2)) - Rational(2), "test 3" ) assertEquals( - ListPolynomial(), + ListPolynomial(Rational(0)), ListPolynomial() - Rational(0), "test 4" ) @@ -285,12 +285,12 @@ class ListPolynomialTest { // TODO: Adapt tests to changes IntModuloRing(35).listPolynomial { assertEquals( ListPolynomial(34, 2, 1, 20, 2), - ListPolynomial(22, 26, 13, 15, 26) * number(27), + ListPolynomial(22, 26, 13, 15, 26) * 27.asConstant(), "test 1" ) assertEquals( - ListPolynomial(), - ListPolynomial(7, 0, 49, 21, 14) * number(15), + ListPolynomial(0, 0, 0, 0, 0), + ListPolynomial(7, 0, 49, 21, 14) * 15.asConstant(), "test 2" ) } @@ -309,12 +309,12 @@ class ListPolynomialTest { // TODO: Adapt tests to changes "test 2" ) assertEquals( - ListPolynomial(), + ListPolynomial(Rational(0)), Rational(2) + ListPolynomial(Rational(-2)), "test 3" ) assertEquals( - ListPolynomial(), + ListPolynomial(Rational(0)), Rational(0) + ListPolynomial(), "test 4" ) @@ -349,12 +349,12 @@ class ListPolynomialTest { // TODO: Adapt tests to changes "test 2" ) assertEquals( - ListPolynomial(), + ListPolynomial(Rational(0)), Rational(-2) - ListPolynomial(Rational(-2)), "test 3" ) assertEquals( - ListPolynomial(), + ListPolynomial(Rational(0)), Rational(0) - ListPolynomial(), "test 4" ) @@ -384,7 +384,7 @@ class ListPolynomialTest { // TODO: Adapt tests to changes "test 1" ) assertEquals( - ListPolynomial(), + ListPolynomial(0, 0, 0, 0, 0), 15 * ListPolynomial(7, 0, 49, 21, 14), "test 2" ) @@ -424,14 +424,14 @@ class ListPolynomialTest { // TODO: Adapt tests to changes ) // (-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( - ListPolynomial(Rational(-18, 7), Rational(-23, 6), Rational(2, 3)), + ListPolynomial(Rational(-18, 7), Rational(-23, 6), Rational(2, 3), Rational(0)), ListPolynomial(Rational(-4, 7), Rational(-2, 6), Rational(0), Rational(0)) + ListPolynomial(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( - ListPolynomial(), + ListPolynomial(Rational(0), Rational(0), Rational(0)), ListPolynomial(Rational(-2, 4), Rational(-6, 9), Rational(-4, 9)) + ListPolynomial(Rational(2, 4), Rational(6, 9), Rational(4, 9)), "test 4" @@ -457,14 +457,14 @@ class ListPolynomialTest { // TODO: Adapt tests to changes ) // (-4/7 - 2/6 x + 0 x^2 + 0 x^3) - (-6/3 - 7/2 x + 2/3 x^2) ?= 10/7 + 19/6 x - 2/3 x^2 assertEquals( - ListPolynomial(Rational(10, 7), Rational(19, 6), Rational(-2, 3)), + ListPolynomial(Rational(10, 7), Rational(19, 6), Rational(-2, 3), Rational(0)), ListPolynomial(Rational(-4, 7), Rational(-2, 6), Rational(0), Rational(0)) - ListPolynomial(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( - ListPolynomial(), + ListPolynomial(Rational(0), Rational(0), Rational(0)), ListPolynomial(Rational(-2, 4), Rational(-6, 9), Rational(-4, 9)) - ListPolynomial(Rational(-2, 4), Rational(-6, 9), Rational(-4, 9)), "test 4" @@ -482,70 +482,10 @@ class ListPolynomialTest { // TODO: Adapt tests to changes ) // Spoiler: 5 * 7 = 0 assertEquals( - ListPolynomial(), + ListPolynomial(0, 0, 0, 0, 0), ListPolynomial(5, -25, 10) * ListPolynomial(21, 14, -7), "test 2" ) } } - @Test - fun test_Polynomial_degree() { - RationalField.listPolynomial { - assertEquals( - 2, - ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)).degree, - "test 1" - ) - assertEquals( - -1, - ListPolynomial().degree, - "test 2" - ) - assertEquals( - -1, - ListPolynomial(Rational(0)).degree, - "test 3" - ) - assertEquals( - -1, - ListPolynomial(Rational(0), Rational(0)).degree, - "test 4" - ) - assertEquals( - -1, - ListPolynomial(Rational(0), Rational(0), Rational(0)).degree, - "test 5" - ) - assertEquals( - 0, - ListPolynomial(Rational(5, 9)).degree, - "test 6" - ) - assertEquals( - 0, - ListPolynomial(Rational(5, 9), Rational(0)).degree, - "test 7" - ) - assertEquals( - 0, - ListPolynomial(Rational(5, 9), Rational(0), Rational(0)).degree, - "test 8" - ) - assertEquals( - 2, - ListPolynomial(Rational(0), Rational(0), Rational(-8, 7)).degree, - "test 9" - ) - assertEquals( - 2, - ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7), Rational(0), Rational(0)).degree, - "test 10" - ) - assertEquals( - 2, - ListPolynomial(Rational(0), Rational(0), Rational(-8, 7), Rational(0), Rational(0)).degree, - "test 11" - ) - } - } } \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt index c4f07d957..c5eb8fb81 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt @@ -12,7 +12,7 @@ import kotlin.test.assertEquals import kotlin.test.assertFailsWith -class ListPolynomialUtilTest { // TODO: Adapt tests to changes +class ListPolynomialUtilTest { @Test fun test_substitute_Double() { assertEquals( @@ -81,7 +81,7 @@ class ListPolynomialUtilTest { // TODO: Adapt tests to changes @Test fun test_substitute_Polynomial() { assertEquals( - ListPolynomial(), + ListPolynomial(Rational(0)), ListPolynomial(Rational(1), Rational(-2), Rational(1)).substitute(RationalField, ListPolynomial(Rational(1))), "test 1" ) @@ -98,7 +98,7 @@ class ListPolynomialUtilTest { // TODO: Adapt tests to changes "test 3" ) assertEquals( - ListPolynomial(Rational(677, 378), Rational(97, 180), Rational(1, 75)), + ListPolynomial(Rational(677, 378), Rational(97, 180), Rational(1, 75), Rational(0)), ListPolynomial(Rational(1, 7), Rational(9, 4), Rational(1, 3), Rational(0)) .substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(1, 5))), "test 4" @@ -110,7 +110,7 @@ class ListPolynomialUtilTest { // TODO: Adapt tests to changes "test 5" ) assertEquals( - ListPolynomial(Rational(89, 54)), + ListPolynomial(Rational(89, 54), Rational(0), Rational(0), Rational(0)), ListPolynomial(Rational(0), Rational(9, 4), Rational(1, 3), Rational(0)) .substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(0))), "test 6" @@ -134,7 +134,7 @@ class ListPolynomialUtilTest { // TODO: Adapt tests to changes "test 3" ) assertEquals( - ListPolynomial(Rational(-8, 3), Rational(8, 9), Rational(15, 7)), + ListPolynomial(Rational(-8, 3), Rational(8, 9), Rational(15, 7), Rational(0)), ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).derivative(RationalField), "test 4" ) @@ -180,7 +180,7 @@ class ListPolynomialUtilTest { // TODO: Adapt tests to changes "test 8" ) assertEquals( - ListPolynomial(Rational(8, 9), Rational(30, 7)), + ListPolynomial(Rational(8, 9), Rational(30, 7), Rational(0)), ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).nthDerivative(RationalField, 2), "test 9" ) @@ -203,7 +203,7 @@ class ListPolynomialUtilTest { // TODO: Adapt tests to changes "test 3" ) assertEquals( - ListPolynomial(Rational(0), Rational(1, 5), Rational(-4, 3), Rational(4, 27), Rational(5, 28)), + ListPolynomial(Rational(0), Rational(1, 5), Rational(-4, 3), Rational(4, 27), Rational(5, 28), Rational(0)), ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).antiderivative(RationalField), "test 4" ) @@ -249,7 +249,7 @@ class ListPolynomialUtilTest { // TODO: Adapt tests to changes "test 8" ) assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(1, 10), Rational(-4, 9), Rational(1, 27), Rational(1, 28)), + ListPolynomial(Rational(0), Rational(0), Rational(1, 10), Rational(-4, 9), Rational(1, 27), Rational(1, 28), Rational(0)), ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).nthAntiderivative(RationalField, 2), "test 9" ) diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt index 535a42846..2353beee6 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt @@ -120,7 +120,7 @@ class IntModuloRing : Ring { } override inline val zero: IntModulo get() = IntModulo(0, modulus, toCheckInput = false) - override inline val one: IntModulo get() = IntModulo(0, modulus, toCheckInput = false) + override inline val one: IntModulo get() = IntModulo(1, modulus, toCheckInput = false) fun number(arg: Int) = IntModulo(arg, modulus, toCheckInput = false) -- 2.34.1 From 7f7b55067422589bc9266f2d7ebc0e8af5b8e402 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sun, 3 Apr 2022 11:44:42 +0300 Subject: [PATCH 059/123] Simplified polynomial builders. --- .../kmath/functions/labeledConstructors.kt | 56 +++++++++++++++++++ .../kmath/functions/numberedConstructors.kt | 47 +++++++++------- 2 files changed, 83 insertions(+), 20 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt index 12688a865..e81a9388e 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt @@ -6,6 +6,7 @@ package space.kscience.kmath.functions import space.kscience.kmath.expressions.Symbol +import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.Ring @@ -103,6 +104,61 @@ public fun > LabeledRationalFunctionSpace.LabeledPolynomial( public fun C.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to this)) +@DslMarker +@UnstableKMathAPI +internal annotation class LabeledPolynomialConstructorDSL + +@UnstableKMathAPI +@LabeledPolynomialConstructorDSL +public class LabeledPolynomialTermSignatureBuilder { + private val signature: MutableMap = LinkedHashMap() + public fun build(): Map = signature + public infix fun Symbol.inPowerOf(deg: UInt) { + signature[this] = deg + } + @Suppress("NOTHING_TO_INLINE") + public inline infix fun Symbol.pow(deg: UInt): Unit = this inPowerOf deg + @Suppress("NOTHING_TO_INLINE") + public inline infix fun Symbol.`in`(deg: UInt): Unit = this inPowerOf deg + @Suppress("NOTHING_TO_INLINE") + public inline infix fun Symbol.of(deg: UInt): Unit = this inPowerOf deg +} + +@UnstableKMathAPI +public class LabeledPolynomialBuilder(private val zero: C, private val add: (C, C) -> C, capacity: Int = 0) { + private val coefficients: MutableMap, C> = LinkedHashMap(capacity) + public fun build(): LabeledPolynomial = LabeledPolynomial(coefficients) + public operator fun C.invoke(block: LabeledPolynomialTermSignatureBuilder.() -> Unit) { + val signature = LabeledPolynomialTermSignatureBuilder().apply(block).build() + coefficients[signature] = add(coefficients.getOrElse(signature) { zero }, this@invoke) + } + @Suppress("NOTHING_TO_INLINE") + public inline infix fun C.with(noinline block: LabeledPolynomialTermSignatureBuilder.() -> Unit): Unit = this.invoke(block) + @Suppress("NOTHING_TO_INLINE") + public inline infix fun (LabeledPolynomialTermSignatureBuilder.() -> Unit).with(coef: C): Unit = coef.invoke(this) + @Suppress("NOTHING_TO_INLINE") + public infix fun sig(block: LabeledPolynomialTermSignatureBuilder.() -> Unit): LabeledPolynomialTermSignatureBuilder.() -> Unit = block +} + +// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available + +@UnstableKMathAPI +@LabeledPolynomialConstructorDSL +@Suppress("FunctionName") +public inline fun > A.LabeledPolynomial(block: LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = LabeledPolynomialBuilder(zero, ::add).apply(block).build() +@UnstableKMathAPI +@LabeledPolynomialConstructorDSL +@Suppress("FunctionName") +public inline fun > A.LabeledPolynomial(capacity: Int, block: LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = LabeledPolynomialBuilder(zero, ::add, capacity).apply(block).build() +@UnstableKMathAPI +@LabeledPolynomialConstructorDSL +@Suppress("FunctionName") +public inline fun > LabeledPolynomialSpace.LabeledPolynomial(block: LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = LabeledPolynomialBuilder(constantZero, { left: C, right: C -> left + right}).apply(block).build() +@UnstableKMathAPI +@LabeledPolynomialConstructorDSL +@Suppress("FunctionName") +public inline fun > LabeledPolynomialSpace.LabeledPolynomial(capacity: Int, block: LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = LabeledPolynomialBuilder(constantZero, { left: C, right: C -> left + right}, capacity).apply(block).build() + // Waiting for context receivers :( FIXME: Replace with context receivers when they will be available @Suppress("FunctionName") diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt index e4b79b0b2..dca8a0cff 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt @@ -5,8 +5,8 @@ package space.kscience.kmath.functions +import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.invoke /** @@ -97,8 +97,10 @@ public fun > NumberedRationalFunctionSpace.NumberedPolynomia public fun C.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomial(mapOf(emptyList() to this)) @DslMarker +@UnstableKMathAPI internal annotation class NumberedPolynomialConstructorDSL +@UnstableKMathAPI @NumberedPolynomialConstructorDSL public class NumberedPolynomialTermSignatureBuilder { private val signature: MutableList = ArrayList() @@ -111,43 +113,48 @@ public class NumberedPolynomialTermSignatureBuilder { signature[this] = deg } } - public infix fun Int.pow(deg: UInt): Unit = this inPowerOf deg - public infix fun Int.of(deg: UInt): Unit = this inPowerOf deg + @Suppress("NOTHING_TO_INLINE") + public inline infix fun Int.pow(deg: UInt): Unit = this inPowerOf deg + @Suppress("NOTHING_TO_INLINE") + public inline infix fun Int.`in`(deg: UInt): Unit = this inPowerOf deg + @Suppress("NOTHING_TO_INLINE") + public inline infix fun Int.of(deg: UInt): Unit = this inPowerOf deg } -@NumberedPolynomialConstructorDSL -public class NumberedPolynomialBuilderOverRing internal constructor(internal val context: Ring, capacity: Int = 0) { +@UnstableKMathAPI +public class NumberedPolynomialBuilder(private val zero: C, private val add: (C, C) -> C, capacity: Int = 0) { private val coefficients: MutableMap, C> = LinkedHashMap(capacity) public fun build(): NumberedPolynomial = NumberedPolynomial(coefficients) public operator fun C.invoke(block: NumberedPolynomialTermSignatureBuilder.() -> Unit) { val signature = NumberedPolynomialTermSignatureBuilder().apply(block).build() - coefficients[signature] = context { coefficients.getOrElse(signature) { zero } + this@invoke } + coefficients[signature] = add(coefficients.getOrElse(signature) { zero }, this@invoke) } - public infix fun C.with(block: NumberedPolynomialTermSignatureBuilder.() -> Unit): Unit = this.invoke(block) + @Suppress("NOTHING_TO_INLINE") + public inline infix fun C.with(noinline block: NumberedPolynomialTermSignatureBuilder.() -> Unit): Unit = this.invoke(block) + @Suppress("NOTHING_TO_INLINE") + public inline infix fun (NumberedPolynomialTermSignatureBuilder.() -> Unit).with(coef: C): Unit = coef.invoke(this) + @Suppress("NOTHING_TO_INLINE") + public infix fun sig(block: NumberedPolynomialTermSignatureBuilder.() -> Unit): NumberedPolynomialTermSignatureBuilder.() -> Unit = block } -@NumberedPolynomialConstructorDSL -public class NumberedPolynomialBuilderOverPolynomialSpace internal constructor(internal val context: NumberedPolynomialSpace, capacity: Int = 0) { - private val coefficients: MutableMap, C> = LinkedHashMap(capacity) - public fun build(): NumberedPolynomial = NumberedPolynomial(coefficients) - public operator fun C.invoke(block: NumberedPolynomialTermSignatureBuilder.() -> Unit) { - val signature = NumberedPolynomialTermSignatureBuilder().apply(block).build() - coefficients[signature] = context { coefficients.getOrElse(signature) { constantZero } + this@invoke } - } -} +// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available +@UnstableKMathAPI @NumberedPolynomialConstructorDSL @Suppress("FunctionName") -public fun > A.NumberedPolynomial(block: NumberedPolynomialBuilderOverRing.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilderOverRing(this).apply(block).build() +public inline fun > A.NumberedPolynomial(block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder(zero, ::add).apply(block).build() +@UnstableKMathAPI @NumberedPolynomialConstructorDSL @Suppress("FunctionName") -public fun > A.NumberedPolynomial(capacity: Int, block: NumberedPolynomialBuilderOverRing.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilderOverRing(this, capacity).apply(block).build() +public inline fun > A.NumberedPolynomial(capacity: Int, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder(zero, ::add, capacity).apply(block).build() +@UnstableKMathAPI @NumberedPolynomialConstructorDSL @Suppress("FunctionName") -public fun > NumberedPolynomialSpace.NumberedPolynomial(block: NumberedPolynomialBuilderOverPolynomialSpace.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilderOverPolynomialSpace(this).apply(block).build() +public inline fun > NumberedPolynomialSpace.NumberedPolynomial(block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder(constantZero, { left: C, right: C -> left + right}).apply(block).build() +@UnstableKMathAPI @NumberedPolynomialConstructorDSL @Suppress("FunctionName") -public fun > NumberedPolynomialSpace.NumberedPolynomial(capacity: Int, block: NumberedPolynomialBuilderOverPolynomialSpace.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilderOverPolynomialSpace(this, capacity).apply(block).build() +public inline fun > NumberedPolynomialSpace.NumberedPolynomial(capacity: Int, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder(constantZero, { left: C, right: C -> left + right}, capacity).apply(block).build() // Waiting for context receivers :( FIXME: Replace with context receivers when they will be available -- 2.34.1 From 89cdbf4d71f188105f12bb9029dc3c0f40a87360 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sat, 11 Jun 2022 15:58:25 +0300 Subject: [PATCH 060/123] Changed names of algebraic stub. Added FIXMEs about KT-31420. Changed JVM/JS names style. --- .../kscience/kmath/functions/Polynomial.kt | 112 +++++----- .../kmath/functions/RationalFunction.kt | 208 +++++++++--------- .../kscience/kmath/functions/algebraicStub.kt | 48 ++-- .../kmath/functions/labeledPolynomialUtil.kt | 16 +- .../kmath/functions/numberedPolynomialUtil.kt | 16 +- .../kmath/functions/AlgebraicStubTest.kt | 208 +++++++++--------- 6 files changed, 304 insertions(+), 304 deletions(-) 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 96e860550..e201f1f6e 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 @@ -22,7 +22,7 @@ public interface Polynomial * @param C the type of constants. Polynomials have them as coefficients in their terms. * @param P the type of polynomials. */ -@Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") +@Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") // FIXME: Waiting for KT-31420 public interface PolynomialSpace> : Ring

{ /** * Returns sum of the constant and the integer represented as constant (member of underlying ring). @@ -76,38 +76,38 @@ public interface PolynomialSpace> : Ring

{ * * The operation is equivalent to adding [other] copies of unit polynomial to [this]. */ - public operator fun P.plus(other: Int): P = addMultipliedBySquaring(this, one, other) + public operator fun P.plus(other: Int): P = addMultipliedByDoubling(this, one, other) /** * Returns difference between the polynomial and the integer represented as polynomial. * * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. */ - public operator fun P.minus(other: Int): P = addMultipliedBySquaring(this, one, -other) + public operator fun P.minus(other: Int): P = addMultipliedByDoubling(this, one, -other) /** * Returns product of the polynomial and the integer represented as polynomial. * * The operation is equivalent to sum of [other] copies of [this]. */ - public operator fun P.times(other: Int): P = multiplyBySquaring(this, other) + public operator fun P.times(other: Int): P = multiplyByDoubling(this, other) /** * Returns sum of the integer represented as polynomial and the polynomial. * * The operation is equivalent to adding [this] copies of unit polynomial to [other]. */ - public operator fun Int.plus(other: P): P = addMultipliedBySquaring(other, one, this) + public operator fun Int.plus(other: P): P = addMultipliedByDoubling(other, one, this) /** * Returns difference between the integer represented as polynomial and the polynomial. * * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. */ - public operator fun Int.minus(other: P): P = addMultipliedBySquaring(-other, one, this) + public operator fun Int.minus(other: P): P = addMultipliedByDoubling(-other, one, this) /** * Returns product of the integer represented as polynomial and the polynomial. * * The operation is equivalent to sum of [this] copies of [other]. */ - public operator fun Int.times(other: P): P = multiplyBySquaring(other, this) + public operator fun Int.times(other: P): P = multiplyByDoubling(other, this) /** * Converts the integer [value] to polynomial. @@ -121,38 +121,38 @@ public interface PolynomialSpace> : Ring

{ /** * Returns the same constant. */ - @JvmName("constantUnaryPlus") - @JsName("constantUnaryPlus") + @JvmName("unaryPlusConstant") + @JsName("unaryPlusConstant") public operator fun C.unaryPlus(): C = this /** * Returns negation of the constant. */ - @JvmName("constantUnaryMinus") - @JsName("constantUnaryMinus") + @JvmName("unaryMinusConstant") + @JsName("unaryMinusConstant") public operator fun C.unaryMinus(): C /** * Returns sum of the constants. */ - @JvmName("constantPlus") - @JsName("constantPlus") + @JvmName("plusConstantConstant") + @JsName("plusConstantConstant") public operator fun C.plus(other: C): C /** * Returns difference of the constants. */ - @JvmName("constantMinus") - @JsName("constantMinus") + @JvmName("minusConstantConstant") + @JsName("minusConstantConstant") public operator fun C.minus(other: C): C /** * Returns product of the constants. */ - @JvmName("constantTimes") - @JsName("constantTimes") + @JvmName("timesConstantConstant") + @JsName("timesConstantConstant") public operator fun C.times(other: C): C /** * Raises [arg] to the integer power [exponent]. */ - @JvmName("constantPower") - @JsName("constantPower") + @JvmName("powerConstant") + @JsName("powerConstant") public fun power(arg: C, exponent: UInt) : C /** @@ -222,7 +222,7 @@ public interface PolynomialSpace> : Ring

{ /** * Raises [arg] to the integer power [exponent]. */ - public override fun power(arg: P, exponent: UInt) : P = exponentiationBySquaring(arg, exponent) + public override fun power(arg: P, exponent: UInt) : P = exponentiateBySquaring(arg, exponent) /** * Instance of zero polynomial (zero of the polynomial ring). @@ -251,7 +251,7 @@ public interface PolynomialSpace> : Ring

{ * @param P the type of polynomials. * @param A the type of algebraic structure (precisely, of ring) provided for constants. */ -@Suppress("INAPPLICABLE_JVM_NAME") +@Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public interface PolynomialSpaceOverRing, A: Ring> : PolynomialSpace { public val ring: A @@ -261,63 +261,63 @@ public interface PolynomialSpaceOverRing, A: Ring> : Poly * * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. */ - public override operator fun C.plus(other: Int): C = ring { addMultipliedBySquaring(this@plus, one, other) } + public override operator fun C.plus(other: Int): C = ring { addMultipliedByDoubling(this@plus, one, other) } /** * Returns difference between the constant and the integer represented as constant (member of underlying ring). * * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. */ - public override operator fun C.minus(other: Int): C = ring { addMultipliedBySquaring(this@minus, one, -other) } + public override operator fun C.minus(other: Int): C = ring { addMultipliedByDoubling(this@minus, one, -other) } /** * Returns product of the constant and the integer represented as constant (member of underlying ring). * * The operation is equivalent to sum of [other] copies of [this]. */ - public override operator fun C.times(other: Int): C = ring { multiplyBySquaring(this@times, other) } + public override operator fun C.times(other: Int): C = ring { multiplyByDoubling(this@times, other) } /** * Returns sum of the integer represented as constant (member of underlying ring) and the constant. * * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. */ - public override operator fun Int.plus(other: C): C = ring { addMultipliedBySquaring(other, one, this@plus) } + public override operator fun Int.plus(other: C): C = ring { addMultipliedByDoubling(other, one, this@plus) } /** * Returns difference between the integer represented as constant (member of underlying ring) and the constant. * * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. */ - public override operator fun Int.minus(other: C): C = ring { addMultipliedBySquaring(-other, one, this@minus) } + public override operator fun Int.minus(other: C): C = ring { addMultipliedByDoubling(-other, one, this@minus) } /** * Returns product of the integer represented as constant (member of underlying ring) and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ - public override operator fun Int.times(other: C): C = ring { multiplyBySquaring(other, this@times) } + public override operator fun Int.times(other: C): C = ring { multiplyByDoubling(other, this@times) } /** * Returns negation of the constant. */ - @JvmName("constantUnaryMinus") + @JvmName("unaryMinusConstant") public override operator fun C.unaryMinus(): C = ring { -this@unaryMinus } /** * Returns sum of the constants. */ - @JvmName("constantPlus") + @JvmName("plusConstantConstant") public override operator fun C.plus(other: C): C = ring { this@plus + other } /** * Returns difference of the constants. */ - @JvmName("constantMinus") + @JvmName("minusConstantConstant") public override operator fun C.minus(other: C): C = ring { this@minus - other } /** * Returns product of the constants. */ - @JvmName("constantTimes") + @JvmName("timesConstantConstant") public override operator fun C.times(other: C): C = ring { this@times * other } /** * Raises [arg] to the integer power [exponent]. */ - @JvmName("constantPower") + @JvmName("powerConstant") override fun power(arg: C, exponent: UInt): C = ring { power(arg, exponent) } /** @@ -330,59 +330,59 @@ public interface PolynomialSpaceOverRing, A: Ring> : Poly public override val constantOne: C get() = ring.one } -@Suppress("INAPPLICABLE_JVM_NAME") +@Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public interface MultivariatePolynomialSpace>: PolynomialSpace { - @JvmName("VariableIntPlus") + @JvmName("plusVariableInt") public operator fun V.plus(other: Int): P - @JvmName("VariableIntMinus") + @JvmName("minusVariableInt") public operator fun V.minus(other: Int): P - @JvmName("VariableIntMinusTimes") + @JvmName("timesVariableInt") public operator fun V.times(other: Int): P - @JvmName("IntVariablePlus") + @JvmName("plusIntVariable") public operator fun Int.plus(other: V): P - @JvmName("IntVariableMinus") + @JvmName("minusIntVariable") public operator fun Int.minus(other: V): P - @JvmName("IntVariableTimes") + @JvmName("timesIntVariable") public operator fun Int.times(other: V): P - @JvmName("ConstantVariablePlus") + @JvmName("plusConstantVariable") public operator fun C.plus(other: V): P - @JvmName("ConstantVariableMinus") + @JvmName("minusConstantVariable") public operator fun C.minus(other: V): P - @JvmName("ConstantVariableTimes") + @JvmName("timesConstantVariable") public operator fun C.times(other: V): P - @JvmName("VariableConstantPlus") + @JvmName("plusVariableConstant") public operator fun V.plus(other: C): P - @JvmName("VariableConstantMinus") + @JvmName("minusVariableConstant") public operator fun V.minus(other: C): P - @JvmName("VariableConstantTimes") + @JvmName("timesVariableConstant") public operator fun V.times(other: C): P - @JvmName("VariableUnaryPlus") + @JvmName("unaryPlusVariable") public operator fun V.unaryPlus(): P - @JvmName("VariableUnaryMinus") + @JvmName("unaryMinusVariable") public operator fun V.unaryMinus(): P - @JvmName("VariablePlus") + @JvmName("plusVariableVariable") public operator fun V.plus(other: V): P - @JvmName("VariableMinus") + @JvmName("minusVariableVariable") public operator fun V.minus(other: V): P - @JvmName("VariableTimes") + @JvmName("timesVariableVariable") public operator fun V.times(other: V): P - @JvmName("VariablePolynomialPlus") + @JvmName("plusVariablePolynomial") public operator fun V.plus(other: P): P - @JvmName("VariablePolynomialMinus") + @JvmName("minusVariablePolynomial") public operator fun V.minus(other: P): P - @JvmName("VariablePolynomialTimes") + @JvmName("timesVariablePolynomial") public operator fun V.times(other: P): P - @JvmName("PolynomialVariablePlus") + @JvmName("plusPolynomialVariable") public operator fun P.plus(other: V): P - @JvmName("PolynomialVariableMinus") + @JvmName("minusPolynomialVariable") public operator fun P.minus(other: V): P - @JvmName("PolynomialVariableTimes") + @JvmName("timesPolynomialVariable") public operator fun P.times(other: V): P /** diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt index eede543ee..dfec126f3 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt @@ -28,7 +28,7 @@ public interface RationalFunction> { * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. * @param R the type of rational functions. */ -@Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") +@Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") // FIXME: Waiting for KT-31420 public interface RationalFunctionalSpace, R: RationalFunction> : Ring { /** * Returns sum of the constant and the integer represented as constant (member of underlying ring). @@ -129,52 +129,52 @@ public interface RationalFunctionalSpace, R: RationalFunctio * * The operation is equivalent to adding [other] copies of unit polynomial to [this]. */ - public operator fun R.plus(other: Int): R = addMultipliedBySquaring(this, one, other) + public operator fun R.plus(other: Int): R = addMultipliedByDoubling(this, one, other) /** * Returns difference between the rational function and the integer represented as rational function. * * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. */ - public operator fun R.minus(other: Int): R = addMultipliedBySquaring(this, one, -other) + public operator fun R.minus(other: Int): R = addMultipliedByDoubling(this, one, -other) /** * Returns product of the rational function and the integer represented as rational function. * * The operation is equivalent to sum of [other] copies of [this]. */ - public operator fun R.times(other: Int): R = multiplyBySquaring(this, other) + public operator fun R.times(other: Int): R = multiplyByDoubling(this, other) /** * Returns quotient of the rational function and the integer represented as rational function. * * The operation is equivalent to creating a new rational function by preserving numerator of [this] and * multiplication denominator of [this] to [other]. */ - public operator fun R.div(other: Int): R = this / multiplyBySquaring(one, other) + public operator fun R.div(other: Int): R = this / multiplyByDoubling(one, other) /** * Returns sum of the integer represented as rational function and the rational function. * * The operation is equivalent to adding [this] copies of unit polynomial to [other]. */ - public operator fun Int.plus(other: R): R = addMultipliedBySquaring(other, one, this) + public operator fun Int.plus(other: R): R = addMultipliedByDoubling(other, one, this) /** * Returns difference between the integer represented as rational function and the rational function. * * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. */ - public operator fun Int.minus(other: R): R = addMultipliedBySquaring(-other, one, this) + public operator fun Int.minus(other: R): R = addMultipliedByDoubling(-other, one, this) /** * Returns product of the integer represented as rational function and the rational function. * * The operation is equivalent to sum of [this] copies of [other]. */ - public operator fun Int.times(other: R): R = multiplyBySquaring(other, this) + public operator fun Int.times(other: R): R = multiplyByDoubling(other, this) /** * Returns quotient of the integer represented as rational function and the rational function. * * The operation is equivalent to creating a new rational function which numerator is [this] times denominator of * [other] and which denominator is [other]'s numerator. */ - public operator fun Int.div(other: R): R = multiplyBySquaring(one / other, this) + public operator fun Int.div(other: R): R = multiplyByDoubling(one / other, this) /** * Converts the integer [value] to rational function. @@ -188,38 +188,38 @@ public interface RationalFunctionalSpace, R: RationalFunctio /** * Returns the same constant. */ - @JvmName("constantUnaryPlus") - @JsName("constantUnaryPlus") + @JvmName("unaryPlusConstant") + @JsName("unaryPlusConstant") public operator fun C.unaryPlus(): C = this /** * Returns negation of the constant. */ - @JvmName("constantUnaryMinus") - @JsName("constantUnaryMinus") + @JvmName("unaryMinusConstant") + @JsName("unaryMinusConstant") public operator fun C.unaryMinus(): C /** * Returns sum of the constants. */ - @JvmName("constantPlus") - @JsName("constantPlus") + @JvmName("plusConstantConstant") + @JsName("plusConstantConstant") public operator fun C.plus(other: C): C /** * Returns difference of the constants. */ - @JvmName("constantMinus") - @JsName("constantMinus") + @JvmName("minusConstantConstant") + @JsName("minusConstantConstant") public operator fun C.minus(other: C): C /** * Returns product of the constants. */ - @JvmName("constantTimes") - @JsName("constantTimes") + @JvmName("timesConstantConstant") + @JsName("timesConstantConstant") public operator fun C.times(other: C): C /** * Raises [arg] to the integer power [exponent]. */ - @JvmName("constantPower") - @JsName("constantPower") + @JvmName("powerConstant") + @JsName("powerConstant") public fun power(arg: C, exponent: UInt) : C /** @@ -417,7 +417,7 @@ public interface RationalFunctionalSpace, R: RationalFunctio /** * Raises [arg] to the integer power [exponent]. */ - public override fun power(arg: R, exponent: UInt) : R = exponentiationBySquaring(arg, exponent) + public override fun power(arg: R, exponent: UInt) : R = exponentiateBySquaring(arg, exponent) /** * Instance of zero rational function (zero of the rational functions ring). @@ -458,7 +458,7 @@ public interface RationalFunctionalSpace, R: RationalFunctio * @param R the type of rational functions. * @param A the type of algebraic structure (precisely, of ring) provided for constants. */ -@Suppress("INAPPLICABLE_JVM_NAME") +@Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public interface RationalFunctionalSpaceOverRing, R: RationalFunction, A: Ring> : RationalFunctionalSpace { public val ring: A @@ -468,68 +468,68 @@ public interface RationalFunctionalSpaceOverRing, R: Rationa * * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. */ - public override operator fun C.plus(other: Int): C = ring { addMultipliedBySquaring(this@plus, one, other) } + public override operator fun C.plus(other: Int): C = ring { addMultipliedByDoubling(this@plus, one, other) } /** * Returns difference between the constant and the integer represented as constant (member of underlying ring). * * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. */ - public override operator fun C.minus(other: Int): C = ring { addMultipliedBySquaring(this@minus, one, -other) } + public override operator fun C.minus(other: Int): C = ring { addMultipliedByDoubling(this@minus, one, -other) } /** * Returns product of the constant and the integer represented as constant (member of underlying ring). * * The operation is equivalent to sum of [other] copies of [this]. */ - public override operator fun C.times(other: Int): C = ring { multiplyBySquaring(this@times, other) } + public override operator fun C.times(other: Int): C = ring { multiplyByDoubling(this@times, other) } /** * Returns sum of the integer represented as constant (member of underlying ring) and the constant. * * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. */ - public override operator fun Int.plus(other: C): C = ring { addMultipliedBySquaring(other, one, this@plus) } + public override operator fun Int.plus(other: C): C = ring { addMultipliedByDoubling(other, one, this@plus) } /** * Returns difference between the integer represented as constant (member of underlying ring) and the constant. * * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. */ - public override operator fun Int.minus(other: C): C = ring { addMultipliedBySquaring(-other, one, this@minus) } + public override operator fun Int.minus(other: C): C = ring { addMultipliedByDoubling(-other, one, this@minus) } /** * Returns product of the integer represented as constant (member of underlying ring) and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ - public override operator fun Int.times(other: C): C = ring { multiplyBySquaring(other, this@times) } + public override operator fun Int.times(other: C): C = ring { multiplyByDoubling(other, this@times) } /** * Returns the same constant. */ - @JvmName("constantUnaryPlus") + @JvmName("unaryPlusConstant") public override operator fun C.unaryPlus(): C = ring { +this@unaryPlus } /** * Returns negation of the constant. */ - @JvmName("constantUnaryMinus") + @JvmName("unaryMinusConstant") public override operator fun C.unaryMinus(): C = ring { -this@unaryMinus } /** * Returns sum of the constants. */ - @JvmName("constantPlus") + @JvmName("plusConstantConstant") public override operator fun C.plus(other: C): C = ring { this@plus + other } /** * Returns difference of the constants. */ - @JvmName("constantMinus") + @JvmName("minusConstantConstant") public override operator fun C.minus(other: C): C = ring { this@minus - other } /** * Returns product of the constants. */ - @JvmName("constantTimes") + @JvmName("timesConstantConstant") public override operator fun C.times(other: C): C = ring { this@times * other } /** * Raises [arg] to the integer power [exponent]. */ - @JvmName("constantPower") + @JvmName("powerConstant") public override fun power(arg: C, exponent: UInt) : C = ring { power(arg, exponent) } /** @@ -552,7 +552,7 @@ public interface RationalFunctionalSpaceOverRing, R: Rationa * @param R the type of rational functions. * @param AP the type of algebraic structure (precisely, of ring) provided for polynomials. */ -@Suppress("INAPPLICABLE_JVM_NAME") +@Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public interface RationalFunctionalSpaceOverPolynomialSpace< C, P: Polynomial, @@ -659,32 +659,32 @@ public interface RationalFunctionalSpaceOverPolynomialSpace< /** * Returns the same constant. */ - @JvmName("constantUnaryPlus") + @JvmName("unaryPlusConstant") public override operator fun C.unaryPlus(): C = polynomialRing { +this@unaryPlus } /** * Returns negation of the constant. */ - @JvmName("constantUnaryMinus") + @JvmName("unaryMinusConstant") public override operator fun C.unaryMinus(): C = polynomialRing { -this@unaryMinus } /** * Returns sum of the constants. */ - @JvmName("constantPlus") + @JvmName("plusConstantConstant") public override operator fun C.plus(other: C): C = polynomialRing { this@plus + other } /** * Returns difference of the constants. */ - @JvmName("constantMinus") + @JvmName("minusConstantConstant") public override operator fun C.minus(other: C): C = polynomialRing { this@minus - other } /** * Returns product of the constants. */ - @JvmName("constantTimes") + @JvmName("timesConstantConstant") public override operator fun C.times(other: C): C = polynomialRing { this@times * other } /** * Raises [arg] to the integer power [exponent]. */ - @JvmName("constantPower") + @JvmName("powerConstant") public override fun power(arg: C, exponent: UInt) : C = polynomialRing { power(arg, exponent) } /** @@ -780,7 +780,7 @@ public interface RationalFunctionalSpaceOverPolynomialSpace< * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. * @param R the type of rational functions. */ -@Suppress("INAPPLICABLE_JVM_NAME") +@Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public abstract class PolynomialSpaceOfFractions< C, P: Polynomial, @@ -1052,78 +1052,78 @@ public abstract class PolynomialSpaceOfFractions< public override val one: R get() = constructRationalFunction(polynomialOne) } -@Suppress("INAPPLICABLE_JVM_NAME") +@Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public interface MultivariateRationalFunctionalSpace< C, V, P: Polynomial, R: RationalFunction >: RationalFunctionalSpace { - @JvmName("VariableIntPlus") + @JvmName("plusVariableInt") public operator fun V.plus(other: Int): P - @JvmName("VariableIntMinus") + @JvmName("minusVariableInt") public operator fun V.minus(other: Int): P - @JvmName("VariableIntMinusTimes") + @JvmName("timesVariableInt") public operator fun V.times(other: Int): P - @JvmName("IntVariablePlus") + @JvmName("plusIntVariable") public operator fun Int.plus(other: V): P - @JvmName("IntVariableMinus") + @JvmName("minusIntVariable") public operator fun Int.minus(other: V): P - @JvmName("IntVariableTimes") + @JvmName("timesIntVariable") public operator fun Int.times(other: V): P - @JvmName("ConstantVariablePlus") + @JvmName("plusConstantVariable") public operator fun C.plus(other: V): P - @JvmName("ConstantVariableMinus") + @JvmName("minusConstantVariable") public operator fun C.minus(other: V): P - @JvmName("ConstantVariableTimes") + @JvmName("timesConstantVariable") public operator fun C.times(other: V): P - @JvmName("VariableConstantPlus") + @JvmName("plusVariableConstant") public operator fun V.plus(other: C): P - @JvmName("VariableConstantMinus") + @JvmName("minusVariableConstant") public operator fun V.minus(other: C): P - @JvmName("VariableConstantTimes") + @JvmName("timesVariableConstant") public operator fun V.times(other: C): P - @JvmName("VariableUnaryPlus") + @JvmName("unaryPlusVariable") public operator fun V.unaryPlus(): P - @JvmName("VariableUnaryMinus") + @JvmName("unaryMinusVariable") public operator fun V.unaryMinus(): P - @JvmName("VariablePlus") + @JvmName("plusVariableVariable") public operator fun V.plus(other: V): P - @JvmName("VariableMinus") + @JvmName("minusVariableVariable") public operator fun V.minus(other: V): P - @JvmName("VariableTimes") + @JvmName("timesVariableVariable") public operator fun V.times(other: V): P - @JvmName("VariablePolynomialPlus") + @JvmName("plusVariablePolynomial") public operator fun V.plus(other: P): P - @JvmName("VariablePolynomialMinus") + @JvmName("minusVariablePolynomial") public operator fun V.minus(other: P): P - @JvmName("VariablePolynomialTimes") + @JvmName("timesVariablePolynomial") public operator fun V.times(other: P): P - @JvmName("PolynomialVariablePlus") + @JvmName("plusPolynomialVariable") public operator fun P.plus(other: V): P - @JvmName("PolynomialVariableMinus") + @JvmName("minusPolynomialVariable") public operator fun P.minus(other: V): P - @JvmName("PolynomialVariableTimes") + @JvmName("timesPolynomialVariable") public operator fun P.times(other: V): P - @JvmName("VariableRationalFunctionPlus") + @JvmName("plusVariableRational") public operator fun V.plus(other: R): R - @JvmName("VariableRationalFunctionMinus") + @JvmName("minusVariableRational") public operator fun V.minus(other: R): R - @JvmName("VariableRationalFunctionTimes") + @JvmName("timesVariableRational") public operator fun V.times(other: R): R - @JvmName("RationalFunctionVariablePlus") + @JvmName("plusRationalVariable") public operator fun R.plus(other: V): R - @JvmName("RationalFunctionVariableMinus") + @JvmName("minusRationalVariable") public operator fun R.minus(other: V): R - @JvmName("RationalFunctionVariableTimes") + @JvmName("timesRationalVariable") public operator fun R.times(other: V): R /** @@ -1177,7 +1177,7 @@ public interface MultivariateRationalFunctionalSpaceOverPolynomialSpace< AP: PolynomialSpace, > : RationalFunctionalSpaceOverPolynomialSpace, MultivariateRationalFunctionalSpace -@Suppress("INAPPLICABLE_JVM_NAME") +@Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public interface MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSpace< C, V, @@ -1185,57 +1185,57 @@ public interface MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSp R: RationalFunction, AP: MultivariatePolynomialSpace, > : MultivariateRationalFunctionalSpaceOverPolynomialSpace { - @JvmName("VariableIntPlus") + @JvmName("plusVariableInt") public override operator fun V.plus(other: Int): P = polynomialRing { this@plus + other } - @JvmName("VariableIntMinus") + @JvmName("minusVariableInt") public override operator fun V.minus(other: Int): P = polynomialRing { this@minus - other } - @JvmName("VariableIntMinusTimes") + @JvmName("timesVariableInt") public override operator fun V.times(other: Int): P = polynomialRing { this@times * other } - @JvmName("IntVariablePlus") + @JvmName("plusIntVariable") public override operator fun Int.plus(other: V): P = polynomialRing { this@plus + other } - @JvmName("IntVariableMinus") + @JvmName("minusIntVariable") public override operator fun Int.minus(other: V): P = polynomialRing { this@minus - other } - @JvmName("IntVariableTimes") + @JvmName("timesIntVariable") public override operator fun Int.times(other: V): P = polynomialRing { this@times * other } - @JvmName("ConstantVariablePlus") + @JvmName("plusConstantVariable") public override operator fun C.plus(other: V): P = polynomialRing { this@plus + other } - @JvmName("ConstantVariableMinus") + @JvmName("minusConstantVariable") public override operator fun C.minus(other: V): P = polynomialRing { this@minus - other } - @JvmName("ConstantVariableTimes") + @JvmName("timesConstantVariable") public override operator fun C.times(other: V): P = polynomialRing { this@times * other } - @JvmName("VariableConstantPlus") + @JvmName("plusVariableConstant") public override operator fun V.plus(other: C): P = polynomialRing { this@plus + other } - @JvmName("VariableConstantMinus") + @JvmName("minusVariableConstant") public override operator fun V.minus(other: C): P = polynomialRing { this@minus - other } - @JvmName("VariableConstantTimes") + @JvmName("timesVariableConstant") public override operator fun V.times(other: C): P = polynomialRing { this@times * other } - @JvmName("VariableUnaryPlus") + @JvmName("unaryPlusVariable") public override operator fun V.unaryPlus(): P = polynomialRing { +this@unaryPlus } - @JvmName("VariableUnaryMinus") + @JvmName("unaryMinusVariable") public override operator fun V.unaryMinus(): P = polynomialRing { -this@unaryMinus } - @JvmName("VariablePlus") + @JvmName("plusVariableVariable") public override operator fun V.plus(other: V): P = polynomialRing { this@plus + other } - @JvmName("VariableMinus") + @JvmName("minusVariableVariable") public override operator fun V.minus(other: V): P = polynomialRing { this@minus - other } - @JvmName("VariableTimes") + @JvmName("timesVariableVariable") public override operator fun V.times(other: V): P = polynomialRing { this@times * other } - @JvmName("VariablePolynomialPlus") + @JvmName("plusVariablePolynomial") public override operator fun V.plus(other: P): P = polynomialRing { this@plus + other } - @JvmName("VariablePolynomialMinus") + @JvmName("minusVariablePolynomial") public override operator fun V.minus(other: P): P = polynomialRing { this@minus - other } - @JvmName("VariablePolynomialTimes") + @JvmName("timesVariablePolynomial") public override operator fun V.times(other: P): P = polynomialRing { this@times * other } - @JvmName("PolynomialVariablePlus") + @JvmName("plusPolynomialVariable") public override operator fun P.plus(other: V): P = polynomialRing { this@plus + other } - @JvmName("PolynomialVariableMinus") + @JvmName("minusPolynomialVariable") public override operator fun P.minus(other: V): P = polynomialRing { this@minus - other } - @JvmName("PolynomialVariableTimes") + @JvmName("timesPolynomialVariable") public override operator fun P.times(other: V): P = polynomialRing { this@times * other } /** @@ -1264,45 +1264,45 @@ public interface MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSp public override val P.countOfVariables: Int get() = polynomialRing { countOfVariables } } -@Suppress("INAPPLICABLE_JVM_NAME") +@Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public abstract class MultivariatePolynomialSpaceOfFractions< C, V, P: Polynomial, R: RationalFunction, > : MultivariateRationalFunctionalSpace, PolynomialSpaceOfFractions() { - @JvmName("VariableRationalFunctionPlus") + @JvmName("plusVariableRational") public override operator fun V.plus(other: R): R = constructRationalFunction( this * other.denominator + other.numerator, other.denominator ) - @JvmName("VariableRationalFunctionMinus") + @JvmName("minusVariableRational") public override operator fun V.minus(other: R): R = constructRationalFunction( this * other.denominator - other.numerator, other.denominator ) - @JvmName("VariableRationalFunctionTimes") + @JvmName("timesVariableRational") public override operator fun V.times(other: R): R = constructRationalFunction( this * other.numerator, other.denominator ) - @JvmName("RationalFunctionVariablePlus") + @JvmName("plusRationalVariable") public override operator fun R.plus(other: V): R = constructRationalFunction( numerator + denominator * other, denominator ) - @JvmName("RationalFunctionVariableMinus") + @JvmName("minusRationalVariable") public override operator fun R.minus(other: V): R = constructRationalFunction( numerator - denominator * other, denominator ) - @JvmName("RationalFunctionVariableTimes") + @JvmName("timesRationalVariable") public override operator fun R.times(other: V): R = constructRationalFunction( numerator * other, diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt index fa97d6a6c..b40aa4775 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt @@ -18,9 +18,9 @@ import space.kscience.kmath.operations.* * @return product of the multiplicand [arg] and the multiplier [multiplier]. * @author Gleb Minaev */ -internal fun Group.multiplyBySquaring(arg: C, multiplier: Int): C = - if (multiplier >= 0) multiplyBySquaring(arg, multiplier.toUInt()) - else multiplyBySquaring(-arg, (-multiplier).toUInt()) +internal fun Group.multiplyByDoubling(arg: C, multiplier: Int): C = + if (multiplier >= 0) multiplyByDoubling(arg, multiplier.toUInt()) + else multiplyByDoubling(-arg, (-multiplier).toUInt()) // FIXME: Move receiver to context receiver /** @@ -32,9 +32,9 @@ internal fun Group.multiplyBySquaring(arg: C, multiplier: Int): C = * @return sum of the augend [base] and product of the multiplicand [arg] and the multiplier [multiplier]. * @author Gleb Minaev */ -internal fun GroupOps.addMultipliedBySquaring(base: C, arg: C, multiplier: Int): C = - if (multiplier >= 0) addMultipliedBySquaring(base, arg, multiplier.toUInt()) - else addMultipliedBySquaring(base, -arg, (-multiplier).toUInt()) +internal fun GroupOps.addMultipliedByDoubling(base: C, arg: C, multiplier: Int): C = + if (multiplier >= 0) addMultipliedByDoubling(base, arg, multiplier.toUInt()) + else addMultipliedByDoubling(base, -arg, (-multiplier).toUInt()) // FIXME: Move receiver to context receiver /** @@ -47,12 +47,12 @@ internal fun GroupOps.addMultipliedBySquaring(base: C, arg: C, multiplier * @return product of the multiplicand [arg] and the multiplier [multiplier]. * @author Gleb Minaev */ -internal tailrec fun Group.multiplyBySquaring(arg: C, multiplier: UInt): C = +internal tailrec fun Group.multiplyByDoubling(arg: C, multiplier: UInt): C = when { multiplier == 0u -> zero multiplier == 1u -> arg - multiplier and 1u == 0u -> multiplyBySquaring(arg + arg, multiplier shr 1) - multiplier and 1u == 1u -> addMultipliedBySquaring(arg, arg + arg, multiplier shr 1) + multiplier and 1u == 0u -> multiplyByDoubling(arg + arg, multiplier shr 1) + multiplier and 1u == 1u -> addMultipliedByDoubling(arg, arg + arg, multiplier shr 1) else -> error("Error in multiplication group instant by unsigned integer: got reminder by division by 2 different from 0 and 1") } @@ -68,12 +68,12 @@ internal tailrec fun Group.multiplyBySquaring(arg: C, multiplier: UInt): * @return sum of the augend [base] and product of the multiplicand [arg] and the multiplier [multiplier]. * @author Gleb Minaev */ -internal tailrec fun GroupOps.addMultipliedBySquaring(base: C, arg: C, multiplier: UInt): C = +internal tailrec fun GroupOps.addMultipliedByDoubling(base: C, arg: C, multiplier: UInt): C = when { multiplier == 0u -> base multiplier == 1u -> base + arg - multiplier and 1u == 0u -> addMultipliedBySquaring(base, arg + arg, multiplier shr 1) - multiplier and 1u == 1u -> addMultipliedBySquaring(base + arg, arg + arg, multiplier shr 1) + multiplier and 1u == 0u -> addMultipliedByDoubling(base, arg + arg, multiplier shr 1) + multiplier and 1u == 1u -> addMultipliedByDoubling(base + arg, arg + arg, multiplier shr 1) else -> error("Error in multiplication group instant by unsigned integer: got reminder by division by 2 different from 0 and 1") } @@ -86,9 +86,9 @@ internal tailrec fun GroupOps.addMultipliedBySquaring(base: C, arg: C, mu * @return [arg] raised to the power [exponent]. * @author Gleb Minaev */ -internal fun Field.exponentiationBySquaring(arg: C, exponent: Int): C = - if (exponent >= 0) exponentiationBySquaring(arg, exponent.toUInt()) - else exponentiationBySquaring(one / arg, (-exponent).toUInt()) +internal fun Field.exponentiateBySquaring(arg: C, exponent: Int): C = + if (exponent >= 0) exponentiateBySquaring(arg, exponent.toUInt()) + else exponentiateBySquaring(one / arg, (-exponent).toUInt()) // FIXME: Move receiver to context receiver /** @@ -100,9 +100,9 @@ internal fun Field.exponentiationBySquaring(arg: C, exponent: Int): C = * @return product of [base] and [arg] raised to the power [exponent]. * @author Gleb Minaev */ -internal fun Field.multiplyExponentiationBySquaring(base: C, arg: C, exponent: Int): C = - if (exponent >= 0) multiplyExponentiationBySquaring(base, arg, exponent.toUInt()) - else multiplyExponentiationBySquaring(base, one / arg, (-exponent).toUInt()) +internal fun Field.multiplyExponentiatedBySquaring(base: C, arg: C, exponent: Int): C = + if (exponent >= 0) multiplyExponentiatedBySquaring(base, arg, exponent.toUInt()) + else multiplyExponentiatedBySquaring(base, one / arg, (-exponent).toUInt()) // FIXME: Move receiver to context receiver /** @@ -115,12 +115,12 @@ internal fun Field.multiplyExponentiationBySquaring(base: C, arg: C, expo * @return [arg] raised to the power [exponent]. * @author Gleb Minaev */ -internal tailrec fun Ring.exponentiationBySquaring(arg: C, exponent: UInt): C = +internal tailrec fun Ring.exponentiateBySquaring(arg: C, exponent: UInt): C = when { exponent == 0u -> zero exponent == 1u -> arg - exponent and 1u == 0u -> exponentiationBySquaring(arg * arg, exponent shr 1) - exponent and 1u == 1u -> multiplyExponentiationBySquaring(arg, arg * arg, exponent shr 1) + exponent and 1u == 0u -> exponentiateBySquaring(arg * arg, exponent shr 1) + exponent and 1u == 1u -> multiplyExponentiatedBySquaring(arg, arg * arg, exponent shr 1) else -> error("Error in multiplication group instant by unsigned integer: got reminder by division by 2 different from 0 and 1") } @@ -136,11 +136,11 @@ internal tailrec fun Ring.exponentiationBySquaring(arg: C, exponent: UInt * @return product of [base] and [arg] raised to the power [exponent]. * @author Gleb Minaev */ -internal tailrec fun RingOps.multiplyExponentiationBySquaring(base: C, arg: C, exponent: UInt): C = +internal tailrec fun RingOps.multiplyExponentiatedBySquaring(base: C, arg: C, exponent: UInt): C = when { exponent == 0u -> base exponent == 1u -> base * arg - exponent and 1u == 0u -> multiplyExponentiationBySquaring(base, arg * arg, exponent shr 1) - exponent and 1u == 1u -> multiplyExponentiationBySquaring(base * arg, arg * arg, exponent shr 1) + exponent and 1u == 0u -> multiplyExponentiatedBySquaring(base, arg * arg, exponent shr 1) + exponent and 1u == 1u -> multiplyExponentiatedBySquaring(base * arg, arg * arg, exponent shr 1) else -> error("Error in multiplication group instant by unsigned integer: got reminder by division by 2 different from 0 and 1") } \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt index 88d357413..af918b9ae 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt @@ -271,7 +271,7 @@ public fun > LabeledPolynomial.derivativeWithRespectTo( } } }, - multiplyBySquaring(c, degs[variable]!!) + multiplyByDoubling(c, degs[variable]!!) ) } } @@ -302,7 +302,7 @@ public fun > LabeledPolynomial.derivativeWithRespectTo( } } }, - cleanedVariables.fold(c) { acc, variable -> multiplyBySquaring(acc, degs[variable]!!) } + cleanedVariables.fold(c) { acc, variable -> multiplyByDoubling(acc, degs[variable]!!) } ) } } @@ -335,7 +335,7 @@ public fun > LabeledPolynomial.nthDerivativeWithRespectTo( }, degs[variable]!!.let { deg -> (deg downTo deg - order + 1u) - .fold(c) { acc, ord -> multiplyBySquaring(acc, ord) } + .fold(c) { acc, ord -> multiplyByDoubling(acc, ord) } } ) } @@ -371,7 +371,7 @@ public fun > LabeledPolynomial.nthDerivativeWithRespectTo( filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> degs[index]!!.let { deg -> (deg downTo deg - order + 1u) - .fold(acc1) { acc2, ord -> multiplyBySquaring(acc2, ord) } + .fold(acc1) { acc2, ord -> multiplyByDoubling(acc2, ord) } } } ) @@ -398,7 +398,7 @@ public fun > LabeledPolynomial.antiderivativeWithRespectTo( } put( newDegs, - c / multiplyBySquaring(one, newDegs[variable]!!) + c / multiplyByDoubling(one, newDegs[variable]!!) ) } } @@ -425,7 +425,7 @@ public fun > LabeledPolynomial.antiderivativeWithRespectTo( } put( newDegs, - cleanedVariables.fold(c) { acc, variable -> acc / multiplyBySquaring(one, newDegs[variable]!!) } + cleanedVariables.fold(c) { acc, variable -> acc / multiplyByDoubling(one, newDegs[variable]!!) } ) } } @@ -454,7 +454,7 @@ public fun > LabeledPolynomial.nthAntiderivativeWithRespectTo newDegs, newDegs[variable]!!.let { deg -> (deg downTo deg - order + 1u) - .fold(c) { acc, ord -> acc / multiplyBySquaring(one, ord) } + .fold(c) { acc, ord -> acc / multiplyByDoubling(one, ord) } } ) } @@ -485,7 +485,7 @@ public fun > LabeledPolynomial.nthAntiderivativeWithRespectTo filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> newDegs[index]!!.let { deg -> (deg downTo deg - order + 1u) - .fold(acc1) { acc2, ord -> acc2 / multiplyBySquaring(one, ord) } + .fold(acc1) { acc2, ord -> acc2 / multiplyByDoubling(one, ord) } } } ) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt index ee85b0f56..ad817c7ba 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt @@ -322,7 +322,7 @@ public fun > NumberedPolynomial.derivativeWithRespectTo( else -> return@forEach } }.cleanUp(), - multiplyBySquaring(c, degs[variable]) + multiplyByDoubling(c, degs[variable]) ) } } @@ -353,7 +353,7 @@ public fun > NumberedPolynomial.derivativeWithRespectTo( else -> return@forEach } }.cleanUp(), - cleanedVariables.fold(c) { acc, variable -> multiplyBySquaring(acc, degs[variable]) } + cleanedVariables.fold(c) { acc, variable -> multiplyByDoubling(acc, degs[variable]) } ) } } @@ -385,7 +385,7 @@ public fun > NumberedPolynomial.nthDerivativeWithRespectTo( }.cleanUp(), degs[variable].let { deg -> (deg downTo deg - order + 1u) - .fold(c) { acc, ord -> multiplyBySquaring(acc, ord) } + .fold(c) { acc, ord -> multiplyByDoubling(acc, ord) } } ) } @@ -418,7 +418,7 @@ public fun > NumberedPolynomial.nthDerivativeWithRespectTo( filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> degs[index].let { deg -> (deg downTo deg - order + 1u) - .fold(acc1) { acc2, ord -> multiplyBySquaring(acc2, ord) } + .fold(acc1) { acc2, ord -> multiplyByDoubling(acc2, ord) } } } ) @@ -441,7 +441,7 @@ public fun > NumberedPolynomial.antiderivativeWithRespectTo( .forEach { (degs, c) -> put( List(max(variable + 1, degs.size)) { if (it != variable) degs[it] else degs[it] + 1u }, - c / multiplyBySquaring(one, degs[variable]) + c / multiplyByDoubling(one, degs[variable]) ) } } @@ -465,7 +465,7 @@ public fun > NumberedPolynomial.antiderivativeWithRespectTo( .forEach { (degs, c) -> put( List(max(maxRespectedVariable + 1, degs.size)) { if (it !in variables) degs[it] else degs[it] + 1u }, - cleanedVariables.fold(c) { acc, variable -> acc / multiplyBySquaring(one, degs[variable]) } + cleanedVariables.fold(c) { acc, variable -> acc / multiplyByDoubling(one, degs[variable]) } ) } } @@ -490,7 +490,7 @@ public fun > NumberedPolynomial.nthAntiderivativeWithRespectT List(max(variable + 1, degs.size)) { if (it != variable) degs[it] else degs[it] + order }, degs[variable].let { deg -> (deg downTo deg - order + 1u) - .fold(c) { acc, ord -> acc / multiplyBySquaring(one, ord) } + .fold(c) { acc, ord -> acc / multiplyByDoubling(one, ord) } } ) } @@ -518,7 +518,7 @@ public fun > NumberedPolynomial.nthAntiderivativeWithRespectT filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> degs[index].let { deg -> (deg downTo deg - order + 1u) - .fold(acc1) { acc2, ord -> acc2 / multiplyBySquaring(one, ord) } + .fold(acc1) { acc2, ord -> acc2 / multiplyByDoubling(one, ord) } } } ) diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/AlgebraicStubTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/AlgebraicStubTest.kt index fe4a82f11..487cd9ee1 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/AlgebraicStubTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/AlgebraicStubTest.kt @@ -31,47 +31,47 @@ class AlgebraicStubTest { ExprRing { assertEquals( "57", - addMultipliedBySquaring(Expr("57"), Expr("179"), 0u).expr, + addMultipliedByDoubling(Expr("57"), Expr("179"), 0u).expr, "tried addMultipliedBySquaring(57, 179, 0u)" ) assertEquals( "(57 + 179)", - addMultipliedBySquaring(Expr("57"), Expr("179"), 1u).expr, + addMultipliedByDoubling(Expr("57"), Expr("179"), 1u).expr, "tried addMultipliedBySquaring(57, 179, 1u)" ) assertEquals( "(57 + (179 + 179))", - addMultipliedBySquaring(Expr("57"), Expr("179"), 2u).expr, + addMultipliedByDoubling(Expr("57"), Expr("179"), 2u).expr, "tried addMultipliedBySquaring(57, 179, 2u)" ) assertEquals( "((57 + 179) + (179 + 179))", - addMultipliedBySquaring(Expr("57"), Expr("179"), 3u).expr, + addMultipliedByDoubling(Expr("57"), Expr("179"), 3u).expr, "tried addMultipliedBySquaring(57, 179, 3u)" ) assertEquals( "(57 + ((179 + 179) + (179 + 179)))", - addMultipliedBySquaring(Expr("57"), Expr("179"), 4u).expr, + addMultipliedByDoubling(Expr("57"), Expr("179"), 4u).expr, "tried addMultipliedBySquaring(57, 179, 4u)" ) assertEquals( "((57 + 179) + ((179 + 179) + (179 + 179)))", - addMultipliedBySquaring(Expr("57"), Expr("179"), 5u).expr, + addMultipliedByDoubling(Expr("57"), Expr("179"), 5u).expr, "tried addMultipliedBySquaring(57, 179, 5u)" ) assertEquals( "((57 + (179 + 179)) + ((179 + 179) + (179 + 179)))", - addMultipliedBySquaring(Expr("57"), Expr("179"), 6u).expr, + addMultipliedByDoubling(Expr("57"), Expr("179"), 6u).expr, "tried addMultipliedBySquaring(57, 179, 6u)" ) assertEquals( "(((57 + 179) + (179 + 179)) + ((179 + 179) + (179 + 179)))", - addMultipliedBySquaring(Expr("57"), Expr("179"), 7u).expr, + addMultipliedByDoubling(Expr("57"), Expr("179"), 7u).expr, "tried addMultipliedBySquaring(57, 179, 7u)" ) assertEquals( "(57 + (((179 + 179) + (179 + 179)) + ((179 + 179) + (179 + 179))))", - addMultipliedBySquaring(Expr("57"), Expr("179"), 8u).expr, + addMultipliedByDoubling(Expr("57"), Expr("179"), 8u).expr, "tried addMultipliedBySquaring(57, 179, 8u)" ) } @@ -81,47 +81,47 @@ class AlgebraicStubTest { ExprRing { assertEquals( "0", - multiplyBySquaring(Expr("57"), 0u).expr, + multiplyByDoubling(Expr("57"), 0u).expr, "tried multiplyBySquaring(57, 0u)" ) assertEquals( "57", - multiplyBySquaring(Expr("57"), 1u).expr, + multiplyByDoubling(Expr("57"), 1u).expr, "tried multiplyBySquaring(57, 1u)" ) assertEquals( "(57 + 57)", - multiplyBySquaring(Expr("57"), 2u).expr, + multiplyByDoubling(Expr("57"), 2u).expr, "tried multiplyBySquaring(57, 2u)" ) assertEquals( "(57 + (57 + 57))", - multiplyBySquaring(Expr("57"), 3u).expr, + multiplyByDoubling(Expr("57"), 3u).expr, "tried multiplyBySquaring(57, 3u)" ) assertEquals( "((57 + 57) + (57 + 57))", - multiplyBySquaring(Expr("57"), 4u).expr, + multiplyByDoubling(Expr("57"), 4u).expr, "tried multiplyBySquaring(57, 4u)" ) assertEquals( "(57 + ((57 + 57) + (57 + 57)))", - multiplyBySquaring(Expr("57"), 5u).expr, + multiplyByDoubling(Expr("57"), 5u).expr, "tried multiplyBySquaring(57, 5u)" ) assertEquals( "((57 + 57) + ((57 + 57) + (57 + 57)))", - multiplyBySquaring(Expr("57"), 6u).expr, + multiplyByDoubling(Expr("57"), 6u).expr, "tried multiplyBySquaring(57, 6u)" ) assertEquals( "((57 + (57 + 57)) + ((57 + 57) + (57 + 57)))", - multiplyBySquaring(Expr("57"), 7u).expr, + multiplyByDoubling(Expr("57"), 7u).expr, "tried multiplyBySquaring(57, 7u)" ) assertEquals( "(((57 + 57) + (57 + 57)) + ((57 + 57) + (57 + 57)))", - multiplyBySquaring(Expr("57"), 8u).expr, + multiplyByDoubling(Expr("57"), 8u).expr, "tried multiplyBySquaring(57, 8u)" ) } @@ -131,87 +131,87 @@ class AlgebraicStubTest { ExprRing { assertEquals( "57", - addMultipliedBySquaring(Expr("57"), Expr("179"), 0).expr, + addMultipliedByDoubling(Expr("57"), Expr("179"), 0).expr, "tried addMultipliedBySquaring(57, 179, 0)" ) assertEquals( "(57 + 179)", - addMultipliedBySquaring(Expr("57"), Expr("179"), 1).expr, + addMultipliedByDoubling(Expr("57"), Expr("179"), 1).expr, "tried addMultipliedBySquaring(57, 179, 1)" ) assertEquals( "(57 + -179)", - addMultipliedBySquaring(Expr("57"), Expr("179"), -1).expr, + addMultipliedByDoubling(Expr("57"), Expr("179"), -1).expr, "tried addMultipliedBySquaring(57, 179, -1)" ) assertEquals( "(57 + (179 + 179))", - addMultipliedBySquaring(Expr("57"), Expr("179"), 2).expr, + addMultipliedByDoubling(Expr("57"), Expr("179"), 2).expr, "tried addMultipliedBySquaring(57, 179, 2)" ) assertEquals( "(57 + (-179 + -179))", - addMultipliedBySquaring(Expr("57"), Expr("179"), -2).expr, + addMultipliedByDoubling(Expr("57"), Expr("179"), -2).expr, "tried addMultipliedBySquaring(57, 179, -2)" ) assertEquals( "((57 + 179) + (179 + 179))", - addMultipliedBySquaring(Expr("57"), Expr("179"), 3).expr, + addMultipliedByDoubling(Expr("57"), Expr("179"), 3).expr, "tried addMultipliedBySquaring(57, 179, 3)" ) assertEquals( "((57 + -179) + (-179 + -179))", - addMultipliedBySquaring(Expr("57"), Expr("179"), -3).expr, + addMultipliedByDoubling(Expr("57"), Expr("179"), -3).expr, "tried addMultipliedBySquaring(57, 179, -3)" ) assertEquals( "(57 + ((179 + 179) + (179 + 179)))", - addMultipliedBySquaring(Expr("57"), Expr("179"), 4).expr, + addMultipliedByDoubling(Expr("57"), Expr("179"), 4).expr, "tried addMultipliedBySquaring(57, 179, 4)" ) assertEquals( "(57 + ((-179 + -179) + (-179 + -179)))", - addMultipliedBySquaring(Expr("57"), Expr("179"), -4).expr, + addMultipliedByDoubling(Expr("57"), Expr("179"), -4).expr, "tried addMultipliedBySquaring(57, 179, -4)" ) assertEquals( "((57 + 179) + ((179 + 179) + (179 + 179)))", - addMultipliedBySquaring(Expr("57"), Expr("179"), 5).expr, + addMultipliedByDoubling(Expr("57"), Expr("179"), 5).expr, "tried addMultipliedBySquaring(57, 179, 5)" ) assertEquals( "((57 + -179) + ((-179 + -179) + (-179 + -179)))", - addMultipliedBySquaring(Expr("57"), Expr("179"), -5).expr, + addMultipliedByDoubling(Expr("57"), Expr("179"), -5).expr, "tried addMultipliedBySquaring(57, 179, -5)" ) assertEquals( "((57 + (179 + 179)) + ((179 + 179) + (179 + 179)))", - addMultipliedBySquaring(Expr("57"), Expr("179"), 6).expr, + addMultipliedByDoubling(Expr("57"), Expr("179"), 6).expr, "tried addMultipliedBySquaring(57, 179, 6)" ) assertEquals( "((57 + (-179 + -179)) + ((-179 + -179) + (-179 + -179)))", - addMultipliedBySquaring(Expr("57"), Expr("179"), -6).expr, + addMultipliedByDoubling(Expr("57"), Expr("179"), -6).expr, "tried addMultipliedBySquaring(57, 179, -6)" ) assertEquals( "(((57 + 179) + (179 + 179)) + ((179 + 179) + (179 + 179)))", - addMultipliedBySquaring(Expr("57"), Expr("179"), 7).expr, + addMultipliedByDoubling(Expr("57"), Expr("179"), 7).expr, "tried addMultipliedBySquaring(57, 179, 7)" ) assertEquals( "(((57 + -179) + (-179 + -179)) + ((-179 + -179) + (-179 + -179)))", - addMultipliedBySquaring(Expr("57"), Expr("179"), -7).expr, + addMultipliedByDoubling(Expr("57"), Expr("179"), -7).expr, "tried addMultipliedBySquaring(57, 179, -7)" ) assertEquals( "(57 + (((179 + 179) + (179 + 179)) + ((179 + 179) + (179 + 179))))", - addMultipliedBySquaring(Expr("57"), Expr("179"), 8).expr, + addMultipliedByDoubling(Expr("57"), Expr("179"), 8).expr, "tried addMultipliedBySquaring(57, 179, 8)" ) assertEquals( "(57 + (((-179 + -179) + (-179 + -179)) + ((-179 + -179) + (-179 + -179))))", - addMultipliedBySquaring(Expr("57"), Expr("179"), -8).expr, + addMultipliedByDoubling(Expr("57"), Expr("179"), -8).expr, "tried addMultipliedBySquaring(57, 179, -8)" ) } @@ -221,87 +221,87 @@ class AlgebraicStubTest { ExprRing { assertEquals( "0", - multiplyBySquaring(Expr("57"), 0).expr, + multiplyByDoubling(Expr("57"), 0).expr, "tried multiplyBySquaring(57, 0)" ) assertEquals( "57", - multiplyBySquaring(Expr("57"), 1).expr, + multiplyByDoubling(Expr("57"), 1).expr, "tried multiplyBySquaring(57, 1)" ) assertEquals( "-57", - multiplyBySquaring(Expr("57"), -1).expr, + multiplyByDoubling(Expr("57"), -1).expr, "tried multiplyBySquaring(57, -1)" ) assertEquals( "(57 + 57)", - multiplyBySquaring(Expr("57"), 2).expr, + multiplyByDoubling(Expr("57"), 2).expr, "tried multiplyBySquaring(57, 2)" ) assertEquals( "(-57 + -57)", - multiplyBySquaring(Expr("57"), -2).expr, + multiplyByDoubling(Expr("57"), -2).expr, "tried multiplyBySquaring(57, -2)" ) assertEquals( "(57 + (57 + 57))", - multiplyBySquaring(Expr("57"), 3).expr, + multiplyByDoubling(Expr("57"), 3).expr, "tried multiplyBySquaring(57, 3)" ) assertEquals( "(-57 + (-57 + -57))", - multiplyBySquaring(Expr("57"), -3).expr, + multiplyByDoubling(Expr("57"), -3).expr, "tried multiplyBySquaring(57, -3)" ) assertEquals( "((57 + 57) + (57 + 57))", - multiplyBySquaring(Expr("57"), 4).expr, + multiplyByDoubling(Expr("57"), 4).expr, "tried multiplyBySquaring(57, 4)" ) assertEquals( "((-57 + -57) + (-57 + -57))", - multiplyBySquaring(Expr("57"), -4).expr, + multiplyByDoubling(Expr("57"), -4).expr, "tried multiplyBySquaring(57, -4)" ) assertEquals( "(57 + ((57 + 57) + (57 + 57)))", - multiplyBySquaring(Expr("57"), 5).expr, + multiplyByDoubling(Expr("57"), 5).expr, "tried multiplyBySquaring(57, 5)" ) assertEquals( "(-57 + ((-57 + -57) + (-57 + -57)))", - multiplyBySquaring(Expr("57"), -5).expr, + multiplyByDoubling(Expr("57"), -5).expr, "tried multiplyBySquaring(57, -5)" ) assertEquals( "((57 + 57) + ((57 + 57) + (57 + 57)))", - multiplyBySquaring(Expr("57"), 6).expr, + multiplyByDoubling(Expr("57"), 6).expr, "tried multiplyBySquaring(57, 6)" ) assertEquals( "((-57 + -57) + ((-57 + -57) + (-57 + -57)))", - multiplyBySquaring(Expr("57"), -6).expr, + multiplyByDoubling(Expr("57"), -6).expr, "tried multiplyBySquaring(57, -6)" ) assertEquals( "((57 + (57 + 57)) + ((57 + 57) + (57 + 57)))", - multiplyBySquaring(Expr("57"), 7).expr, + multiplyByDoubling(Expr("57"), 7).expr, "tried multiplyBySquaring(57, 7)" ) assertEquals( "((-57 + (-57 + -57)) + ((-57 + -57) + (-57 + -57)))", - multiplyBySquaring(Expr("57"), -7).expr, + multiplyByDoubling(Expr("57"), -7).expr, "tried multiplyBySquaring(57, -7)" ) assertEquals( "(((57 + 57) + (57 + 57)) + ((57 + 57) + (57 + 57)))", - multiplyBySquaring(Expr("57"), 8).expr, + multiplyByDoubling(Expr("57"), 8).expr, "tried multiplyBySquaring(57, 8)" ) assertEquals( "(((-57 + -57) + (-57 + -57)) + ((-57 + -57) + (-57 + -57)))", - multiplyBySquaring(Expr("57"), -8).expr, + multiplyByDoubling(Expr("57"), -8).expr, "tried multiplyBySquaring(57, -8)" ) } @@ -311,47 +311,47 @@ class AlgebraicStubTest { ExprRing { assertEquals( "57", - multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 0u).expr, + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 0u).expr, "tried multiplyExponentiationBySquaring(57, 179, 0u)" ) assertEquals( "(57 * 179)", - multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 1u).expr, + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 1u).expr, "tried multiplyExponentiationBySquaring(57, 179, 1u)" ) assertEquals( "(57 * (179 * 179))", - multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 2u).expr, + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 2u).expr, "tried multiplyExponentiationBySquaring(57, 179, 2u)" ) assertEquals( "((57 * 179) * (179 * 179))", - multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 3u).expr, + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 3u).expr, "tried multiplyExponentiationBySquaring(57, 179, 3u)" ) assertEquals( "(57 * ((179 * 179) * (179 * 179)))", - multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 4u).expr, + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 4u).expr, "tried multiplyExponentiationBySquaring(57, 179, 4u)" ) assertEquals( "((57 * 179) * ((179 * 179) * (179 * 179)))", - multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 5u).expr, + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 5u).expr, "tried multiplyExponentiationBySquaring(57, 179, 5u)" ) assertEquals( "((57 * (179 * 179)) * ((179 * 179) * (179 * 179)))", - multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 6u).expr, + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 6u).expr, "tried multiplyExponentiationBySquaring(57, 179, 6u)" ) assertEquals( "(((57 * 179) * (179 * 179)) * ((179 * 179) * (179 * 179)))", - multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 7u).expr, + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 7u).expr, "tried multiplyExponentiationBySquaring(57, 179, 7u)" ) assertEquals( "(57 * (((179 * 179) * (179 * 179)) * ((179 * 179) * (179 * 179))))", - multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 8u).expr, + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 8u).expr, "tried multiplyExponentiationBySquaring(57, 179, 8u)" ) } @@ -361,47 +361,47 @@ class AlgebraicStubTest { ExprRing { assertEquals( "0", - exponentiationBySquaring(Expr("57"), 0u).expr, + exponentiateBySquaring(Expr("57"), 0u).expr, "tried exponentiationBySquaring(57, 0u)" ) assertEquals( "57", - exponentiationBySquaring(Expr("57"), 1u).expr, + exponentiateBySquaring(Expr("57"), 1u).expr, "tried exponentiationBySquaring(57, 1u)" ) assertEquals( "(57 * 57)", - exponentiationBySquaring(Expr("57"), 2u).expr, + exponentiateBySquaring(Expr("57"), 2u).expr, "tried exponentiationBySquaring(57, 2u)" ) assertEquals( "(57 * (57 * 57))", - exponentiationBySquaring(Expr("57"), 3u).expr, + exponentiateBySquaring(Expr("57"), 3u).expr, "tried exponentiationBySquaring(57, 3u)" ) assertEquals( "((57 * 57) * (57 * 57))", - exponentiationBySquaring(Expr("57"), 4u).expr, + exponentiateBySquaring(Expr("57"), 4u).expr, "tried exponentiationBySquaring(57, 4u)" ) assertEquals( "(57 * ((57 * 57) * (57 * 57)))", - exponentiationBySquaring(Expr("57"), 5u).expr, + exponentiateBySquaring(Expr("57"), 5u).expr, "tried exponentiationBySquaring(57, 5u)" ) assertEquals( "((57 * 57) * ((57 * 57) * (57 * 57)))", - exponentiationBySquaring(Expr("57"), 6u).expr, + exponentiateBySquaring(Expr("57"), 6u).expr, "tried exponentiationBySquaring(57, 6u)" ) assertEquals( "((57 * (57 * 57)) * ((57 * 57) * (57 * 57)))", - exponentiationBySquaring(Expr("57"), 7u).expr, + exponentiateBySquaring(Expr("57"), 7u).expr, "tried exponentiationBySquaring(57, 7u)" ) assertEquals( "(((57 * 57) * (57 * 57)) * ((57 * 57) * (57 * 57)))", - exponentiationBySquaring(Expr("57"), 8u).expr, + exponentiateBySquaring(Expr("57"), 8u).expr, "tried exponentiationBySquaring(57, 8u)" ) } @@ -411,87 +411,87 @@ class AlgebraicStubTest { ExprRing { assertEquals( "57", - multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 0).expr, + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 0).expr, "tried multiplyExponentiationBySquaring(57, 179, 0)" ) assertEquals( "(57 * 179)", - multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 1).expr, + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 1).expr, "tried multiplyExponentiationBySquaring(57, 179, 1)" ) assertEquals( "(57 * (1 / 179))", - multiplyExponentiationBySquaring(Expr("57"), Expr("179"), -1).expr, + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -1).expr, "tried multiplyExponentiationBySquaring(57, 179, -1)" ) assertEquals( "(57 * (179 * 179))", - multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 2).expr, + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 2).expr, "tried multiplyExponentiationBySquaring(57, 179, 2)" ) assertEquals( "(57 * ((1 / 179) * (1 / 179)))", - multiplyExponentiationBySquaring(Expr("57"), Expr("179"), -2).expr, + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -2).expr, "tried multiplyExponentiationBySquaring(57, 179, -2)" ) assertEquals( "((57 * 179) * (179 * 179))", - multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 3).expr, + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 3).expr, "tried multiplyExponentiationBySquaring(57, 179, 3)" ) assertEquals( "((57 * (1 / 179)) * ((1 / 179) * (1 / 179)))", - multiplyExponentiationBySquaring(Expr("57"), Expr("179"), -3).expr, + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -3).expr, "tried multiplyExponentiationBySquaring(57, 179, -3)" ) assertEquals( "(57 * ((179 * 179) * (179 * 179)))", - multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 4).expr, + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 4).expr, "tried multiplyExponentiationBySquaring(57, 179, 4)" ) assertEquals( "(57 * (((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179))))", - multiplyExponentiationBySquaring(Expr("57"), Expr("179"), -4).expr, + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -4).expr, "tried multiplyExponentiationBySquaring(57, 179, -4)" ) assertEquals( "((57 * 179) * ((179 * 179) * (179 * 179)))", - multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 5).expr, + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 5).expr, "tried multiplyExponentiationBySquaring(57, 179, 5)" ) assertEquals( "((57 * (1 / 179)) * (((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179))))", - multiplyExponentiationBySquaring(Expr("57"), Expr("179"), -5).expr, + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -5).expr, "tried multiplyExponentiationBySquaring(57, 179, -5)" ) assertEquals( "((57 * (179 * 179)) * ((179 * 179) * (179 * 179)))", - multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 6).expr, + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 6).expr, "tried multiplyExponentiationBySquaring(57, 179, 6)" ) assertEquals( "((57 * ((1 / 179) * (1 / 179))) * (((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179))))", - multiplyExponentiationBySquaring(Expr("57"), Expr("179"), -6).expr, + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -6).expr, "tried multiplyExponentiationBySquaring(57, 179, -6)" ) assertEquals( "(((57 * 179) * (179 * 179)) * ((179 * 179) * (179 * 179)))", - multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 7).expr, + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 7).expr, "tried multiplyExponentiationBySquaring(57, 179, 7)" ) assertEquals( "(((57 * (1 / 179)) * ((1 / 179) * (1 / 179))) * (((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179))))", - multiplyExponentiationBySquaring(Expr("57"), Expr("179"), -7).expr, + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -7).expr, "tried multiplyExponentiationBySquaring(57, 179, -7)" ) assertEquals( "(57 * (((179 * 179) * (179 * 179)) * ((179 * 179) * (179 * 179))))", - multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 8).expr, + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 8).expr, "tried multiplyExponentiationBySquaring(57, 179, 8)" ) assertEquals( "(57 * ((((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179))) * (((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179)))))", - multiplyExponentiationBySquaring(Expr("57"), Expr("179"), -8).expr, + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -8).expr, "tried multiplyExponentiationBySquaring(57, 179, -8)" ) } @@ -501,87 +501,87 @@ class AlgebraicStubTest { ExprRing { assertEquals( "0", - exponentiationBySquaring(Expr("57"), 0).expr, + exponentiateBySquaring(Expr("57"), 0).expr, "tried exponentiationBySquaring(57, 0)" ) assertEquals( "57", - exponentiationBySquaring(Expr("57"), 1).expr, + exponentiateBySquaring(Expr("57"), 1).expr, "tried exponentiationBySquaring(57, 1)" ) assertEquals( "(1 / 57)", - exponentiationBySquaring(Expr("57"), -1).expr, + exponentiateBySquaring(Expr("57"), -1).expr, "tried exponentiationBySquaring(57, -1)" ) assertEquals( "(57 * 57)", - exponentiationBySquaring(Expr("57"), 2).expr, + exponentiateBySquaring(Expr("57"), 2).expr, "tried exponentiationBySquaring(57, 2)" ) assertEquals( "((1 / 57) * (1 / 57))", - exponentiationBySquaring(Expr("57"), -2).expr, + exponentiateBySquaring(Expr("57"), -2).expr, "tried exponentiationBySquaring(57, -2)" ) assertEquals( "(57 * (57 * 57))", - exponentiationBySquaring(Expr("57"), 3).expr, + exponentiateBySquaring(Expr("57"), 3).expr, "tried exponentiationBySquaring(57, 3)" ) assertEquals( "((1 / 57) * ((1 / 57) * (1 / 57)))", - exponentiationBySquaring(Expr("57"), -3).expr, + exponentiateBySquaring(Expr("57"), -3).expr, "tried exponentiationBySquaring(57, -3)" ) assertEquals( "((57 * 57) * (57 * 57))", - exponentiationBySquaring(Expr("57"), 4).expr, + exponentiateBySquaring(Expr("57"), 4).expr, "tried exponentiationBySquaring(57, 4)" ) assertEquals( "(((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57)))", - exponentiationBySquaring(Expr("57"), -4).expr, + exponentiateBySquaring(Expr("57"), -4).expr, "tried exponentiationBySquaring(57, -4)" ) assertEquals( "(57 * ((57 * 57) * (57 * 57)))", - exponentiationBySquaring(Expr("57"), 5).expr, + exponentiateBySquaring(Expr("57"), 5).expr, "tried exponentiationBySquaring(57, 5)" ) assertEquals( "((1 / 57) * (((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57))))", - exponentiationBySquaring(Expr("57"), -5).expr, + exponentiateBySquaring(Expr("57"), -5).expr, "tried exponentiationBySquaring(57, -5)" ) assertEquals( "((57 * 57) * ((57 * 57) * (57 * 57)))", - exponentiationBySquaring(Expr("57"), 6).expr, + exponentiateBySquaring(Expr("57"), 6).expr, "tried exponentiationBySquaring(57, 6)" ) assertEquals( "(((1 / 57) * (1 / 57)) * (((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57))))", - exponentiationBySquaring(Expr("57"), -6).expr, + exponentiateBySquaring(Expr("57"), -6).expr, "tried exponentiationBySquaring(57, -6)" ) assertEquals( "((57 * (57 * 57)) * ((57 * 57) * (57 * 57)))", - exponentiationBySquaring(Expr("57"), 7).expr, + exponentiateBySquaring(Expr("57"), 7).expr, "tried exponentiationBySquaring(57, 7)" ) assertEquals( "(((1 / 57) * ((1 / 57) * (1 / 57))) * (((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57))))", - exponentiationBySquaring(Expr("57"), -7).expr, + exponentiateBySquaring(Expr("57"), -7).expr, "tried exponentiationBySquaring(57, -7)" ) assertEquals( "(((57 * 57) * (57 * 57)) * ((57 * 57) * (57 * 57)))", - exponentiationBySquaring(Expr("57"), 8).expr, + exponentiateBySquaring(Expr("57"), 8).expr, "tried exponentiationBySquaring(57, 8)" ) assertEquals( "((((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57))) * (((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57))))", - exponentiationBySquaring(Expr("57"), -8).expr, + exponentiateBySquaring(Expr("57"), -8).expr, "tried exponentiationBySquaring(57, -8)" ) } -- 2.34.1 From 9b51062bf7c8b7d65f93120ac36a87bc6731742e Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sat, 11 Jun 2022 16:09:24 +0300 Subject: [PATCH 061/123] Sift. --- .../kmath/functions/LabeledPolynomial.kt | 539 ------------------ .../functions/LabeledRationalFunction.kt | 139 ----- .../kmath/functions/ListPolynomial.kt | 367 ------------ .../kmath/functions/ListRationalFunction.kt | 105 ---- .../kmath/functions/NumberedPolynomial.kt | 389 ------------- .../functions/NumberedRationalFunction.kt | 188 ------ .../kscience/kmath/functions/Piecewise.kt | 132 ----- .../kmath/functions/labeledConstructors.kt | 203 ------- .../kmath/functions/labeledPolynomialUtil.kt | 495 ---------------- .../functions/labeledRationalFunctionUtil.kt | 33 -- .../kmath/functions/listConstructors.kt | 60 -- .../kmath/functions/listPolynomialUtil.kt | 233 -------- .../functions/listRationalFunctionUtil.kt | 221 ------- .../kmath/functions/numberedConstructors.kt | 195 ------- .../kmath/functions/numberedPolynomialUtil.kt | 528 ----------------- .../functions/numberedRationalFunctionUtil.kt | 33 -- .../kmath/integration/SplineIntegrator.kt | 107 ---- .../kmath/functions/ListPolynomialTest.kt | 491 ---------------- .../kmath/functions/ListPolynomialUtilTest.kt | 257 --------- 19 files changed, 4715 deletions(-) delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listPolynomialUtil.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listRationalFunctionUtil.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt delete mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt delete mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt deleted file mode 100644 index b904f7331..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt +++ /dev/null @@ -1,539 +0,0 @@ -/* - * 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.functions - -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.ScaleOperations -import kotlin.math.max - - -/** - * Represents multivariate polynomials with labeled variables. - * - * @param C Ring in which the polynomial is considered. - */ -public data class LabeledPolynomial -internal constructor( - /** - * Map that collects coefficients of the polynomial. Every non-zero monomial - * `a x_1^{d_1} ... x_n^{d_n}` is represented as pair "key-value" in the map, where value is coefficients `a` and - * key is map that associates variables in the monomial with multiplicity of them occurring in the monomial. - * For example polynomial - * ``` - * 5 a^2 c^3 - 6 b + 0 b c - * ``` - * has coefficients represented as - * ``` - * mapOf( - * mapOf( - * a to 2, - * c to 3 - * ) to 5, - * mapOf( - * b to 1 - * ) to (-6) - * ) - * ``` - * where `a`, `b` and `c` are corresponding [Symbol] objects. - */ - public val coefficients: Map, C> -) : Polynomial { - override fun toString(): String = "LabeledPolynomial$coefficients" -} - -/** - * Space of polynomials. - * - * @param C the type of operated polynomials. - * @param A the intersection of [Ring] of [C] and [ScaleOperations] of [C]. - * @param ring the [A] instance. - */ -public class LabeledPolynomialSpace>( - public override val ring: A, -) : MultivariatePolynomialSpace>, PolynomialSpaceOverRing, A> { - public override operator fun Symbol.plus(other: Int): LabeledPolynomial = - if (other == 0) LabeledPolynomial(mapOf( - mapOf(this@plus to 1U) to constantOne, - )) - else LabeledPolynomial(mapOf( - mapOf(this@plus to 1U) to constantOne, - emptyMap() to constantOne * other, - )) - public override operator fun Symbol.minus(other: Int): LabeledPolynomial = - if (other == 0) LabeledPolynomial(mapOf( - mapOf(this@minus to 1U) to -constantOne, - )) - else LabeledPolynomial(mapOf( - mapOf(this@minus to 1U) to -constantOne, - emptyMap() to constantOne * other, - )) - public override operator fun Symbol.times(other: Int): LabeledPolynomial = - if (other == 0) zero - else LabeledPolynomial(mapOf( - mapOf(this to 1U) to constantOne * other, - )) - - public override operator fun Int.plus(other: Symbol): LabeledPolynomial = - if (this == 0) LabeledPolynomial(mapOf( - mapOf(other to 1U) to constantOne, - )) - else LabeledPolynomial(mapOf( - mapOf(other to 1U) to constantOne, - emptyMap() to constantOne * this@plus, - )) - public override operator fun Int.minus(other: Symbol): LabeledPolynomial = - if (this == 0) LabeledPolynomial(mapOf( - mapOf(other to 1U) to -constantOne, - )) - else LabeledPolynomial(mapOf( - mapOf(other to 1U) to -constantOne, - emptyMap() to constantOne * this@minus, - )) - public override operator fun Int.times(other: Symbol): LabeledPolynomial = - if (this == 0) zero - else LabeledPolynomial(mapOf( - mapOf(other to 1U) to constantOne * this@times, - )) - - /** - * Returns sum of the polynomial and the integer represented as polynomial. - * - * The operation is equivalent to adding [other] copies of unit polynomial to [this]. - */ - public override operator fun LabeledPolynomial.plus(other: Int): LabeledPolynomial = - if (other == 0) this - else with(coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to other.asConstant())) - else LabeledPolynomial( - toMutableMap() - .apply { - val degs = emptyMap() - - this[degs] = getOrElse(degs) { constantZero } + other - } - ) - } - /** - * Returns difference between the polynomial and the integer represented as polynomial. - * - * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. - */ - public override operator fun LabeledPolynomial.minus(other: Int): LabeledPolynomial = - if (other == 0) this - else with(coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to (-other).asConstant())) - else LabeledPolynomial( - toMutableMap() - .apply { - val degs = emptyMap() - - this[degs] = getOrElse(degs) { constantZero } - other - } - ) - } - /** - * Returns product of the polynomial and the integer represented as polynomial. - * - * The operation is equivalent to sum of [other] copies of [this]. - */ - public override operator fun LabeledPolynomial.times(other: Int): LabeledPolynomial = - if (other == 0) zero - else LabeledPolynomial( - coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this[degs]!! * other - } - ) - - /** - * Returns sum of the integer represented as polynomial and the polynomial. - * - * The operation is equivalent to adding [this] copies of unit polynomial to [other]. - */ - public override operator fun Int.plus(other: LabeledPolynomial): LabeledPolynomial = - if (this == 0) other - else with(other.coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to this@plus.asConstant())) - else LabeledPolynomial( - toMutableMap() - .apply { - val degs = emptyMap() - - this[degs] = this@plus + getOrElse(degs) { constantZero } - } - ) - } - /** - * Returns difference between the integer represented as polynomial and the polynomial. - * - * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. - */ - public override operator fun Int.minus(other: LabeledPolynomial): LabeledPolynomial = - if (this == 0) other - else with(other.coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to this@minus.asConstant())) - else LabeledPolynomial( - toMutableMap() - .apply { - val degs = emptyMap() - - this[degs] = this@minus - getOrElse(degs) { constantZero } - } - ) - } - /** - * Returns product of the integer represented as polynomial and the polynomial. - * - * The operation is equivalent to sum of [this] copies of [other]. - */ - public override operator fun Int.times(other: LabeledPolynomial): LabeledPolynomial = - if (this == 0) zero - else LabeledPolynomial( - other.coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this@times * this[degs]!! - } - ) - - /** - * Converts the integer [value] to polynomial. - */ - public override fun number(value: Int): LabeledPolynomial = number(constantNumber(value)) - - public override operator fun C.plus(other: Symbol): LabeledPolynomial = - LabeledPolynomial(mapOf( - mapOf(other to 1U) to constantOne, - emptyMap() to this@plus, - )) - public override operator fun C.minus(other: Symbol): LabeledPolynomial = - LabeledPolynomial(mapOf( - mapOf(other to 1U) to -constantOne, - emptyMap() to this@minus, - )) - public override operator fun C.times(other: Symbol): LabeledPolynomial = - LabeledPolynomial(mapOf( - mapOf(other to 1U) to this@times, - )) - - public override operator fun Symbol.plus(other: C): LabeledPolynomial = - LabeledPolynomial(mapOf( - mapOf(this@plus to 1U) to constantOne, - emptyMap() to other, - )) - public override operator fun Symbol.minus(other: C): LabeledPolynomial = - LabeledPolynomial(mapOf( - mapOf(this@minus to 1U) to -constantOne, - emptyMap() to other, - )) - public override operator fun Symbol.times(other: C): LabeledPolynomial = - LabeledPolynomial(mapOf( - mapOf(this@times to 1U) to other, - )) - - /** - * Returns sum of the constant represented as polynomial and the polynomial. - */ - override operator fun C.plus(other: LabeledPolynomial): LabeledPolynomial = - with(other.coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to this@plus)) - else LabeledPolynomial( - toMutableMap() - .apply { - val degs = emptyMap() - - this[degs] = this@plus + getOrElse(degs) { constantZero } - } - ) - } - /** - * Returns difference between the constant represented as polynomial and the polynomial. - */ - override operator fun C.minus(other: LabeledPolynomial): LabeledPolynomial = - with(other.coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to this@minus)) - else LabeledPolynomial( - toMutableMap() - .apply { - forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } - - val degs = emptyMap() - - this[degs] = this@minus - getOrElse(degs) { constantZero } - } - ) - } - /** - * Returns product of the constant represented as polynomial and the polynomial. - */ - override operator fun C.times(other: LabeledPolynomial): LabeledPolynomial = - LabeledPolynomial( - other.coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this@times * this[degs]!! - } - ) - - /** - * Returns sum of the constant represented as polynomial and the polynomial. - */ - override operator fun LabeledPolynomial.plus(other: C): LabeledPolynomial = - with(coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to other)) - else LabeledPolynomial( - toMutableMap() - .apply { - val degs = emptyMap() - - this[degs] = getOrElse(degs) { constantZero } + other - } - ) - } - /** - * Returns difference between the constant represented as polynomial and the polynomial. - */ - override operator fun LabeledPolynomial.minus(other: C): LabeledPolynomial = - with(coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to other)) - else LabeledPolynomial( - toMutableMap() - .apply { - forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } - - val degs = emptyMap() - - this[degs] = getOrElse(degs) { constantZero } - other - } - ) - } - /** - * Returns product of the constant represented as polynomial and the polynomial. - */ - override operator fun LabeledPolynomial.times(other: C): LabeledPolynomial = - LabeledPolynomial( - coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this[degs]!! * other - } - ) - - /** - * Converts the constant [value] to polynomial. - */ - public override fun number(value: C): LabeledPolynomial = - LabeledPolynomial(mapOf(emptyMap() to value)) - - public override operator fun Symbol.unaryPlus(): LabeledPolynomial = - LabeledPolynomial(mapOf( - mapOf(this to 1U) to constantOne, - )) - public override operator fun Symbol.unaryMinus(): LabeledPolynomial = - LabeledPolynomial(mapOf( - mapOf(this to 1U) to -constantOne, - )) - public override operator fun Symbol.plus(other: Symbol): LabeledPolynomial = - if (this == other) LabeledPolynomial(mapOf( - mapOf(this to 1U) to constantOne * 2 - )) - else LabeledPolynomial(mapOf( - mapOf(this to 1U) to constantOne, - mapOf(other to 1U) to constantOne, - )) - public override operator fun Symbol.minus(other: Symbol): LabeledPolynomial = - if (this == other) zero - else LabeledPolynomial(mapOf( - mapOf(this to 1U) to constantOne, - mapOf(other to 1U) to -constantOne, - )) - public override operator fun Symbol.times(other: Symbol): LabeledPolynomial = - if (this == other) LabeledPolynomial(mapOf( - mapOf(this to 2U) to constantOne - )) - else LabeledPolynomial(mapOf( - mapOf(this to 1U, other to 1U) to constantOne, - )) - - public override operator fun Symbol.plus(other: LabeledPolynomial): LabeledPolynomial = - with(other.coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(mapOf(this@plus to 1u) to constantOne)) - else LabeledPolynomial( - toMutableMap() - .apply { - val degs = mapOf(this@plus to 1U) - - this[degs] = constantOne + getOrElse(degs) { constantZero } - } - ) - } - public override operator fun Symbol.minus(other: LabeledPolynomial): LabeledPolynomial = - with(other.coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(mapOf(this@minus to 1u) to constantOne)) - else LabeledPolynomial( - toMutableMap() - .apply { - forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } - - val degs = mapOf(this@minus to 1U) - - this[degs] = constantOne - getOrElse(degs) { constantZero } - } - ) - } - public override operator fun Symbol.times(other: LabeledPolynomial): LabeledPolynomial = - LabeledPolynomial( - other.coefficients - .mapKeys { (degs, _) -> degs.toMutableMap().also{ it[this] = if (this in it) it[this]!! + 1U else 1U } } - ) - - public override operator fun LabeledPolynomial.plus(other: Symbol): LabeledPolynomial = - with(coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(mapOf(other to 1u) to constantOne)) - else LabeledPolynomial( - toMutableMap() - .apply { - val degs = mapOf(other to 1U) - - this[degs] = constantOne + getOrElse(degs) { constantZero } - } - ) - } - public override operator fun LabeledPolynomial.minus(other: Symbol): LabeledPolynomial = - with(coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(mapOf(other to 1u) to constantOne)) - else LabeledPolynomial( - toMutableMap() - .apply { - val degs = mapOf(other to 1U) - - this[degs] = constantOne - getOrElse(degs) { constantZero } - } - ) - } - public override operator fun LabeledPolynomial.times(other: Symbol): LabeledPolynomial = - LabeledPolynomial( - coefficients - .mapKeys { (degs, _) -> degs.toMutableMap().also{ it[other] = if (other in it) it[other]!! + 1U else 1U } } - ) - - /** - * Returns negation of the polynomial. - */ - override fun LabeledPolynomial.unaryMinus(): LabeledPolynomial = - LabeledPolynomial( - coefficients.mapValues { -it.value } - ) - /** - * Returns sum of the polynomials. - */ - override operator fun LabeledPolynomial.plus(other: LabeledPolynomial): LabeledPolynomial = - LabeledPolynomial( - buildMap(coefficients.size + other.coefficients.size) { - other.coefficients.mapValuesTo(this) { it.value } - other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! + value else value } - } - ) - /** - * Returns difference of the polynomials. - */ - override operator fun LabeledPolynomial.minus(other: LabeledPolynomial): LabeledPolynomial = - LabeledPolynomial( - buildMap(coefficients.size + other.coefficients.size) { - other.coefficients.mapValuesTo(this) { it.value } - other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! - value else -value } - } - ) - /** - * Returns product of the polynomials. - */ - override operator fun LabeledPolynomial.times(other: LabeledPolynomial): LabeledPolynomial = - LabeledPolynomial( - buildMap(coefficients.size * other.coefficients.size) { - for ((degs1, c1) in coefficients) for ((degs2, c2) in other.coefficients) { - val degs = degs1.toMutableMap() - degs2.mapValuesTo(degs) { (variable, deg) -> degs.getOrElse(variable) { 0u } + deg } - val c = c1 * c2 - this[degs] = if (degs in this) this[degs]!! + c else c - } - } - ) - - /** - * Instance of zero polynomial (zero of the polynomial ring). - */ - override val zero: LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to constantZero)) - /** - * Instance of unit polynomial (unit of the polynomial ring). - */ - override val one: LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to constantOne)) - - /** - * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is - * zero, degree is -1. - */ - override val LabeledPolynomial.degree: Int - get() = coefficients.entries.maxOfOrNull { (degs, c) -> degs.values.sum().toInt() } ?: -1 - /** - * Map that associates variables (that appear in the polynomial in positive exponents) with their most exponents - * in which they are appeared in the polynomial. - * - * As consequence all values in the map are positive integers. Also, if the polynomial is constant, the map is empty. - * And keys of the map is the same as in [variables]. - */ - public override val LabeledPolynomial.degrees: Map - get() = - buildMap { - coefficients.entries.forEach { (degs, _) -> - degs.mapValuesTo(this) { (variable, deg) -> - max(getOrElse(variable) { 0u }, deg) - } - } - } - /** - * Counts degree of the polynomial by the specified [variable]. - */ - public override fun LabeledPolynomial.degreeBy(variable: Symbol): UInt = - coefficients.entries.maxOfOrNull { (degs, _) -> degs.getOrElse(variable) { 0u } } ?: 0u - /** - * Counts degree of the polynomial by the specified [variables]. - */ - public override fun LabeledPolynomial.degreeBy(variables: Collection): UInt = - coefficients.entries.maxOfOrNull { (degs, _) -> degs.filterKeys { it in variables }.values.sum() } ?: 0u - /** - * Set of all variables that appear in the polynomial in positive exponents. - */ - public override val LabeledPolynomial.variables: Set - get() = - buildSet { - coefficients.entries.forEach { (degs, _) -> addAll(degs.keys) } - } - /** - * Count of all variables that appear in the polynomial in positive exponents. - */ - public override val LabeledPolynomial.countOfVariables: Int get() = variables.size - -// @Suppress("NOTHING_TO_INLINE") -// public inline fun LabeledPolynomial.substitute(argument: Map): LabeledPolynomial = this.substitute(ring, argument) -// @Suppress("NOTHING_TO_INLINE") -// @JvmName("substitutePolynomial") -// public inline fun LabeledPolynomial.substitute(argument: Map>): LabeledPolynomial = this.substitute(ring, argument) -// -// @Suppress("NOTHING_TO_INLINE") -// public inline fun LabeledPolynomial.asFunction(): (Map) -> LabeledPolynomial = { this.substitute(ring, it) } -// @Suppress("NOTHING_TO_INLINE") -// public inline fun LabeledPolynomial.asFunctionOnConstants(): (Map) -> LabeledPolynomial = { this.substitute(ring, it) } -// @Suppress("NOTHING_TO_INLINE") -// public inline fun LabeledPolynomial.asFunctionOnPolynomials(): (Map>) -> LabeledPolynomial = { this.substitute(ring, it) } -// -// @Suppress("NOTHING_TO_INLINE") -// public inline operator fun LabeledPolynomial.invoke(argument: Map): LabeledPolynomial = this.substitute(ring, argument) -// @Suppress("NOTHING_TO_INLINE") -// @JvmName("invokePolynomial") -// public inline operator fun LabeledPolynomial.invoke(argument: Map>): LabeledPolynomial = this.substitute(ring, argument) -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt deleted file mode 100644 index 76c6874f5..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt +++ /dev/null @@ -1,139 +0,0 @@ -/* - * 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.functions - -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.invoke - - -public class LabeledRationalFunction( - public override val numerator: LabeledPolynomial, - public override val denominator: LabeledPolynomial -) : RationalFunction> { - override fun toString(): String = "LabeledRationalFunction${numerator.coefficients}/${denominator.coefficients}" -} - -public class LabeledRationalFunctionSpace>( - public val ring: A, -) : - MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSpace< - C, - Symbol, - LabeledPolynomial, - LabeledRationalFunction, - LabeledPolynomialSpace, - >, - MultivariatePolynomialSpaceOfFractions< - C, - Symbol, - LabeledPolynomial, - LabeledRationalFunction, - >() { - - override val polynomialRing : LabeledPolynomialSpace = LabeledPolynomialSpace(ring) - override fun constructRationalFunction( - numerator: LabeledPolynomial, - denominator: LabeledPolynomial - ): LabeledRationalFunction = - LabeledRationalFunction(numerator, denominator) - - /** - * Instance of zero rational function (zero of the rational functions ring). - */ - public override val zero: LabeledRationalFunction = LabeledRationalFunction(polynomialZero, polynomialOne) - /** - * Instance of unit polynomial (unit of the rational functions ring). - */ - public override val one: LabeledRationalFunction = LabeledRationalFunction(polynomialOne, polynomialOne) - - // TODO: Разобрать - -// operator fun invoke(arg: Map): LabeledRationalFunction = -// LabeledRationalFunction( -// numerator(arg), -// denominator(arg) -// ) -// -// @JvmName("invokeLabeledPolynomial") -// operator fun invoke(arg: Map>): LabeledRationalFunction = -// LabeledRationalFunction( -// numerator(arg), -// denominator(arg) -// ) -// -// @JvmName("invokeLabeledRationalFunction") -// operator fun invoke(arg: Map>): LabeledRationalFunction { -// var num = numerator invokeRFTakeNumerator arg -// var den = denominator invokeRFTakeNumerator arg -// for (variable in variables) if (variable in arg) { -// val degreeDif = degrees[variable]!! -// if (degreeDif > 0) -// den = multiplyByPower(den, arg[variable]!!.denominator, degreeDif) -// else -// num = multiplyByPower(num, arg[variable]!!.denominator, -degreeDif) -// } -// return LabeledRationalFunction(num, den) -// } -// -// override fun toString(): String = toString(emptyMap()) -// -// fun toString(names: Map = emptyMap()): String = -// when (true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toString(names) -// else -> "${numerator.toStringWithBrackets(names)}/${denominator.toStringWithBrackets(names)}" -// } -// -// fun toString(namer: (Symbol) -> String): String = -// when (true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toString(namer) -// else -> "${numerator.toStringWithBrackets(namer)}/${denominator.toStringWithBrackets(namer)}" -// } -// -// fun toStringWithBrackets(names: Map = emptyMap()): String = -// when (true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toStringWithBrackets(names) -// else -> "(${numerator.toStringWithBrackets(names)}/${denominator.toStringWithBrackets(names)})" -// } -// -// fun toStringWithBrackets(namer: (Symbol) -> String): String = -// when (true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toStringWithBrackets(namer) -// else -> "(${numerator.toStringWithBrackets(namer)}/${denominator.toStringWithBrackets(namer)})" -// } -// -// fun toReversedString(names: Map = emptyMap()): String = -// when (true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedString(names) -// else -> "${numerator.toReversedStringWithBrackets(names)}/${denominator.toReversedStringWithBrackets(names)}" -// } -// -// fun toReversedString(namer: (Symbol) -> String): String = -// when (true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedString(namer) -// else -> "${numerator.toReversedStringWithBrackets(namer)}/${denominator.toReversedStringWithBrackets(namer)}" -// } -// -// fun toReversedStringWithBrackets(names: Map = emptyMap()): String = -// when (true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedStringWithBrackets(names) -// else -> "(${numerator.toReversedStringWithBrackets(names)}/${denominator.toReversedStringWithBrackets(names)})" -// } -// -// fun toReversedStringWithBrackets(namer: (Symbol) -> String): String = -// when (true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedStringWithBrackets(namer) -// else -> "(${numerator.toReversedStringWithBrackets(namer)}/${denominator.toReversedStringWithBrackets(namer)})" -// } -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt deleted file mode 100644 index 585da95ea..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt +++ /dev/null @@ -1,367 +0,0 @@ -/* - * 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.functions - -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.ScaleOperations -import space.kscience.kmath.operations.invoke -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract -import kotlin.experimental.ExperimentalTypeInference -import kotlin.jvm.JvmName -import kotlin.math.max -import kotlin.math.min - - -/** - * Polynomial model without fixation on specific context they are applied to. - * - * @param coefficients constant is the leftmost coefficient. - */ -public data class ListPolynomial( - /** - * List that collects coefficients of the polynomial. Every monomial `a x^d` is represented as a coefficients - * `a` placed into the list with index `d`. For example coefficients of polynomial `5 x^2 - 6` can be represented as - * ``` - * listOf( - * -6, // -6 + - * 0, // 0 x + - * 5, // 5 x^2 - * ) - * ``` - * and also as - * ``` - * listOf( - * -6, // -6 + - * 0, // 0 x + - * 5, // 5 x^2 - * 0, // 0 x^3 - * 0, // 0 x^4 - * ) - * ``` - * It is recommended not to put extra zeros at end of the list (as for `0x^3` and `0x^4` in the example), but is not - * prohibited. - */ - public val coefficients: List -) : Polynomial { - override fun toString(): String = "Polynomial$coefficients" -} - -/** - * Space of univariate polynomials constructed over ring. - * - * @param C the type of constants. Polynomials have them as a coefficients in their terms. - * @param A type of underlying ring of constants. It's [Ring] of [C]. - * @param ring underlying ring of constants of type [A]. - */ -public open class ListPolynomialSpace>( - public override val ring: A, -) : PolynomialSpaceOverRing, A> { - /** - * Returns sum of the polynomial and the integer represented as polynomial. - * - * The operation is equivalent to adding [other] copies of unit polynomial to [this]. - */ - public override operator fun ListPolynomial.plus(other: Int): ListPolynomial = - if (other == 0) this - else - ListPolynomial( - coefficients - .toMutableList() - .apply { - val result = getOrElse(0) { constantZero } + other - - if(size == 0) add(result) - else this[0] = result - } - ) - /** - * Returns difference between the polynomial and the integer represented as polynomial. - * - * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. - */ - public override operator fun ListPolynomial.minus(other: Int): ListPolynomial = - if (other == 0) this - else - ListPolynomial( - coefficients - .toMutableList() - .apply { - val result = getOrElse(0) { constantZero } - other - - if(size == 0) add(result) - else this[0] = result - } - ) - /** - * Returns product of the polynomial and the integer represented as polynomial. - * - * The operation is equivalent to sum of [other] copies of [this]. - */ - public override operator fun ListPolynomial.times(other: Int): ListPolynomial = - if (other == 0) zero - else ListPolynomial( - coefficients - .toMutableList() - .apply { - for (deg in indices) this[deg] = this[deg] * other - } - ) - - /** - * Returns sum of the integer represented as polynomial and the polynomial. - * - * The operation is equivalent to adding [this] copies of unit polynomial to [other]. - */ - public override operator fun Int.plus(other: ListPolynomial): ListPolynomial = - if (this == 0) other - else - ListPolynomial( - other.coefficients - .toMutableList() - .apply { - val result = this@plus + getOrElse(0) { constantZero } - - if(size == 0) add(result) - else this[0] = result - } - ) - /** - * Returns difference between the integer represented as polynomial and the polynomial. - * - * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. - */ - public override operator fun Int.minus(other: ListPolynomial): ListPolynomial = - if (this == 0) other - else - ListPolynomial( - other.coefficients - .toMutableList() - .apply { - forEachIndexed { index, c -> if (index != 0) this[index] = -c } - - val result = this@minus - getOrElse(0) { constantZero } - - if(size == 0) add(result) - else this[0] = result - } - ) - /** - * Returns product of the integer represented as polynomial and the polynomial. - * - * The operation is equivalent to sum of [this] copies of [other]. - */ - public override operator fun Int.times(other: ListPolynomial): ListPolynomial = - if (this == 0) zero - else ListPolynomial( - other.coefficients - .toMutableList() - .apply { - for (deg in indices) this[deg] = this@times * this[deg] - } - ) - - /** - * Converts the integer [value] to polynomial. - */ - public override fun number(value: Int): ListPolynomial = number(constantNumber(value)) - - /** - * Returns sum of the constant represented as polynomial and the polynomial. - */ - public override operator fun C.plus(other: ListPolynomial): ListPolynomial = - with(other.coefficients) { - if (isEmpty()) ListPolynomial(listOf(this@plus)) - else ListPolynomial( - toMutableList() - .apply { - val result = if (size == 0) this@plus else this@plus + get(0) - - if(size == 0) add(result) - else this[0] = result - } - ) - } - /** - * Returns difference between the constant represented as polynomial and the polynomial. - */ - public override operator fun C.minus(other: ListPolynomial): ListPolynomial = - with(other.coefficients) { - if (isEmpty()) ListPolynomial(listOf(this@minus)) - else ListPolynomial( - toMutableList() - .apply { - forEachIndexed { index, c -> if (index != 0) this[index] = -c } - - val result = if (size == 0) this@minus else this@minus - get(0) - - if(size == 0) add(result) - else this[0] = result - } - ) - } - /** - * Returns product of the constant represented as polynomial and the polynomial. - */ - public override operator fun C.times(other: ListPolynomial): ListPolynomial = - ListPolynomial( - other.coefficients - .toMutableList() - .apply { - for (deg in indices) this[deg] = this@times * this[deg] - } - ) - - /** - * Returns sum of the constant represented as polynomial and the polynomial. - */ - public override operator fun ListPolynomial.plus(other: C): ListPolynomial = - with(coefficients) { - if (isEmpty()) ListPolynomial(listOf(other)) - else ListPolynomial( - toMutableList() - .apply { - val result = if (size == 0) other else get(0) + other - - if(size == 0) add(result) - else this[0] = result - } - ) - } - /** - * Returns difference between the constant represented as polynomial and the polynomial. - */ - public override operator fun ListPolynomial.minus(other: C): ListPolynomial = - with(coefficients) { - if (isEmpty()) ListPolynomial(listOf(-other)) - else ListPolynomial( - toMutableList() - .apply { - val result = if (size == 0) other else get(0) - other - - if(size == 0) add(result) - else this[0] = result - } - ) - } - /** - * Returns product of the constant represented as polynomial and the polynomial. - */ - public override operator fun ListPolynomial.times(other: C): ListPolynomial = - ListPolynomial( - coefficients - .toMutableList() - .apply { - for (deg in indices) this[deg] = this[deg] * other - } - ) - - /** - * Converts the constant [value] to polynomial. - */ - public override fun number(value: C): ListPolynomial = ListPolynomial(value) - - /** - * Returns negation of the polynomial. - */ - public override operator fun ListPolynomial.unaryMinus(): ListPolynomial = - ListPolynomial(coefficients.map { -it }) - /** - * Returns sum of the polynomials. - */ - public override operator fun ListPolynomial.plus(other: ListPolynomial): ListPolynomial { - val thisDegree = degree - val otherDegree = other.degree - return ListPolynomial( - List(max(thisDegree, otherDegree) + 1) { - when { - it > thisDegree -> other.coefficients[it] - it > otherDegree -> coefficients[it] - else -> coefficients[it] + other.coefficients[it] - } - } - ) - } - /** - * Returns difference of the polynomials. - */ - public override operator fun ListPolynomial.minus(other: ListPolynomial): ListPolynomial { - val thisDegree = degree - val otherDegree = other.degree - return ListPolynomial( - List(max(thisDegree, otherDegree) + 1) { - when { - it > thisDegree -> -other.coefficients[it] - it > otherDegree -> coefficients[it] - else -> coefficients[it] - other.coefficients[it] - } - } - ) - } - /** - * Returns product of the polynomials. - */ - public override operator fun ListPolynomial.times(other: ListPolynomial): ListPolynomial { - val thisDegree = degree - val otherDegree = other.degree - return ListPolynomial( - List(thisDegree + otherDegree + 1) { d -> - (max(0, d - otherDegree)..min(thisDegree, d)) - .map { coefficients[it] * other.coefficients[d - it] } - .reduce { acc, rational -> acc + rational } - } - ) - } - - /** - * Instance of zero polynomial (zero of the polynomial ring). - */ - override val zero: ListPolynomial = ListPolynomial(emptyList()) - /** - * Instance of unit constant (unit of the underlying ring). - */ - override val one: ListPolynomial = ListPolynomial(listOf(constantOne)) - - /** - * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is - * zero, degree is -1. - */ - public override val ListPolynomial.degree: Int get() = coefficients.lastIndex - - @Suppress("NOTHING_TO_INLINE") - public inline fun ListPolynomial.substitute(argument: C): C = this.substitute(ring, argument) - @Suppress("NOTHING_TO_INLINE") - public inline fun ListPolynomial.substitute(argument: ListPolynomial): ListPolynomial = this.substitute(ring, argument) - - @Suppress("NOTHING_TO_INLINE") - public inline fun ListPolynomial.asFunction(): (C) -> C = { this.substitute(ring, it) } - @Suppress("NOTHING_TO_INLINE") - public inline fun ListPolynomial.asFunctionOnConstants(): (C) -> C = { this.substitute(ring, it) } - @Suppress("NOTHING_TO_INLINE") - public inline fun ListPolynomial.asFunctionOnPolynomials(): (ListPolynomial) -> ListPolynomial = { this.substitute(ring, it) } - - /** - * Evaluates the polynomial for the given value [argument]. - */ - @Suppress("NOTHING_TO_INLINE") - public inline operator fun ListPolynomial.invoke(argument: C): C = this.substitute(ring, argument) - @Suppress("NOTHING_TO_INLINE") - public inline operator fun ListPolynomial.invoke(argument: ListPolynomial): ListPolynomial = this.substitute(ring, argument) -} - -/** - * Space of polynomials constructed over ring. - * - * @param C the type of constants. Polynomials have them as a coefficients in their terms. - * @param A type of underlying ring of constants. It's [Ring] of [C]. - * @param ring underlying ring of constants of type [A]. - */ -public class ScalableListPolynomialSpace( - ring: A, -) : ListPolynomialSpace(ring), ScaleOperations> where A : Ring, A : ScaleOperations { - override fun scale(a: ListPolynomial, value: Double): ListPolynomial = - ring { ListPolynomial(a.coefficients.map { scale(it, value) }) } -} diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt deleted file mode 100644 index 7b6c23ac3..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt +++ /dev/null @@ -1,105 +0,0 @@ -/* - * 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.functions - -import space.kscience.kmath.operations.Ring - - -public data class ListRationalFunction( - public override val numerator: ListPolynomial, - public override val denominator: ListPolynomial -) : RationalFunction> { - override fun toString(): String = "RationalFunction${numerator.coefficients}/${denominator.coefficients}" -} - -public class ListRationalFunctionSpace> ( - public val ring: A, -) : - RationalFunctionalSpaceOverPolynomialSpace< - C, - ListPolynomial, - ListRationalFunction, - ListPolynomialSpace, - >, - PolynomialSpaceOfFractions< - C, - ListPolynomial, - ListRationalFunction, - >() { - - override val polynomialRing : ListPolynomialSpace = ListPolynomialSpace(ring) - override fun constructRationalFunction(numerator: ListPolynomial, denominator: ListPolynomial): ListRationalFunction = - ListRationalFunction(numerator, denominator) - - /** - * Instance of zero rational function (zero of the rational functions ring). - */ - public override val zero: ListRationalFunction = ListRationalFunction(polynomialZero, polynomialOne) - /** - * Instance of unit polynomial (unit of the rational functions ring). - */ - public override val one: ListRationalFunction = ListRationalFunction(polynomialOne, polynomialOne) - - // TODO: Разобрать - -// operator fun invoke(arg: UnivariatePolynomial): RationalFunction = -// RationalFunction( -// numerator(arg), -// denominator(arg) -// ) -// -// operator fun invoke(arg: RationalFunction): RationalFunction { -// val num = numerator invokeRFTakeNumerator arg -// val den = denominator invokeRFTakeNumerator arg -// val degreeDif = numeratorDegree - denominatorDegree -// return if (degreeDif > 0) -// RationalFunction( -// num, -// multiplyByPower(den, arg.denominator, degreeDif) -// ) -// else -// RationalFunction( -// multiplyByPower(num, arg.denominator, -degreeDif), -// den -// ) -// } -// -// override fun toString(): String = toString(UnivariatePolynomial.variableName) -// -// fun toString(withVariableName: String = UnivariatePolynomial.variableName): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toString(withVariableName) -// else -> "${numerator.toStringWithBrackets(withVariableName)}/${denominator.toStringWithBrackets(withVariableName)}" -// } -// -// fun toStringWithBrackets(withVariableName: String = UnivariatePolynomial.variableName): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toStringWithBrackets(withVariableName) -// else -> "(${numerator.toStringWithBrackets(withVariableName)}/${denominator.toStringWithBrackets(withVariableName)})" -// } -// -// fun toReversedString(withVariableName: String = UnivariatePolynomial.variableName): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedString(withVariableName) -// else -> "${numerator.toReversedStringWithBrackets(withVariableName)}/${denominator.toReversedStringWithBrackets(withVariableName)}" -// } -// -// fun toReversedStringWithBrackets(withVariableName: String = UnivariatePolynomial.variableName): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedStringWithBrackets(withVariableName) -// else -> "(${numerator.toReversedStringWithBrackets(withVariableName)}/${denominator.toReversedStringWithBrackets(withVariableName)})" -// } -// -// fun removeZeros() = -// RationalFunction( -// numerator.removeZeros(), -// denominator.removeZeros() -// ) -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt deleted file mode 100644 index e75373819..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ /dev/null @@ -1,389 +0,0 @@ -/* - * 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.functions - -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.ScaleOperations -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract -import kotlin.experimental.ExperimentalTypeInference -import kotlin.jvm.JvmName -import kotlin.math.max - - -/** - * Polynomial model without fixation on specific context they are applied to. - * - * @param C the type of constants. - */ -public data class NumberedPolynomial -internal constructor( - /** - * Map that collects coefficients of the polynomial. Every monomial `a x_1^{d_1} ... x_n^{d_n}` is represented as - * pair "key-value" in the map, where value is coefficients `a` and - * key is list that associates index of every variable in the monomial with multiplicity of the variable occurring - * in the monomial. For example coefficients of polynomial `5 x_1^2 x_3^3 - 6 x_2` can be represented as - * ``` - * mapOf( - * listOf(2, 0, 3) to 5, - * listOf(0, 1) to (-6), - * ) - * ``` - * and also as - * ``` - * mapOf( - * listOf(2, 0, 3) to 5, - * listOf(0, 1) to (-6), - * listOf(0, 1, 1) to 0, - * ) - * ``` - * It is recommended not to put zero monomials into the map, but is not prohibited. Lists of degrees always do not - * contain any zeros on end, but can contain zeros on start or anywhere in middle. - */ - public val coefficients: Map, C> -) : Polynomial { - override fun toString(): String = "NumberedPolynomial$coefficients" -} - -/** - * Space of polynomials. - * - * @param C the type of operated polynomials. - * @param A the intersection of [Ring] of [C] and [ScaleOperations] of [C]. - * @param ring the [A] instance. - */ -public open class NumberedPolynomialSpace>( - public final override val ring: A, -) : PolynomialSpaceOverRing, A> { - /** - * Returns sum of the polynomial and the integer represented as polynomial. - * - * The operation is equivalent to adding [other] copies of unit polynomial to [this]. - */ - public override operator fun NumberedPolynomial.plus(other: Int): NumberedPolynomial = - if (other == 0) this - else - NumberedPolynomial( - coefficients - .toMutableMap() - .apply { - val degs = emptyList() - - this[degs] = getOrElse(degs) { constantZero } + other - } - ) - /** - * Returns difference between the polynomial and the integer represented as polynomial. - * - * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. - */ - public override operator fun NumberedPolynomial.minus(other: Int): NumberedPolynomial = - if (other == 0) this - else - NumberedPolynomial( - coefficients - .toMutableMap() - .apply { - val degs = emptyList() - - this[degs] = getOrElse(degs) { constantZero } - other - } - ) - /** - * Returns product of the polynomial and the integer represented as polynomial. - * - * The operation is equivalent to sum of [other] copies of [this]. - */ - public override operator fun NumberedPolynomial.times(other: Int): NumberedPolynomial = - if (other == 0) zero - else NumberedPolynomial( - coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this[degs]!! * other - } - ) - - /** - * Returns sum of the integer represented as polynomial and the polynomial. - * - * The operation is equivalent to adding [this] copies of unit polynomial to [other]. - */ - public override operator fun Int.plus(other: NumberedPolynomial): NumberedPolynomial = - if (this == 0) other - else - NumberedPolynomial( - other.coefficients - .toMutableMap() - .apply { - val degs = emptyList() - - this[degs] = this@plus + getOrElse(degs) { constantZero } - } - ) - /** - * Returns difference between the integer represented as polynomial and the polynomial. - * - * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. - */ - public override operator fun Int.minus(other: NumberedPolynomial): NumberedPolynomial = - if (this == 0) other - else - NumberedPolynomial( - other.coefficients - .toMutableMap() - .apply { - val degs = emptyList() - - this[degs] = this@minus - getOrElse(degs) { constantZero } - } - ) - /** - * Returns product of the integer represented as polynomial and the polynomial. - * - * The operation is equivalent to sum of [this] copies of [other]. - */ - public override operator fun Int.times(other: NumberedPolynomial): NumberedPolynomial = - if (this == 0) zero - else NumberedPolynomial( - other.coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this@times * this[degs]!! - } - ) - - /** - * Converts the integer [value] to polynomial. - */ - public override fun number(value: Int): NumberedPolynomial = number(constantNumber(value)) - - /** - * Returns sum of the constant represented as polynomial and the polynomial. - */ - override operator fun C.plus(other: NumberedPolynomial): NumberedPolynomial = - with(other.coefficients) { - if (isEmpty()) NumberedPolynomial(mapOf(emptyList() to this@plus)) - else NumberedPolynomial( - toMutableMap() - .apply { - val degs = emptyList() - - this[degs] = this@plus + getOrElse(degs) { constantZero } - } - ) - } - /** - * Returns difference between the constant represented as polynomial and the polynomial. - */ - override operator fun C.minus(other: NumberedPolynomial): NumberedPolynomial = - with(other.coefficients) { - if (isEmpty()) NumberedPolynomial(mapOf(emptyList() to this@minus)) - else NumberedPolynomial( - toMutableMap() - .apply { - forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } - - val degs = emptyList() - - this[degs] = this@minus - getOrElse(degs) { constantZero } - } - ) - } - /** - * Returns product of the constant represented as polynomial and the polynomial. - */ - override operator fun C.times(other: NumberedPolynomial): NumberedPolynomial = - NumberedPolynomial( - other.coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this@times * this[degs]!! - } - ) - - /** - * Returns sum of the constant represented as polynomial and the polynomial. - */ - override operator fun NumberedPolynomial.plus(other: C): NumberedPolynomial = - with(coefficients) { - if (isEmpty()) NumberedPolynomial(mapOf(emptyList() to other)) - else NumberedPolynomial( - toMutableMap() - .apply { - val degs = emptyList() - - this[degs] = getOrElse(degs) { constantZero } + other - } - ) - } - /** - * Returns difference between the constant represented as polynomial and the polynomial. - */ - override operator fun NumberedPolynomial.minus(other: C): NumberedPolynomial = - with(coefficients) { - if (isEmpty()) NumberedPolynomial(mapOf(emptyList() to other)) - else NumberedPolynomial( - toMutableMap() - .apply { - val degs = emptyList() - - this[degs] = getOrElse(degs) { constantZero } - other - } - ) - } - /** - * Returns product of the constant represented as polynomial and the polynomial. - */ - override operator fun NumberedPolynomial.times(other: C): NumberedPolynomial = - NumberedPolynomial( - coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this[degs]!! * other - } - ) - - /** - * Converts the constant [value] to polynomial. - */ - public override fun number(value: C): NumberedPolynomial = - NumberedPolynomial(mapOf(emptyList() to value)) - - /** - * Returns negation of the polynomial. - */ - override fun NumberedPolynomial.unaryMinus(): NumberedPolynomial = - NumberedPolynomial( - coefficients.mapValues { -it.value } - ) - /** - * Returns sum of the polynomials. - */ - override operator fun NumberedPolynomial.plus(other: NumberedPolynomial): NumberedPolynomial = - NumberedPolynomial( - buildMap(coefficients.size + other.coefficients.size) { - other.coefficients.mapValuesTo(this) { it.value } - other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! + value else value } - } - ) - /** - * Returns difference of the polynomials. - */ - override operator fun NumberedPolynomial.minus(other: NumberedPolynomial): NumberedPolynomial = - NumberedPolynomial( - buildMap(coefficients.size + other.coefficients.size) { - other.coefficients.mapValuesTo(this) { it.value } - other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! - value else -value } - } - ) - /** - * Returns product of the polynomials. - */ - override operator fun NumberedPolynomial.times(other: NumberedPolynomial): NumberedPolynomial = - NumberedPolynomial( - buildMap(coefficients.size * other.coefficients.size) { - for ((degs1, c1) in coefficients) for ((degs2, c2) in other.coefficients) { - val degs = - (0..max(degs1.lastIndex, degs2.lastIndex)) - .map { degs1.getOrElse(it) { 0U } + degs2.getOrElse(it) { 0U } } - val c = c1 * c2 - this[degs] = if (degs in this) this[degs]!! + c else c - } - } - ) - - /** - * Instance of zero polynomial (zero of the polynomial ring). - */ - override val zero: NumberedPolynomial = NumberedPolynomial(emptyMap()) - /** - * Instance of unit polynomial (unit of the polynomial ring). - */ - override val one: NumberedPolynomial = - NumberedPolynomial( - mapOf( - emptyList() to constantOne // 1 * x_1^0 * x_2^0 * ... - ) - ) - - /** - * Maximal index (ID) of variable occurring in the polynomial with positive power. If there is no such variable, - * the result is `-1`. - */ - public val NumberedPolynomial.lastVariable: Int - get() = coefficients.entries.maxOfOrNull { (degs, _) -> degs.lastIndex } ?: -1 - /** - * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is - * zero, degree is -1. - */ - override val NumberedPolynomial.degree: Int - get() = coefficients.entries.maxOfOrNull { (degs, _) -> degs.sum().toInt() } ?: -1 - /** - * List that associates indices of variables (that appear in the polynomial in positive exponents) with their most - * exponents in which the variables are appeared in the polynomial. - * - * As consequence all values in the list are non-negative integers. Also, if the polynomial is constant, the list is empty. - * And last index of the list is [lastVariable]. - */ - public val NumberedPolynomial.degrees: List - get() = - MutableList(lastVariable + 1) { 0u }.apply { - coefficients.entries.forEach { (degs, _) -> - degs.forEachIndexed { index, deg -> - this[index] = max(this[index], deg) - } - } - } - /** - * Counts degree of the polynomial by the specified [variable]. - */ - public fun NumberedPolynomial.degreeBy(variable: Int): UInt = - coefficients.entries.maxOfOrNull { (degs, _) -> degs.getOrElse(variable) { 0u } } ?: 0u - /** - * Counts degree of the polynomial by the specified [variables]. - */ - public fun NumberedPolynomial.degreeBy(variables: Collection): UInt = - coefficients.entries.maxOfOrNull { (degs, _) -> - degs.withIndex().filter { (index, _) -> index in variables }.sumOf { it.value } - } ?: 0u - /** - * Count of variables occurring in the polynomial with positive power. If there is no such variable, - * the result is `0`. - */ - public val NumberedPolynomial.countOfVariables: Int - get() = - MutableList(lastVariable + 1) { false }.apply { - coefficients.entries.forEach { (degs, _) -> - degs.forEachIndexed { index, deg -> - if (deg != 0u) this[index] = true - } - } - }.count { it } - - @Suppress("NOTHING_TO_INLINE") - public inline fun NumberedPolynomial.substitute(argument: Map): NumberedPolynomial = this.substitute(ring, argument) - @Suppress("NOTHING_TO_INLINE") - @JvmName("substitutePolynomial") - public inline fun NumberedPolynomial.substitute(argument: Map>): NumberedPolynomial = this.substitute(ring, argument) - - @Suppress("NOTHING_TO_INLINE") - public inline fun NumberedPolynomial.asFunction(): (Map) -> NumberedPolynomial = { this.substitute(ring, it) } - @Suppress("NOTHING_TO_INLINE") - public inline fun NumberedPolynomial.asFunctionOnConstants(): (Map) -> NumberedPolynomial = { this.substitute(ring, it) } - @Suppress("NOTHING_TO_INLINE") - public inline fun NumberedPolynomial.asFunctionOnPolynomials(): (Map>) -> NumberedPolynomial = { this.substitute(ring, it) } - - @Suppress("NOTHING_TO_INLINE") - public inline operator fun NumberedPolynomial.invoke(argument: Map): NumberedPolynomial = this.substitute(ring, argument) - @Suppress("NOTHING_TO_INLINE") - @JvmName("invokePolynomial") - public inline operator fun NumberedPolynomial.invoke(argument: Map>): NumberedPolynomial = this.substitute(ring, argument) - - // FIXME: Move to other constructors with context receiver - public fun C.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomial(mapOf(emptyList() to this)) -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt deleted file mode 100644 index 30c7f0188..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt +++ /dev/null @@ -1,188 +0,0 @@ -/* - * 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.functions - -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.invoke -import kotlin.math.max - - -public class NumberedRationalFunction internal constructor( - public override val numerator: NumberedPolynomial, - public override val denominator: NumberedPolynomial -) : RationalFunction> { - override fun toString(): String = "NumberedRationalFunction${numerator.coefficients}/${denominator.coefficients}" -} - -public class NumberedRationalFunctionSpace> ( - public val ring: A, -) : - RationalFunctionalSpaceOverPolynomialSpace< - C, - NumberedPolynomial, - NumberedRationalFunction, - NumberedPolynomialSpace, - >, - PolynomialSpaceOfFractions< - C, - NumberedPolynomial, - NumberedRationalFunction, - >() { - - override val polynomialRing : NumberedPolynomialSpace = NumberedPolynomialSpace(ring) - override fun constructRationalFunction( - numerator: NumberedPolynomial, - denominator: NumberedPolynomial - ): NumberedRationalFunction = - NumberedRationalFunction(numerator, denominator) - - /** - * Instance of zero rational function (zero of the rational functions ring). - */ - public override val zero: NumberedRationalFunction = NumberedRationalFunction(polynomialZero, polynomialOne) - /** - * Instance of unit polynomial (unit of the rational functions ring). - */ - public override val one: NumberedRationalFunction = NumberedRationalFunction(polynomialOne, polynomialOne) - - /** - * Maximal index (ID) of variable occurring in the polynomial with positive power. If there is no such variable, - * the result is `-1`. - */ - public val NumberedPolynomial.lastVariable: Int get() = polynomialRing { lastVariable } - /** - * List that associates indices of variables (that appear in the polynomial in positive exponents) with their most - * exponents in which the variables are appeared in the polynomial. - * - * As consequence all values in the list are non-negative integers. Also, if the polynomial is constant, the list is empty. - * And last index of the list is [lastVariable]. - */ - public val NumberedPolynomial.degrees: List get() = polynomialRing { degrees } - /** - * Counts degree of the polynomial by the specified [variable]. - */ - public fun NumberedPolynomial.degreeBy(variable: Int): UInt = polynomialRing { degreeBy(variable) } - /** - * Counts degree of the polynomial by the specified [variables]. - */ - public fun NumberedPolynomial.degreeBy(variables: Collection): UInt = polynomialRing { degreeBy(variables) } - /** - * Count of variables occurring in the polynomial with positive power. If there is no such variable, - * the result is `0`. - */ - public val NumberedPolynomial.countOfVariables: Int get() = polynomialRing { countOfVariables } - - /** - * Count of all variables that appear in the polynomial in positive exponents. - */ - public val NumberedRationalFunction.lastVariable: Int - get() = polynomialRing { max(numerator.lastVariable, denominator.lastVariable) } - /** - * Count of variables occurring in the rational function with positive power. If there is no such variable, - * the result is `0`. - */ - public val NumberedRationalFunction.countOfVariables: Int - get() = - MutableList(lastVariable + 1) { false }.apply { - numerator.coefficients.entries.forEach { (degs, _) -> - degs.forEachIndexed { index, deg -> - if (deg != 0u) this[index] = true - } - } - denominator.coefficients.entries.forEach { (degs, _) -> - degs.forEachIndexed { index, deg -> - if (deg != 0u) this[index] = true - } - } - }.count { it } - - // TODO: Разобрать - -// operator fun invoke(arg: Map): NumberedRationalFunction = -// NumberedRationalFunction( -// numerator(arg), -// denominator(arg) -// ) -// -// @JvmName("invokePolynomial") -// operator fun invoke(arg: Map>): NumberedRationalFunction = -// NumberedRationalFunction( -// numerator(arg), -// denominator(arg) -// ) -// -// @JvmName("invokeRationalFunction") -// operator fun invoke(arg: Map>): NumberedRationalFunction { -// var num = numerator invokeRFTakeNumerator arg -// var den = denominator invokeRFTakeNumerator arg -// for (variable in 0 until max(numerator.countOfVariables, denominator.countOfVariables)) if (variable in arg) { -// val degreeDif = numerator.degrees.getOrElse(variable) { 0 } - denominator.degrees.getOrElse(variable) { 0 } -// if (degreeDif > 0) -// den = multiplyByPower(den, arg[variable]!!.denominator, degreeDif) -// else -// num = multiplyByPower(num, arg[variable]!!.denominator, -degreeDif) -// } -// return NumberedRationalFunction(num, den) -// } -// -// override fun toString(): String = toString(Polynomial.variableName) -// -// fun toString(withVariableName: String = Polynomial.variableName): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toString(withVariableName) -// else -> "${numerator.toStringWithBrackets(withVariableName)}/${denominator.toStringWithBrackets(withVariableName)}" -// } -// -// fun toString(namer: (Int) -> String): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toString(namer) -// else -> "${numerator.toStringWithBrackets(namer)}/${denominator.toStringWithBrackets(namer)}" -// } -// -// fun toStringWithBrackets(withVariableName: String = Polynomial.variableName): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toStringWithBrackets(withVariableName) -// else -> "(${numerator.toStringWithBrackets(withVariableName)}/${denominator.toStringWithBrackets(withVariableName)})" -// } -// -// fun toStringWithBrackets(namer: (Int) -> String): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toStringWithBrackets(namer) -// else -> "(${numerator.toStringWithBrackets(namer)}/${denominator.toStringWithBrackets(namer)})" -// } -// -// fun toReversedString(withVariableName: String = Polynomial.variableName): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedString(withVariableName) -// else -> "${numerator.toReversedStringWithBrackets(withVariableName)}/${denominator.toReversedStringWithBrackets(withVariableName)}" -// } -// -// fun toReversedString(namer: (Int) -> String): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedString(namer) -// else -> "${numerator.toReversedStringWithBrackets(namer)}/${denominator.toReversedStringWithBrackets(namer)}" -// } -// -// fun toReversedStringWithBrackets(withVariableName: String = Polynomial.variableName): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedStringWithBrackets(withVariableName) -// else -> "(${numerator.toReversedStringWithBrackets(withVariableName)}/${denominator.toReversedStringWithBrackets(withVariableName)})" -// } -// -// fun toReversedStringWithBrackets(namer: (Int) -> String): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedStringWithBrackets(namer) -// else -> "(${numerator.toReversedStringWithBrackets(namer)}/${denominator.toReversedStringWithBrackets(namer)})" -// } -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt deleted file mode 100644 index 612b00535..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt +++ /dev/null @@ -1,132 +0,0 @@ -/* - * 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.functions - -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.operations.Ring - -/** - * Represents piecewise-defined function. - * - * @param T the piece key type. - * @param R the sub-function type. - */ -public fun interface Piecewise { - /** - * Returns the appropriate sub-function for given piece key. - */ - public fun findPiece(arg: T): R? -} - -/** - * Represents piecewise-defined function where all the sub-functions are polynomials. - * - * @property pieces An ordered list of range-polynomial pairs. The list does not in general guarantee that there are no - * "holes" in it. - */ -public interface PiecewisePolynomial> : Piecewise> { - public val pieces: Collection, ListPolynomial>> - - override fun findPiece(arg: T): ListPolynomial? -} - -/** - * A generic piecewise without constraints on how pieces are placed - */ -@PerformancePitfall("findPiece method of resulting piecewise is slow") -public fun > PiecewisePolynomial( - pieces: Collection, ListPolynomial>>, -): PiecewisePolynomial = object : PiecewisePolynomial { - override val pieces: Collection, ListPolynomial>> = pieces - - override fun findPiece(arg: T): ListPolynomial? = pieces.firstOrNull { arg in it.first }?.second -} - -/** - * An optimized piecewise that uses not separate pieces, but a range separated by delimiters. - * The pieces search is logarithmic. - */ -private class OrderedPiecewisePolynomial>( - override val pieces: List, ListPolynomial>>, -) : PiecewisePolynomial { - - override fun findPiece(arg: T): ListPolynomial? { - val index = pieces.binarySearch { (range, _) -> - when { - arg >= range.endInclusive -> -1 - arg < range.start -> +1 - else -> 0 - } - } - return if (index < 0) null else pieces[index].second - } - -} - -/** - * A [Piecewise] builder where all the pieces are ordered by the [Comparable] type instances. - * - * @param T the comparable piece key type. - * @param delimiter the initial piecewise separator - */ -public class PiecewiseBuilder>(delimiter: T) { - private val delimiters: MutableList = arrayListOf(delimiter) - private val pieces: MutableList> = arrayListOf() - - /** - * Dynamically adds a piece to the right side (beyond maximum argument value of previous piece) - * - * @param right new rightmost position. If is less than current rightmost position, an error is thrown. - * @param piece the sub-function. - */ - public fun putRight(right: T, piece: ListPolynomial) { - require(right > delimiters.last()) { "New delimiter should be to the right of old one" } - delimiters += right - pieces += piece - } - - /** - * Dynamically adds a piece to the left side (beyond maximum argument value of previous piece) - * - * @param left the new leftmost position. If is less than current rightmost position, an error is thrown. - * @param piece the sub-function. - */ - public fun putLeft(left: T, piece: ListPolynomial) { - require(left < delimiters.first()) { "New delimiter should be to the left of old one" } - delimiters.add(0, left) - pieces.add(0, piece) - } - - public fun build(): PiecewisePolynomial = OrderedPiecewisePolynomial(delimiters.zipWithNext { l, r -> - l..r - }.zip(pieces)) -} - -/** - * A builder for [PiecewisePolynomial] - */ -public fun > PiecewisePolynomial( - startingPoint: T, - builder: PiecewiseBuilder.() -> Unit, -): PiecewisePolynomial = PiecewiseBuilder(startingPoint).apply(builder).build() - -/** - * Return a value of polynomial function with given [ring] a given [arg] or null if argument is outside piecewise - * definition. - */ -public fun , C : Ring> PiecewisePolynomial.substitute(ring: C, arg: T): T? = - findPiece(arg)?.substitute(ring, arg) - -/** - * Convert this polynomial to a function returning nullable value (null if argument is outside piecewise range). - */ -public fun , C : Ring> PiecewisePolynomial.asFunction(ring: C): (T) -> T? = { substitute(ring, it) } - -/** - * Convert this polynomial to a function using [defaultValue] for arguments outside the piecewise range. - */ -public fun , C : Ring> PiecewisePolynomial.asFunction(ring: C, defaultValue: T): (T) -> T = - { substitute(ring, it) ?: defaultValue } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt deleted file mode 100644 index e81a9388e..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt +++ /dev/null @@ -1,203 +0,0 @@ -/* - * 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.functions - -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.Ring - - -/** - * Returns the same degrees' description of the monomial, but without zero degrees. - */ -internal fun Map.cleanUp() = filterValues { it > 0U } - -// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available - -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > LabeledPolynomialSpace.LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(coefs, toCheckInput) -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(coefs, toCheckInput) -@Suppress("FunctionName") -internal fun > A.LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : LabeledPolynomial { - if (!toCheckInput) return LabeledPolynomial(coefs) - - val fixedCoefs = LinkedHashMap, C>(coefs.size) - - for (entry in coefs) { - val key = entry.key.cleanUp() - val value = entry.value - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return LabeledPolynomial(fixedCoefs) -} - -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > LabeledPolynomialSpace.LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(pairs, toCheckInput) -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(pairs, toCheckInput) -@Suppress("FunctionName") -internal fun > A.LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : LabeledPolynomial { - if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) - - val fixedCoefs = LinkedHashMap, C>(pairs.size) - - for (entry in pairs) { - val key = entry.first.cleanUp() - val value = entry.second - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return LabeledPolynomial(fixedCoefs) -} - -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > LabeledPolynomialSpace.LabeledPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(pairs = pairs, toCheckInput = toCheckInput) -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(pairs = pairs, toCheckInput = toCheckInput) -@Suppress("FunctionName") -internal fun > A.LabeledPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : LabeledPolynomial { - if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) - - val fixedCoefs = LinkedHashMap, C>(pairs.size) - - for (entry in pairs) { - val key = entry.first.cleanUp() - val value = entry.second - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return LabeledPolynomial(fixedCoefs) -} - -@Suppress("FunctionName") -public fun > A.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) -@Suppress("FunctionName") -public fun > LabeledPolynomialSpace.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) -@Suppress("FunctionName") -public fun > LabeledRationalFunctionSpace.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) - -@Suppress("FunctionName") -public fun > A.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > LabeledPolynomialSpace.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > LabeledRationalFunctionSpace.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) - -@Suppress("FunctionName") -public fun > A.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > LabeledPolynomialSpace.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > LabeledRationalFunctionSpace.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs, toCheckInput = true) - -//context(A) -//public fun > Symbol.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1u) to one)) -//context(LabeledPolynomialSpace) -//public fun > Symbol.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1u) to constantOne)) -//context(LabeledRationalFunctionSpace) -//public fun > Symbol.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1u) to constantOne)) - -public fun C.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to this)) - -@DslMarker -@UnstableKMathAPI -internal annotation class LabeledPolynomialConstructorDSL - -@UnstableKMathAPI -@LabeledPolynomialConstructorDSL -public class LabeledPolynomialTermSignatureBuilder { - private val signature: MutableMap = LinkedHashMap() - public fun build(): Map = signature - public infix fun Symbol.inPowerOf(deg: UInt) { - signature[this] = deg - } - @Suppress("NOTHING_TO_INLINE") - public inline infix fun Symbol.pow(deg: UInt): Unit = this inPowerOf deg - @Suppress("NOTHING_TO_INLINE") - public inline infix fun Symbol.`in`(deg: UInt): Unit = this inPowerOf deg - @Suppress("NOTHING_TO_INLINE") - public inline infix fun Symbol.of(deg: UInt): Unit = this inPowerOf deg -} - -@UnstableKMathAPI -public class LabeledPolynomialBuilder(private val zero: C, private val add: (C, C) -> C, capacity: Int = 0) { - private val coefficients: MutableMap, C> = LinkedHashMap(capacity) - public fun build(): LabeledPolynomial = LabeledPolynomial(coefficients) - public operator fun C.invoke(block: LabeledPolynomialTermSignatureBuilder.() -> Unit) { - val signature = LabeledPolynomialTermSignatureBuilder().apply(block).build() - coefficients[signature] = add(coefficients.getOrElse(signature) { zero }, this@invoke) - } - @Suppress("NOTHING_TO_INLINE") - public inline infix fun C.with(noinline block: LabeledPolynomialTermSignatureBuilder.() -> Unit): Unit = this.invoke(block) - @Suppress("NOTHING_TO_INLINE") - public inline infix fun (LabeledPolynomialTermSignatureBuilder.() -> Unit).with(coef: C): Unit = coef.invoke(this) - @Suppress("NOTHING_TO_INLINE") - public infix fun sig(block: LabeledPolynomialTermSignatureBuilder.() -> Unit): LabeledPolynomialTermSignatureBuilder.() -> Unit = block -} - -// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available - -@UnstableKMathAPI -@LabeledPolynomialConstructorDSL -@Suppress("FunctionName") -public inline fun > A.LabeledPolynomial(block: LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = LabeledPolynomialBuilder(zero, ::add).apply(block).build() -@UnstableKMathAPI -@LabeledPolynomialConstructorDSL -@Suppress("FunctionName") -public inline fun > A.LabeledPolynomial(capacity: Int, block: LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = LabeledPolynomialBuilder(zero, ::add, capacity).apply(block).build() -@UnstableKMathAPI -@LabeledPolynomialConstructorDSL -@Suppress("FunctionName") -public inline fun > LabeledPolynomialSpace.LabeledPolynomial(block: LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = LabeledPolynomialBuilder(constantZero, { left: C, right: C -> left + right}).apply(block).build() -@UnstableKMathAPI -@LabeledPolynomialConstructorDSL -@Suppress("FunctionName") -public inline fun > LabeledPolynomialSpace.LabeledPolynomial(capacity: Int, block: LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = LabeledPolynomialBuilder(constantZero, { left: C, right: C -> left + right}, capacity).apply(block).build() - -// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available - -@Suppress("FunctionName") -public fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): LabeledRationalFunction = - LabeledRationalFunction( - LabeledPolynomial(numeratorCoefficients, toCheckInput = true), - LabeledPolynomial(denominatorCoefficients, toCheckInput = true) - ) -@Suppress("FunctionName") -public fun > A.LabeledRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): LabeledRationalFunction = - LabeledRationalFunction( - LabeledPolynomial(numeratorCoefficients, toCheckInput = true), - LabeledPolynomial(denominatorCoefficients, toCheckInput = true) - ) -@Suppress("FunctionName") -public fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numerator: LabeledPolynomial): LabeledRationalFunction = - LabeledRationalFunction(numerator, polynomialOne) -@Suppress("FunctionName") -public fun > A.LabeledRationalFunction(numerator: LabeledPolynomial): LabeledRationalFunction = - LabeledRationalFunction(numerator, LabeledPolynomial(mapOf(emptyMap() to one), toCheckInput = false)) -@Suppress("FunctionName") -public fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numeratorCoefficients: Map, C>): LabeledRationalFunction = - LabeledRationalFunction( - LabeledPolynomial(numeratorCoefficients, toCheckInput = true), - polynomialOne - ) -@Suppress("FunctionName") -public fun > A.LabeledRationalFunction(numeratorCoefficients: Map, C>): LabeledRationalFunction = - LabeledRationalFunction( - LabeledPolynomial(numeratorCoefficients, toCheckInput = true), - LabeledPolynomial(mapOf(emptyMap() to one), toCheckInput = false) - ) - -//context(A) -//public fun > Symbol.asLabeledRationalFunction() : LabeledRationalFunction = LabeledRationalFunction(asLabeledPolynomial()) -//context(LabeledRationalFunctionSpace) -//public fun > Symbol.asLabeledRationalFunction() : LabeledRationalFunction = LabeledRationalFunction(asLabeledPolynomial()) - -//context(A) -//public fun > C.asLabeledRationalFunction() : LabeledRationalFunction = LabeledRationalFunction(asLabeledPolynomial()) -//context(LabeledRationalFunctionSpace) -//public fun > C.asLabeledRationalFunction() : LabeledRationalFunction = LabeledRationalFunction(asLabeledPolynomial()) \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt deleted file mode 100644 index af918b9ae..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt +++ /dev/null @@ -1,495 +0,0 @@ -/* - * 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.functions - -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.Field -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.invoke -import kotlin.contracts.ExperimentalContracts -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract - - -// TODO: Docs - -/** - * Creates a [LabeledPolynomialSpace] over a received ring. - */ -public fun > A.labeledPolynomial(): LabeledPolynomialSpace = - LabeledPolynomialSpace(this) - -/** - * Creates a [LabeledPolynomialSpace]'s scope over a received ring. - */ -@OptIn(ExperimentalContracts::class) -public inline fun , R> A.labeledPolynomial(block: LabeledPolynomialSpace.() -> R): R { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return LabeledPolynomialSpace(this).block() -} - -///** -// * Represents the polynomial as a [String] with names of variables substituted with names from [names]. -// * Consider that monomials are sorted in lexicographic order. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.represent(names: Map = emptyMap()): String = -// coefficients.entries -// .sortedWith { o1, o2 -> LabeledPolynomial.monomialComparator.compare(o1.key, o2.key) } -// .asSequence() -// .map { (degs, t) -> -// if (degs.isEmpty()) "$t" -// else { -// when { -// t.isOne() -> "" -// t.isMinusOne() -> "-" -// else -> "$t " -// } + -// degs -// .toSortedMap() -// .filter { it.value > 0U } -// .map { (variable, deg) -> -// val variableName = names.getOrDefault(variable, variable.toString()) -// when (deg) { -// 1U -> variableName -// else -> "$variableName^$deg" -// } -// } -// .joinToString(separator = " ") { it } -// } -// } -// .joinToString(separator = " + ") { it } -// .ifEmpty { "0" } -// -///** -// * Represents the polynomial as a [String] naming variables by [namer]. -// * Consider that monomials are sorted in lexicographic order. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.represent(namer: (Symbol) -> String): String = -// coefficients.entries -// .sortedWith { o1, o2 -> LabeledPolynomial.monomialComparator.compare(o1.key, o2.key) } -// .asSequence() -// .map { (degs, t) -> -// if (degs.isEmpty()) "$t" -// else { -// when { -// t.isOne() -> "" -// t.isMinusOne() -> "-" -// else -> "$t " -// } + -// degs -// .toSortedMap() -// .filter { it.value > 0U } -// .map { (variable, deg) -> -// when (deg) { -// 1U -> namer(variable) -// else -> "${namer(variable)}^$deg" -// } -// } -// .joinToString(separator = " ") { it } -// } -// } -// .joinToString(separator = " + ") { it } -// .ifEmpty { "0" } -// -///** -// * Represents the polynomial as a [String] with names of variables substituted with names from [names] and with -// * brackets around the string if needed (i.e. when there are at least two addends in the representation). -// * Consider that monomials are sorted in lexicographic order. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.representWithBrackets(names: Map = emptyMap()): String = -// with(represent(names)) { if (coefficients.count() == 1) this else "($this)" } -// -///** -// * Represents the polynomial as a [String] naming variables by [namer] and with brackets around the string if needed -// * (i.e. when there are at least two addends in the representation). -// * Consider that monomials are sorted in lexicographic order. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.representWithBrackets(namer: (Symbol) -> String): String = -// with(represent(namer)) { if (coefficients.count() == 1) this else "($this)" } -// -///** -// * Represents the polynomial as a [String] with names of variables substituted with names from [names]. -// * Consider that monomials are sorted in **reversed** lexicographic order. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.representReversed(names: Map = emptyMap()): String = -// coefficients.entries -// .sortedWith { o1, o2 -> -LabeledPolynomial.monomialComparator.compare(o1.key, o2.key) } -// .asSequence() -// .map { (degs, t) -> -// if (degs.isEmpty()) "$t" -// else { -// when { -// t.isOne() -> "" -// t.isMinusOne() -> "-" -// else -> "$t " -// } + -// degs -// .toSortedMap() -// .filter { it.value > 0U } -// .map { (variable, deg) -> -// val variableName = names.getOrDefault(variable, variable.toString()) -// when (deg) { -// 1U -> variableName -// else -> "$variableName^$deg" -// } -// } -// .joinToString(separator = " ") { it } -// } -// } -// .joinToString(separator = " + ") { it } -// .ifEmpty { "0" } -// -///** -// * Represents the polynomial as a [String] naming variables by [namer]. -// * Consider that monomials are sorted in **reversed** lexicographic order. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.representReversed(namer: (Symbol) -> String): String = -// coefficients.entries -// .sortedWith { o1, o2 -> -LabeledPolynomial.monomialComparator.compare(o1.key, o2.key) } -// .asSequence() -// .map { (degs, t) -> -// if (degs.isEmpty()) "$t" -// else { -// when { -// t.isOne() -> "" -// t.isMinusOne() -> "-" -// else -> "$t " -// } + -// degs -// .toSortedMap() -// .filter { it.value > 0U } -// .map { (variable, deg) -> -// when (deg) { -// 1U -> namer(variable) -// else -> "${namer(variable)}^$deg" -// } -// } -// .joinToString(separator = " ") { it } -// } -// } -// .joinToString(separator = " + ") { it } -// .ifEmpty { "0" } -// -///** -// * Represents the polynomial as a [String] with names of variables substituted with names from [names] and with -// * brackets around the string if needed (i.e. when there are at least two addends in the representation). -// * Consider that monomials are sorted in **reversed** lexicographic order. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.representReversedWithBrackets(names: Map = emptyMap()): String = -// with(representReversed(names)) { if (coefficients.count() == 1) this else "($this)" } -// -///** -// * Represents the polynomial as a [String] naming variables by [namer] and with brackets around the string if needed -// * (i.e. when there are at least two addends in the representation). -// * Consider that monomials are sorted in **reversed** lexicographic order. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.representReversedWithBrackets(namer: (Symbol) -> String): String = -// with(representReversed(namer)) { if (coefficients.count() == 1) this else "($this)" } - -//operator fun > Polynomial.div(other: T): Polynomial = -// if (other.isZero()) throw ArithmeticException("/ by zero") -// else -// Polynomial( -// coefficients -// .mapValues { it.value / other }, -// toCheckInput = false -// ) - -//public fun LabeledPolynomial.substitute(ring: Ring, args: Map): LabeledPolynomial = ring { -// if (coefficients.isEmpty()) return this@substitute -// LabeledPolynomial( -// buildMap { -// coefficients.forEach { (degs, c) -> -// val newDegs = degs.filterKeys { it !in args } -// val newC = degs.entries.asSequence().filter { it.key in args }.fold(c) { acc, (variable, deg) -> -// multiplyWithPower(acc, args[variable]!!, deg) -// } -// this[newDegs] = if (newDegs in this) this[newDegs]!! + newC else newC -// } -// } -// ) -//} -// -//// TODO: Replace with optimisation: the [result] may be unboxed, and all operations may be performed as soon as -//// possible on it -//@JvmName("substitutePolynomial") -//fun LabeledPolynomial.substitute(ring: Ring, arg: Map>) : LabeledPolynomial = -// ring.labeledPolynomial { -// if (coefficients.isEmpty()) return zero -// coefficients -// .asSequence() -// .map { (degs, c) -> -// degs.entries -// .asSequence() -// .filter { it.key in arg } -// .fold(LabeledPolynomial(mapOf(degs.filterKeys { it !in arg } to c))) { acc, (index, deg) -> -// multiplyWithPower(acc, arg[index]!!, deg) -// } -// } -// .reduce { acc, polynomial -> acc + polynomial } // TODO: Rewrite. Might be slow. -// } -// -//// TODO: Substitute rational function -// -//fun > LabeledPolynomial.asFunctionOver(ring: A): (Map) -> LabeledPolynomial = -// { substitute(ring, it) } -// -//fun > LabeledPolynomial.asPolynomialFunctionOver(ring: A): (Map>) -> LabeledPolynomial = -// { substitute(ring, it) } - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > LabeledPolynomial.derivativeWithRespectTo( - algebra: A, - variable: Symbol, -): LabeledPolynomial = algebra { - LabeledPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - if (variable !in degs) return@forEach - put( - buildMap { - degs.forEach { (vari, deg) -> - when { - vari != variable -> put(vari, deg) - deg > 1u -> put(vari, deg - 1u) - } - } - }, - multiplyByDoubling(c, degs[variable]!!) - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > LabeledPolynomial.derivativeWithRespectTo( - algebra: A, - variables: Collection, -): LabeledPolynomial = algebra { - val cleanedVariables = variables.toSet() - if (cleanedVariables.isEmpty()) return this@derivativeWithRespectTo - LabeledPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - if (!degs.keys.containsAll(cleanedVariables)) return@forEach - put( - buildMap { - degs.forEach { (vari, deg) -> - when { - vari !in cleanedVariables -> put(vari, deg) - deg > 1u -> put(vari, deg - 1u) - } - } - }, - cleanedVariables.fold(c) { acc, variable -> multiplyByDoubling(acc, degs[variable]!!) } - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > LabeledPolynomial.nthDerivativeWithRespectTo( - algebra: A, - variable: Symbol, - order: UInt -): LabeledPolynomial = algebra { - if (order == 0u) return this@nthDerivativeWithRespectTo - LabeledPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - if (degs.getOrElse(variable) { 0u } < order) return@forEach - put( - buildMap { - degs.forEach { (vari, deg) -> - when { - vari != variable -> put(vari, deg) - deg > order -> put(vari, deg - order) - } - } - }, - degs[variable]!!.let { deg -> - (deg downTo deg - order + 1u) - .fold(c) { acc, ord -> multiplyByDoubling(acc, ord) } - } - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > LabeledPolynomial.nthDerivativeWithRespectTo( - algebra: A, - variablesAndOrders: Map, -): LabeledPolynomial = algebra { - val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u } - if (filteredVariablesAndOrders.isEmpty()) return this@nthDerivativeWithRespectTo - LabeledPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - if (filteredVariablesAndOrders.any { (variable, order) -> degs.getOrElse(variable) { 0u } < order }) return@forEach - put( - buildMap { - degs.forEach { (vari, deg) -> - if (vari !in filteredVariablesAndOrders) put(vari, deg) - else { - val order = filteredVariablesAndOrders[vari]!! - if (deg > order) put(vari, deg - order) - } - } - }, - filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> - degs[index]!!.let { deg -> - (deg downTo deg - order + 1u) - .fold(acc1) { acc2, ord -> multiplyByDoubling(acc2, ord) } - } - } - ) - } - } - ) -} - -/** - * Returns algebraic antiderivative of received polynomial. - */ -@UnstableKMathAPI -public fun > LabeledPolynomial.antiderivativeWithRespectTo( - algebra: A, - variable: Symbol, -): LabeledPolynomial = algebra { - LabeledPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - val newDegs = buildMap(degs.size + 1) { - put(variable, 1u) - for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) - } - put( - newDegs, - c / multiplyByDoubling(one, newDegs[variable]!!) - ) - } - } - ) -} - -/** - * Returns algebraic antiderivative of received polynomial. - */ -@UnstableKMathAPI -public fun > LabeledPolynomial.antiderivativeWithRespectTo( - algebra: A, - variables: Collection, -): LabeledPolynomial = algebra { - val cleanedVariables = variables.toSet() - if (cleanedVariables.isEmpty()) return this@antiderivativeWithRespectTo - LabeledPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - val newDegs = buildMap(degs.size + 1) { - for (variable in cleanedVariables) put(variable, 1u) - for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) - } - put( - newDegs, - cleanedVariables.fold(c) { acc, variable -> acc / multiplyByDoubling(one, newDegs[variable]!!) } - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > LabeledPolynomial.nthAntiderivativeWithRespectTo( - algebra: A, - variable: Symbol, - order: UInt -): LabeledPolynomial = algebra { - if (order == 0u) return this@nthAntiderivativeWithRespectTo - LabeledPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - val newDegs = buildMap(degs.size + 1) { - put(variable, order) - for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) - } - put( - newDegs, - newDegs[variable]!!.let { deg -> - (deg downTo deg - order + 1u) - .fold(c) { acc, ord -> acc / multiplyByDoubling(one, ord) } - } - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > LabeledPolynomial.nthAntiderivativeWithRespectTo( - algebra: A, - variablesAndOrders: Map, -): LabeledPolynomial = algebra { - val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u } - if (filteredVariablesAndOrders.isEmpty()) return this@nthAntiderivativeWithRespectTo - LabeledPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - val newDegs = buildMap(degs.size + 1) { - for ((variable, order) in filteredVariablesAndOrders) put(variable, order) - for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) - } - put( - newDegs, - filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> - newDegs[index]!!.let { deg -> - (deg downTo deg - order + 1u) - .fold(acc1) { acc2, ord -> acc2 / multiplyByDoubling(one, ord) } - } - } - ) - } - } - ) -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt deleted file mode 100644 index 583160cf4..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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.functions - -import space.kscience.kmath.operations.Ring -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract - - -/** - * Creates a [LabeledRationalFunctionSpace] over a received ring. - */ -public fun > A.labeledRationalFunction(): LabeledRationalFunctionSpace = - LabeledRationalFunctionSpace(this) - -/** - * Creates a [LabeledRationalFunctionSpace]'s scope over a received ring. - */ -public inline fun , R> A.labeledRationalFunction(block: LabeledRationalFunctionSpace.() -> R): R { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return LabeledRationalFunctionSpace(this).block() -} - -//fun > LabeledRationalFunction.reduced(): LabeledRationalFunction { -// val greatestCommonDivider = polynomialGCD(numerator, denominator) -// return LabeledRationalFunction( -// numerator / greatestCommonDivider, -// denominator / greatestCommonDivider -// ) -//} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt deleted file mode 100644 index 9498c77ca..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt +++ /dev/null @@ -1,60 +0,0 @@ -/* - * 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.functions - -import space.kscience.kmath.operations.Ring - - -/** - * Returns a [ListPolynomial] instance with given [coefficients]. The collection of coefficients will be reversed if - * [reverse] parameter is true. - */ -@Suppress("FunctionName") -public fun ListPolynomial(coefficients: List, reverse: Boolean = false): ListPolynomial = - ListPolynomial(with(coefficients) { if (reverse) reversed() else this }) - -/** - * Returns a [ListPolynomial] instance with given [coefficients]. The collection of coefficients will be reversed if - * [reverse] parameter is true. - */ -@Suppress("FunctionName") -public fun ListPolynomial(vararg coefficients: C, reverse: Boolean = false): ListPolynomial = - ListPolynomial(with(coefficients) { if (reverse) reversed() else toList() }) - -public fun C.asListPolynomial() : ListPolynomial = ListPolynomial(listOf(this)) - - -// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available - -@Suppress("FunctionName") -public fun ListRationalFunction(numeratorCoefficients: List, denominatorCoefficients: List, reverse: Boolean = false): ListRationalFunction = - ListRationalFunction( - ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), - ListPolynomial( with(denominatorCoefficients) { if (reverse) reversed() else this } ) - ) -@Suppress("FunctionName") -public fun > ListRationalFunctionSpace.ListRationalFunction(numerator: ListPolynomial): ListRationalFunction = - ListRationalFunction(numerator, polynomialOne) -@Suppress("FunctionName") -public fun > A.ListRationalFunction(numerator: ListPolynomial): ListRationalFunction = - ListRationalFunction(numerator, ListPolynomial(listOf(one))) -@Suppress("FunctionName") -public fun > ListRationalFunctionSpace.ListRationalFunction(numeratorCoefficients: List, reverse: Boolean = false): ListRationalFunction = - ListRationalFunction( - ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), - polynomialOne - ) -@Suppress("FunctionName") -public fun > A.ListRationalFunction(numeratorCoefficients: List, reverse: Boolean = false): ListRationalFunction = - ListRationalFunction( - ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), - ListPolynomial(listOf(one)) - ) - -//context(A) -//public fun > C.asListRationalFunction() : ListRationalFunction = ListRationalFunction(asListPolynomial()) -//context(ListRationalFunctionSpace) -//public fun > C.asListRationalFunction() : ListRationalFunction = ListRationalFunction(asListPolynomial()) \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listPolynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listPolynomialUtil.kt deleted file mode 100644 index 50313cab9..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listPolynomialUtil.kt +++ /dev/null @@ -1,233 +0,0 @@ -/* - * 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.functions - -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.* -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract -import kotlin.math.max -import kotlin.math.min -import kotlin.math.pow - - -/** - * Removes zeros on the end of the coefficient list of polynomial. - */ -//context(PolynomialSpace) -//fun > Polynomial.removeZeros() : Polynomial = -// if (degree > -1) Polynomial(coefficients.subList(0, degree + 1)) else zero - -/** - * Creates a [ListPolynomialSpace] over a received ring. - */ -public fun > A.listPolynomial(): ListPolynomialSpace = - ListPolynomialSpace(this) - -/** - * Creates a [ListPolynomialSpace]'s scope over a received ring. - */ -public inline fun , R> A.listPolynomial(block: ListPolynomialSpace.() -> R): R { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return ListPolynomialSpace(this).block() -} - -/** - * Creates a [ScalableListPolynomialSpace] over a received scalable ring. - */ -public fun A.scalableListPolynomial(): ScalableListPolynomialSpace where A : Ring, A : ScaleOperations = - ScalableListPolynomialSpace(this) - -/** - * Creates a [ScalableListPolynomialSpace]'s scope over a received scalable ring. - */ -public inline fun A.scalableListPolynomial(block: ScalableListPolynomialSpace.() -> R): R where A : Ring, A : ScaleOperations { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return ScalableListPolynomialSpace(this).block() -} - -@Suppress("NOTHING_TO_INLINE") -internal inline fun copyTo( - origin: List, - originDegree: Int, - target: MutableList, -) { - for (deg in 0 .. originDegree) target[deg] = origin[deg] -} - -@Suppress("NOTHING_TO_INLINE") -internal inline fun multiplyAddingToUpdater( - ring: Ring, - multiplicand: MutableList, - multiplicandDegree: Int, - multiplier: List, - multiplierDegree: Int, - updater: MutableList, - zero: C, -) { - multiplyAddingTo( - ring = ring, - multiplicand = multiplicand, - multiplicandDegree = multiplicandDegree, - multiplier = multiplier, - multiplierDegree = multiplierDegree, - target = updater - ) - for (updateDeg in 0 .. multiplicandDegree + multiplierDegree) { - multiplicand[updateDeg] = updater[updateDeg] - updater[updateDeg] = zero - } -} - -@Suppress("NOTHING_TO_INLINE") -internal inline fun multiplyAddingTo( - ring: Ring, - multiplicand: List, - multiplicandDegree: Int, - multiplier: List, - multiplierDegree: Int, - target: MutableList -) = ring { - for (d in 0 .. multiplicandDegree + multiplierDegree) - for (k in max(0, d - multiplierDegree)..min(multiplicandDegree, d)) - target[d] += multiplicand[k] * multiplier[d - k] -} - -/** - * Evaluates the value of the given double polynomial for given double argument. - */ -public fun ListPolynomial.substitute(arg: Double): Double = - coefficients.reduceIndexedOrNull { index, acc, c -> - acc + c * arg.pow(index) - } ?: .0 - -/** - * Evaluates the value of the given polynomial for given argument. - * - * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). - */ -public fun ListPolynomial.substitute(ring: Ring, arg: C): C = ring { - if (coefficients.isEmpty()) return@ring zero - var result: C = coefficients.last() - for (j in coefficients.size - 2 downTo 0) { - result = (arg * result) + coefficients[j] - } - return result -} - -public fun ListPolynomial.substitute(ring: Ring, arg: ListPolynomial) : ListPolynomial = ring { - if (coefficients.isEmpty()) return ListPolynomial(emptyList()) - - val thisDegree = coefficients.lastIndex - if (thisDegree == -1) return ListPolynomial(emptyList()) - val argDegree = arg.coefficients.lastIndex - if (argDegree == -1) return coefficients[0].asListPolynomial() - val constantZero = zero - val resultCoefs: MutableList = MutableList(thisDegree * argDegree + 1) { constantZero } - resultCoefs[0] = coefficients[thisDegree] - val resultCoefsUpdate: MutableList = MutableList(thisDegree * argDegree + 1) { constantZero } - var resultDegree = 0 - for (deg in thisDegree - 1 downTo 0) { - resultCoefsUpdate[0] = coefficients[deg] - multiplyAddingToUpdater( - ring = ring, - multiplicand = resultCoefs, - multiplicandDegree = resultDegree, - multiplier = arg.coefficients, - multiplierDegree = argDegree, - updater = resultCoefsUpdate, - zero = constantZero - ) - resultDegree += argDegree - } - - return ListPolynomial(resultCoefs) -} - -/** - * Represent the polynomial as a regular context-less function. - */ -public fun > ListPolynomial.asFunction(ring: A): (C) -> C = { substitute(ring, it) } - -/** - * Represent the polynomial as a regular context-less function. - */ -public fun > ListPolynomial.asPolynomialFunctionOver(ring: A): (ListPolynomial) -> ListPolynomial = { substitute(ring, it) } - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun ListPolynomial.derivative( - algebra: A, -): ListPolynomial where A : Ring, A : NumericAlgebra = algebra { - ListPolynomial( - buildList(max(0, coefficients.size - 1)) { - for (deg in 1 .. coefficients.lastIndex) add(number(deg) * coefficients[deg]) - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun ListPolynomial.nthDerivative( - algebra: A, - order: Int, -): ListPolynomial where A : Ring, A : NumericAlgebra = algebra { - require(order >= 0) { "Order of derivative must be non-negative" } - ListPolynomial( - buildList(max(0, coefficients.size - order)) { - for (deg in order.. coefficients.lastIndex) - add((deg - order + 1 .. deg).fold(coefficients[deg]) { acc, d -> acc * number(d) }) - } - ) -} - -/** - * Returns algebraic antiderivative of received polynomial. - */ -@UnstableKMathAPI -public fun ListPolynomial.antiderivative( - algebra: A, -): ListPolynomial where A : Field, A : NumericAlgebra = algebra { - ListPolynomial( - buildList(coefficients.size + 1) { - add(zero) - coefficients.mapIndexedTo(this) { index, t -> t / number(index + 1) } - } - ) -} - -/** - * Returns algebraic antiderivative of received polynomial. - */ -@UnstableKMathAPI -public fun ListPolynomial.nthAntiderivative( - algebra: A, - order: Int, -): ListPolynomial where A : Field, A : NumericAlgebra = algebra { - require(order >= 0) { "Order of antiderivative must be non-negative" } - ListPolynomial( - buildList(coefficients.size + order) { - repeat(order) { add(zero) } - coefficients.mapIndexedTo(this) { index, c -> (1..order).fold(c) { acc, i -> acc / number(index + i) } } - } - ) -} - -/** - * Compute a definite integral of a given polynomial in a [range] - */ -@UnstableKMathAPI -public fun > ListPolynomial.integrate( - algebra: Field, - range: ClosedRange, -): C = algebra { - val integral = antiderivative(algebra) - integral.substitute(algebra, range.endInclusive) - integral.substitute(algebra, range.start) -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listRationalFunctionUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listRationalFunctionUtil.kt deleted file mode 100644 index 367212588..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listRationalFunctionUtil.kt +++ /dev/null @@ -1,221 +0,0 @@ -/* - * 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.functions - -import space.kscience.kmath.operations.Field -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.invoke -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract -import kotlin.math.max - - -/** - * Creates a [ListRationalFunctionSpace] over a received ring. - */ -public fun > A.listRationalFunction(): ListRationalFunctionSpace = - ListRationalFunctionSpace(this) - -/** - * Creates a [ListRationalFunctionSpace]'s scope over a received ring. - */ -public inline fun , R> A.listRationalFunction(block: ListRationalFunctionSpace.() -> R): R { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return ListRationalFunctionSpace(this).block() -} - -/** - * Evaluates the value of the given double polynomial for given double argument. - */ -public fun ListRationalFunction.substitute(arg: Double): Double = - numerator.substitute(arg) / denominator.substitute(arg) - -/** - * Evaluates the value of the given polynomial for given argument. - * - * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). - */ -public fun ListRationalFunction.substitute(ring: Field, arg: C): C = ring { - numerator.substitute(ring, arg) / denominator.substitute(ring, arg) -} - -/** - * Returns numerator (polynomial) of rational function gotten by substitution rational function [arg] to the polynomial instance. - * More concrete, if [arg] is a fraction `f(x)/g(x)` and the receiving instance is `p(x)`, then - * ``` - * p(f/g) * g^deg(p) - * ``` - * is returned. - * - * Used in [ListPolynomial.substitute] and [ListRationalFunction.substitute] for performance optimisation. - */ // TODO: Дописать -internal fun ListPolynomial.substituteRationalFunctionTakeNumerator(ring: Ring, arg: ListRationalFunction): ListPolynomial = ring { - if (coefficients.isEmpty()) return ListPolynomial(emptyList()) - - val thisDegree = coefficients.lastIndex - if (thisDegree == -1) return ListPolynomial(emptyList()) - val thisDegreeLog2 = 31 - thisDegree.countLeadingZeroBits() - val numeratorDegree = arg.numerator.coefficients.lastIndex - val denominatorDegree = arg.denominator.coefficients.lastIndex - val argDegree = max(numeratorDegree, denominatorDegree) - val constantZero = zero - val powersOf2 = buildList(thisDegreeLog2 + 1) { - var result = 1 - for (exp in 0 .. thisDegreeLog2) { - add(result) - result = result shl 1 - } - } - val hashes = powersOf2.runningReduce { acc, i -> acc + i } - val numeratorPowers = buildList>(thisDegreeLog2 + 1) { - add(arg.numerator.coefficients) - repeat(thisDegreeLog2) { - val next = MutableList(powersOf2[it + 1] * numeratorDegree + 1) { constantZero } - add(next) - val last = last() - multiplyAddingTo( - ring = ring, - multiplicand = last, - multiplicandDegree = powersOf2[it] * numeratorDegree + 1, - multiplier = last, - multiplierDegree = powersOf2[it] * numeratorDegree + 1, - target = next, - ) - } - } - val denominatorPowers = buildList>(thisDegreeLog2 + 1) { - add(arg.denominator.coefficients) - repeat(thisDegreeLog2) { - val next = MutableList(powersOf2[it + 1] * denominatorDegree + 1) { constantZero } - add(next) - val last = last() - multiplyAddingTo( - ring = ring, - multiplicand = last, - multiplicandDegree = powersOf2[it] * denominatorDegree + 1, - multiplier = last, - multiplierDegree = powersOf2[it] * denominatorDegree + 1, - target = next, - ) - } - } - val levelResultCoefsPool = buildList>(thisDegreeLog2 + 1) { - repeat(thisDegreeLog2 + 1) { - add(MutableList(hashes[it] * argDegree) { constantZero }) - } - } - val edgedMultiplier = MutableList(0) { TODO() } - val edgedMultiplierUpdater = MutableList(0) { TODO() } - - fun MutableList.reset() { - for (i in indices) set(i, constantZero) - } - - fun processLevel(level: Int, start: Int, end: Int) : List { - val levelResultCoefs = levelResultCoefsPool[level + 1] - - if (level == -1) { - levelResultCoefs[0] = coefficients[start] - } else { - levelResultCoefs.reset() - multiplyAddingTo( - ring = ring, - multiplicand = processLevel(level = level - 1, start = start, end = (start + end) / 2), - multiplicandDegree = hashes[level] * argDegree, - multiplier = denominatorPowers[level], - multiplierDegree = powersOf2[level] * denominatorDegree, - target = levelResultCoefs - ) - multiplyAddingTo( - ring = ring, - multiplicand = processLevel(level = level - 1, start = (start + end) / 2, end = end), - multiplicandDegree = hashes[level] * argDegree, - multiplier = numeratorPowers[level], - multiplierDegree = powersOf2[level] * numeratorDegree, - target = levelResultCoefs - ) - } - - return levelResultCoefs - } - - fun processLevelEdged(level: Int, start: Int, end: Int) : List { - val levelResultCoefs = levelResultCoefsPool[level + 1] - - if (level == -1) { - levelResultCoefs[0] = coefficients[start] - } else { - val levelsPowerOf2 = powersOf2[level] - if (end - start >= levelsPowerOf2) { - multiplyAddingTo( - ring = ring, - multiplicand = processLevelEdged(level = level - 1, start = start + levelsPowerOf2, end = end), - multiplicandDegree = hashes[level] * argDegree, // TODO: Ввести переменную - multiplier = numeratorPowers[level], - multiplierDegree = powersOf2[level] * numeratorDegree, - target = levelResultCoefs - ) - multiplyAddingTo( - ring = ring, - multiplicand = processLevel(level = level - 1, start = start, end = start + levelsPowerOf2), - multiplicandDegree = hashes[level] * argDegree, - multiplier = edgedMultiplier, - multiplierDegree = max((hashes[level] and thisDegree) - powersOf2[level] + 1, 0) * denominatorDegree, // TODO: Ввести переменную - target = levelResultCoefs - ) - if (level != thisDegreeLog2) { - multiplyAddingToUpdater( - ring = ring, - multiplicand = edgedMultiplier, - multiplicandDegree = max((hashes[level] and thisDegree) - powersOf2[level] + 1, 0) * denominatorDegree, // TODO: Ввести переменную - multiplier = denominatorPowers[level], - multiplierDegree = powersOf2[level] * denominatorDegree, - updater = edgedMultiplierUpdater, - zero = constantZero - ) - } - } else { - copyTo( - origin = processLevelEdged(level = level - 1, start = start + levelsPowerOf2, end = end), - originDegree = hashes[level] * argDegree, // TODO: Ввести переменную - target = levelResultCoefs - ) - } - } - - return levelResultCoefs - } - - return ListPolynomial( - processLevelEdged( - level = thisDegreeLog2, - start = 0, - end = thisDegree + 1 - ) - ) -} - -//operator fun > RationalFunction.invoke(arg: T): T = numerator(arg) / denominator(arg) -// -//fun > RationalFunction.reduced(): RationalFunction = -// polynomialGCD(numerator, denominator).let { -// RationalFunction( -// numerator / it, -// denominator / it -// ) -// } - -///** -// * Returns result of applying formal derivative to the polynomial. -// * -// * @param T Field where we are working now. -// * @return Result of the operator. -// */ -//fun > RationalFunction.derivative() = -// RationalFunction( -// numerator.derivative() * denominator - denominator.derivative() * numerator, -// denominator * denominator -// ) \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt deleted file mode 100644 index dca8a0cff..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt +++ /dev/null @@ -1,195 +0,0 @@ -/* - * 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.functions - -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.Ring - - -/** - * Returns the same degrees' description of the monomial, but without extra zero degrees on the end. - */ -internal fun List.cleanUp() = subList(0, indexOfLast { it != 0U } + 1) - -// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available - -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > NumberedPolynomialSpace.NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(coefs, toCheckInput) -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(coefs, toCheckInput) -@Suppress("FunctionName") -internal fun > A.NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : NumberedPolynomial { - if (!toCheckInput) return NumberedPolynomial(coefs) - - val fixedCoefs = mutableMapOf, C>() - - for (entry in coefs) { - val key = entry.key.cleanUp() - val value = entry.value - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return NumberedPolynomial(fixedCoefs) -} - -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > NumberedPolynomialSpace.NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(pairs, toCheckInput) -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(pairs, toCheckInput) -@Suppress("FunctionName") -internal fun > A.NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : NumberedPolynomial { - if (!toCheckInput) return NumberedPolynomial(pairs.toMap()) - - val fixedCoefs = mutableMapOf, C>() - - for (entry in pairs) { - val key = entry.first.cleanUp() - val value = entry.second - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return NumberedPolynomial(fixedCoefs) -} - -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > NumberedPolynomialSpace.NumberedPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(pairs = pairs, toCheckInput = toCheckInput) -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(pairs = pairs, toCheckInput = toCheckInput) -@Suppress("FunctionName") -internal fun > A.NumberedPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : NumberedPolynomial { - if (!toCheckInput) return NumberedPolynomial(pairs.toMap()) - - val fixedCoefs = mutableMapOf, C>() - - for (entry in pairs) { - val key = entry.first.cleanUp() - val value = entry.second - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return NumberedPolynomial(fixedCoefs) -} - -@Suppress("FunctionName") -public fun > A.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, toCheckInput = true) -@Suppress("FunctionName") -public fun > NumberedPolynomialSpace.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, toCheckInput = true) -@Suppress("FunctionName") -public fun > NumberedRationalFunctionSpace.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, toCheckInput = true) - -@Suppress("FunctionName") -public fun > A.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > NumberedPolynomialSpace.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > NumberedRationalFunctionSpace.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, toCheckInput = true) - -@Suppress("FunctionName") -public fun > A.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > NumberedPolynomialSpace.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > NumberedRationalFunctionSpace.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs, toCheckInput = true) - -public fun C.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomial(mapOf(emptyList() to this)) - -@DslMarker -@UnstableKMathAPI -internal annotation class NumberedPolynomialConstructorDSL - -@UnstableKMathAPI -@NumberedPolynomialConstructorDSL -public class NumberedPolynomialTermSignatureBuilder { - private val signature: MutableList = ArrayList() - public fun build(): List = signature - public infix fun Int.inPowerOf(deg: UInt) { - if (this > signature.lastIndex) { - signature.addAll(List(this - signature.lastIndex - 1) { 0u }) - signature.add(deg) - } else { - signature[this] = deg - } - } - @Suppress("NOTHING_TO_INLINE") - public inline infix fun Int.pow(deg: UInt): Unit = this inPowerOf deg - @Suppress("NOTHING_TO_INLINE") - public inline infix fun Int.`in`(deg: UInt): Unit = this inPowerOf deg - @Suppress("NOTHING_TO_INLINE") - public inline infix fun Int.of(deg: UInt): Unit = this inPowerOf deg -} - -@UnstableKMathAPI -public class NumberedPolynomialBuilder(private val zero: C, private val add: (C, C) -> C, capacity: Int = 0) { - private val coefficients: MutableMap, C> = LinkedHashMap(capacity) - public fun build(): NumberedPolynomial = NumberedPolynomial(coefficients) - public operator fun C.invoke(block: NumberedPolynomialTermSignatureBuilder.() -> Unit) { - val signature = NumberedPolynomialTermSignatureBuilder().apply(block).build() - coefficients[signature] = add(coefficients.getOrElse(signature) { zero }, this@invoke) - } - @Suppress("NOTHING_TO_INLINE") - public inline infix fun C.with(noinline block: NumberedPolynomialTermSignatureBuilder.() -> Unit): Unit = this.invoke(block) - @Suppress("NOTHING_TO_INLINE") - public inline infix fun (NumberedPolynomialTermSignatureBuilder.() -> Unit).with(coef: C): Unit = coef.invoke(this) - @Suppress("NOTHING_TO_INLINE") - public infix fun sig(block: NumberedPolynomialTermSignatureBuilder.() -> Unit): NumberedPolynomialTermSignatureBuilder.() -> Unit = block -} - -// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available - -@UnstableKMathAPI -@NumberedPolynomialConstructorDSL -@Suppress("FunctionName") -public inline fun > A.NumberedPolynomial(block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder(zero, ::add).apply(block).build() -@UnstableKMathAPI -@NumberedPolynomialConstructorDSL -@Suppress("FunctionName") -public inline fun > A.NumberedPolynomial(capacity: Int, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder(zero, ::add, capacity).apply(block).build() -@UnstableKMathAPI -@NumberedPolynomialConstructorDSL -@Suppress("FunctionName") -public inline fun > NumberedPolynomialSpace.NumberedPolynomial(block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder(constantZero, { left: C, right: C -> left + right}).apply(block).build() -@UnstableKMathAPI -@NumberedPolynomialConstructorDSL -@Suppress("FunctionName") -public inline fun > NumberedPolynomialSpace.NumberedPolynomial(capacity: Int, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder(constantZero, { left: C, right: C -> left + right}, capacity).apply(block).build() - -// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available - -@Suppress("FunctionName") -public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): NumberedRationalFunction = - NumberedRationalFunction( - NumberedPolynomial(numeratorCoefficients, toCheckInput = true), - NumberedPolynomial(denominatorCoefficients, toCheckInput = true) - ) -@Suppress("FunctionName") -public fun > A.NumberedRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): NumberedRationalFunction = - NumberedRationalFunction( - NumberedPolynomial(numeratorCoefficients, toCheckInput = true), - NumberedPolynomial(denominatorCoefficients, toCheckInput = true) - ) -@Suppress("FunctionName") -public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numerator: NumberedPolynomial): NumberedRationalFunction = - NumberedRationalFunction(numerator, polynomialOne) -@Suppress("FunctionName") -public fun > A.NumberedRationalFunction(numerator: NumberedPolynomial): NumberedRationalFunction = - NumberedRationalFunction(numerator, NumberedPolynomial(mapOf(emptyList() to one), toCheckInput = false)) -@Suppress("FunctionName") -public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numeratorCoefficients: Map, C>): NumberedRationalFunction = - NumberedRationalFunction( - NumberedPolynomial(numeratorCoefficients, toCheckInput = true), - polynomialOne - ) -@Suppress("FunctionName") -public fun > A.NumberedRationalFunction(numeratorCoefficients: Map, C>): NumberedRationalFunction = - NumberedRationalFunction( - NumberedPolynomial(numeratorCoefficients, toCheckInput = true), - NumberedPolynomial(mapOf(emptyList() to one), toCheckInput = false) - ) - -//context(A) -//public fun > C.asNumberedRationalFunction() : NumberedRationalFunction = NumberedRationalFunction(asLabeledPolynomial()) -//context(NumberedRationalFunctionSpace) -//public fun > C.asNumberedRationalFunction() : NumberedRationalFunction = NumberedRationalFunction(asLabeledPolynomial()) \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt deleted file mode 100644 index ad817c7ba..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt +++ /dev/null @@ -1,528 +0,0 @@ -package space.kscience.kmath.functions - -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.* -import kotlin.contracts.* -import kotlin.jvm.JvmName -import kotlin.math.max - - -// TODO: Docs - -/** - * Creates a [NumberedPolynomialSpace] over a received ring. - */ -public fun > A.numberedPolynomial(): NumberedPolynomialSpace = - NumberedPolynomialSpace(this) - -/** - * Creates a [NumberedPolynomialSpace]'s scope over a received ring. - */ -@OptIn(ExperimentalContracts::class) -public inline fun , R> A.numberedPolynomial(block: NumberedPolynomialSpace.() -> R): R { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return NumberedPolynomialSpace(this).block() -} - -///** -// * Represents the polynomial as a [String] where name of variable with index `i` is [withVariableName] + `"_${i+1}"`. -// * Consider that monomials are sorted in lexicographic order. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial.represent(withVariableName: String = NumberedPolynomial.defaultVariableName): String = -// coefficients.entries -// .sortedWith { o1, o2 -> NumberedPolynomial.monomialComparator.compare(o1.key, o2.key) } -// .asSequence() -// .map { (degs, t) -> -// if (degs.isEmpty()) "$t" -// else { -// when { -// t.isOne() -> "" -// t.isMinusOne() -> "-" -// else -> "$t " -// } + -// degs -// .mapIndexed { index, deg -> -// when (deg) { -// 0U -> "" -// 1U -> "${withVariableName}_${index+1}" -// else -> "${withVariableName}_${index+1}^$deg" -// } -// } -// .filter { it.isNotEmpty() } -// .joinToString(separator = " ") { it } -// } -// } -// .joinToString(separator = " + ") { it } -// .ifEmpty { "0" } -// -///** -// * Represents the polynomial as a [String] naming variables by [namer]. -// * Consider that monomials are sorted in lexicographic order. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial.represent(namer: (Int) -> String): String = -// coefficients.entries -// .sortedWith { o1, o2 -> NumberedPolynomial.monomialComparator.compare(o1.key, o2.key) } -// .asSequence() -// .map { (degs, t) -> -// if (degs.isEmpty()) "$t" -// else { -// when { -// t.isOne() -> "" -// t.isMinusOne() -> "-" -// else -> "$t " -// } + -// degs -// .mapIndexed { index, deg -> -// when (deg) { -// 0U -> "" -// 1U -> namer(index) -// else -> "${namer(index)}^$deg" -// } -// } -// .filter { it.isNotEmpty() } -// .joinToString(separator = " ") { it } -// } -// } -// .joinToString(separator = " + ") { it } -// .ifEmpty { "0" } -// -///** -// * Represents the polynomial as a [String] where name of variable with index `i` is [withVariableName] + `"_${i+1}"` -// * and with brackets around the string if needed (i.e. when there are at least two addends in the representation). -// * Consider that monomials are sorted in lexicographic order. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial.representWithBrackets(withVariableName: String = NumberedPolynomial.defaultVariableName): String = -// with(represent(withVariableName)) { if (coefficients.count() == 1) this else "($this)" } -// -///** -// * Represents the polynomial as a [String] naming variables by [namer] and with brackets around the string if needed -// * (i.e. when there are at least two addends in the representation). -// * Consider that monomials are sorted in lexicographic order. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial.representWithBrackets(namer: (Int) -> String): String = -// with(represent(namer)) { if (coefficients.count() == 1) this else "($this)" } -// -///** -// * Represents the polynomial as a [String] where name of variable with index `i` is [withVariableName] + `"_${i+1}"`. -// * Consider that monomials are sorted in **reversed** lexicographic order. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial.representReversed(withVariableName: String = NumberedPolynomial.defaultVariableName): String = -// coefficients.entries -// .sortedWith { o1, o2 -> -NumberedPolynomial.monomialComparator.compare(o1.key, o2.key) } -// .asSequence() -// .map { (degs, t) -> -// if (degs.isEmpty()) "$t" -// else { -// when { -// t.isOne() -> "" -// t.isMinusOne() -> "-" -// else -> "$t " -// } + -// degs -// .mapIndexed { index, deg -> -// when (deg) { -// 0U -> "" -// 1U -> "${withVariableName}_${index+1}" -// else -> "${withVariableName}_${index+1}^$deg" -// } -// } -// .filter { it.isNotEmpty() } -// .joinToString(separator = " ") { it } -// } -// } -// .joinToString(separator = " + ") { it } -// .ifEmpty { "0" } -// -///** -// * Represents the polynomial as a [String] naming variables by [namer]. -// * Consider that monomials are sorted in **reversed** lexicographic order. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial.representReversed(namer: (Int) -> String): String = -// coefficients.entries -// .sortedWith { o1, o2 -> -NumberedPolynomial.monomialComparator.compare(o1.key, o2.key) } -// .asSequence() -// .map { (degs, t) -> -// if (degs.isEmpty()) "$t" -// else { -// when { -// t.isOne() -> "" -// t.isMinusOne() -> "-" -// else -> "$t " -// } + -// degs -// .mapIndexed { index, deg -> -// when (deg) { -// 0U -> "" -// 1U -> namer(index) -// else -> "${namer(index)}^$deg" -// } -// } -// .filter { it.isNotEmpty() } -// .joinToString(separator = " ") { it } -// } -// } -// .joinToString(separator = " + ") { it } -// .ifEmpty { "0" } -// -///** -// * Represents the polynomial as a [String] where name of variable with index `i` is [withVariableName] + `"_${i+1}"` -// * and with brackets around the string if needed (i.e. when there are at least two addends in the representation). -// * Consider that monomials are sorted in **reversed** lexicographic order. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial.representReversedWithBrackets(withVariableName: String = NumberedPolynomial.defaultVariableName): String = -// with(representReversed(withVariableName)) { if (coefficients.count() == 1) this else "($this)" } -// -///** -// * Represents the polynomial as a [String] naming variables by [namer] and with brackets around the string if needed -// * (i.e. when there are at least two addends in the representation). -// * Consider that monomials are sorted in **reversed** lexicographic order. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial.representReversedWithBrackets(namer: (Int) -> String): String = -// with(representReversed(namer)) { if (coefficients.count() == 1) this else "($this)" } - -//public fun NumberedPolynomial.substitute(ring: Ring, args: Map): NumberedPolynomial = ring { -// if (coefficients.isEmpty()) return this@substitute -// NumberedPolynomial( -// buildMap { -// coefficients.forEach { (degs, c) -> -// val newDegs = degs.mapIndexed { index, deg -> if (index in args) 0U else deg }.cleanUp() -// val newC = degs.foldIndexed(c) { index, acc, deg -> -// if (index in args) multiplyWithPower(acc, args[index]!!, deg) -// else acc -// } -// this[newDegs] = if (newDegs in this) this[newDegs]!! + newC else newC -// } -// } -// ) -//} -// -//// TODO: Replace with optimisation: the [result] may be unboxed, and all operations may be performed as soon as -//// possible on it -//@JvmName("substitutePolynomial") -//public fun NumberedPolynomial.substitute(ring: Ring, arg: Map>) : NumberedPolynomial = -// ring.numberedPolynomialSpace { -// if (coefficients.isEmpty()) return zero -// coefficients -// .asSequence() -// .map { (degs, c) -> -// degs.foldIndexed( -// NumberedPolynomial( -// degs.mapIndexed { index, deg -> if (index in arg) 0U else deg } to c -// ) -// ) { index, acc, deg -> if (index in arg) multiplyWithPower(acc, arg[index]!!, deg) else acc } -// } -// .reduce { acc, polynomial -> acc + polynomial } // TODO: Rewrite. Might be slow. -// } -// -//// TODO: Substitute rational function -// -//public fun > NumberedPolynomial.asFunctionOver(ring: A): (Map) -> NumberedPolynomial = -// { substitute(ring, it) } -// -//public fun > NumberedPolynomial.asPolynomialFunctionOver(ring: A): (Map>) -> NumberedPolynomial = -// { substitute(ring, it) } - -//operator fun > Polynomial.div(other: T): Polynomial = -// if (other.isZero()) throw ArithmeticException("/ by zero") -// else -// Polynomial( -// coefficients -// .mapValues { it.value / other }, -// toCheckInput = false -// ) - -/** - * Evaluates the value of the given double polynomial for given double argument. - */ -public fun NumberedPolynomial.substitute(args: Map): NumberedPolynomial = Double.algebra { - val acc = LinkedHashMap, Double>(coefficients.size) - for ((degs, c) in coefficients) { - val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp() - val newC = args.entries.fold(c) { product, (variable, substitution) -> - val deg = degs.getOrElse(variable) { 0u } - if (deg == 0u) product else product * substitution.pow(deg.toInt()) - } - if (newDegs !in acc) acc[newDegs] = newC - else acc[newDegs] = acc[newDegs]!! + newC - } - return NumberedPolynomial(acc) -} - -/** - * Evaluates the value of the given polynomial for given argument. - * - * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). - */ -public fun NumberedPolynomial.substitute(ring: Ring, args: Map): NumberedPolynomial = ring { - val acc = LinkedHashMap, C>(coefficients.size) - for ((degs, c) in coefficients) { - val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp() - val newC = args.entries.fold(c) { product, (variable, substitution) -> - val deg = degs.getOrElse(variable) { 0u } - if (deg == 0u) product else product * power(substitution, deg) - } - if (newDegs !in acc) acc[newDegs] = newC - else acc[newDegs] = acc[newDegs]!! + newC - } - return NumberedPolynomial(acc) -} - -// TODO: (Waiting for hero) Replace with optimisation: the [result] may be unboxed, and all operations may be performed -// as soon as possible on it -@JvmName("substitutePolynomial") -public fun NumberedPolynomial.substitute(ring: Ring, args: Map>) : NumberedPolynomial = TODO() /*ring.numberedPolynomial { - val acc = LinkedHashMap, NumberedPolynomial>(coefficients.size) - for ((degs, c) in coefficients) { - val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp() - val newC = args.entries.fold(c.asNumberedPolynomial()) { product, (variable, substitution) -> - val deg = degs.getOrElse(variable) { 0u } - if (deg == 0u) product else product * power(substitution, deg) - } - if (newDegs !in acc) acc[newDegs] = c.asNumberedPolynomial() - else acc[newDegs] = acc[newDegs]!! + c - } -}*/ - -/** - * Represent the polynomial as a regular context-less function. - */ -public fun > NumberedPolynomial.asFunction(ring: A): (Map) -> NumberedPolynomial = { substitute(ring, it) } - -/** - * Represent the polynomial as a regular context-less function. - */ -public fun > NumberedPolynomial.asPolynomialFunctionOver(ring: A): (Map>) -> NumberedPolynomial = { substitute(ring, it) } - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > NumberedPolynomial.derivativeWithRespectTo( - algebra: A, - variable: Int, -): NumberedPolynomial = algebra { - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - if (degs.size > variable) return@forEach - put( - degs.mapIndexed { index, deg -> - when { - index != variable -> deg - deg > 0u -> deg - 1u - else -> return@forEach - } - }.cleanUp(), - multiplyByDoubling(c, degs[variable]) - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > NumberedPolynomial.derivativeWithRespectTo( - algebra: A, - variables: Collection, -): NumberedPolynomial = algebra { - val cleanedVariables = variables.toSet() - if (cleanedVariables.isEmpty()) return this@derivativeWithRespectTo - val maxRespectedVariable = cleanedVariables.maxOrNull()!! - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - if (degs.size > maxRespectedVariable) return@forEach - put( - degs.mapIndexed { index, deg -> - when { - index !in cleanedVariables -> deg - deg > 0u -> deg - 1u - else -> return@forEach - } - }.cleanUp(), - cleanedVariables.fold(c) { acc, variable -> multiplyByDoubling(acc, degs[variable]) } - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > NumberedPolynomial.nthDerivativeWithRespectTo( - algebra: A, - variable: Int, - order: UInt -): NumberedPolynomial = algebra { - if (order == 0u) return this@nthDerivativeWithRespectTo - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - if (degs.size > variable) return@forEach - put( - degs.mapIndexed { index, deg -> - when { - index != variable -> deg - deg >= order -> deg - order - else -> return@forEach - } - }.cleanUp(), - degs[variable].let { deg -> - (deg downTo deg - order + 1u) - .fold(c) { acc, ord -> multiplyByDoubling(acc, ord) } - } - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > NumberedPolynomial.nthDerivativeWithRespectTo( - algebra: A, - variablesAndOrders: Map, -): NumberedPolynomial = algebra { - val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u } - if (filteredVariablesAndOrders.isEmpty()) return this@nthDerivativeWithRespectTo - val maxRespectedVariable = filteredVariablesAndOrders.keys.maxOrNull()!! - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - if (degs.size > maxRespectedVariable) return@forEach - put( - degs.mapIndexed { index, deg -> - if (index !in filteredVariablesAndOrders) return@mapIndexed deg - val order = filteredVariablesAndOrders[index]!! - if (deg >= order) deg - order else return@forEach - }.cleanUp(), - filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> - degs[index].let { deg -> - (deg downTo deg - order + 1u) - .fold(acc1) { acc2, ord -> multiplyByDoubling(acc2, ord) } - } - } - ) - } - } - ) -} - -/** - * Returns algebraic antiderivative of received polynomial. - */ -@UnstableKMathAPI -public fun > NumberedPolynomial.antiderivativeWithRespectTo( - algebra: A, - variable: Int, -): NumberedPolynomial = algebra { - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - put( - List(max(variable + 1, degs.size)) { if (it != variable) degs[it] else degs[it] + 1u }, - c / multiplyByDoubling(one, degs[variable]) - ) - } - } - ) -} - -/** - * Returns algebraic antiderivative of received polynomial. - */ -@UnstableKMathAPI -public fun > NumberedPolynomial.antiderivativeWithRespectTo( - algebra: A, - variables: Collection, -): NumberedPolynomial = algebra { - val cleanedVariables = variables.toSet() - if (cleanedVariables.isEmpty()) return this@antiderivativeWithRespectTo - val maxRespectedVariable = cleanedVariables.maxOrNull()!! - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - put( - List(max(maxRespectedVariable + 1, degs.size)) { if (it !in variables) degs[it] else degs[it] + 1u }, - cleanedVariables.fold(c) { acc, variable -> acc / multiplyByDoubling(one, degs[variable]) } - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > NumberedPolynomial.nthAntiderivativeWithRespectTo( - algebra: A, - variable: Int, - order: UInt -): NumberedPolynomial = algebra { - if (order == 0u) return this@nthAntiderivativeWithRespectTo - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - put( - List(max(variable + 1, degs.size)) { if (it != variable) degs[it] else degs[it] + order }, - degs[variable].let { deg -> - (deg downTo deg - order + 1u) - .fold(c) { acc, ord -> acc / multiplyByDoubling(one, ord) } - } - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > NumberedPolynomial.nthAntiderivativeWithRespectTo( - algebra: A, - variablesAndOrders: Map, -): NumberedPolynomial = algebra { - val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u } - if (filteredVariablesAndOrders.isEmpty()) return this@nthAntiderivativeWithRespectTo - val maxRespectedVariable = filteredVariablesAndOrders.keys.maxOrNull()!! - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - put( - List(max(maxRespectedVariable + 1, degs.size)) { degs[it] + filteredVariablesAndOrders.getOrElse(it) { 0u } }, - filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> - degs[index].let { deg -> - (deg downTo deg - order + 1u) - .fold(acc1) { acc2, ord -> acc2 / multiplyByDoubling(one, ord) } - } - } - ) - } - } - ) -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt deleted file mode 100644 index 5cd0679ab..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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.functions - -import space.kscience.kmath.operations.Ring -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract - - -/** - * Creates a [NumberedRationalFunctionSpace] over a received ring. - */ -public fun > A.numberedRationalFunction(): NumberedRationalFunctionSpace = - NumberedRationalFunctionSpace(this) - -/** - * Creates a [NumberedRationalFunctionSpace]'s scope over a received ring. - */ -public inline fun , R> A.numberedRationalFunction(block: NumberedRationalFunctionSpace.() -> R): R { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return NumberedRationalFunctionSpace(this).block() -} - -//fun > NumberedRationalFunction.reduced(): NumberedRationalFunction { -// val greatestCommonDivider = polynomialGCD(numerator, denominator) -// return NumberedRationalFunction( -// numerator / greatestCommonDivider, -// denominator / greatestCommonDivider -// ) -//} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt deleted file mode 100644 index 0fcd4c6e5..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt +++ /dev/null @@ -1,107 +0,0 @@ -/* - * 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.integration - -import space.kscience.kmath.functions.PiecewisePolynomial -import space.kscience.kmath.functions.integrate -import space.kscience.kmath.functions.antiderivative -import space.kscience.kmath.interpolation.PolynomialInterpolator -import space.kscience.kmath.interpolation.SplineInterpolator -import space.kscience.kmath.interpolation.interpolatePolynomials -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.* -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.DoubleBuffer -import space.kscience.kmath.structures.MutableBufferFactory - -/** - * Compute analytical indefinite integral of this [PiecewisePolynomial], keeping all intervals intact - */ -@OptIn(PerformancePitfall::class) -@UnstableKMathAPI -public fun > PiecewisePolynomial.integrate(algebra: Field): PiecewisePolynomial = - PiecewisePolynomial(pieces.map { it.first to it.second.antiderivative(algebra) }) - -/** - * Compute definite integral of given [PiecewisePolynomial] piece by piece in a given [range] - * Requires [UnivariateIntegrationNodes] or [IntegrationRange] and [IntegrandMaxCalls] - * - * TODO use context receiver for algebra - */ -@UnstableKMathAPI -public fun > PiecewisePolynomial.integrate( - algebra: Field, range: ClosedRange, -): T = algebra.sum( - pieces.map { (region, poly) -> - val intersectedRange = maxOf(range.start, region.start)..minOf(range.endInclusive, region.endInclusive) - //Check if polynomial range is not used - if (intersectedRange.start == intersectedRange.endInclusive) algebra.zero - else poly.integrate(algebra, intersectedRange) - } -) - -/** - * A generic spline-interpolation-based analytic integration - * * [IntegrationRange]—the univariate range of integration. By default, uses `0..1` interval. - * * [IntegrandMaxCalls]—the maximum number of function calls during integration. For non-iterative rules, always uses - * the maximum number of points. By default, uses 10 points. - */ -@UnstableKMathAPI -public class SplineIntegrator>( - public val algebra: Field, - public val bufferFactory: MutableBufferFactory, -) : UnivariateIntegrator { - override fun process(integrand: UnivariateIntegrand): UnivariateIntegrand = algebra { - val range = integrand.getFeature()?.range ?: 0.0..1.0 - - val interpolator: PolynomialInterpolator = SplineInterpolator(algebra, bufferFactory) - - val nodes: Buffer = integrand.getFeature()?.nodes ?: run { - val numPoints = integrand.getFeature()?.maxCalls ?: 100 - val step = (range.endInclusive - range.start) / (numPoints - 1) - DoubleBuffer(numPoints) { i -> range.start + i * step } - } - - val values = nodes.map(bufferFactory) { integrand.function(it) } - val polynomials = interpolator.interpolatePolynomials( - nodes.map(bufferFactory) { number(it) }, - values - ) - val res = polynomials.integrate(algebra, number(range.start)..number(range.endInclusive)) - integrand + IntegrandValue(res) + IntegrandCallsPerformed(integrand.calls + nodes.size) - } -} - -/** - * A simplified double-based spline-interpolation-based analytic integration - * * [IntegrationRange]—the univariate range of integration. By default, uses `0.0..1.0` interval. - * * [IntegrandMaxCalls]—the maximum number of function calls during integration. For non-iterative rules, always - * uses the maximum number of points. By default, uses 10 points. - */ -@UnstableKMathAPI -public object DoubleSplineIntegrator : UnivariateIntegrator { - override fun process(integrand: UnivariateIntegrand): UnivariateIntegrand { - val range = integrand.getFeature()?.range ?: 0.0..1.0 - val interpolator: PolynomialInterpolator = SplineInterpolator(DoubleField, ::DoubleBuffer) - - val nodes: Buffer = integrand.getFeature()?.nodes ?: run { - val numPoints = integrand.getFeature()?.maxCalls ?: 100 - val step = (range.endInclusive - range.start) / (numPoints - 1) - DoubleBuffer(numPoints) { i -> range.start + i * step } - } - - val values = nodes.map { integrand.function(it) } - val polynomials = interpolator.interpolatePolynomials(nodes, values) - val res = polynomials.integrate(DoubleField, range) - return integrand + IntegrandValue(res) + IntegrandCallsPerformed(integrand.calls + nodes.size) - } -} - -@Suppress("unused") -@UnstableKMathAPI -public inline val DoubleField.splineIntegrator: UnivariateIntegrator - get() = DoubleSplineIntegrator \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt deleted file mode 100644 index 5401be707..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt +++ /dev/null @@ -1,491 +0,0 @@ -/* - * 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.functions - -import space.kscience.kmath.test.misc.* -import kotlin.test.* - - -class ListPolynomialTest { - @Test - fun test_Polynomial_Int_plus() { - RationalField.listPolynomial { - assertEquals( - ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), - ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + -3, - "test 1" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + 2, - "test 2" - ) - assertEquals( - ListPolynomial(Rational(0)), - ListPolynomial(Rational(-2)) + 2, - "test 3" - ) - assertEquals( - ListPolynomial(), - ListPolynomial() + 0, - "test 4" - ) - assertEquals( - ListPolynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + 1, - "test 5" - ) - assertEquals( - ListPolynomial(Rational(-1)), - ListPolynomial(Rational(-2)) + 1, - "test 6" - ) - assertEquals( - ListPolynomial(Rational(2)), - ListPolynomial() + 2, - "test 7" - ) - } - } - @Test - fun test_Polynomial_Int_minus() { - RationalField.listPolynomial { - assertEquals( - ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), - ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - -3, - "test 1" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), - ListPolynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - 2, - "test 2" - ) - assertEquals( - ListPolynomial(Rational(0)), - ListPolynomial(Rational(2)) - 2, - "test 3" - ) - assertEquals( - ListPolynomial(), - ListPolynomial() - 0, - "test 4" - ) - assertEquals( - ListPolynomial(Rational(1), Rational(0), Rational(0), Rational(0)), - ListPolynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - 1, - "test 5" - ) - assertEquals( - ListPolynomial(Rational(1)), - ListPolynomial(Rational(2)) - 1, - "test 6" - ) - assertEquals( - ListPolynomial(Rational(-2)), - ListPolynomial() - 2, - "test 7" - ) - } - } - @Test - fun test_Polynomial_Int_times() { - IntModuloRing(35).listPolynomial { - assertEquals( - ListPolynomial(34, 2, 1, 20, 2), - ListPolynomial(22, 26, 13, 15, 26) * 27, - "test 1" - ) - assertEquals( - ListPolynomial(0, 0, 0, 0, 0), - ListPolynomial(7, 0, 49, 21, 14) * 15, - "test 2" - ) - } - } - @Test - fun test_Int_Polynomial_plus() { - RationalField.listPolynomial { - assertEquals( - ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), - -3 + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)), - "test 1" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), - 2 + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 2" - ) - assertEquals( - ListPolynomial(Rational(0)), - 2 + ListPolynomial(Rational(-2)), - "test 3" - ) - assertEquals( - ListPolynomial(), - 0 + ListPolynomial(), - "test 4" - ) - assertEquals( - ListPolynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), - 1 + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 5" - ) - assertEquals( - ListPolynomial(Rational(-1)), - 1 + ListPolynomial(Rational(-2)), - "test 6" - ) - assertEquals( - ListPolynomial(Rational(2)), - 2 + ListPolynomial(), - "test 7" - ) - } - } - @Test - fun test_Int_Polynomial_minus() { - RationalField.listPolynomial { - assertEquals( - ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), - 3 - ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), - "test 1" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), - -2 - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 2" - ) - assertEquals( - ListPolynomial(Rational(0)), - -2 - ListPolynomial(Rational(-2)), - "test 3" - ) - assertEquals( - ListPolynomial(), - 0 - ListPolynomial(), - "test 4" - ) - assertEquals( - ListPolynomial(Rational(1), Rational(0), Rational(0), Rational(0)), - -1 - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 5" - ) - assertEquals( - ListPolynomial(Rational(1)), - -1 - ListPolynomial(Rational(-2)), - "test 6" - ) - assertEquals( - ListPolynomial(Rational(-2)), - -2 - ListPolynomial(), - "test 7" - ) - } - } - @Test - fun test_Int_Polynomial_times() { - IntModuloRing(35).listPolynomial { - assertEquals( - ListPolynomial(34, 2, 1, 20, 2), - 27 * ListPolynomial(22, 26, 13, 15, 26), - "test 1" - ) - assertEquals( - ListPolynomial(0, 0, 0, 0, 0), - 15 * ListPolynomial(7, 0, 49, 21, 14), - "test 2" - ) - } - } - @Test - fun test_Polynomial_Constant_plus() { - RationalField.listPolynomial { - assertEquals( - ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), - ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + Rational(-3), - "test 1" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + Rational(2), - "test 2" - ) - assertEquals( - ListPolynomial(Rational(0)), - ListPolynomial(Rational(-2)) + Rational(2), - "test 3" - ) - assertEquals( - ListPolynomial(Rational(0)), - ListPolynomial() + Rational(0), - "test 4" - ) - assertEquals( - ListPolynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + Rational(1), - "test 5" - ) - assertEquals( - ListPolynomial(Rational(-1)), - ListPolynomial(Rational(-2)) + Rational(1), - "test 6" - ) - assertEquals( - ListPolynomial(Rational(2)), - ListPolynomial() + Rational(2), - "test 7" - ) - } - } - @Test - fun test_Polynomial_Constant_minus() { - RationalField.listPolynomial { - assertEquals( - ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), - ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - Rational(-3), - "test 1" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), - ListPolynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - Rational(2), - "test 2" - ) - assertEquals( - ListPolynomial(Rational(0)), - ListPolynomial(Rational(2)) - Rational(2), - "test 3" - ) - assertEquals( - ListPolynomial(Rational(0)), - ListPolynomial() - Rational(0), - "test 4" - ) - assertEquals( - ListPolynomial(Rational(1), Rational(0), Rational(0), Rational(0)), - ListPolynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - Rational(1), - "test 5" - ) - assertEquals( - ListPolynomial(Rational(1)), - ListPolynomial(Rational(2)) - Rational(1), - "test 6" - ) - assertEquals( - ListPolynomial(Rational(-2)), - ListPolynomial() - Rational(2), - "test 7" - ) - } - } - @Test - fun test_Polynomial_Constant_times() { - IntModuloRing(35).listPolynomial { - assertEquals( - ListPolynomial(34, 2, 1, 20, 2), - ListPolynomial(22, 26, 13, 15, 26) * 27.asConstant(), - "test 1" - ) - assertEquals( - ListPolynomial(0, 0, 0, 0, 0), - ListPolynomial(7, 0, 49, 21, 14) * 15.asConstant(), - "test 2" - ) - } - } - @Test - fun test_Constant_Polynomial_plus() { - RationalField.listPolynomial { - assertEquals( - ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), - Rational(-3) + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)), - "test 1" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), - Rational(2) + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 2" - ) - assertEquals( - ListPolynomial(Rational(0)), - Rational(2) + ListPolynomial(Rational(-2)), - "test 3" - ) - assertEquals( - ListPolynomial(Rational(0)), - Rational(0) + ListPolynomial(), - "test 4" - ) - assertEquals( - ListPolynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), - Rational(1) + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 5" - ) - assertEquals( - ListPolynomial(Rational(-1)), - Rational(1) + ListPolynomial(Rational(-2)), - "test 6" - ) - assertEquals( - ListPolynomial(Rational(2)), - Rational(2) + ListPolynomial(), - "test 7" - ) - } - } - @Test - fun test_Constant_Polynomial_minus() { - RationalField.listPolynomial { - assertEquals( - ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), - Rational(3) - ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), - "test 1" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), - Rational(-2) - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 2" - ) - assertEquals( - ListPolynomial(Rational(0)), - Rational(-2) - ListPolynomial(Rational(-2)), - "test 3" - ) - assertEquals( - ListPolynomial(Rational(0)), - Rational(0) - ListPolynomial(), - "test 4" - ) - assertEquals( - ListPolynomial(Rational(1), Rational(0), Rational(0), Rational(0)), - Rational(-1) - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 5" - ) - assertEquals( - ListPolynomial(Rational(1)), - Rational(-1) - ListPolynomial(Rational(-2)), - "test 6" - ) - assertEquals( - ListPolynomial(Rational(-2)), - Rational(-2) - ListPolynomial(), - "test 7" - ) - } - } - @Test - fun test_Constant_Polynomial_times() { - IntModuloRing(35).listPolynomial { - assertEquals( - ListPolynomial(34, 2, 1, 20, 2), - 27 * ListPolynomial(22, 26, 13, 15, 26), - "test 1" - ) - assertEquals( - ListPolynomial(0, 0, 0, 0, 0), - 15 * ListPolynomial(7, 0, 49, 21, 14), - "test 2" - ) - } - } - @Test - fun test_Polynomial_unaryMinus() { - RationalField.listPolynomial { - assertEquals( - ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), - -ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)), - "test 1" - ) - assertEquals( - ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7), Rational(0), Rational(0)), - -ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7), Rational(0), Rational(0)), - "test 2" - ) - } - } - @Test - fun test_Polynomial_Polynomial_plus() { - RationalField.listPolynomial { - // (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( - ListPolynomial(Rational(-10, 63), Rational(37, 9), Rational(-29, 56)), - ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + - ListPolynomial(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( - ListPolynomial(Rational(-2, 9), Rational(-5, 12), Rational(2, 4)), - ListPolynomial(Rational(-2, 9), Rational(-8, 3)) + - ListPolynomial(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( - ListPolynomial(Rational(-18, 7), Rational(-23, 6), Rational(2, 3), Rational(0)), - ListPolynomial(Rational(-4, 7), Rational(-2, 6), Rational(0), Rational(0)) + - ListPolynomial(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( - ListPolynomial(Rational(0), Rational(0), Rational(0)), - ListPolynomial(Rational(-2, 4), Rational(-6, 9), Rational(-4, 9)) + - ListPolynomial(Rational(2, 4), Rational(6, 9), Rational(4, 9)), - "test 4" - ) - } - } - @Test - fun test_Polynomial_Polynomial_minus() { - RationalField.listPolynomial { - // (5/9 - 8/9 x - 8/7 x^2) - (-5/7 + 5/1 x + 5/8 x^2) ?= 80/63 - 53/9 x - 99/56 x^2 - assertEquals( - ListPolynomial(Rational(80, 63), Rational(-53, 9), Rational(-99, 56)), - ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - - ListPolynomial(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 - 59/12 x - 2/4 x^2 - assertEquals( - ListPolynomial(Rational(-2, 9), Rational(-59, 12), Rational(-2, 4)), - ListPolynomial(Rational(-2, 9), Rational(-8, 3)) - - ListPolynomial(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) ?= 10/7 + 19/6 x - 2/3 x^2 - assertEquals( - ListPolynomial(Rational(10, 7), Rational(19, 6), Rational(-2, 3), Rational(0)), - ListPolynomial(Rational(-4, 7), Rational(-2, 6), Rational(0), Rational(0)) - - ListPolynomial(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( - ListPolynomial(Rational(0), Rational(0), Rational(0)), - ListPolynomial(Rational(-2, 4), Rational(-6, 9), Rational(-4, 9)) - - ListPolynomial(Rational(-2, 4), Rational(-6, 9), Rational(-4, 9)), - "test 4" - ) - } - } - @Test - fun test_Polynomial_Polynomial_times() { - IntModuloRing(35).listPolynomial { - // (1 + x + x^2) * (1 - x + x^2) ?= 1 + x^2 + x^4 - assertEquals( - ListPolynomial(1, 0, 1, 0, 1), - ListPolynomial(1, -1, 1) * ListPolynomial(1, 1, 1), - "test 1" - ) - // Spoiler: 5 * 7 = 0 - assertEquals( - ListPolynomial(0, 0, 0, 0, 0), - ListPolynomial(5, -25, 10) * ListPolynomial(21, 14, -7), - "test 2" - ) - } - } -} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt deleted file mode 100644 index c5eb8fb81..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt +++ /dev/null @@ -1,257 +0,0 @@ -/* - * 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.functions - -import space.kscience.kmath.test.misc.Rational -import space.kscience.kmath.test.misc.RationalField -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertFailsWith - - -class ListPolynomialUtilTest { - @Test - fun test_substitute_Double() { - assertEquals( - 0.0, - ListPolynomial(1.0, -2.0, 1.0).substitute(1.0), - 0.001, - "test 1" - ) - assertEquals( - 1.1931904761904761, - ListPolynomial(0.625, 2.6666666666666665, 0.5714285714285714, 1.5).substitute(0.2), - 0.001, - "test 2" - ) - assertEquals( - 0.5681904761904762, - ListPolynomial(0.0, 2.6666666666666665, 0.5714285714285714, 1.5).substitute(0.2), - 0.001, - "test 3" - ) - assertEquals( - 1.1811904761904761, - ListPolynomial(0.625, 2.6666666666666665, 0.5714285714285714, 0.0).substitute(0.2), - 0.001, - "test 4" - ) - assertEquals( - 1.1703333333333332, - ListPolynomial(0.625, 2.6666666666666665, 0.0, 1.5).substitute(0.2), - 0.001, - "test 5" - ) - } - @Test - fun test_substitute_Constant() { - assertEquals( - Rational(0), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).substitute(RationalField, Rational(1)), - "test 1" - ) - assertEquals( - Rational(25057, 21000), - ListPolynomial(Rational(5,8), Rational(8, 3), Rational(4, 7), Rational(3, 2)) - .substitute(RationalField, Rational(1, 5)), - "test 2" - ) - assertEquals( - Rational(2983, 5250), - ListPolynomial(Rational(0), Rational(8, 3), Rational(4, 7), Rational(3, 2)) - .substitute(RationalField, Rational(1, 5)), - "test 3" - ) - assertEquals( - Rational(4961, 4200), - ListPolynomial(Rational(5,8), Rational(8, 3), Rational(4, 7), Rational(0)) - .substitute(RationalField, Rational(1, 5)), - "test 4" - ) - assertEquals( - Rational(3511, 3000), - ListPolynomial(Rational(5,8), Rational(8, 3), Rational(0), Rational(3, 2)) - .substitute(RationalField, Rational(1, 5)), - "test 5" - ) - } - @Test - fun test_substitute_Polynomial() { - assertEquals( - ListPolynomial(Rational(0)), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).substitute(RationalField, ListPolynomial(Rational(1))), - "test 1" - ) - assertEquals( - ListPolynomial(Rational(709, 378), Rational(155, 252), Rational(19, 525), Rational(2, 875)), - ListPolynomial(Rational(1, 7), Rational(9, 4), Rational(1, 3), Rational(2, 7)) - .substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(1, 5))), - "test 2" - ) - assertEquals( - ListPolynomial(Rational(655, 378), Rational(155, 252), Rational(19, 525), Rational(2, 875)), - ListPolynomial(Rational(0), Rational(9, 4), Rational(1, 3), Rational(2, 7)) - .substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(1, 5))), - "test 3" - ) - assertEquals( - ListPolynomial(Rational(677, 378), Rational(97, 180), Rational(1, 75), Rational(0)), - ListPolynomial(Rational(1, 7), Rational(9, 4), Rational(1, 3), Rational(0)) - .substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(1, 5))), - "test 4" - ) - assertEquals( - ListPolynomial(Rational(653, 378), Rational(221, 420), Rational(4, 175), Rational(2, 875)), - ListPolynomial(Rational(1, 7), Rational(9, 4), Rational(0), Rational(2, 7)) - .substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(1, 5))), - "test 5" - ) - assertEquals( - ListPolynomial(Rational(89, 54), Rational(0), Rational(0), Rational(0)), - ListPolynomial(Rational(0), Rational(9, 4), Rational(1, 3), Rational(0)) - .substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(0))), - "test 6" - ) - } - @Test - fun test_derivative() { - assertEquals( - ListPolynomial(Rational(-2), Rational(2)), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).derivative(RationalField), - "test 1" - ) - assertEquals( - ListPolynomial(Rational(-8, 3), Rational(8, 9), Rational(15, 7), Rational(-20, 9)), - ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).derivative(RationalField), - "test 2" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(8, 9), Rational(15, 7), Rational(-20, 9)), - ListPolynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).derivative(RationalField), - "test 3" - ) - assertEquals( - ListPolynomial(Rational(-8, 3), Rational(8, 9), Rational(15, 7), Rational(0)), - ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).derivative(RationalField), - "test 4" - ) - } - @Test - fun test_nthDerivative() { - assertEquals( - ListPolynomial(Rational(-2), Rational(2)), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 1), - "test 1" - ) - assertFailsWith("test2") { - ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, -1) - } - assertEquals( - ListPolynomial(Rational(1), Rational(-2), Rational(1)), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 0), - "test 3" - ) - assertEquals( - ListPolynomial(Rational(2)), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 2), - "test 4" - ) - assertEquals( - ListPolynomial(), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 3), - "test 5" - ) - assertEquals( - ListPolynomial(), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 4), - "test 6" - ) - assertEquals( - ListPolynomial(Rational(8, 9), Rational(30, 7), Rational(-20, 3)), - ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthDerivative(RationalField, 2), - "test 7" - ) - assertEquals( - ListPolynomial(Rational(8, 9), Rational(30, 7), Rational(-20, 3)), - ListPolynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthDerivative(RationalField, 2), - "test 8" - ) - assertEquals( - ListPolynomial(Rational(8, 9), Rational(30, 7), Rational(0)), - ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).nthDerivative(RationalField, 2), - "test 9" - ) - } - @Test - fun test_antiderivative() { - assertEquals( - ListPolynomial(Rational(0), Rational(1), Rational(-1), Rational(1, 3)), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).antiderivative(RationalField), - "test 1" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(1, 5), Rational(-4, 3), Rational(4, 27), Rational(5, 28), Rational(-1, 9)), - ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).antiderivative(RationalField), - "test 2" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(4, 27), Rational(5, 28), Rational(-1, 9)), - ListPolynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).antiderivative(RationalField), - "test 3" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(1, 5), Rational(-4, 3), Rational(4, 27), Rational(5, 28), Rational(0)), - ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).antiderivative(RationalField), - "test 4" - ) - } - @Test - fun test_nthAntiderivative() { - assertEquals( - ListPolynomial(Rational(0), Rational(1), Rational(-1), Rational(1, 3)), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 1), - "test 1" - ) - assertFailsWith("test2") { - ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, -1) - } - assertEquals( - ListPolynomial(Rational(1), Rational(-2), Rational(1)), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 0), - "test 3" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(1, 2), Rational(-1, 3), Rational(1, 12)), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 2), - "test 4" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(1, 6), Rational(-1, 12), Rational(1, 60)), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 3), - "test 5" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0), Rational(1, 24), Rational(-1, 60), Rational(1, 360)), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 4), - "test 6" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(1, 10), Rational(-4, 9), Rational(1, 27), Rational(1, 28), Rational(-1, 54)), - ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthAntiderivative(RationalField, 2), - "test 7" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0), Rational(1, 27), Rational(1, 28), Rational(-1, 54)), - ListPolynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthAntiderivative(RationalField, 2), - "test 8" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(1, 10), Rational(-4, 9), Rational(1, 27), Rational(1, 28), Rational(0)), - ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).nthAntiderivative(RationalField, 2), - "test 9" - ) - } -} \ No newline at end of file -- 2.34.1 From a2b02ef09e3b077b11db7023eb82882738ff5aca Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sat, 11 Jun 2022 16:15:59 +0300 Subject: [PATCH 062/123] Sifted rest usage of non-basic polynomial things. --- .../kmath/interpolation/Interpolator.kt | 92 ------------ .../kmath/interpolation/LinearInterpolator.kt | 43 ------ .../kmath/interpolation/SplineInterpolator.kt | 83 ---------- .../kmath/integration/SplineIntegralTest.kt | 48 ------ .../interpolation/LinearInterpolatorTest.kt | 29 ---- .../interpolation/SplineInterpolatorTest.kt | 31 ---- .../kscience/kmath/test/misc/IntModulo.kt | 142 ------------------ .../kscience/kmath/test/misc/Rational.kt | 135 ----------------- .../test/misc/RationalWithMemorization.kt | 107 ------------- .../kscience/kmath/test/misc/memorization.kt | 51 ------- .../space/kscience/kmath/test/misc/misc.kt | 31 ---- 11 files changed, 792 deletions(-) delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt delete mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt delete mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt delete mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt delete mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt delete mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt delete mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/RationalWithMemorization.kt delete mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/memorization.kt delete mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt deleted file mode 100644 index 62819be0c..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt +++ /dev/null @@ -1,92 +0,0 @@ -/* - * 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. - */ - -@file:OptIn(UnstableKMathAPI::class) - -package space.kscience.kmath.interpolation - -import space.kscience.kmath.data.XYColumnarData -import space.kscience.kmath.functions.PiecewisePolynomial -import space.kscience.kmath.functions.asFunction -import space.kscience.kmath.functions.substitute -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.asBuffer - -/** - * And interpolator for data with x column type [X], y column type [Y]. - */ -public fun interface Interpolator { - public fun interpolate(points: XYColumnarData): (X) -> Y -} - -/** - * And interpolator returning [PiecewisePolynomial] function - */ -public interface PolynomialInterpolator> : Interpolator { - public val algebra: Ring - - public fun getDefaultValue(): T = error("Out of bounds") - - public fun interpolatePolynomials(points: XYColumnarData): PiecewisePolynomial - - override fun interpolate(points: XYColumnarData): (T) -> T = { x -> - interpolatePolynomials(points).substitute(algebra, x) ?: getDefaultValue() - } -} - - -public fun > PolynomialInterpolator.interpolatePolynomials( - x: Buffer, - y: Buffer, -): PiecewisePolynomial { - val pointSet = XYColumnarData.of(x, y) - return interpolatePolynomials(pointSet) -} - -public fun > PolynomialInterpolator.interpolatePolynomials( - data: Map, -): PiecewisePolynomial { - val pointSet = XYColumnarData.of(data.keys.toList().asBuffer(), data.values.toList().asBuffer()) - return interpolatePolynomials(pointSet) -} - -public fun > PolynomialInterpolator.interpolatePolynomials( - data: List>, -): PiecewisePolynomial { - val pointSet = XYColumnarData.of(data.map { it.first }.asBuffer(), data.map { it.second }.asBuffer()) - return interpolatePolynomials(pointSet) -} - -public fun > PolynomialInterpolator.interpolate( - x: Buffer, - y: Buffer, -): (T) -> T? = interpolatePolynomials(x, y).asFunction(algebra) - -public fun > PolynomialInterpolator.interpolate( - data: Map, -): (T) -> T? = interpolatePolynomials(data).asFunction(algebra) - -public fun > PolynomialInterpolator.interpolate( - data: List>, -): (T) -> T? = interpolatePolynomials(data).asFunction(algebra) - - -public fun > PolynomialInterpolator.interpolate( - x: Buffer, - y: Buffer, - defaultValue: T, -): (T) -> T = interpolatePolynomials(x, y).asFunction(algebra, defaultValue) - -public fun > PolynomialInterpolator.interpolate( - data: Map, - defaultValue: T, -): (T) -> T = interpolatePolynomials(data).asFunction(algebra, defaultValue) - -public fun > PolynomialInterpolator.interpolate( - data: List>, - defaultValue: T, -): (T) -> T = interpolatePolynomials(data).asFunction(algebra, defaultValue) \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt deleted file mode 100644 index b55f16cf2..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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.interpolation - -import space.kscience.kmath.data.XYColumnarData -import space.kscience.kmath.functions.PiecewisePolynomial -import space.kscience.kmath.functions.ListPolynomial -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.Field -import space.kscience.kmath.operations.invoke - -@OptIn(UnstableKMathAPI::class) -internal fun > insureSorted(points: XYColumnarData<*, T, *>) { - for (i in 0 until points.size - 1) - require(points.x[i + 1] > points.x[i]) { "Input data is not sorted at index $i" } -} - -/** - * Reference JVM implementation: https://github.com/apache/commons-math/blob/master/src/main/java/org/apache/commons/math4/analysis/interpolation/LinearInterpolator.java - */ -public class LinearInterpolator>(override val algebra: Field) : PolynomialInterpolator { - - @OptIn(UnstableKMathAPI::class) - override fun interpolatePolynomials(points: XYColumnarData): PiecewisePolynomial = algebra { - require(points.size > 0) { "Point array should not be empty" } - insureSorted(points) - - PiecewisePolynomial(points.x[0]) { - for (i in 0 until points.size - 1) { - val slope = (points.y[i + 1] - points.y[i]) / (points.x[i + 1] - points.x[i]) - val const = points.y[i] - slope * points.x[i] - val polynomial = ListPolynomial(const, slope) - putRight(points.x[i + 1], polynomial) - } - } - } -} - -public val > Field.linearInterpolator: LinearInterpolator - get() = LinearInterpolator(this) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt deleted file mode 100644 index 48c90ff23..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt +++ /dev/null @@ -1,83 +0,0 @@ -/* - * 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.interpolation - -import space.kscience.kmath.data.XYColumnarData -import space.kscience.kmath.functions.PiecewisePolynomial -import space.kscience.kmath.functions.ListPolynomial -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.Field -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.structures.DoubleBuffer -import space.kscience.kmath.structures.MutableBufferFactory - -/** - * Generic spline interpolator. Not recommended for performance critical places, use platform-specific and type - * specific ones. - * - * Based on - * https://github.com/apache/commons-math/blob/eb57d6d457002a0bb5336d789a3381a24599affe/src/main/java/org/apache/commons/math4/analysis/interpolation/SplineInterpolator.java - */ -public class SplineInterpolator>( - override val algebra: Field, - public val bufferFactory: MutableBufferFactory, -) : PolynomialInterpolator { - //TODO possibly optimize zeroed buffers - - @OptIn(UnstableKMathAPI::class) - override fun interpolatePolynomials(points: XYColumnarData): PiecewisePolynomial = algebra { - require(points.size >= 3) { "Can't use spline interpolator with less than 3 points" } - insureSorted(points) - // Number of intervals. The number of data points is n + 1. - val n = points.size - 1 - // Differences between knot points - val h = bufferFactory(n) { i -> points.x[i + 1] - points.x[i] } - val mu = bufferFactory(n) { zero } - val z = bufferFactory(n + 1) { zero } - - for (i in 1 until n) { - val g = 2.0 * (points.x[i + 1] - points.x[i - 1]) - h[i - 1] * mu[i - 1] - mu[i] = h[i] / g - z[i] = - ((points.y[i + 1] * h[i - 1] - points.y[i] * (points.x[i + 1] - points.x[i - 1]) + points.y[i - 1] * h[i]) * 3.0 / - (h[i - 1] * h[i]) - h[i - 1] * z[i - 1]) / g - } - - // cubic spline coefficients -- b is linear, c quadratic, d is cubic (original y's are constants) - - PiecewisePolynomial(points.x[points.size - 1]) { - var cOld = zero - - for (j in n - 1 downTo 0) { - val c = z[j] - mu[j] * cOld - val a = points.y[j] - val b = (points.y[j + 1] - points.y[j]) / h[j] - h[j] * (cOld + 2.0 * c) / 3.0 - val d = (cOld - c) / (3.0 * h[j]) - val x0 = points.x[j] - val x02 = x0 * x0 - val x03 = x02 * x0 - //Shift coefficients to represent absolute polynomial instead of one with an offset - val polynomial = ListPolynomial( - a - b * x0 + c * x02 - d * x03, - b - 2 * c * x0 + 3 * d * x02, - c - 3 * d * x0, - d - ) - cOld = c - putLeft(x0, polynomial) - } - } - } -} - - -public fun > Field.splineInterpolator( - bufferFactory: MutableBufferFactory, -): SplineInterpolator = SplineInterpolator(this, bufferFactory) - -public val DoubleField.splineInterpolator: SplineInterpolator - get() = SplineInterpolator(this, ::DoubleBuffer) \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt deleted file mode 100644 index aae0ad017..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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.integration - -import space.kscience.kmath.functions.ListPolynomial -import space.kscience.kmath.functions.integrate -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.DoubleField -import kotlin.math.PI -import kotlin.math.sin -import kotlin.test.Test -import kotlin.test.assertEquals - -@OptIn(UnstableKMathAPI::class) -class SplineIntegralTest { - - @Test - fun integratePolynomial(){ - val polynomial = ListPolynomial(1.0, 2.0, 3.0) - val integral = polynomial.integrate(DoubleField,1.0..2.0) - assertEquals(11.0, integral, 0.001) - } - - @Test - fun gaussSin() { - val res = DoubleField.splineIntegrator.integrate(0.0..2 * PI, IntegrandMaxCalls(5)) { x -> - sin(x) - } - assertEquals(0.0, res.value, 1e-2) - } - - @Test - fun gaussUniform() { - val res = DoubleField.splineIntegrator.integrate(35.0..100.0, IntegrandMaxCalls(20)) { x -> - if(x in 30.0..50.0){ - 1.0 - } else { - 0.0 - } - } - assertEquals(15.0, res.value, 0.5) - } - - -} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt deleted file mode 100644 index 1143036d4..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt +++ /dev/null @@ -1,29 +0,0 @@ -/* - * 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.interpolation - -import space.kscience.kmath.operations.DoubleField -import kotlin.test.Test -import kotlin.test.assertEquals - -internal class LinearInterpolatorTest { - @Test - fun testInterpolation() { - val data = listOf( - 0.0 to 0.0, - 1.0 to 1.0, - 2.0 to 3.0, - 3.0 to 4.0 - ) - - //val polynomial: PiecewisePolynomial = DoubleField.linearInterpolator.interpolatePolynomials(data) - val function = DoubleField.linearInterpolator.interpolate(data) - assertEquals(null, function(-1.0)) - assertEquals(0.5, function(0.5)) - assertEquals(2.0, function(1.5)) - assertEquals(3.0, function(2.0)) - } -} diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt deleted file mode 100644 index 4c7d816d4..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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.interpolation - -import space.kscience.kmath.operations.DoubleField -import kotlin.math.PI -import kotlin.math.sin -import kotlin.test.Test -import kotlin.test.assertEquals - -internal class SplineInterpolatorTest { - @Test - fun testInterpolation() { - val data = (0..10).map { - val x = it.toDouble() / 5 * PI - x to sin(x) - } - - //val polynomial: PiecewisePolynomial = DoubleField.splineInterpolator.interpolatePolynomials(data) - - val function = DoubleField.splineInterpolator.interpolate(data, Double.NaN) - - assertEquals(Double.NaN, function(-1.0)) - assertEquals(sin(0.5), function(0.5), 0.1) - assertEquals(sin(1.5), function(1.5), 0.1) - assertEquals(sin(2.0), function(2.0), 0.1) - } -} diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt deleted file mode 100644 index 2353beee6..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt +++ /dev/null @@ -1,142 +0,0 @@ -/* - * 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.functions.ListPolynomial -import space.kscience.kmath.functions.ListPolynomialSpace -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.Ring - - -class IntModulo { - val residue: Int - val modulus: Int - - @PublishedApi - internal constructor(residue: Int, modulus: Int, toCheckInput: Boolean = true) { - if (toCheckInput) { - require(modulus != 0) { "modulus can not be zero" } - this.modulus = if (modulus < 0) -modulus else modulus - this.residue = residue.mod(modulus) - } else { - this.residue = residue - this.modulus = modulus - } - } - - constructor(residue: Int, modulus: Int) : this(residue, modulus, true) - - operator fun unaryPlus(): IntModulo = this - operator fun unaryMinus(): IntModulo = - IntModulo( - if (residue == 0) 0 else modulus - residue, - modulus, - toCheckInput = false - ) - operator fun plus(other: IntModulo): IntModulo { - require(modulus == other.modulus) { "can not add two residue different modulo" } - return IntModulo( - (residue + other.residue) % modulus, - modulus, - toCheckInput = false - ) - } - operator fun plus(other: Int): IntModulo = - IntModulo( - (residue + other) % modulus, - modulus, - toCheckInput = false - ) - operator fun minus(other: IntModulo): IntModulo { - require(modulus == other.modulus) { "can not subtract two residue different modulo" } - return IntModulo( - (residue - other.residue) % modulus, - modulus, - toCheckInput = false - ) - } - operator fun minus(other: Int): IntModulo = - IntModulo( - (residue - other) % modulus, - modulus, - toCheckInput = false - ) - operator fun times(other: IntModulo): IntModulo { - require(modulus == other.modulus) { "can not multiply two residue different modulo" } - return IntModulo( - (residue * other.residue) % modulus, - modulus, - toCheckInput = false - ) - } - operator fun times(other: Int): IntModulo = - IntModulo( - (residue * other) % modulus, - modulus, - toCheckInput = false - ) - operator fun div(other: IntModulo): IntModulo { - require(modulus == other.modulus) { "can not divide two residue different modulo" } - val (reciprocalCandidate, gcdOfOtherResidueAndModulus) = bezoutIdentityWithGCD(other.residue, modulus) - require(gcdOfOtherResidueAndModulus == 1) { "can not divide to residue that has non-trivial GCD with modulo" } - return IntModulo( - (residue * reciprocalCandidate) % modulus, - modulus, - toCheckInput = false - ) - } - operator fun div(other: Int): IntModulo { - val (reciprocalCandidate, gcdOfOtherResidueAndModulus) = bezoutIdentityWithGCD(other, modulus) - require(gcdOfOtherResidueAndModulus == 1) { "can not divide to residue that has non-trivial GCD with modulo" } - return IntModulo( - (residue * reciprocalCandidate) % modulus, - modulus, - toCheckInput = false - ) - } - override fun equals(other: Any?): Boolean = - when (other) { - is IntModulo -> residue == other.residue && modulus == other.modulus - else -> false - } - - override fun hashCode(): Int = residue.hashCode() - - override fun toString(): String = "$residue mod $modulus" -} - -@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") -@OptIn(UnstableKMathAPI::class) -class IntModuloRing : Ring { - - val modulus: Int - - constructor(modulus: Int) { - require(modulus != 0) { "modulus can not be zero" } - this.modulus = if (modulus < 0) -modulus else modulus - } - - override inline val zero: IntModulo get() = IntModulo(0, modulus, toCheckInput = false) - override inline val one: IntModulo get() = IntModulo(1, modulus, toCheckInput = false) - - fun number(arg: Int) = IntModulo(arg, modulus, toCheckInput = false) - - override inline fun add(left: IntModulo, right: IntModulo): IntModulo = left + right - override inline fun multiply(left: IntModulo, right: IntModulo): IntModulo = left * right - - override inline fun IntModulo.unaryMinus(): IntModulo = -this - override inline fun IntModulo.plus(arg: IntModulo): IntModulo = this + arg - override inline fun IntModulo.minus(arg: IntModulo): IntModulo = this - arg - override inline fun IntModulo.times(arg: IntModulo): IntModulo = this * arg - inline fun IntModulo.div(arg: IntModulo): IntModulo = this / arg -} - -fun ListPolynomialSpace.number(arg: Int) = IntModulo(arg, ring.modulus, toCheckInput = false) - -fun ListPolynomialSpace.ListPolynomial(vararg coefs: Int): ListPolynomial = - ListPolynomial(coefs.map { IntModulo(it, ring.modulus) }) -fun IntModuloRing.ListPolynomial(vararg coefs: Int): ListPolynomial = - ListPolynomial(coefs.map { IntModulo(it, modulus) }) \ No newline at end of file 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 deleted file mode 100644 index 72bb5942c..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt +++ /dev/null @@ -1,135 +0,0 @@ -/* - * 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.Field -import space.kscience.kmath.operations.NumbersAddOps - -class Rational { - companion object { - val ZERO: Rational = Rational(0L) - val ONE: Rational = Rational(1L) - } - - val numerator: Long - val denominator: Long - - internal constructor(numerator: Long, denominator: Long, toCheckInput: Boolean = true) { - if (toCheckInput) { - if (denominator == 0L) throw ArithmeticException("/ by zero") - - val greatestCommonDivider = gcd(numerator, denominator).let { if (denominator < 0L) -it else it } - - this.numerator = numerator / greatestCommonDivider - this.denominator = denominator / greatestCommonDivider - } else { - this.numerator = numerator - this.denominator = denominator - } - } - - constructor(numerator: Int, denominator: Int) : this(numerator.toLong(), denominator.toLong(), true) - constructor(numerator: Int, denominator: Long) : this(numerator.toLong(), denominator, true) - constructor(numerator: Long, denominator: Int) : this(numerator, denominator.toLong(), true) - constructor(numerator: Long, denominator: Long) : this(numerator, denominator, true) - constructor(numerator: Int) : this(numerator.toLong(), 1L, false) - constructor(numerator: Long) : this(numerator, 1L, false) - - operator fun unaryPlus(): Rational = this - operator fun unaryMinus(): Rational = Rational(-this.numerator, this.denominator) - operator fun plus(other: Rational): Rational = - Rational( - numerator * other.denominator + denominator * other.numerator, - denominator * other.denominator - ) - operator fun plus(other: Int): Rational = - Rational( - numerator + denominator * other.toLong(), - denominator - ) - operator fun plus(other: Long): Rational = - Rational( - numerator + denominator * other, - denominator - ) - operator fun minus(other: Rational): Rational = - Rational( - numerator * other.denominator - denominator * other.numerator, - denominator * other.denominator - ) - operator fun minus(other: Int): Rational = - Rational( - numerator - denominator * other.toLong(), - denominator - ) - operator fun minus(other: Long): Rational = - Rational( - numerator - denominator * other, - denominator - ) - operator fun times(other: Rational): Rational = - Rational( - numerator * other.numerator, - denominator * other.denominator - ) - operator fun times(other: Int): Rational = - Rational( - numerator * other.toLong(), - denominator - ) - operator fun times(other: Long): Rational = - Rational( - numerator * other, - denominator - ) - operator fun div(other: Rational): Rational = - Rational( - numerator * other.denominator, - denominator * other.numerator - ) - operator fun div(other: Int): Rational = - Rational( - numerator, - denominator * other.toLong() - ) - operator fun div(other: Long): Rational = - Rational( - numerator, - denominator * other - ) - override fun equals(other: Any?): Boolean = - when (other) { - is Rational -> numerator == other.numerator && denominator == other.denominator - is Int -> numerator == other && denominator == 1L - is Long -> numerator == other && denominator == 1L - else -> false - } - - override fun hashCode(): Int = 31 * numerator.hashCode() + denominator.hashCode() - - override fun toString(): String = if (denominator == 1L) "$numerator" else "$numerator/$denominator" -} - -@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") -@OptIn(UnstableKMathAPI::class) -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 deleted file mode 100644 index 05d9115fa..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/RationalWithMemorization.kt +++ /dev/null @@ -1,107 +0,0 @@ -/* - * 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 { - 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 {}) - } - constructor(numerator: Int, denominator: Int) : this(Rational(numerator, denominator), object : Endpoint {}) - constructor(numerator: Int, denominator: Long) : this(Rational(numerator, denominator), object : Endpoint {}) - constructor(numerator: Long, denominator: Int) : this(Rational(numerator, denominator), object : Endpoint {}) - constructor(numerator: Long, denominator: Long) : this(Rational(numerator, denominator), object : Endpoint {}) - constructor(numerator: Int) : this(Rational(numerator), object : Endpoint {}) - constructor(numerator: Long) : this(Rational(numerator), object : Endpoint {}) - - operator fun unaryPlus(): RationalWithMemorization = this - operator fun unaryMinus(): RationalWithMemorization = RationalWithMemorization( - -value, - object : Negation { - override val negated: OperationsMemory = memory - } - ) - operator fun plus(other: RationalWithMemorization): RationalWithMemorization = RationalWithMemorization( - value + other.value, - object : Sum { - override val augend: OperationsMemory = memory - override val addend: OperationsMemory = other.memory - } - ) - operator fun minus(other: RationalWithMemorization): RationalWithMemorization = RationalWithMemorization( - value - other.value, - object : Difference { - override val minuend: OperationsMemory = memory - override val subtrahend: OperationsMemory = other.memory - } - ) - operator fun times(other: RationalWithMemorization): RationalWithMemorization = RationalWithMemorization( - value * other.value, - object : Product { - override val multiplicand: OperationsMemory = memory - override val multiplier: OperationsMemory = other.memory - } - ) - operator fun div(other: RationalWithMemorization): RationalWithMemorization = RationalWithMemorization( - value / other.value, - object : Quotient { - override val dividend: OperationsMemory = memory - override val divisor: OperationsMemory = other.memory - } - ) - - override fun equals(other: Any?): Boolean = - other is RationalWithMemorization && value == other.value - - override fun hashCode(): Int = value.hashCode() - - override fun toString(): String = value.toString() -} - -@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") -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") -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 deleted file mode 100644 index a4fb81274..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/memorization.kt +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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 deleted file mode 100644 index cc647fa2c..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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 - -// TODO: Move to corresponding module "kmath-number-theory" - -import kotlin.math.abs - - -data class BezoutIdentityWithGCD(val first: T, val second: T, val gcd: T) - -tailrec fun gcd(a: Long, b: Long): Long = if (a == 0L) abs(b) else gcd(b % a, a) - -fun bezoutIdentityWithGCD(a: Int, b: Int): BezoutIdentityWithGCD = - when { - a < 0 && b < 0 -> with(bezoutIdentityWithGCDInternalLogic(-a, -b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(-first, -second, gcd) } - a < 0 -> with(bezoutIdentityWithGCDInternalLogic(-a, b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(-first, second, gcd) } - b < 0 -> with(bezoutIdentityWithGCDInternalLogic(a, -b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(first, -second, gcd) } - else -> bezoutIdentityWithGCDInternalLogic(a, b, 1, 0, 0, 1) - } - -internal tailrec fun bezoutIdentityWithGCDInternalLogic(a: Int, b: Int, m1: Int, m2: Int, m3: Int, m4: Int): BezoutIdentityWithGCD = - if (b == 0) BezoutIdentityWithGCD(m1, m3, a) - else { - val quotient = a / b - val reminder = a % b - bezoutIdentityWithGCDInternalLogic(b, reminder, m2, m1 - quotient * m2, m4, m3 - quotient * m4) - } \ No newline at end of file -- 2.34.1 From 8af183a969e2099cea5d3c293be319e7aa1b0080 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sat, 11 Jun 2022 19:22:57 +0300 Subject: [PATCH 063/123] Fixed typos. Added docstrings. Added variable convertional methods. --- .../kscience/kmath/functions/Polynomial.kt | 150 ++++-- .../kmath/functions/RationalFunction.kt | 467 +++++++++++++----- 2 files changed, 468 insertions(+), 149 deletions(-) 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 e201f1f6e..f2eba10d5 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 @@ -25,38 +25,38 @@ public interface Polynomial @Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") // FIXME: Waiting for KT-31420 public interface PolynomialSpace> : Ring

{ /** - * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * Returns sum of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. */ public operator fun C.plus(other: Int): C /** - * Returns difference between the constant and the integer represented as constant (member of underlying ring). + * Returns difference between the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. */ public operator fun C.minus(other: Int): C /** - * Returns product of the constant and the integer represented as constant (member of underlying ring). + * Returns product of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to sum of [other] copies of [this]. */ public operator fun C.times(other: Int): C /** - * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * Returns sum of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. */ public operator fun Int.plus(other: C): C /** - * Returns difference between the integer represented as constant (member of underlying ring) and the constant. + * Returns difference between the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. */ public operator fun Int.minus(other: C): C /** - * Returns product of the integer represented as constant (member of underlying ring) and the constant. + * Returns product of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -72,38 +72,38 @@ public interface PolynomialSpace> : Ring

{ public fun Int.asConstant(): C = constantNumber(this) /** - * Returns sum of the polynomial and the integer represented as polynomial. + * Returns sum of the polynomial and the integer represented as a polynomial. * * The operation is equivalent to adding [other] copies of unit polynomial to [this]. */ public operator fun P.plus(other: Int): P = addMultipliedByDoubling(this, one, other) /** - * Returns difference between the polynomial and the integer represented as polynomial. + * Returns difference between the polynomial and the integer represented as a polynomial. * * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. */ public operator fun P.minus(other: Int): P = addMultipliedByDoubling(this, one, -other) /** - * Returns product of the polynomial and the integer represented as polynomial. + * Returns product of the polynomial and the integer represented as a polynomial. * * The operation is equivalent to sum of [other] copies of [this]. */ public operator fun P.times(other: Int): P = multiplyByDoubling(this, other) /** - * Returns sum of the integer represented as polynomial and the polynomial. + * Returns sum of the integer represented as a polynomial and the polynomial. * * The operation is equivalent to adding [this] copies of unit polynomial to [other]. */ public operator fun Int.plus(other: P): P = addMultipliedByDoubling(other, one, this) /** - * Returns difference between the integer represented as polynomial and the polynomial. + * Returns difference between the integer represented as a polynomial and the polynomial. * * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. */ public operator fun Int.minus(other: P): P = addMultipliedByDoubling(-other, one, this) /** - * Returns product of the integer represented as polynomial and the polynomial. + * Returns product of the integer represented as a polynomial and the polynomial. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -165,28 +165,28 @@ public interface PolynomialSpace> : Ring

{ public val constantOne: C /** - * Returns sum of the constant represented as polynomial and the polynomial. + * Returns sum of the constant represented as a polynomial and the polynomial. */ public operator fun C.plus(other: P): P /** - * Returns difference between the constant represented as polynomial and the polynomial. + * Returns difference between the constant represented as a polynomial and the polynomial. */ public operator fun C.minus(other: P): P /** - * Returns product of the constant represented as polynomial and the polynomial. + * Returns product of the constant represented as a polynomial and the polynomial. */ public operator fun C.times(other: P): P /** - * Returns sum of the constant represented as polynomial and the polynomial. + * Returns sum of the constant represented as a polynomial and the polynomial. */ public operator fun P.plus(other: C): P /** - * Returns difference between the constant represented as polynomial and the polynomial. + * Returns difference between the constant represented as a polynomial and the polynomial. */ public operator fun P.minus(other: C): P /** - * Returns product of the constant represented as polynomial and the polynomial. + * Returns product of the constant represented as a polynomial and the polynomial. */ public operator fun P.times(other: C): P @@ -254,41 +254,44 @@ public interface PolynomialSpace> : Ring

{ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public interface PolynomialSpaceOverRing, A: Ring> : PolynomialSpace { + /** + * Underlying ring of constants. Its operations on constants are inherited by local operations on constants. + */ public val ring: A /** - * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * Returns sum of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. */ public override operator fun C.plus(other: Int): C = ring { addMultipliedByDoubling(this@plus, one, other) } /** - * Returns difference between the constant and the integer represented as constant (member of underlying ring). + * Returns difference between the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. */ public override operator fun C.minus(other: Int): C = ring { addMultipliedByDoubling(this@minus, one, -other) } /** - * Returns product of the constant and the integer represented as constant (member of underlying ring). + * Returns product of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to sum of [other] copies of [this]. */ public override operator fun C.times(other: Int): C = ring { multiplyByDoubling(this@times, other) } /** - * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * Returns sum of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. */ public override operator fun Int.plus(other: C): C = ring { addMultipliedByDoubling(other, one, this@plus) } /** - * Returns difference between the integer represented as constant (member of underlying ring) and the constant. + * Returns difference between the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. */ public override operator fun Int.minus(other: C): C = ring { addMultipliedByDoubling(-other, one, this@minus) } /** - * Returns product of the integer represented as constant (member of underlying ring) and the constant. + * Returns product of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -330,58 +333,143 @@ public interface PolynomialSpaceOverRing, A: Ring> : Poly public override val constantOne: C get() = ring.one } +/** + * Abstraction of ring of polynomials of type [P] of variables of type [V] and over ring of constants of type [C]. + * + * @param C the type of constants. Polynomials have them as coefficients in their terms. + * @param V the type of variables. Polynomials have them in representations of terms. + * @param P the type of polynomials. + */ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public interface MultivariatePolynomialSpace>: PolynomialSpace { + /** + * Returns sum of the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("plusVariableInt") public operator fun V.plus(other: Int): P + /** + * Returns difference between the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("minusVariableInt") public operator fun V.minus(other: Int): P + /** + * Returns product of the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("timesVariableInt") public operator fun V.times(other: Int): P + /** + * Returns sum of the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("plusIntVariable") public operator fun Int.plus(other: V): P + /** + * Returns difference between the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("minusIntVariable") public operator fun Int.minus(other: V): P + /** + * Returns product of the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("timesIntVariable") public operator fun Int.times(other: V): P - @JvmName("plusConstantVariable") - public operator fun C.plus(other: V): P - @JvmName("minusConstantVariable") - public operator fun C.minus(other: V): P - @JvmName("timesConstantVariable") - public operator fun C.times(other: V): P - + /** + * Returns sum of the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("plusVariableConstant") public operator fun V.plus(other: C): P + /** + * Returns difference between the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("minusVariableConstant") public operator fun V.minus(other: C): P + /** + * Returns product of the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("timesVariableConstant") public operator fun V.times(other: C): P + /** + * Returns sum of the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("plusConstantVariable") + public operator fun C.plus(other: V): P + /** + * Returns difference between the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("minusConstantVariable") + public operator fun C.minus(other: V): P + /** + * Returns product of the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("timesConstantVariable") + public operator fun C.times(other: V): P + + /** + * Represents the variable as a monic monomial. + */ @JvmName("unaryPlusVariable") public operator fun V.unaryPlus(): P + /** + * Returns negation of representation of the variable as a monic monomial. + */ @JvmName("unaryMinusVariable") public operator fun V.unaryMinus(): P + /** + * Returns sum of the variables represented as monic monomials. + */ @JvmName("plusVariableVariable") public operator fun V.plus(other: V): P + /** + * Returns difference between the variables represented as monic monomials. + */ @JvmName("minusVariableVariable") public operator fun V.minus(other: V): P + /** + * Returns product of the variables represented as monic monomials. + */ @JvmName("timesVariableVariable") public operator fun V.times(other: V): P + /** + * Represents the [variable] as a monic monomial. + */ + public fun number(variable: V): P = +variable + /** + * Represents the variable as a monic monomial. + */ + public fun V.asPolynomial(): P = number(this) + + /** + * Returns sum of the variable represented as a monic monomial and the polynomial. + */ @JvmName("plusVariablePolynomial") public operator fun V.plus(other: P): P + /** + * Returns difference between the variable represented as a monic monomial and the polynomial. + */ @JvmName("minusVariablePolynomial") public operator fun V.minus(other: P): P + /** + * Returns product of the variable represented as a monic monomial and the polynomial. + */ @JvmName("timesVariablePolynomial") public operator fun V.times(other: P): P + /** + * Returns sum of the polynomial and the variable represented as a monic monomial. + */ @JvmName("plusPolynomialVariable") public operator fun P.plus(other: V): P + /** + * Returns difference between the polynomial and the variable represented as a monic monomial. + */ @JvmName("minusPolynomialVariable") public operator fun P.minus(other: V): P + /** + * Returns product of the polynomial and the variable represented as a monic monomial. + */ @JvmName("timesPolynomialVariable") public operator fun P.times(other: V): P diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt index dfec126f3..edc9dfa5c 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt @@ -25,44 +25,44 @@ public interface RationalFunction> { * [C]. * * @param C the type of constants. Polynomials have them as coefficients in their terms. - * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. + * @param P the type of polynomials. Rational functions have them as numerators and denominators. * @param R the type of rational functions. */ @Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") // FIXME: Waiting for KT-31420 public interface RationalFunctionalSpace, R: RationalFunction> : Ring { /** - * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * Returns sum of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. */ public operator fun C.plus(other: Int): C /** - * Returns difference between the constant and the integer represented as constant (member of underlying ring). + * Returns difference between the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. */ public operator fun C.minus(other: Int): C /** - * Returns product of the constant and the integer represented as constant (member of underlying ring). + * Returns product of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to sum of [other] copies of [this]. */ public operator fun C.times(other: Int): C /** - * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * Returns sum of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. */ public operator fun Int.plus(other: C): C /** - * Returns difference between the integer represented as constant (member of underlying ring) and the constant. + * Returns difference between the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. */ public operator fun Int.minus(other: C): C /** - * Returns product of the integer represented as constant (member of underlying ring) and the constant. + * Returns product of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -78,38 +78,38 @@ public interface RationalFunctionalSpace, R: RationalFunctio public fun Int.asConstant(): C = constantNumber(this) /** - * Returns sum of the constant and the integer represented as polynomial. + * Returns sum of the constant and the integer represented as a polynomial. * * The operation is equivalent to adding [other] copies of unit polynomial to [this]. */ public operator fun P.plus(other: Int): P /** - * Returns difference between the constant and the integer represented as polynomial. + * Returns difference between the constant and the integer represented as a polynomial. * * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. */ public operator fun P.minus(other: Int): P /** - * Returns product of the constant and the integer represented as polynomial. + * Returns product of the constant and the integer represented as a polynomial. * * The operation is equivalent to sum of [other] copies of [this]. */ public operator fun P.times(other: Int): P /** - * Returns sum of the integer represented as polynomial and the constant. + * Returns sum of the integer represented as a polynomial and the constant. * * The operation is equivalent to adding [this] copies of unit polynomial to [other]. */ public operator fun Int.plus(other: P): P /** - * Returns difference between the integer represented as polynomial and the constant. + * Returns difference between the integer represented as a polynomial and the constant. * * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. */ public operator fun Int.minus(other: P): P /** - * Returns product of the integer represented as polynomial and the constant. + * Returns product of the integer represented as a polynomial and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -125,25 +125,25 @@ public interface RationalFunctionalSpace, R: RationalFunctio public fun Int.asPolynomial(): P = polynomialNumber(this) /** - * Returns sum of the rational function and the integer represented as rational function. + * Returns sum of the rational function and the integer represented as a rational function. * * The operation is equivalent to adding [other] copies of unit polynomial to [this]. */ public operator fun R.plus(other: Int): R = addMultipliedByDoubling(this, one, other) /** - * Returns difference between the rational function and the integer represented as rational function. + * Returns difference between the rational function and the integer represented as a rational function. * * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. */ public operator fun R.minus(other: Int): R = addMultipliedByDoubling(this, one, -other) /** - * Returns product of the rational function and the integer represented as rational function. + * Returns product of the rational function and the integer represented as a rational function. * * The operation is equivalent to sum of [other] copies of [this]. */ public operator fun R.times(other: Int): R = multiplyByDoubling(this, other) /** - * Returns quotient of the rational function and the integer represented as rational function. + * Returns quotient of the rational function and the integer represented as a rational function. * * The operation is equivalent to creating a new rational function by preserving numerator of [this] and * multiplication denominator of [this] to [other]. @@ -151,25 +151,25 @@ public interface RationalFunctionalSpace, R: RationalFunctio public operator fun R.div(other: Int): R = this / multiplyByDoubling(one, other) /** - * Returns sum of the integer represented as rational function and the rational function. + * Returns sum of the integer represented as a rational function and the rational function. * * The operation is equivalent to adding [this] copies of unit polynomial to [other]. */ public operator fun Int.plus(other: R): R = addMultipliedByDoubling(other, one, this) /** - * Returns difference between the integer represented as rational function and the rational function. + * Returns difference between the integer represented as a rational function and the rational function. * * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. */ public operator fun Int.minus(other: R): R = addMultipliedByDoubling(-other, one, this) /** - * Returns product of the integer represented as rational function and the rational function. + * Returns product of the integer represented as a rational function and the rational function. * * The operation is equivalent to sum of [this] copies of [other]. */ public operator fun Int.times(other: R): R = multiplyByDoubling(other, this) /** - * Returns quotient of the integer represented as rational function and the rational function. + * Returns quotient of the integer represented as a rational function and the rational function. * * The operation is equivalent to creating a new rational function which numerator is [this] times denominator of * [other] and which denominator is [other]'s numerator. @@ -232,28 +232,28 @@ public interface RationalFunctionalSpace, R: RationalFunctio public val constantOne: C /** - * Returns sum of the constant represented as polynomial and the polynomial. + * Returns sum of the constant represented as a polynomial and the polynomial. */ public operator fun C.plus(other: P): P /** - * Returns difference between the constant represented as polynomial and the polynomial. + * Returns difference between the constant represented as a polynomial and the polynomial. */ public operator fun C.minus(other: P): P /** - * Returns product of the constant represented as polynomial and the polynomial. + * Returns product of the constant represented as a polynomial and the polynomial. */ public operator fun C.times(other: P): P /** - * Returns sum of the constant represented as polynomial and the polynomial. + * Returns sum of the constant represented as a polynomial and the polynomial. */ public operator fun P.plus(other: C): P /** - * Returns difference between the constant represented as polynomial and the polynomial. + * Returns difference between the constant represented as a polynomial and the polynomial. */ public operator fun P.minus(other: C): P /** - * Returns product of the constant represented as polynomial and the polynomial. + * Returns product of the constant represented as a polynomial and the polynomial. */ public operator fun P.times(other: C): P @@ -305,36 +305,36 @@ public interface RationalFunctionalSpace, R: RationalFunctio public val polynomialOne: P /** - * Returns sum of the constant represented as rational function and the rational function. + * Returns sum of the constant represented as a rational function and the rational function. */ public operator fun C.plus(other: R): R /** - * Returns difference between the constant represented as polynomial and the rational function. + * Returns difference between the constant represented as a polynomial and the rational function. */ public operator fun C.minus(other: R): R /** - * Returns product of the constant represented as polynomial and the rational function. + * Returns product of the constant represented as a polynomial and the rational function. */ public operator fun C.times(other: R): R /** - * Returns quotient of the constant represented as polynomial and the rational function. + * Returns quotient of the constant represented as a polynomial and the rational function. */ public operator fun C.div(other: R): R /** - * Returns sum of the rational function and the constant represented as rational function. + * Returns sum of the rational function and the constant represented as a rational function. */ public operator fun R.plus(other: C): R /** - * Returns difference between the rational function and the constant represented as rational function. + * Returns difference between the rational function and the constant represented as a rational function. */ public operator fun R.minus(other: C): R /** - * Returns product of the rational function and the constant represented as rational function. + * Returns product of the rational function and the constant represented as a rational function. */ public operator fun R.times(other: C): R /** - * Returns quotient of the rational function and the constant represented as rational function. + * Returns quotient of the rational function and the constant represented as a rational function. */ public operator fun R.div(other: C): R @@ -348,36 +348,36 @@ public interface RationalFunctionalSpace, R: RationalFunctio public fun C.asRationalFunction(): R = number(this) /** - * Returns sum of the polynomial represented as rational function and the rational function. + * Returns sum of the polynomial represented as a rational function and the rational function. */ public operator fun P.plus(other: R): R /** - * Returns difference between the polynomial represented as polynomial and the rational function. + * Returns difference between the polynomial represented as a polynomial and the rational function. */ public operator fun P.minus(other: R): R /** - * Returns product of the polynomial represented as polynomial and the rational function. + * Returns product of the polynomial represented as a polynomial and the rational function. */ public operator fun P.times(other: R): R /** - * Returns quotient of the polynomial represented as polynomial and the rational function. + * Returns quotient of the polynomial represented as a polynomial and the rational function. */ public operator fun P.div(other: R): R /** - * Returns sum of the rational function and the polynomial represented as rational function. + * Returns sum of the rational function and the polynomial represented as a rational function. */ public operator fun R.plus(other: P): R /** - * Returns difference between the rational function and the polynomial represented as rational function. + * Returns difference between the rational function and the polynomial represented as a rational function. */ public operator fun R.minus(other: P): R /** - * Returns product of the rational function and the polynomial represented as rational function. + * Returns product of the rational function and the polynomial represented as a rational function. */ public operator fun R.times(other: P): R /** - * Returns quotient of the rational function and the polynomial represented as rational function. + * Returns quotient of the rational function and the polynomial represented as a rational function. */ public operator fun R.div(other: P): R @@ -459,43 +459,51 @@ public interface RationalFunctionalSpace, R: RationalFunctio * @param A the type of algebraic structure (precisely, of ring) provided for constants. */ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 -public interface RationalFunctionalSpaceOverRing, R: RationalFunction, A: Ring> : RationalFunctionalSpace { +public interface RationalFunctionalSpaceOverRing< + C, + P: Polynomial, + R: RationalFunction, + A: Ring + > : RationalFunctionalSpace { + /** + * Underlying ring of constants. Its operations on constants are inherited by local operations on constants. + */ public val ring: A /** - * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * Returns sum of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. */ public override operator fun C.plus(other: Int): C = ring { addMultipliedByDoubling(this@plus, one, other) } /** - * Returns difference between the constant and the integer represented as constant (member of underlying ring). + * Returns difference between the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. */ public override operator fun C.minus(other: Int): C = ring { addMultipliedByDoubling(this@minus, one, -other) } /** - * Returns product of the constant and the integer represented as constant (member of underlying ring). + * Returns product of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to sum of [other] copies of [this]. */ public override operator fun C.times(other: Int): C = ring { multiplyByDoubling(this@times, other) } /** - * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * Returns sum of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. */ public override operator fun Int.plus(other: C): C = ring { addMultipliedByDoubling(other, one, this@plus) } /** - * Returns difference between the integer represented as constant (member of underlying ring) and the constant. + * Returns difference between the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. */ public override operator fun Int.minus(other: C): C = ring { addMultipliedByDoubling(-other, one, this@minus) } /** - * Returns product of the integer represented as constant (member of underlying ring) and the constant. + * Returns product of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -560,41 +568,44 @@ public interface RationalFunctionalSpaceOverPolynomialSpace< AP: PolynomialSpace, > : RationalFunctionalSpace { + /** + * Underlying polynomial ring. Its polynomial operations are inherited by local polynomial operations. + */ public val polynomialRing: AP /** - * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * Returns sum of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. */ public override operator fun C.plus(other: Int): C = polynomialRing { this@plus + other } /** - * Returns difference between the constant and the integer represented as constant (member of underlying ring). + * Returns difference between the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. */ public override operator fun C.minus(other: Int): C = polynomialRing { this@minus - other } /** - * Returns product of the constant and the integer represented as constant (member of underlying ring). + * Returns product of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to sum of [other] copies of [this]. */ public override operator fun C.times(other: Int): C = polynomialRing { this@times * other } /** - * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * Returns sum of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. */ public override operator fun Int.plus(other: C): C = polynomialRing { this@plus + other } /** - * Returns difference between the integer represented as constant (member of underlying ring) and the constant. + * Returns difference between the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. */ public override operator fun Int.minus(other: C): C = polynomialRing { this@minus - other } /** - * Returns product of the integer represented as constant (member of underlying ring) and the constant. + * Returns product of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -610,38 +621,38 @@ public interface RationalFunctionalSpaceOverPolynomialSpace< override fun Int.asConstant(): C = polynomialRing { asConstant() } /** - * Returns sum of the constant and the integer represented as polynomial. + * Returns sum of the constant and the integer represented as a polynomial. * * The operation is equivalent to adding [other] copies of unit polynomial to [this]. */ public override operator fun P.plus(other: Int): P = polynomialRing { this@plus + other } /** - * Returns difference between the constant and the integer represented as polynomial. + * Returns difference between the constant and the integer represented as a polynomial. * * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. */ public override operator fun P.minus(other: Int): P = polynomialRing { this@minus - other } /** - * Returns product of the constant and the integer represented as polynomial. + * Returns product of the constant and the integer represented as a polynomial. * * The operation is equivalent to sum of [other] copies of [this]. */ public override operator fun P.times(other: Int): P = polynomialRing { this@times * other } /** - * Returns sum of the integer represented as polynomial and the constant. + * Returns sum of the integer represented as a polynomial and the constant. * * The operation is equivalent to adding [this] copies of unit polynomial to [other]. */ public override operator fun Int.plus(other: P): P = polynomialRing { this@plus + other } /** - * Returns difference between the integer represented as polynomial and the constant. + * Returns difference between the integer represented as a polynomial and the constant. * * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. */ public override operator fun Int.minus(other: P): P = polynomialRing { this@minus - other } /** - * Returns product of the integer represented as polynomial and the constant. + * Returns product of the integer represented as a polynomial and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -697,28 +708,28 @@ public interface RationalFunctionalSpaceOverPolynomialSpace< public override val constantOne: C get() = polynomialRing.constantOne /** - * Returns sum of the constant represented as polynomial and the polynomial. + * Returns sum of the constant represented as a polynomial and the polynomial. */ public override operator fun C.plus(other: P): P = polynomialRing { this@plus + other } /** - * Returns difference between the constant represented as polynomial and the polynomial. + * Returns difference between the constant represented as a polynomial and the polynomial. */ public override operator fun C.minus(other: P): P = polynomialRing { this@minus - other } /** - * Returns product of the constant represented as polynomial and the polynomial. + * Returns product of the constant represented as a polynomial and the polynomial. */ public override operator fun C.times(other: P): P = polynomialRing { this@times * other } /** - * Returns sum of the constant represented as polynomial and the polynomial. + * Returns sum of the constant represented as a polynomial and the polynomial. */ public override operator fun P.plus(other: C): P = polynomialRing { this@plus + other } /** - * Returns difference between the constant represented as polynomial and the polynomial. + * Returns difference between the constant represented as a polynomial and the polynomial. */ public override operator fun P.minus(other: C): P = polynomialRing { this@minus - other } /** - * Returns product of the constant represented as polynomial and the polynomial. + * Returns product of the constant represented as a polynomial and the polynomial. */ public override operator fun P.times(other: C): P = polynomialRing { this@times * other } @@ -774,7 +785,8 @@ public interface RationalFunctionalSpaceOverPolynomialSpace< /** * Abstraction of field of rational functions of type [R] with respect to polynomials of type [P] and constants of type - * [C]. It also assumes that there is provided constructor + * [C]. It also assumes that there is provided constructor [constructRationalFunction] of rational functions from + * polynomial numerator and denominator. * * @param C the type of constants. Polynomials have them as coefficients in their terms. * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. @@ -786,10 +798,14 @@ public abstract class PolynomialSpaceOfFractions< P: Polynomial, R: RationalFunction, > : RationalFunctionalSpace { + + /** + * Constructor of rational functions (of type [R]) from numerator and denominator (of type [P]). + */ protected abstract fun constructRationalFunction(numerator: P, denominator: P = polynomialOne) : R /** - * Returns sum of the rational function and the integer represented as rational function. + * Returns sum of the rational function and the integer represented as a rational function. * * The operation is equivalent to adding [other] copies of unit polynomial to [this]. */ @@ -799,7 +815,7 @@ public abstract class PolynomialSpaceOfFractions< denominator ) /** - * Returns difference between the rational function and the integer represented as rational function. + * Returns difference between the rational function and the integer represented as a rational function. * * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. */ @@ -809,7 +825,7 @@ public abstract class PolynomialSpaceOfFractions< denominator ) /** - * Returns product of the rational function and the integer represented as rational function. + * Returns product of the rational function and the integer represented as a rational function. * * The operation is equivalent to sum of [other] copies of [this]. */ @@ -826,7 +842,7 @@ public abstract class PolynomialSpaceOfFractions< ) /** - * Returns sum of the integer represented as rational function and the rational function. + * Returns sum of the integer represented as a rational function and the rational function. * * The operation is equivalent to adding [this] copies of unit polynomial to [other]. */ @@ -836,7 +852,7 @@ public abstract class PolynomialSpaceOfFractions< other.denominator ) /** - * Returns difference between the integer represented as rational function and the rational function. + * Returns difference between the integer represented as a rational function and the rational function. * * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. */ @@ -846,7 +862,7 @@ public abstract class PolynomialSpaceOfFractions< other.denominator ) /** - * Returns product of the integer represented as rational function and the rational function. + * Returns product of the integer represented as a rational function and the rational function. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -873,7 +889,7 @@ public abstract class PolynomialSpaceOfFractions< public override operator fun P.div(other: P): R = constructRationalFunction(this, other) /** - * Returns sum of the constant represented as rational function and the rational function. + * Returns sum of the constant represented as a rational function and the rational function. */ public override operator fun C.plus(other: R): R = constructRationalFunction( @@ -881,7 +897,7 @@ public abstract class PolynomialSpaceOfFractions< other.denominator ) /** - * Returns difference between the constant represented as polynomial and the rational function. + * Returns difference between the constant represented as a polynomial and the rational function. */ public override operator fun C.minus(other: R): R = constructRationalFunction( @@ -889,7 +905,7 @@ public abstract class PolynomialSpaceOfFractions< other.denominator ) /** - * Returns product of the constant represented as polynomial and the rational function. + * Returns product of the constant represented as a polynomial and the rational function. */ public override operator fun C.times(other: R): R = constructRationalFunction( @@ -904,7 +920,7 @@ public abstract class PolynomialSpaceOfFractions< ) /** - * Returns sum of the constant represented as rational function and the rational function. + * Returns sum of the constant represented as a rational function and the rational function. */ public override operator fun R.plus(other: C): R = constructRationalFunction( @@ -912,7 +928,7 @@ public abstract class PolynomialSpaceOfFractions< denominator ) /** - * Returns difference between the constant represented as rational function and the rational function. + * Returns difference between the constant represented as a rational function and the rational function. */ public override operator fun R.minus(other: C): R = constructRationalFunction( @@ -920,7 +936,7 @@ public abstract class PolynomialSpaceOfFractions< denominator ) /** - * Returns product of the constant represented as rational function and the rational function. + * Returns product of the constant represented as a rational function and the rational function. */ public override operator fun R.times(other: C): R = constructRationalFunction( @@ -940,7 +956,7 @@ public abstract class PolynomialSpaceOfFractions< public override fun number(value: C): R = constructRationalFunction(polynomialNumber(value)) /** - * Returns sum of the polynomial represented as rational function and the rational function. + * Returns sum of the polynomial represented as a rational function and the rational function. */ public override operator fun P.plus(other: R): R = constructRationalFunction( @@ -948,7 +964,7 @@ public abstract class PolynomialSpaceOfFractions< other.denominator ) /** - * Returns difference between the polynomial represented as polynomial and the rational function. + * Returns difference between the polynomial represented as a polynomial and the rational function. */ public override operator fun P.minus(other: R): R = constructRationalFunction( @@ -956,7 +972,7 @@ public abstract class PolynomialSpaceOfFractions< other.denominator ) /** - * Returns product of the polynomial represented as polynomial and the rational function. + * Returns product of the polynomial represented as a polynomial and the rational function. */ public override operator fun P.times(other: R): R = constructRationalFunction( @@ -971,7 +987,7 @@ public abstract class PolynomialSpaceOfFractions< ) /** - * Returns sum of the polynomial represented as rational function and the rational function. + * Returns sum of the polynomial represented as a rational function and the rational function. */ public override operator fun R.plus(other: P): R = constructRationalFunction( @@ -979,7 +995,7 @@ public abstract class PolynomialSpaceOfFractions< denominator ) /** - * Returns difference between the polynomial represented as rational function and the rational function. + * Returns difference between the polynomial represented as a rational function and the rational function. */ public override operator fun R.minus(other: P): R = constructRationalFunction( @@ -987,7 +1003,7 @@ public abstract class PolynomialSpaceOfFractions< denominator ) /** - * Returns product of the polynomial represented as rational function and the rational function. + * Returns product of the polynomial represented as a rational function and the rational function. */ public override operator fun R.times(other: P): R = constructRationalFunction( @@ -1052,6 +1068,15 @@ public abstract class PolynomialSpaceOfFractions< public override val one: R get() = constructRationalFunction(polynomialOne) } +/** + * Abstraction of field of rational functions of type [R] with respect to polynomials of type [P] of variables of type + * [V] and over ring of constants of type [C]. + * + * @param C the type of constants. Polynomials have them as coefficients in their terms. + * @param V the type of variables. Polynomials have them in representations of terms. + * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. + * @param R the type of rational functions. + */ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public interface MultivariateRationalFunctionalSpace< C, @@ -1059,70 +1084,175 @@ public interface MultivariateRationalFunctionalSpace< P: Polynomial, R: RationalFunction >: RationalFunctionalSpace { + /** + * Returns sum of the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("plusVariableInt") public operator fun V.plus(other: Int): P + /** + * Returns difference between the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("minusVariableInt") public operator fun V.minus(other: Int): P + /** + * Returns product of the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("timesVariableInt") public operator fun V.times(other: Int): P + /** + * Returns sum of the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("plusIntVariable") public operator fun Int.plus(other: V): P + /** + * Returns difference between the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("minusIntVariable") public operator fun Int.minus(other: V): P + /** + * Returns product of the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("timesIntVariable") public operator fun Int.times(other: V): P - @JvmName("plusConstantVariable") - public operator fun C.plus(other: V): P - @JvmName("minusConstantVariable") - public operator fun C.minus(other: V): P - @JvmName("timesConstantVariable") - public operator fun C.times(other: V): P - + /** + * Returns sum of the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("plusVariableConstant") public operator fun V.plus(other: C): P + /** + * Returns difference between the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("minusVariableConstant") public operator fun V.minus(other: C): P + /** + * Returns product of the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("timesVariableConstant") public operator fun V.times(other: C): P + /** + * Returns sum of the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("plusConstantVariable") + public operator fun C.plus(other: V): P + /** + * Returns difference between the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("minusConstantVariable") + public operator fun C.minus(other: V): P + /** + * Returns product of the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("timesConstantVariable") + public operator fun C.times(other: V): P + + /** + * Represents the variable as a monic monomial. + */ @JvmName("unaryPlusVariable") public operator fun V.unaryPlus(): P + /** + * Returns negation of representation of the variable as a monic monomial. + */ @JvmName("unaryMinusVariable") public operator fun V.unaryMinus(): P + /** + * Returns sum of the variables represented as monic monomials. + */ @JvmName("plusVariableVariable") public operator fun V.plus(other: V): P + /** + * Returns difference between the variables represented as monic monomials. + */ @JvmName("minusVariableVariable") public operator fun V.minus(other: V): P + /** + * Returns product of the variables represented as monic monomials. + */ @JvmName("timesVariableVariable") public operator fun V.times(other: V): P + /** + * Represents the [variable] as a monic monomial. + */ + public fun polynomialNumber(variable: V): P = +variable + /** + * Represents the variable as a monic monomial. + */ + public fun V.asPolynomial(): P = polynomialNumber(this) + + /** + * Represents the [variable] as a rational function. + */ + public fun number(variable: V): R = number(polynomialNumber(variable)) + /** + * Represents the variable as a rational function. + */ + public fun V.asRationalFunction(): R = number(this) + + /** + * Returns sum of the variable represented as a monic monomial and the polynomial. + */ @JvmName("plusVariablePolynomial") public operator fun V.plus(other: P): P + /** + * Returns difference between the variable represented as a monic monomial and the polynomial. + */ @JvmName("minusVariablePolynomial") public operator fun V.minus(other: P): P + /** + * Returns product of the variable represented as a monic monomial and the polynomial. + */ @JvmName("timesVariablePolynomial") public operator fun V.times(other: P): P + /** + * Returns sum of the polynomial and the variable represented as a monic monomial. + */ @JvmName("plusPolynomialVariable") public operator fun P.plus(other: V): P + /** + * Returns difference between the polynomial and the variable represented as a monic monomial. + */ @JvmName("minusPolynomialVariable") public operator fun P.minus(other: V): P + /** + * Returns product of the polynomial and the variable represented as a monic monomial. + */ @JvmName("timesPolynomialVariable") public operator fun P.times(other: V): P + /** + * Returns sum of the variable represented as a rational function and the rational function. + */ @JvmName("plusVariableRational") public operator fun V.plus(other: R): R + /** + * Returns difference between the variable represented as a rational function and the rational function. + */ @JvmName("minusVariableRational") public operator fun V.minus(other: R): R + /** + * Returns product of the variable represented as a rational function and the rational function. + */ @JvmName("timesVariableRational") public operator fun V.times(other: R): R + /** + * Returns sum of the rational function and the variable represented as a rational function. + */ @JvmName("plusRationalVariable") public operator fun R.plus(other: V): R + /** + * Returns difference between the rational function and the variable represented as a rational function. + */ @JvmName("minusRationalVariable") public operator fun R.minus(other: V): R + /** + * Returns product of the rational function and the variable represented as a rational function. + */ @JvmName("timesRationalVariable") public operator fun R.times(other: V): R @@ -1161,22 +1291,17 @@ public interface MultivariateRationalFunctionalSpace< public val R.countOfVariables: Int get() = variables.size } -public interface MultivariateRationalFunctionalSpaceOverRing< - C, - V, - P: Polynomial, - R: RationalFunction, - A: Ring - > : RationalFunctionalSpaceOverRing, MultivariateRationalFunctionalSpace - -public interface MultivariateRationalFunctionalSpaceOverPolynomialSpace< - C, - V, - P: Polynomial, - R: RationalFunction, - AP: PolynomialSpace, - > : RationalFunctionalSpaceOverPolynomialSpace, MultivariateRationalFunctionalSpace - +/** + * Abstraction of field of rational functions of type [R] with respect to polynomials of type [P] of variables of type + * [V] and over ring of constants of type [C]. It also assumes that there is provided [polynomialRing] (of type [AP]), + * that provides constant-, variable- and polynomial-wise operations. + * + * @param C the type of constants. Polynomials have them as coefficients in their terms. + * @param V the type of variables. Polynomials have them in representations of terms. + * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. + * @param R the type of rational functions. + * @param AP the type of algebraic structure (precisely, of ring) provided for polynomials. + */ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public interface MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSpace< C, @@ -1184,57 +1309,135 @@ public interface MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSp P: Polynomial, R: RationalFunction, AP: MultivariatePolynomialSpace, - > : MultivariateRationalFunctionalSpaceOverPolynomialSpace { + > : RationalFunctionalSpaceOverPolynomialSpace, MultivariateRationalFunctionalSpace { + /** + * Returns sum of the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("plusVariableInt") public override operator fun V.plus(other: Int): P = polynomialRing { this@plus + other } + /** + * Returns difference between the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("minusVariableInt") public override operator fun V.minus(other: Int): P = polynomialRing { this@minus - other } + /** + * Returns product of the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("timesVariableInt") public override operator fun V.times(other: Int): P = polynomialRing { this@times * other } + /** + * Returns sum of the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("plusIntVariable") public override operator fun Int.plus(other: V): P = polynomialRing { this@plus + other } + /** + * Returns difference between the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("minusIntVariable") public override operator fun Int.minus(other: V): P = polynomialRing { this@minus - other } + /** + * Returns product of the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("timesIntVariable") public override operator fun Int.times(other: V): P = polynomialRing { this@times * other } - @JvmName("plusConstantVariable") - public override operator fun C.plus(other: V): P = polynomialRing { this@plus + other } - @JvmName("minusConstantVariable") - public override operator fun C.minus(other: V): P = polynomialRing { this@minus - other } - @JvmName("timesConstantVariable") - public override operator fun C.times(other: V): P = polynomialRing { this@times * other } - + /** + * Returns sum of the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("plusVariableConstant") public override operator fun V.plus(other: C): P = polynomialRing { this@plus + other } + /** + * Returns difference between the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("minusVariableConstant") public override operator fun V.minus(other: C): P = polynomialRing { this@minus - other } + /** + * Returns product of the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("timesVariableConstant") public override operator fun V.times(other: C): P = polynomialRing { this@times * other } + /** + * Returns sum of the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("plusConstantVariable") + public override operator fun C.plus(other: V): P = polynomialRing { this@plus + other } + /** + * Returns difference between the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("minusConstantVariable") + public override operator fun C.minus(other: V): P = polynomialRing { this@minus - other } + /** + * Returns product of the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("timesConstantVariable") + public override operator fun C.times(other: V): P = polynomialRing { this@times * other } + + /** + * Represents the variable as a monic monomial. + */ @JvmName("unaryPlusVariable") public override operator fun V.unaryPlus(): P = polynomialRing { +this@unaryPlus } + /** + * Returns negation of representation of the variable as a monic monomial. + */ @JvmName("unaryMinusVariable") public override operator fun V.unaryMinus(): P = polynomialRing { -this@unaryMinus } + /** + * Returns sum of the variables represented as monic monomials. + */ @JvmName("plusVariableVariable") public override operator fun V.plus(other: V): P = polynomialRing { this@plus + other } + /** + * Returns difference between the variables represented as monic monomials. + */ @JvmName("minusVariableVariable") public override operator fun V.minus(other: V): P = polynomialRing { this@minus - other } + /** + * Returns product of the variables represented as monic monomials. + */ @JvmName("timesVariableVariable") public override operator fun V.times(other: V): P = polynomialRing { this@times * other } + /** + * Represents the [variable] as a monic monomial. + */ + public override fun polynomialNumber(variable: V): P = polynomialRing { number(variable) } + /** + * Represents the variable as a monic monomial. + */ + public override fun V.asPolynomial(): P = polynomialRing { this@asPolynomial.asPolynomial() } + + /** + * Returns sum of the variable represented as a monic monomial and the polynomial. + */ @JvmName("plusVariablePolynomial") public override operator fun V.plus(other: P): P = polynomialRing { this@plus + other } + /** + * Returns difference between the variable represented as a monic monomial and the polynomial. + */ @JvmName("minusVariablePolynomial") public override operator fun V.minus(other: P): P = polynomialRing { this@minus - other } + /** + * Returns product of the variable represented as a monic monomial and the polynomial. + */ @JvmName("timesVariablePolynomial") public override operator fun V.times(other: P): P = polynomialRing { this@times * other } + /** + * Returns sum of the polynomial and the variable represented as a monic monomial. + */ @JvmName("plusPolynomialVariable") public override operator fun P.plus(other: V): P = polynomialRing { this@plus + other } + /** + * Returns difference between the polynomial and the variable represented as a monic monomial. + */ @JvmName("minusPolynomialVariable") public override operator fun P.minus(other: V): P = polynomialRing { this@minus - other } + /** + * Returns product of the polynomial and the variable represented as a monic monomial. + */ @JvmName("timesPolynomialVariable") public override operator fun P.times(other: V): P = polynomialRing { this@times * other } @@ -1264,6 +1467,16 @@ public interface MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSp public override val P.countOfVariables: Int get() = polynomialRing { countOfVariables } } +/** + * Abstraction of field of rational functions of type [R] with respect to polynomials of type [P] of variables of type + * [V] and over ring of constants of type [C]. It also assumes that there is provided constructor + * [constructRationalFunction] of rational functions from polynomial numerator and denominator. + * + * @param C the type of constants. Polynomials have them as coefficients in their terms. + * @param V the type of variables. Polynomials have them in representations of terms. + * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. + * @param R the type of rational functions. + */ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public abstract class MultivariatePolynomialSpaceOfFractions< C, @@ -1271,18 +1484,27 @@ public abstract class MultivariatePolynomialSpaceOfFractions< P: Polynomial, R: RationalFunction, > : MultivariateRationalFunctionalSpace, PolynomialSpaceOfFractions() { + /** + * Returns sum of the variable represented as a rational function and the rational function. + */ @JvmName("plusVariableRational") public override operator fun V.plus(other: R): R = constructRationalFunction( this * other.denominator + other.numerator, other.denominator ) + /** + * Returns difference between the variable represented as a rational function and the rational function. + */ @JvmName("minusVariableRational") public override operator fun V.minus(other: R): R = constructRationalFunction( this * other.denominator - other.numerator, other.denominator ) + /** + * Returns product of the variable represented as a rational function and the rational function. + */ @JvmName("timesVariableRational") public override operator fun V.times(other: R): R = constructRationalFunction( @@ -1290,18 +1512,27 @@ public abstract class MultivariatePolynomialSpaceOfFractions< other.denominator ) + /** + * Returns sum of the rational function and the variable represented as a rational function. + */ @JvmName("plusRationalVariable") public override operator fun R.plus(other: V): R = constructRationalFunction( numerator + denominator * other, denominator ) + /** + * Returns difference between the rational function and the variable represented as a rational function. + */ @JvmName("minusRationalVariable") public override operator fun R.minus(other: V): R = constructRationalFunction( numerator - denominator * other, denominator ) + /** + * Returns product of the rational function and the variable represented as a rational function. + */ @JvmName("timesRationalVariable") public override operator fun R.times(other: V): R = constructRationalFunction( -- 2.34.1 From 03b92de6e0803c0813bf53469cf9d195699f016a Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sat, 11 Jun 2022 19:29:14 +0300 Subject: [PATCH 064/123] Sifted ListPolynomial's basics. --- .../kmath/functions/LabeledPolynomial.kt | 539 ------------------ .../functions/LabeledRationalFunction.kt | 139 ----- .../kmath/functions/NumberedPolynomial.kt | 389 ------------- .../functions/NumberedRationalFunction.kt | 188 ------ .../kscience/kmath/functions/Piecewise.kt | 132 ----- .../kmath/functions/labeledConstructors.kt | 203 ------- .../kmath/functions/labeledPolynomialUtil.kt | 495 ---------------- .../functions/labeledRationalFunctionUtil.kt | 33 -- .../kmath/functions/numberedConstructors.kt | 195 ------- .../kmath/functions/numberedPolynomialUtil.kt | 528 ----------------- .../functions/numberedRationalFunctionUtil.kt | 33 -- .../kmath/integration/SplineIntegrator.kt | 107 ---- .../kmath/interpolation/Interpolator.kt | 92 --- .../kmath/interpolation/LinearInterpolator.kt | 43 -- .../kmath/interpolation/SplineInterpolator.kt | 83 --- .../kmath/integration/SplineIntegralTest.kt | 48 -- .../interpolation/LinearInterpolatorTest.kt | 29 - .../interpolation/SplineInterpolatorTest.kt | 31 - .../kscience/kmath/test/misc/IntModulo.kt | 142 ----- .../kscience/kmath/test/misc/Rational.kt | 135 ----- .../test/misc/RationalWithMemorization.kt | 107 ---- .../kscience/kmath/test/misc/memorization.kt | 51 -- .../space/kscience/kmath/test/misc/misc.kt | 31 - 23 files changed, 3773 deletions(-) delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt delete mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt delete mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt delete mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt delete mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt delete mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt delete mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/RationalWithMemorization.kt delete mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/memorization.kt delete mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt deleted file mode 100644 index b904f7331..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt +++ /dev/null @@ -1,539 +0,0 @@ -/* - * 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.functions - -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.ScaleOperations -import kotlin.math.max - - -/** - * Represents multivariate polynomials with labeled variables. - * - * @param C Ring in which the polynomial is considered. - */ -public data class LabeledPolynomial -internal constructor( - /** - * Map that collects coefficients of the polynomial. Every non-zero monomial - * `a x_1^{d_1} ... x_n^{d_n}` is represented as pair "key-value" in the map, where value is coefficients `a` and - * key is map that associates variables in the monomial with multiplicity of them occurring in the monomial. - * For example polynomial - * ``` - * 5 a^2 c^3 - 6 b + 0 b c - * ``` - * has coefficients represented as - * ``` - * mapOf( - * mapOf( - * a to 2, - * c to 3 - * ) to 5, - * mapOf( - * b to 1 - * ) to (-6) - * ) - * ``` - * where `a`, `b` and `c` are corresponding [Symbol] objects. - */ - public val coefficients: Map, C> -) : Polynomial { - override fun toString(): String = "LabeledPolynomial$coefficients" -} - -/** - * Space of polynomials. - * - * @param C the type of operated polynomials. - * @param A the intersection of [Ring] of [C] and [ScaleOperations] of [C]. - * @param ring the [A] instance. - */ -public class LabeledPolynomialSpace>( - public override val ring: A, -) : MultivariatePolynomialSpace>, PolynomialSpaceOverRing, A> { - public override operator fun Symbol.plus(other: Int): LabeledPolynomial = - if (other == 0) LabeledPolynomial(mapOf( - mapOf(this@plus to 1U) to constantOne, - )) - else LabeledPolynomial(mapOf( - mapOf(this@plus to 1U) to constantOne, - emptyMap() to constantOne * other, - )) - public override operator fun Symbol.minus(other: Int): LabeledPolynomial = - if (other == 0) LabeledPolynomial(mapOf( - mapOf(this@minus to 1U) to -constantOne, - )) - else LabeledPolynomial(mapOf( - mapOf(this@minus to 1U) to -constantOne, - emptyMap() to constantOne * other, - )) - public override operator fun Symbol.times(other: Int): LabeledPolynomial = - if (other == 0) zero - else LabeledPolynomial(mapOf( - mapOf(this to 1U) to constantOne * other, - )) - - public override operator fun Int.plus(other: Symbol): LabeledPolynomial = - if (this == 0) LabeledPolynomial(mapOf( - mapOf(other to 1U) to constantOne, - )) - else LabeledPolynomial(mapOf( - mapOf(other to 1U) to constantOne, - emptyMap() to constantOne * this@plus, - )) - public override operator fun Int.minus(other: Symbol): LabeledPolynomial = - if (this == 0) LabeledPolynomial(mapOf( - mapOf(other to 1U) to -constantOne, - )) - else LabeledPolynomial(mapOf( - mapOf(other to 1U) to -constantOne, - emptyMap() to constantOne * this@minus, - )) - public override operator fun Int.times(other: Symbol): LabeledPolynomial = - if (this == 0) zero - else LabeledPolynomial(mapOf( - mapOf(other to 1U) to constantOne * this@times, - )) - - /** - * Returns sum of the polynomial and the integer represented as polynomial. - * - * The operation is equivalent to adding [other] copies of unit polynomial to [this]. - */ - public override operator fun LabeledPolynomial.plus(other: Int): LabeledPolynomial = - if (other == 0) this - else with(coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to other.asConstant())) - else LabeledPolynomial( - toMutableMap() - .apply { - val degs = emptyMap() - - this[degs] = getOrElse(degs) { constantZero } + other - } - ) - } - /** - * Returns difference between the polynomial and the integer represented as polynomial. - * - * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. - */ - public override operator fun LabeledPolynomial.minus(other: Int): LabeledPolynomial = - if (other == 0) this - else with(coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to (-other).asConstant())) - else LabeledPolynomial( - toMutableMap() - .apply { - val degs = emptyMap() - - this[degs] = getOrElse(degs) { constantZero } - other - } - ) - } - /** - * Returns product of the polynomial and the integer represented as polynomial. - * - * The operation is equivalent to sum of [other] copies of [this]. - */ - public override operator fun LabeledPolynomial.times(other: Int): LabeledPolynomial = - if (other == 0) zero - else LabeledPolynomial( - coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this[degs]!! * other - } - ) - - /** - * Returns sum of the integer represented as polynomial and the polynomial. - * - * The operation is equivalent to adding [this] copies of unit polynomial to [other]. - */ - public override operator fun Int.plus(other: LabeledPolynomial): LabeledPolynomial = - if (this == 0) other - else with(other.coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to this@plus.asConstant())) - else LabeledPolynomial( - toMutableMap() - .apply { - val degs = emptyMap() - - this[degs] = this@plus + getOrElse(degs) { constantZero } - } - ) - } - /** - * Returns difference between the integer represented as polynomial and the polynomial. - * - * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. - */ - public override operator fun Int.minus(other: LabeledPolynomial): LabeledPolynomial = - if (this == 0) other - else with(other.coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to this@minus.asConstant())) - else LabeledPolynomial( - toMutableMap() - .apply { - val degs = emptyMap() - - this[degs] = this@minus - getOrElse(degs) { constantZero } - } - ) - } - /** - * Returns product of the integer represented as polynomial and the polynomial. - * - * The operation is equivalent to sum of [this] copies of [other]. - */ - public override operator fun Int.times(other: LabeledPolynomial): LabeledPolynomial = - if (this == 0) zero - else LabeledPolynomial( - other.coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this@times * this[degs]!! - } - ) - - /** - * Converts the integer [value] to polynomial. - */ - public override fun number(value: Int): LabeledPolynomial = number(constantNumber(value)) - - public override operator fun C.plus(other: Symbol): LabeledPolynomial = - LabeledPolynomial(mapOf( - mapOf(other to 1U) to constantOne, - emptyMap() to this@plus, - )) - public override operator fun C.minus(other: Symbol): LabeledPolynomial = - LabeledPolynomial(mapOf( - mapOf(other to 1U) to -constantOne, - emptyMap() to this@minus, - )) - public override operator fun C.times(other: Symbol): LabeledPolynomial = - LabeledPolynomial(mapOf( - mapOf(other to 1U) to this@times, - )) - - public override operator fun Symbol.plus(other: C): LabeledPolynomial = - LabeledPolynomial(mapOf( - mapOf(this@plus to 1U) to constantOne, - emptyMap() to other, - )) - public override operator fun Symbol.minus(other: C): LabeledPolynomial = - LabeledPolynomial(mapOf( - mapOf(this@minus to 1U) to -constantOne, - emptyMap() to other, - )) - public override operator fun Symbol.times(other: C): LabeledPolynomial = - LabeledPolynomial(mapOf( - mapOf(this@times to 1U) to other, - )) - - /** - * Returns sum of the constant represented as polynomial and the polynomial. - */ - override operator fun C.plus(other: LabeledPolynomial): LabeledPolynomial = - with(other.coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to this@plus)) - else LabeledPolynomial( - toMutableMap() - .apply { - val degs = emptyMap() - - this[degs] = this@plus + getOrElse(degs) { constantZero } - } - ) - } - /** - * Returns difference between the constant represented as polynomial and the polynomial. - */ - override operator fun C.minus(other: LabeledPolynomial): LabeledPolynomial = - with(other.coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to this@minus)) - else LabeledPolynomial( - toMutableMap() - .apply { - forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } - - val degs = emptyMap() - - this[degs] = this@minus - getOrElse(degs) { constantZero } - } - ) - } - /** - * Returns product of the constant represented as polynomial and the polynomial. - */ - override operator fun C.times(other: LabeledPolynomial): LabeledPolynomial = - LabeledPolynomial( - other.coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this@times * this[degs]!! - } - ) - - /** - * Returns sum of the constant represented as polynomial and the polynomial. - */ - override operator fun LabeledPolynomial.plus(other: C): LabeledPolynomial = - with(coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to other)) - else LabeledPolynomial( - toMutableMap() - .apply { - val degs = emptyMap() - - this[degs] = getOrElse(degs) { constantZero } + other - } - ) - } - /** - * Returns difference between the constant represented as polynomial and the polynomial. - */ - override operator fun LabeledPolynomial.minus(other: C): LabeledPolynomial = - with(coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to other)) - else LabeledPolynomial( - toMutableMap() - .apply { - forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } - - val degs = emptyMap() - - this[degs] = getOrElse(degs) { constantZero } - other - } - ) - } - /** - * Returns product of the constant represented as polynomial and the polynomial. - */ - override operator fun LabeledPolynomial.times(other: C): LabeledPolynomial = - LabeledPolynomial( - coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this[degs]!! * other - } - ) - - /** - * Converts the constant [value] to polynomial. - */ - public override fun number(value: C): LabeledPolynomial = - LabeledPolynomial(mapOf(emptyMap() to value)) - - public override operator fun Symbol.unaryPlus(): LabeledPolynomial = - LabeledPolynomial(mapOf( - mapOf(this to 1U) to constantOne, - )) - public override operator fun Symbol.unaryMinus(): LabeledPolynomial = - LabeledPolynomial(mapOf( - mapOf(this to 1U) to -constantOne, - )) - public override operator fun Symbol.plus(other: Symbol): LabeledPolynomial = - if (this == other) LabeledPolynomial(mapOf( - mapOf(this to 1U) to constantOne * 2 - )) - else LabeledPolynomial(mapOf( - mapOf(this to 1U) to constantOne, - mapOf(other to 1U) to constantOne, - )) - public override operator fun Symbol.minus(other: Symbol): LabeledPolynomial = - if (this == other) zero - else LabeledPolynomial(mapOf( - mapOf(this to 1U) to constantOne, - mapOf(other to 1U) to -constantOne, - )) - public override operator fun Symbol.times(other: Symbol): LabeledPolynomial = - if (this == other) LabeledPolynomial(mapOf( - mapOf(this to 2U) to constantOne - )) - else LabeledPolynomial(mapOf( - mapOf(this to 1U, other to 1U) to constantOne, - )) - - public override operator fun Symbol.plus(other: LabeledPolynomial): LabeledPolynomial = - with(other.coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(mapOf(this@plus to 1u) to constantOne)) - else LabeledPolynomial( - toMutableMap() - .apply { - val degs = mapOf(this@plus to 1U) - - this[degs] = constantOne + getOrElse(degs) { constantZero } - } - ) - } - public override operator fun Symbol.minus(other: LabeledPolynomial): LabeledPolynomial = - with(other.coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(mapOf(this@minus to 1u) to constantOne)) - else LabeledPolynomial( - toMutableMap() - .apply { - forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } - - val degs = mapOf(this@minus to 1U) - - this[degs] = constantOne - getOrElse(degs) { constantZero } - } - ) - } - public override operator fun Symbol.times(other: LabeledPolynomial): LabeledPolynomial = - LabeledPolynomial( - other.coefficients - .mapKeys { (degs, _) -> degs.toMutableMap().also{ it[this] = if (this in it) it[this]!! + 1U else 1U } } - ) - - public override operator fun LabeledPolynomial.plus(other: Symbol): LabeledPolynomial = - with(coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(mapOf(other to 1u) to constantOne)) - else LabeledPolynomial( - toMutableMap() - .apply { - val degs = mapOf(other to 1U) - - this[degs] = constantOne + getOrElse(degs) { constantZero } - } - ) - } - public override operator fun LabeledPolynomial.minus(other: Symbol): LabeledPolynomial = - with(coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(mapOf(other to 1u) to constantOne)) - else LabeledPolynomial( - toMutableMap() - .apply { - val degs = mapOf(other to 1U) - - this[degs] = constantOne - getOrElse(degs) { constantZero } - } - ) - } - public override operator fun LabeledPolynomial.times(other: Symbol): LabeledPolynomial = - LabeledPolynomial( - coefficients - .mapKeys { (degs, _) -> degs.toMutableMap().also{ it[other] = if (other in it) it[other]!! + 1U else 1U } } - ) - - /** - * Returns negation of the polynomial. - */ - override fun LabeledPolynomial.unaryMinus(): LabeledPolynomial = - LabeledPolynomial( - coefficients.mapValues { -it.value } - ) - /** - * Returns sum of the polynomials. - */ - override operator fun LabeledPolynomial.plus(other: LabeledPolynomial): LabeledPolynomial = - LabeledPolynomial( - buildMap(coefficients.size + other.coefficients.size) { - other.coefficients.mapValuesTo(this) { it.value } - other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! + value else value } - } - ) - /** - * Returns difference of the polynomials. - */ - override operator fun LabeledPolynomial.minus(other: LabeledPolynomial): LabeledPolynomial = - LabeledPolynomial( - buildMap(coefficients.size + other.coefficients.size) { - other.coefficients.mapValuesTo(this) { it.value } - other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! - value else -value } - } - ) - /** - * Returns product of the polynomials. - */ - override operator fun LabeledPolynomial.times(other: LabeledPolynomial): LabeledPolynomial = - LabeledPolynomial( - buildMap(coefficients.size * other.coefficients.size) { - for ((degs1, c1) in coefficients) for ((degs2, c2) in other.coefficients) { - val degs = degs1.toMutableMap() - degs2.mapValuesTo(degs) { (variable, deg) -> degs.getOrElse(variable) { 0u } + deg } - val c = c1 * c2 - this[degs] = if (degs in this) this[degs]!! + c else c - } - } - ) - - /** - * Instance of zero polynomial (zero of the polynomial ring). - */ - override val zero: LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to constantZero)) - /** - * Instance of unit polynomial (unit of the polynomial ring). - */ - override val one: LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to constantOne)) - - /** - * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is - * zero, degree is -1. - */ - override val LabeledPolynomial.degree: Int - get() = coefficients.entries.maxOfOrNull { (degs, c) -> degs.values.sum().toInt() } ?: -1 - /** - * Map that associates variables (that appear in the polynomial in positive exponents) with their most exponents - * in which they are appeared in the polynomial. - * - * As consequence all values in the map are positive integers. Also, if the polynomial is constant, the map is empty. - * And keys of the map is the same as in [variables]. - */ - public override val LabeledPolynomial.degrees: Map - get() = - buildMap { - coefficients.entries.forEach { (degs, _) -> - degs.mapValuesTo(this) { (variable, deg) -> - max(getOrElse(variable) { 0u }, deg) - } - } - } - /** - * Counts degree of the polynomial by the specified [variable]. - */ - public override fun LabeledPolynomial.degreeBy(variable: Symbol): UInt = - coefficients.entries.maxOfOrNull { (degs, _) -> degs.getOrElse(variable) { 0u } } ?: 0u - /** - * Counts degree of the polynomial by the specified [variables]. - */ - public override fun LabeledPolynomial.degreeBy(variables: Collection): UInt = - coefficients.entries.maxOfOrNull { (degs, _) -> degs.filterKeys { it in variables }.values.sum() } ?: 0u - /** - * Set of all variables that appear in the polynomial in positive exponents. - */ - public override val LabeledPolynomial.variables: Set - get() = - buildSet { - coefficients.entries.forEach { (degs, _) -> addAll(degs.keys) } - } - /** - * Count of all variables that appear in the polynomial in positive exponents. - */ - public override val LabeledPolynomial.countOfVariables: Int get() = variables.size - -// @Suppress("NOTHING_TO_INLINE") -// public inline fun LabeledPolynomial.substitute(argument: Map): LabeledPolynomial = this.substitute(ring, argument) -// @Suppress("NOTHING_TO_INLINE") -// @JvmName("substitutePolynomial") -// public inline fun LabeledPolynomial.substitute(argument: Map>): LabeledPolynomial = this.substitute(ring, argument) -// -// @Suppress("NOTHING_TO_INLINE") -// public inline fun LabeledPolynomial.asFunction(): (Map) -> LabeledPolynomial = { this.substitute(ring, it) } -// @Suppress("NOTHING_TO_INLINE") -// public inline fun LabeledPolynomial.asFunctionOnConstants(): (Map) -> LabeledPolynomial = { this.substitute(ring, it) } -// @Suppress("NOTHING_TO_INLINE") -// public inline fun LabeledPolynomial.asFunctionOnPolynomials(): (Map>) -> LabeledPolynomial = { this.substitute(ring, it) } -// -// @Suppress("NOTHING_TO_INLINE") -// public inline operator fun LabeledPolynomial.invoke(argument: Map): LabeledPolynomial = this.substitute(ring, argument) -// @Suppress("NOTHING_TO_INLINE") -// @JvmName("invokePolynomial") -// public inline operator fun LabeledPolynomial.invoke(argument: Map>): LabeledPolynomial = this.substitute(ring, argument) -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt deleted file mode 100644 index 76c6874f5..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt +++ /dev/null @@ -1,139 +0,0 @@ -/* - * 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.functions - -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.invoke - - -public class LabeledRationalFunction( - public override val numerator: LabeledPolynomial, - public override val denominator: LabeledPolynomial -) : RationalFunction> { - override fun toString(): String = "LabeledRationalFunction${numerator.coefficients}/${denominator.coefficients}" -} - -public class LabeledRationalFunctionSpace>( - public val ring: A, -) : - MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSpace< - C, - Symbol, - LabeledPolynomial, - LabeledRationalFunction, - LabeledPolynomialSpace, - >, - MultivariatePolynomialSpaceOfFractions< - C, - Symbol, - LabeledPolynomial, - LabeledRationalFunction, - >() { - - override val polynomialRing : LabeledPolynomialSpace = LabeledPolynomialSpace(ring) - override fun constructRationalFunction( - numerator: LabeledPolynomial, - denominator: LabeledPolynomial - ): LabeledRationalFunction = - LabeledRationalFunction(numerator, denominator) - - /** - * Instance of zero rational function (zero of the rational functions ring). - */ - public override val zero: LabeledRationalFunction = LabeledRationalFunction(polynomialZero, polynomialOne) - /** - * Instance of unit polynomial (unit of the rational functions ring). - */ - public override val one: LabeledRationalFunction = LabeledRationalFunction(polynomialOne, polynomialOne) - - // TODO: Разобрать - -// operator fun invoke(arg: Map): LabeledRationalFunction = -// LabeledRationalFunction( -// numerator(arg), -// denominator(arg) -// ) -// -// @JvmName("invokeLabeledPolynomial") -// operator fun invoke(arg: Map>): LabeledRationalFunction = -// LabeledRationalFunction( -// numerator(arg), -// denominator(arg) -// ) -// -// @JvmName("invokeLabeledRationalFunction") -// operator fun invoke(arg: Map>): LabeledRationalFunction { -// var num = numerator invokeRFTakeNumerator arg -// var den = denominator invokeRFTakeNumerator arg -// for (variable in variables) if (variable in arg) { -// val degreeDif = degrees[variable]!! -// if (degreeDif > 0) -// den = multiplyByPower(den, arg[variable]!!.denominator, degreeDif) -// else -// num = multiplyByPower(num, arg[variable]!!.denominator, -degreeDif) -// } -// return LabeledRationalFunction(num, den) -// } -// -// override fun toString(): String = toString(emptyMap()) -// -// fun toString(names: Map = emptyMap()): String = -// when (true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toString(names) -// else -> "${numerator.toStringWithBrackets(names)}/${denominator.toStringWithBrackets(names)}" -// } -// -// fun toString(namer: (Symbol) -> String): String = -// when (true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toString(namer) -// else -> "${numerator.toStringWithBrackets(namer)}/${denominator.toStringWithBrackets(namer)}" -// } -// -// fun toStringWithBrackets(names: Map = emptyMap()): String = -// when (true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toStringWithBrackets(names) -// else -> "(${numerator.toStringWithBrackets(names)}/${denominator.toStringWithBrackets(names)})" -// } -// -// fun toStringWithBrackets(namer: (Symbol) -> String): String = -// when (true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toStringWithBrackets(namer) -// else -> "(${numerator.toStringWithBrackets(namer)}/${denominator.toStringWithBrackets(namer)})" -// } -// -// fun toReversedString(names: Map = emptyMap()): String = -// when (true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedString(names) -// else -> "${numerator.toReversedStringWithBrackets(names)}/${denominator.toReversedStringWithBrackets(names)}" -// } -// -// fun toReversedString(namer: (Symbol) -> String): String = -// when (true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedString(namer) -// else -> "${numerator.toReversedStringWithBrackets(namer)}/${denominator.toReversedStringWithBrackets(namer)}" -// } -// -// fun toReversedStringWithBrackets(names: Map = emptyMap()): String = -// when (true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedStringWithBrackets(names) -// else -> "(${numerator.toReversedStringWithBrackets(names)}/${denominator.toReversedStringWithBrackets(names)})" -// } -// -// fun toReversedStringWithBrackets(namer: (Symbol) -> String): String = -// when (true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedStringWithBrackets(namer) -// else -> "(${numerator.toReversedStringWithBrackets(namer)}/${denominator.toReversedStringWithBrackets(namer)})" -// } -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt deleted file mode 100644 index e75373819..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ /dev/null @@ -1,389 +0,0 @@ -/* - * 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.functions - -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.ScaleOperations -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract -import kotlin.experimental.ExperimentalTypeInference -import kotlin.jvm.JvmName -import kotlin.math.max - - -/** - * Polynomial model without fixation on specific context they are applied to. - * - * @param C the type of constants. - */ -public data class NumberedPolynomial -internal constructor( - /** - * Map that collects coefficients of the polynomial. Every monomial `a x_1^{d_1} ... x_n^{d_n}` is represented as - * pair "key-value" in the map, where value is coefficients `a` and - * key is list that associates index of every variable in the monomial with multiplicity of the variable occurring - * in the monomial. For example coefficients of polynomial `5 x_1^2 x_3^3 - 6 x_2` can be represented as - * ``` - * mapOf( - * listOf(2, 0, 3) to 5, - * listOf(0, 1) to (-6), - * ) - * ``` - * and also as - * ``` - * mapOf( - * listOf(2, 0, 3) to 5, - * listOf(0, 1) to (-6), - * listOf(0, 1, 1) to 0, - * ) - * ``` - * It is recommended not to put zero monomials into the map, but is not prohibited. Lists of degrees always do not - * contain any zeros on end, but can contain zeros on start or anywhere in middle. - */ - public val coefficients: Map, C> -) : Polynomial { - override fun toString(): String = "NumberedPolynomial$coefficients" -} - -/** - * Space of polynomials. - * - * @param C the type of operated polynomials. - * @param A the intersection of [Ring] of [C] and [ScaleOperations] of [C]. - * @param ring the [A] instance. - */ -public open class NumberedPolynomialSpace>( - public final override val ring: A, -) : PolynomialSpaceOverRing, A> { - /** - * Returns sum of the polynomial and the integer represented as polynomial. - * - * The operation is equivalent to adding [other] copies of unit polynomial to [this]. - */ - public override operator fun NumberedPolynomial.plus(other: Int): NumberedPolynomial = - if (other == 0) this - else - NumberedPolynomial( - coefficients - .toMutableMap() - .apply { - val degs = emptyList() - - this[degs] = getOrElse(degs) { constantZero } + other - } - ) - /** - * Returns difference between the polynomial and the integer represented as polynomial. - * - * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. - */ - public override operator fun NumberedPolynomial.minus(other: Int): NumberedPolynomial = - if (other == 0) this - else - NumberedPolynomial( - coefficients - .toMutableMap() - .apply { - val degs = emptyList() - - this[degs] = getOrElse(degs) { constantZero } - other - } - ) - /** - * Returns product of the polynomial and the integer represented as polynomial. - * - * The operation is equivalent to sum of [other] copies of [this]. - */ - public override operator fun NumberedPolynomial.times(other: Int): NumberedPolynomial = - if (other == 0) zero - else NumberedPolynomial( - coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this[degs]!! * other - } - ) - - /** - * Returns sum of the integer represented as polynomial and the polynomial. - * - * The operation is equivalent to adding [this] copies of unit polynomial to [other]. - */ - public override operator fun Int.plus(other: NumberedPolynomial): NumberedPolynomial = - if (this == 0) other - else - NumberedPolynomial( - other.coefficients - .toMutableMap() - .apply { - val degs = emptyList() - - this[degs] = this@plus + getOrElse(degs) { constantZero } - } - ) - /** - * Returns difference between the integer represented as polynomial and the polynomial. - * - * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. - */ - public override operator fun Int.minus(other: NumberedPolynomial): NumberedPolynomial = - if (this == 0) other - else - NumberedPolynomial( - other.coefficients - .toMutableMap() - .apply { - val degs = emptyList() - - this[degs] = this@minus - getOrElse(degs) { constantZero } - } - ) - /** - * Returns product of the integer represented as polynomial and the polynomial. - * - * The operation is equivalent to sum of [this] copies of [other]. - */ - public override operator fun Int.times(other: NumberedPolynomial): NumberedPolynomial = - if (this == 0) zero - else NumberedPolynomial( - other.coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this@times * this[degs]!! - } - ) - - /** - * Converts the integer [value] to polynomial. - */ - public override fun number(value: Int): NumberedPolynomial = number(constantNumber(value)) - - /** - * Returns sum of the constant represented as polynomial and the polynomial. - */ - override operator fun C.plus(other: NumberedPolynomial): NumberedPolynomial = - with(other.coefficients) { - if (isEmpty()) NumberedPolynomial(mapOf(emptyList() to this@plus)) - else NumberedPolynomial( - toMutableMap() - .apply { - val degs = emptyList() - - this[degs] = this@plus + getOrElse(degs) { constantZero } - } - ) - } - /** - * Returns difference between the constant represented as polynomial and the polynomial. - */ - override operator fun C.minus(other: NumberedPolynomial): NumberedPolynomial = - with(other.coefficients) { - if (isEmpty()) NumberedPolynomial(mapOf(emptyList() to this@minus)) - else NumberedPolynomial( - toMutableMap() - .apply { - forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } - - val degs = emptyList() - - this[degs] = this@minus - getOrElse(degs) { constantZero } - } - ) - } - /** - * Returns product of the constant represented as polynomial and the polynomial. - */ - override operator fun C.times(other: NumberedPolynomial): NumberedPolynomial = - NumberedPolynomial( - other.coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this@times * this[degs]!! - } - ) - - /** - * Returns sum of the constant represented as polynomial and the polynomial. - */ - override operator fun NumberedPolynomial.plus(other: C): NumberedPolynomial = - with(coefficients) { - if (isEmpty()) NumberedPolynomial(mapOf(emptyList() to other)) - else NumberedPolynomial( - toMutableMap() - .apply { - val degs = emptyList() - - this[degs] = getOrElse(degs) { constantZero } + other - } - ) - } - /** - * Returns difference between the constant represented as polynomial and the polynomial. - */ - override operator fun NumberedPolynomial.minus(other: C): NumberedPolynomial = - with(coefficients) { - if (isEmpty()) NumberedPolynomial(mapOf(emptyList() to other)) - else NumberedPolynomial( - toMutableMap() - .apply { - val degs = emptyList() - - this[degs] = getOrElse(degs) { constantZero } - other - } - ) - } - /** - * Returns product of the constant represented as polynomial and the polynomial. - */ - override operator fun NumberedPolynomial.times(other: C): NumberedPolynomial = - NumberedPolynomial( - coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this[degs]!! * other - } - ) - - /** - * Converts the constant [value] to polynomial. - */ - public override fun number(value: C): NumberedPolynomial = - NumberedPolynomial(mapOf(emptyList() to value)) - - /** - * Returns negation of the polynomial. - */ - override fun NumberedPolynomial.unaryMinus(): NumberedPolynomial = - NumberedPolynomial( - coefficients.mapValues { -it.value } - ) - /** - * Returns sum of the polynomials. - */ - override operator fun NumberedPolynomial.plus(other: NumberedPolynomial): NumberedPolynomial = - NumberedPolynomial( - buildMap(coefficients.size + other.coefficients.size) { - other.coefficients.mapValuesTo(this) { it.value } - other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! + value else value } - } - ) - /** - * Returns difference of the polynomials. - */ - override operator fun NumberedPolynomial.minus(other: NumberedPolynomial): NumberedPolynomial = - NumberedPolynomial( - buildMap(coefficients.size + other.coefficients.size) { - other.coefficients.mapValuesTo(this) { it.value } - other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! - value else -value } - } - ) - /** - * Returns product of the polynomials. - */ - override operator fun NumberedPolynomial.times(other: NumberedPolynomial): NumberedPolynomial = - NumberedPolynomial( - buildMap(coefficients.size * other.coefficients.size) { - for ((degs1, c1) in coefficients) for ((degs2, c2) in other.coefficients) { - val degs = - (0..max(degs1.lastIndex, degs2.lastIndex)) - .map { degs1.getOrElse(it) { 0U } + degs2.getOrElse(it) { 0U } } - val c = c1 * c2 - this[degs] = if (degs in this) this[degs]!! + c else c - } - } - ) - - /** - * Instance of zero polynomial (zero of the polynomial ring). - */ - override val zero: NumberedPolynomial = NumberedPolynomial(emptyMap()) - /** - * Instance of unit polynomial (unit of the polynomial ring). - */ - override val one: NumberedPolynomial = - NumberedPolynomial( - mapOf( - emptyList() to constantOne // 1 * x_1^0 * x_2^0 * ... - ) - ) - - /** - * Maximal index (ID) of variable occurring in the polynomial with positive power. If there is no such variable, - * the result is `-1`. - */ - public val NumberedPolynomial.lastVariable: Int - get() = coefficients.entries.maxOfOrNull { (degs, _) -> degs.lastIndex } ?: -1 - /** - * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is - * zero, degree is -1. - */ - override val NumberedPolynomial.degree: Int - get() = coefficients.entries.maxOfOrNull { (degs, _) -> degs.sum().toInt() } ?: -1 - /** - * List that associates indices of variables (that appear in the polynomial in positive exponents) with their most - * exponents in which the variables are appeared in the polynomial. - * - * As consequence all values in the list are non-negative integers. Also, if the polynomial is constant, the list is empty. - * And last index of the list is [lastVariable]. - */ - public val NumberedPolynomial.degrees: List - get() = - MutableList(lastVariable + 1) { 0u }.apply { - coefficients.entries.forEach { (degs, _) -> - degs.forEachIndexed { index, deg -> - this[index] = max(this[index], deg) - } - } - } - /** - * Counts degree of the polynomial by the specified [variable]. - */ - public fun NumberedPolynomial.degreeBy(variable: Int): UInt = - coefficients.entries.maxOfOrNull { (degs, _) -> degs.getOrElse(variable) { 0u } } ?: 0u - /** - * Counts degree of the polynomial by the specified [variables]. - */ - public fun NumberedPolynomial.degreeBy(variables: Collection): UInt = - coefficients.entries.maxOfOrNull { (degs, _) -> - degs.withIndex().filter { (index, _) -> index in variables }.sumOf { it.value } - } ?: 0u - /** - * Count of variables occurring in the polynomial with positive power. If there is no such variable, - * the result is `0`. - */ - public val NumberedPolynomial.countOfVariables: Int - get() = - MutableList(lastVariable + 1) { false }.apply { - coefficients.entries.forEach { (degs, _) -> - degs.forEachIndexed { index, deg -> - if (deg != 0u) this[index] = true - } - } - }.count { it } - - @Suppress("NOTHING_TO_INLINE") - public inline fun NumberedPolynomial.substitute(argument: Map): NumberedPolynomial = this.substitute(ring, argument) - @Suppress("NOTHING_TO_INLINE") - @JvmName("substitutePolynomial") - public inline fun NumberedPolynomial.substitute(argument: Map>): NumberedPolynomial = this.substitute(ring, argument) - - @Suppress("NOTHING_TO_INLINE") - public inline fun NumberedPolynomial.asFunction(): (Map) -> NumberedPolynomial = { this.substitute(ring, it) } - @Suppress("NOTHING_TO_INLINE") - public inline fun NumberedPolynomial.asFunctionOnConstants(): (Map) -> NumberedPolynomial = { this.substitute(ring, it) } - @Suppress("NOTHING_TO_INLINE") - public inline fun NumberedPolynomial.asFunctionOnPolynomials(): (Map>) -> NumberedPolynomial = { this.substitute(ring, it) } - - @Suppress("NOTHING_TO_INLINE") - public inline operator fun NumberedPolynomial.invoke(argument: Map): NumberedPolynomial = this.substitute(ring, argument) - @Suppress("NOTHING_TO_INLINE") - @JvmName("invokePolynomial") - public inline operator fun NumberedPolynomial.invoke(argument: Map>): NumberedPolynomial = this.substitute(ring, argument) - - // FIXME: Move to other constructors with context receiver - public fun C.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomial(mapOf(emptyList() to this)) -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt deleted file mode 100644 index 30c7f0188..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt +++ /dev/null @@ -1,188 +0,0 @@ -/* - * 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.functions - -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.invoke -import kotlin.math.max - - -public class NumberedRationalFunction internal constructor( - public override val numerator: NumberedPolynomial, - public override val denominator: NumberedPolynomial -) : RationalFunction> { - override fun toString(): String = "NumberedRationalFunction${numerator.coefficients}/${denominator.coefficients}" -} - -public class NumberedRationalFunctionSpace> ( - public val ring: A, -) : - RationalFunctionalSpaceOverPolynomialSpace< - C, - NumberedPolynomial, - NumberedRationalFunction, - NumberedPolynomialSpace, - >, - PolynomialSpaceOfFractions< - C, - NumberedPolynomial, - NumberedRationalFunction, - >() { - - override val polynomialRing : NumberedPolynomialSpace = NumberedPolynomialSpace(ring) - override fun constructRationalFunction( - numerator: NumberedPolynomial, - denominator: NumberedPolynomial - ): NumberedRationalFunction = - NumberedRationalFunction(numerator, denominator) - - /** - * Instance of zero rational function (zero of the rational functions ring). - */ - public override val zero: NumberedRationalFunction = NumberedRationalFunction(polynomialZero, polynomialOne) - /** - * Instance of unit polynomial (unit of the rational functions ring). - */ - public override val one: NumberedRationalFunction = NumberedRationalFunction(polynomialOne, polynomialOne) - - /** - * Maximal index (ID) of variable occurring in the polynomial with positive power. If there is no such variable, - * the result is `-1`. - */ - public val NumberedPolynomial.lastVariable: Int get() = polynomialRing { lastVariable } - /** - * List that associates indices of variables (that appear in the polynomial in positive exponents) with their most - * exponents in which the variables are appeared in the polynomial. - * - * As consequence all values in the list are non-negative integers. Also, if the polynomial is constant, the list is empty. - * And last index of the list is [lastVariable]. - */ - public val NumberedPolynomial.degrees: List get() = polynomialRing { degrees } - /** - * Counts degree of the polynomial by the specified [variable]. - */ - public fun NumberedPolynomial.degreeBy(variable: Int): UInt = polynomialRing { degreeBy(variable) } - /** - * Counts degree of the polynomial by the specified [variables]. - */ - public fun NumberedPolynomial.degreeBy(variables: Collection): UInt = polynomialRing { degreeBy(variables) } - /** - * Count of variables occurring in the polynomial with positive power. If there is no such variable, - * the result is `0`. - */ - public val NumberedPolynomial.countOfVariables: Int get() = polynomialRing { countOfVariables } - - /** - * Count of all variables that appear in the polynomial in positive exponents. - */ - public val NumberedRationalFunction.lastVariable: Int - get() = polynomialRing { max(numerator.lastVariable, denominator.lastVariable) } - /** - * Count of variables occurring in the rational function with positive power. If there is no such variable, - * the result is `0`. - */ - public val NumberedRationalFunction.countOfVariables: Int - get() = - MutableList(lastVariable + 1) { false }.apply { - numerator.coefficients.entries.forEach { (degs, _) -> - degs.forEachIndexed { index, deg -> - if (deg != 0u) this[index] = true - } - } - denominator.coefficients.entries.forEach { (degs, _) -> - degs.forEachIndexed { index, deg -> - if (deg != 0u) this[index] = true - } - } - }.count { it } - - // TODO: Разобрать - -// operator fun invoke(arg: Map): NumberedRationalFunction = -// NumberedRationalFunction( -// numerator(arg), -// denominator(arg) -// ) -// -// @JvmName("invokePolynomial") -// operator fun invoke(arg: Map>): NumberedRationalFunction = -// NumberedRationalFunction( -// numerator(arg), -// denominator(arg) -// ) -// -// @JvmName("invokeRationalFunction") -// operator fun invoke(arg: Map>): NumberedRationalFunction { -// var num = numerator invokeRFTakeNumerator arg -// var den = denominator invokeRFTakeNumerator arg -// for (variable in 0 until max(numerator.countOfVariables, denominator.countOfVariables)) if (variable in arg) { -// val degreeDif = numerator.degrees.getOrElse(variable) { 0 } - denominator.degrees.getOrElse(variable) { 0 } -// if (degreeDif > 0) -// den = multiplyByPower(den, arg[variable]!!.denominator, degreeDif) -// else -// num = multiplyByPower(num, arg[variable]!!.denominator, -degreeDif) -// } -// return NumberedRationalFunction(num, den) -// } -// -// override fun toString(): String = toString(Polynomial.variableName) -// -// fun toString(withVariableName: String = Polynomial.variableName): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toString(withVariableName) -// else -> "${numerator.toStringWithBrackets(withVariableName)}/${denominator.toStringWithBrackets(withVariableName)}" -// } -// -// fun toString(namer: (Int) -> String): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toString(namer) -// else -> "${numerator.toStringWithBrackets(namer)}/${denominator.toStringWithBrackets(namer)}" -// } -// -// fun toStringWithBrackets(withVariableName: String = Polynomial.variableName): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toStringWithBrackets(withVariableName) -// else -> "(${numerator.toStringWithBrackets(withVariableName)}/${denominator.toStringWithBrackets(withVariableName)})" -// } -// -// fun toStringWithBrackets(namer: (Int) -> String): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toStringWithBrackets(namer) -// else -> "(${numerator.toStringWithBrackets(namer)}/${denominator.toStringWithBrackets(namer)})" -// } -// -// fun toReversedString(withVariableName: String = Polynomial.variableName): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedString(withVariableName) -// else -> "${numerator.toReversedStringWithBrackets(withVariableName)}/${denominator.toReversedStringWithBrackets(withVariableName)}" -// } -// -// fun toReversedString(namer: (Int) -> String): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedString(namer) -// else -> "${numerator.toReversedStringWithBrackets(namer)}/${denominator.toReversedStringWithBrackets(namer)}" -// } -// -// fun toReversedStringWithBrackets(withVariableName: String = Polynomial.variableName): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedStringWithBrackets(withVariableName) -// else -> "(${numerator.toReversedStringWithBrackets(withVariableName)}/${denominator.toReversedStringWithBrackets(withVariableName)})" -// } -// -// fun toReversedStringWithBrackets(namer: (Int) -> String): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedStringWithBrackets(namer) -// else -> "(${numerator.toReversedStringWithBrackets(namer)}/${denominator.toReversedStringWithBrackets(namer)})" -// } -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt deleted file mode 100644 index 612b00535..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt +++ /dev/null @@ -1,132 +0,0 @@ -/* - * 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.functions - -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.operations.Ring - -/** - * Represents piecewise-defined function. - * - * @param T the piece key type. - * @param R the sub-function type. - */ -public fun interface Piecewise { - /** - * Returns the appropriate sub-function for given piece key. - */ - public fun findPiece(arg: T): R? -} - -/** - * Represents piecewise-defined function where all the sub-functions are polynomials. - * - * @property pieces An ordered list of range-polynomial pairs. The list does not in general guarantee that there are no - * "holes" in it. - */ -public interface PiecewisePolynomial> : Piecewise> { - public val pieces: Collection, ListPolynomial>> - - override fun findPiece(arg: T): ListPolynomial? -} - -/** - * A generic piecewise without constraints on how pieces are placed - */ -@PerformancePitfall("findPiece method of resulting piecewise is slow") -public fun > PiecewisePolynomial( - pieces: Collection, ListPolynomial>>, -): PiecewisePolynomial = object : PiecewisePolynomial { - override val pieces: Collection, ListPolynomial>> = pieces - - override fun findPiece(arg: T): ListPolynomial? = pieces.firstOrNull { arg in it.first }?.second -} - -/** - * An optimized piecewise that uses not separate pieces, but a range separated by delimiters. - * The pieces search is logarithmic. - */ -private class OrderedPiecewisePolynomial>( - override val pieces: List, ListPolynomial>>, -) : PiecewisePolynomial { - - override fun findPiece(arg: T): ListPolynomial? { - val index = pieces.binarySearch { (range, _) -> - when { - arg >= range.endInclusive -> -1 - arg < range.start -> +1 - else -> 0 - } - } - return if (index < 0) null else pieces[index].second - } - -} - -/** - * A [Piecewise] builder where all the pieces are ordered by the [Comparable] type instances. - * - * @param T the comparable piece key type. - * @param delimiter the initial piecewise separator - */ -public class PiecewiseBuilder>(delimiter: T) { - private val delimiters: MutableList = arrayListOf(delimiter) - private val pieces: MutableList> = arrayListOf() - - /** - * Dynamically adds a piece to the right side (beyond maximum argument value of previous piece) - * - * @param right new rightmost position. If is less than current rightmost position, an error is thrown. - * @param piece the sub-function. - */ - public fun putRight(right: T, piece: ListPolynomial) { - require(right > delimiters.last()) { "New delimiter should be to the right of old one" } - delimiters += right - pieces += piece - } - - /** - * Dynamically adds a piece to the left side (beyond maximum argument value of previous piece) - * - * @param left the new leftmost position. If is less than current rightmost position, an error is thrown. - * @param piece the sub-function. - */ - public fun putLeft(left: T, piece: ListPolynomial) { - require(left < delimiters.first()) { "New delimiter should be to the left of old one" } - delimiters.add(0, left) - pieces.add(0, piece) - } - - public fun build(): PiecewisePolynomial = OrderedPiecewisePolynomial(delimiters.zipWithNext { l, r -> - l..r - }.zip(pieces)) -} - -/** - * A builder for [PiecewisePolynomial] - */ -public fun > PiecewisePolynomial( - startingPoint: T, - builder: PiecewiseBuilder.() -> Unit, -): PiecewisePolynomial = PiecewiseBuilder(startingPoint).apply(builder).build() - -/** - * Return a value of polynomial function with given [ring] a given [arg] or null if argument is outside piecewise - * definition. - */ -public fun , C : Ring> PiecewisePolynomial.substitute(ring: C, arg: T): T? = - findPiece(arg)?.substitute(ring, arg) - -/** - * Convert this polynomial to a function returning nullable value (null if argument is outside piecewise range). - */ -public fun , C : Ring> PiecewisePolynomial.asFunction(ring: C): (T) -> T? = { substitute(ring, it) } - -/** - * Convert this polynomial to a function using [defaultValue] for arguments outside the piecewise range. - */ -public fun , C : Ring> PiecewisePolynomial.asFunction(ring: C, defaultValue: T): (T) -> T = - { substitute(ring, it) ?: defaultValue } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt deleted file mode 100644 index e81a9388e..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt +++ /dev/null @@ -1,203 +0,0 @@ -/* - * 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.functions - -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.Ring - - -/** - * Returns the same degrees' description of the monomial, but without zero degrees. - */ -internal fun Map.cleanUp() = filterValues { it > 0U } - -// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available - -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > LabeledPolynomialSpace.LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(coefs, toCheckInput) -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(coefs, toCheckInput) -@Suppress("FunctionName") -internal fun > A.LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : LabeledPolynomial { - if (!toCheckInput) return LabeledPolynomial(coefs) - - val fixedCoefs = LinkedHashMap, C>(coefs.size) - - for (entry in coefs) { - val key = entry.key.cleanUp() - val value = entry.value - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return LabeledPolynomial(fixedCoefs) -} - -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > LabeledPolynomialSpace.LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(pairs, toCheckInput) -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(pairs, toCheckInput) -@Suppress("FunctionName") -internal fun > A.LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : LabeledPolynomial { - if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) - - val fixedCoefs = LinkedHashMap, C>(pairs.size) - - for (entry in pairs) { - val key = entry.first.cleanUp() - val value = entry.second - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return LabeledPolynomial(fixedCoefs) -} - -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > LabeledPolynomialSpace.LabeledPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(pairs = pairs, toCheckInput = toCheckInput) -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(pairs = pairs, toCheckInput = toCheckInput) -@Suppress("FunctionName") -internal fun > A.LabeledPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : LabeledPolynomial { - if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) - - val fixedCoefs = LinkedHashMap, C>(pairs.size) - - for (entry in pairs) { - val key = entry.first.cleanUp() - val value = entry.second - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return LabeledPolynomial(fixedCoefs) -} - -@Suppress("FunctionName") -public fun > A.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) -@Suppress("FunctionName") -public fun > LabeledPolynomialSpace.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) -@Suppress("FunctionName") -public fun > LabeledRationalFunctionSpace.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) - -@Suppress("FunctionName") -public fun > A.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > LabeledPolynomialSpace.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > LabeledRationalFunctionSpace.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) - -@Suppress("FunctionName") -public fun > A.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > LabeledPolynomialSpace.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > LabeledRationalFunctionSpace.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs, toCheckInput = true) - -//context(A) -//public fun > Symbol.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1u) to one)) -//context(LabeledPolynomialSpace) -//public fun > Symbol.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1u) to constantOne)) -//context(LabeledRationalFunctionSpace) -//public fun > Symbol.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1u) to constantOne)) - -public fun C.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to this)) - -@DslMarker -@UnstableKMathAPI -internal annotation class LabeledPolynomialConstructorDSL - -@UnstableKMathAPI -@LabeledPolynomialConstructorDSL -public class LabeledPolynomialTermSignatureBuilder { - private val signature: MutableMap = LinkedHashMap() - public fun build(): Map = signature - public infix fun Symbol.inPowerOf(deg: UInt) { - signature[this] = deg - } - @Suppress("NOTHING_TO_INLINE") - public inline infix fun Symbol.pow(deg: UInt): Unit = this inPowerOf deg - @Suppress("NOTHING_TO_INLINE") - public inline infix fun Symbol.`in`(deg: UInt): Unit = this inPowerOf deg - @Suppress("NOTHING_TO_INLINE") - public inline infix fun Symbol.of(deg: UInt): Unit = this inPowerOf deg -} - -@UnstableKMathAPI -public class LabeledPolynomialBuilder(private val zero: C, private val add: (C, C) -> C, capacity: Int = 0) { - private val coefficients: MutableMap, C> = LinkedHashMap(capacity) - public fun build(): LabeledPolynomial = LabeledPolynomial(coefficients) - public operator fun C.invoke(block: LabeledPolynomialTermSignatureBuilder.() -> Unit) { - val signature = LabeledPolynomialTermSignatureBuilder().apply(block).build() - coefficients[signature] = add(coefficients.getOrElse(signature) { zero }, this@invoke) - } - @Suppress("NOTHING_TO_INLINE") - public inline infix fun C.with(noinline block: LabeledPolynomialTermSignatureBuilder.() -> Unit): Unit = this.invoke(block) - @Suppress("NOTHING_TO_INLINE") - public inline infix fun (LabeledPolynomialTermSignatureBuilder.() -> Unit).with(coef: C): Unit = coef.invoke(this) - @Suppress("NOTHING_TO_INLINE") - public infix fun sig(block: LabeledPolynomialTermSignatureBuilder.() -> Unit): LabeledPolynomialTermSignatureBuilder.() -> Unit = block -} - -// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available - -@UnstableKMathAPI -@LabeledPolynomialConstructorDSL -@Suppress("FunctionName") -public inline fun > A.LabeledPolynomial(block: LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = LabeledPolynomialBuilder(zero, ::add).apply(block).build() -@UnstableKMathAPI -@LabeledPolynomialConstructorDSL -@Suppress("FunctionName") -public inline fun > A.LabeledPolynomial(capacity: Int, block: LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = LabeledPolynomialBuilder(zero, ::add, capacity).apply(block).build() -@UnstableKMathAPI -@LabeledPolynomialConstructorDSL -@Suppress("FunctionName") -public inline fun > LabeledPolynomialSpace.LabeledPolynomial(block: LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = LabeledPolynomialBuilder(constantZero, { left: C, right: C -> left + right}).apply(block).build() -@UnstableKMathAPI -@LabeledPolynomialConstructorDSL -@Suppress("FunctionName") -public inline fun > LabeledPolynomialSpace.LabeledPolynomial(capacity: Int, block: LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = LabeledPolynomialBuilder(constantZero, { left: C, right: C -> left + right}, capacity).apply(block).build() - -// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available - -@Suppress("FunctionName") -public fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): LabeledRationalFunction = - LabeledRationalFunction( - LabeledPolynomial(numeratorCoefficients, toCheckInput = true), - LabeledPolynomial(denominatorCoefficients, toCheckInput = true) - ) -@Suppress("FunctionName") -public fun > A.LabeledRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): LabeledRationalFunction = - LabeledRationalFunction( - LabeledPolynomial(numeratorCoefficients, toCheckInput = true), - LabeledPolynomial(denominatorCoefficients, toCheckInput = true) - ) -@Suppress("FunctionName") -public fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numerator: LabeledPolynomial): LabeledRationalFunction = - LabeledRationalFunction(numerator, polynomialOne) -@Suppress("FunctionName") -public fun > A.LabeledRationalFunction(numerator: LabeledPolynomial): LabeledRationalFunction = - LabeledRationalFunction(numerator, LabeledPolynomial(mapOf(emptyMap() to one), toCheckInput = false)) -@Suppress("FunctionName") -public fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numeratorCoefficients: Map, C>): LabeledRationalFunction = - LabeledRationalFunction( - LabeledPolynomial(numeratorCoefficients, toCheckInput = true), - polynomialOne - ) -@Suppress("FunctionName") -public fun > A.LabeledRationalFunction(numeratorCoefficients: Map, C>): LabeledRationalFunction = - LabeledRationalFunction( - LabeledPolynomial(numeratorCoefficients, toCheckInput = true), - LabeledPolynomial(mapOf(emptyMap() to one), toCheckInput = false) - ) - -//context(A) -//public fun > Symbol.asLabeledRationalFunction() : LabeledRationalFunction = LabeledRationalFunction(asLabeledPolynomial()) -//context(LabeledRationalFunctionSpace) -//public fun > Symbol.asLabeledRationalFunction() : LabeledRationalFunction = LabeledRationalFunction(asLabeledPolynomial()) - -//context(A) -//public fun > C.asLabeledRationalFunction() : LabeledRationalFunction = LabeledRationalFunction(asLabeledPolynomial()) -//context(LabeledRationalFunctionSpace) -//public fun > C.asLabeledRationalFunction() : LabeledRationalFunction = LabeledRationalFunction(asLabeledPolynomial()) \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt deleted file mode 100644 index af918b9ae..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt +++ /dev/null @@ -1,495 +0,0 @@ -/* - * 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.functions - -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.Field -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.invoke -import kotlin.contracts.ExperimentalContracts -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract - - -// TODO: Docs - -/** - * Creates a [LabeledPolynomialSpace] over a received ring. - */ -public fun > A.labeledPolynomial(): LabeledPolynomialSpace = - LabeledPolynomialSpace(this) - -/** - * Creates a [LabeledPolynomialSpace]'s scope over a received ring. - */ -@OptIn(ExperimentalContracts::class) -public inline fun , R> A.labeledPolynomial(block: LabeledPolynomialSpace.() -> R): R { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return LabeledPolynomialSpace(this).block() -} - -///** -// * Represents the polynomial as a [String] with names of variables substituted with names from [names]. -// * Consider that monomials are sorted in lexicographic order. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.represent(names: Map = emptyMap()): String = -// coefficients.entries -// .sortedWith { o1, o2 -> LabeledPolynomial.monomialComparator.compare(o1.key, o2.key) } -// .asSequence() -// .map { (degs, t) -> -// if (degs.isEmpty()) "$t" -// else { -// when { -// t.isOne() -> "" -// t.isMinusOne() -> "-" -// else -> "$t " -// } + -// degs -// .toSortedMap() -// .filter { it.value > 0U } -// .map { (variable, deg) -> -// val variableName = names.getOrDefault(variable, variable.toString()) -// when (deg) { -// 1U -> variableName -// else -> "$variableName^$deg" -// } -// } -// .joinToString(separator = " ") { it } -// } -// } -// .joinToString(separator = " + ") { it } -// .ifEmpty { "0" } -// -///** -// * Represents the polynomial as a [String] naming variables by [namer]. -// * Consider that monomials are sorted in lexicographic order. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.represent(namer: (Symbol) -> String): String = -// coefficients.entries -// .sortedWith { o1, o2 -> LabeledPolynomial.monomialComparator.compare(o1.key, o2.key) } -// .asSequence() -// .map { (degs, t) -> -// if (degs.isEmpty()) "$t" -// else { -// when { -// t.isOne() -> "" -// t.isMinusOne() -> "-" -// else -> "$t " -// } + -// degs -// .toSortedMap() -// .filter { it.value > 0U } -// .map { (variable, deg) -> -// when (deg) { -// 1U -> namer(variable) -// else -> "${namer(variable)}^$deg" -// } -// } -// .joinToString(separator = " ") { it } -// } -// } -// .joinToString(separator = " + ") { it } -// .ifEmpty { "0" } -// -///** -// * Represents the polynomial as a [String] with names of variables substituted with names from [names] and with -// * brackets around the string if needed (i.e. when there are at least two addends in the representation). -// * Consider that monomials are sorted in lexicographic order. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.representWithBrackets(names: Map = emptyMap()): String = -// with(represent(names)) { if (coefficients.count() == 1) this else "($this)" } -// -///** -// * Represents the polynomial as a [String] naming variables by [namer] and with brackets around the string if needed -// * (i.e. when there are at least two addends in the representation). -// * Consider that monomials are sorted in lexicographic order. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.representWithBrackets(namer: (Symbol) -> String): String = -// with(represent(namer)) { if (coefficients.count() == 1) this else "($this)" } -// -///** -// * Represents the polynomial as a [String] with names of variables substituted with names from [names]. -// * Consider that monomials are sorted in **reversed** lexicographic order. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.representReversed(names: Map = emptyMap()): String = -// coefficients.entries -// .sortedWith { o1, o2 -> -LabeledPolynomial.monomialComparator.compare(o1.key, o2.key) } -// .asSequence() -// .map { (degs, t) -> -// if (degs.isEmpty()) "$t" -// else { -// when { -// t.isOne() -> "" -// t.isMinusOne() -> "-" -// else -> "$t " -// } + -// degs -// .toSortedMap() -// .filter { it.value > 0U } -// .map { (variable, deg) -> -// val variableName = names.getOrDefault(variable, variable.toString()) -// when (deg) { -// 1U -> variableName -// else -> "$variableName^$deg" -// } -// } -// .joinToString(separator = " ") { it } -// } -// } -// .joinToString(separator = " + ") { it } -// .ifEmpty { "0" } -// -///** -// * Represents the polynomial as a [String] naming variables by [namer]. -// * Consider that monomials are sorted in **reversed** lexicographic order. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.representReversed(namer: (Symbol) -> String): String = -// coefficients.entries -// .sortedWith { o1, o2 -> -LabeledPolynomial.monomialComparator.compare(o1.key, o2.key) } -// .asSequence() -// .map { (degs, t) -> -// if (degs.isEmpty()) "$t" -// else { -// when { -// t.isOne() -> "" -// t.isMinusOne() -> "-" -// else -> "$t " -// } + -// degs -// .toSortedMap() -// .filter { it.value > 0U } -// .map { (variable, deg) -> -// when (deg) { -// 1U -> namer(variable) -// else -> "${namer(variable)}^$deg" -// } -// } -// .joinToString(separator = " ") { it } -// } -// } -// .joinToString(separator = " + ") { it } -// .ifEmpty { "0" } -// -///** -// * Represents the polynomial as a [String] with names of variables substituted with names from [names] and with -// * brackets around the string if needed (i.e. when there are at least two addends in the representation). -// * Consider that monomials are sorted in **reversed** lexicographic order. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.representReversedWithBrackets(names: Map = emptyMap()): String = -// with(representReversed(names)) { if (coefficients.count() == 1) this else "($this)" } -// -///** -// * Represents the polynomial as a [String] naming variables by [namer] and with brackets around the string if needed -// * (i.e. when there are at least two addends in the representation). -// * Consider that monomials are sorted in **reversed** lexicographic order. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.representReversedWithBrackets(namer: (Symbol) -> String): String = -// with(representReversed(namer)) { if (coefficients.count() == 1) this else "($this)" } - -//operator fun > Polynomial.div(other: T): Polynomial = -// if (other.isZero()) throw ArithmeticException("/ by zero") -// else -// Polynomial( -// coefficients -// .mapValues { it.value / other }, -// toCheckInput = false -// ) - -//public fun LabeledPolynomial.substitute(ring: Ring, args: Map): LabeledPolynomial = ring { -// if (coefficients.isEmpty()) return this@substitute -// LabeledPolynomial( -// buildMap { -// coefficients.forEach { (degs, c) -> -// val newDegs = degs.filterKeys { it !in args } -// val newC = degs.entries.asSequence().filter { it.key in args }.fold(c) { acc, (variable, deg) -> -// multiplyWithPower(acc, args[variable]!!, deg) -// } -// this[newDegs] = if (newDegs in this) this[newDegs]!! + newC else newC -// } -// } -// ) -//} -// -//// TODO: Replace with optimisation: the [result] may be unboxed, and all operations may be performed as soon as -//// possible on it -//@JvmName("substitutePolynomial") -//fun LabeledPolynomial.substitute(ring: Ring, arg: Map>) : LabeledPolynomial = -// ring.labeledPolynomial { -// if (coefficients.isEmpty()) return zero -// coefficients -// .asSequence() -// .map { (degs, c) -> -// degs.entries -// .asSequence() -// .filter { it.key in arg } -// .fold(LabeledPolynomial(mapOf(degs.filterKeys { it !in arg } to c))) { acc, (index, deg) -> -// multiplyWithPower(acc, arg[index]!!, deg) -// } -// } -// .reduce { acc, polynomial -> acc + polynomial } // TODO: Rewrite. Might be slow. -// } -// -//// TODO: Substitute rational function -// -//fun > LabeledPolynomial.asFunctionOver(ring: A): (Map) -> LabeledPolynomial = -// { substitute(ring, it) } -// -//fun > LabeledPolynomial.asPolynomialFunctionOver(ring: A): (Map>) -> LabeledPolynomial = -// { substitute(ring, it) } - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > LabeledPolynomial.derivativeWithRespectTo( - algebra: A, - variable: Symbol, -): LabeledPolynomial = algebra { - LabeledPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - if (variable !in degs) return@forEach - put( - buildMap { - degs.forEach { (vari, deg) -> - when { - vari != variable -> put(vari, deg) - deg > 1u -> put(vari, deg - 1u) - } - } - }, - multiplyByDoubling(c, degs[variable]!!) - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > LabeledPolynomial.derivativeWithRespectTo( - algebra: A, - variables: Collection, -): LabeledPolynomial = algebra { - val cleanedVariables = variables.toSet() - if (cleanedVariables.isEmpty()) return this@derivativeWithRespectTo - LabeledPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - if (!degs.keys.containsAll(cleanedVariables)) return@forEach - put( - buildMap { - degs.forEach { (vari, deg) -> - when { - vari !in cleanedVariables -> put(vari, deg) - deg > 1u -> put(vari, deg - 1u) - } - } - }, - cleanedVariables.fold(c) { acc, variable -> multiplyByDoubling(acc, degs[variable]!!) } - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > LabeledPolynomial.nthDerivativeWithRespectTo( - algebra: A, - variable: Symbol, - order: UInt -): LabeledPolynomial = algebra { - if (order == 0u) return this@nthDerivativeWithRespectTo - LabeledPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - if (degs.getOrElse(variable) { 0u } < order) return@forEach - put( - buildMap { - degs.forEach { (vari, deg) -> - when { - vari != variable -> put(vari, deg) - deg > order -> put(vari, deg - order) - } - } - }, - degs[variable]!!.let { deg -> - (deg downTo deg - order + 1u) - .fold(c) { acc, ord -> multiplyByDoubling(acc, ord) } - } - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > LabeledPolynomial.nthDerivativeWithRespectTo( - algebra: A, - variablesAndOrders: Map, -): LabeledPolynomial = algebra { - val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u } - if (filteredVariablesAndOrders.isEmpty()) return this@nthDerivativeWithRespectTo - LabeledPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - if (filteredVariablesAndOrders.any { (variable, order) -> degs.getOrElse(variable) { 0u } < order }) return@forEach - put( - buildMap { - degs.forEach { (vari, deg) -> - if (vari !in filteredVariablesAndOrders) put(vari, deg) - else { - val order = filteredVariablesAndOrders[vari]!! - if (deg > order) put(vari, deg - order) - } - } - }, - filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> - degs[index]!!.let { deg -> - (deg downTo deg - order + 1u) - .fold(acc1) { acc2, ord -> multiplyByDoubling(acc2, ord) } - } - } - ) - } - } - ) -} - -/** - * Returns algebraic antiderivative of received polynomial. - */ -@UnstableKMathAPI -public fun > LabeledPolynomial.antiderivativeWithRespectTo( - algebra: A, - variable: Symbol, -): LabeledPolynomial = algebra { - LabeledPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - val newDegs = buildMap(degs.size + 1) { - put(variable, 1u) - for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) - } - put( - newDegs, - c / multiplyByDoubling(one, newDegs[variable]!!) - ) - } - } - ) -} - -/** - * Returns algebraic antiderivative of received polynomial. - */ -@UnstableKMathAPI -public fun > LabeledPolynomial.antiderivativeWithRespectTo( - algebra: A, - variables: Collection, -): LabeledPolynomial = algebra { - val cleanedVariables = variables.toSet() - if (cleanedVariables.isEmpty()) return this@antiderivativeWithRespectTo - LabeledPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - val newDegs = buildMap(degs.size + 1) { - for (variable in cleanedVariables) put(variable, 1u) - for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) - } - put( - newDegs, - cleanedVariables.fold(c) { acc, variable -> acc / multiplyByDoubling(one, newDegs[variable]!!) } - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > LabeledPolynomial.nthAntiderivativeWithRespectTo( - algebra: A, - variable: Symbol, - order: UInt -): LabeledPolynomial = algebra { - if (order == 0u) return this@nthAntiderivativeWithRespectTo - LabeledPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - val newDegs = buildMap(degs.size + 1) { - put(variable, order) - for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) - } - put( - newDegs, - newDegs[variable]!!.let { deg -> - (deg downTo deg - order + 1u) - .fold(c) { acc, ord -> acc / multiplyByDoubling(one, ord) } - } - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > LabeledPolynomial.nthAntiderivativeWithRespectTo( - algebra: A, - variablesAndOrders: Map, -): LabeledPolynomial = algebra { - val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u } - if (filteredVariablesAndOrders.isEmpty()) return this@nthAntiderivativeWithRespectTo - LabeledPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - val newDegs = buildMap(degs.size + 1) { - for ((variable, order) in filteredVariablesAndOrders) put(variable, order) - for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) - } - put( - newDegs, - filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> - newDegs[index]!!.let { deg -> - (deg downTo deg - order + 1u) - .fold(acc1) { acc2, ord -> acc2 / multiplyByDoubling(one, ord) } - } - } - ) - } - } - ) -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt deleted file mode 100644 index 583160cf4..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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.functions - -import space.kscience.kmath.operations.Ring -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract - - -/** - * Creates a [LabeledRationalFunctionSpace] over a received ring. - */ -public fun > A.labeledRationalFunction(): LabeledRationalFunctionSpace = - LabeledRationalFunctionSpace(this) - -/** - * Creates a [LabeledRationalFunctionSpace]'s scope over a received ring. - */ -public inline fun , R> A.labeledRationalFunction(block: LabeledRationalFunctionSpace.() -> R): R { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return LabeledRationalFunctionSpace(this).block() -} - -//fun > LabeledRationalFunction.reduced(): LabeledRationalFunction { -// val greatestCommonDivider = polynomialGCD(numerator, denominator) -// return LabeledRationalFunction( -// numerator / greatestCommonDivider, -// denominator / greatestCommonDivider -// ) -//} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt deleted file mode 100644 index dca8a0cff..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt +++ /dev/null @@ -1,195 +0,0 @@ -/* - * 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.functions - -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.Ring - - -/** - * Returns the same degrees' description of the monomial, but without extra zero degrees on the end. - */ -internal fun List.cleanUp() = subList(0, indexOfLast { it != 0U } + 1) - -// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available - -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > NumberedPolynomialSpace.NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(coefs, toCheckInput) -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(coefs, toCheckInput) -@Suppress("FunctionName") -internal fun > A.NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : NumberedPolynomial { - if (!toCheckInput) return NumberedPolynomial(coefs) - - val fixedCoefs = mutableMapOf, C>() - - for (entry in coefs) { - val key = entry.key.cleanUp() - val value = entry.value - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return NumberedPolynomial(fixedCoefs) -} - -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > NumberedPolynomialSpace.NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(pairs, toCheckInput) -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(pairs, toCheckInput) -@Suppress("FunctionName") -internal fun > A.NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : NumberedPolynomial { - if (!toCheckInput) return NumberedPolynomial(pairs.toMap()) - - val fixedCoefs = mutableMapOf, C>() - - for (entry in pairs) { - val key = entry.first.cleanUp() - val value = entry.second - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return NumberedPolynomial(fixedCoefs) -} - -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > NumberedPolynomialSpace.NumberedPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(pairs = pairs, toCheckInput = toCheckInput) -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(pairs = pairs, toCheckInput = toCheckInput) -@Suppress("FunctionName") -internal fun > A.NumberedPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : NumberedPolynomial { - if (!toCheckInput) return NumberedPolynomial(pairs.toMap()) - - val fixedCoefs = mutableMapOf, C>() - - for (entry in pairs) { - val key = entry.first.cleanUp() - val value = entry.second - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return NumberedPolynomial(fixedCoefs) -} - -@Suppress("FunctionName") -public fun > A.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, toCheckInput = true) -@Suppress("FunctionName") -public fun > NumberedPolynomialSpace.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, toCheckInput = true) -@Suppress("FunctionName") -public fun > NumberedRationalFunctionSpace.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, toCheckInput = true) - -@Suppress("FunctionName") -public fun > A.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > NumberedPolynomialSpace.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > NumberedRationalFunctionSpace.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, toCheckInput = true) - -@Suppress("FunctionName") -public fun > A.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > NumberedPolynomialSpace.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > NumberedRationalFunctionSpace.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs, toCheckInput = true) - -public fun C.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomial(mapOf(emptyList() to this)) - -@DslMarker -@UnstableKMathAPI -internal annotation class NumberedPolynomialConstructorDSL - -@UnstableKMathAPI -@NumberedPolynomialConstructorDSL -public class NumberedPolynomialTermSignatureBuilder { - private val signature: MutableList = ArrayList() - public fun build(): List = signature - public infix fun Int.inPowerOf(deg: UInt) { - if (this > signature.lastIndex) { - signature.addAll(List(this - signature.lastIndex - 1) { 0u }) - signature.add(deg) - } else { - signature[this] = deg - } - } - @Suppress("NOTHING_TO_INLINE") - public inline infix fun Int.pow(deg: UInt): Unit = this inPowerOf deg - @Suppress("NOTHING_TO_INLINE") - public inline infix fun Int.`in`(deg: UInt): Unit = this inPowerOf deg - @Suppress("NOTHING_TO_INLINE") - public inline infix fun Int.of(deg: UInt): Unit = this inPowerOf deg -} - -@UnstableKMathAPI -public class NumberedPolynomialBuilder(private val zero: C, private val add: (C, C) -> C, capacity: Int = 0) { - private val coefficients: MutableMap, C> = LinkedHashMap(capacity) - public fun build(): NumberedPolynomial = NumberedPolynomial(coefficients) - public operator fun C.invoke(block: NumberedPolynomialTermSignatureBuilder.() -> Unit) { - val signature = NumberedPolynomialTermSignatureBuilder().apply(block).build() - coefficients[signature] = add(coefficients.getOrElse(signature) { zero }, this@invoke) - } - @Suppress("NOTHING_TO_INLINE") - public inline infix fun C.with(noinline block: NumberedPolynomialTermSignatureBuilder.() -> Unit): Unit = this.invoke(block) - @Suppress("NOTHING_TO_INLINE") - public inline infix fun (NumberedPolynomialTermSignatureBuilder.() -> Unit).with(coef: C): Unit = coef.invoke(this) - @Suppress("NOTHING_TO_INLINE") - public infix fun sig(block: NumberedPolynomialTermSignatureBuilder.() -> Unit): NumberedPolynomialTermSignatureBuilder.() -> Unit = block -} - -// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available - -@UnstableKMathAPI -@NumberedPolynomialConstructorDSL -@Suppress("FunctionName") -public inline fun > A.NumberedPolynomial(block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder(zero, ::add).apply(block).build() -@UnstableKMathAPI -@NumberedPolynomialConstructorDSL -@Suppress("FunctionName") -public inline fun > A.NumberedPolynomial(capacity: Int, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder(zero, ::add, capacity).apply(block).build() -@UnstableKMathAPI -@NumberedPolynomialConstructorDSL -@Suppress("FunctionName") -public inline fun > NumberedPolynomialSpace.NumberedPolynomial(block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder(constantZero, { left: C, right: C -> left + right}).apply(block).build() -@UnstableKMathAPI -@NumberedPolynomialConstructorDSL -@Suppress("FunctionName") -public inline fun > NumberedPolynomialSpace.NumberedPolynomial(capacity: Int, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder(constantZero, { left: C, right: C -> left + right}, capacity).apply(block).build() - -// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available - -@Suppress("FunctionName") -public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): NumberedRationalFunction = - NumberedRationalFunction( - NumberedPolynomial(numeratorCoefficients, toCheckInput = true), - NumberedPolynomial(denominatorCoefficients, toCheckInput = true) - ) -@Suppress("FunctionName") -public fun > A.NumberedRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): NumberedRationalFunction = - NumberedRationalFunction( - NumberedPolynomial(numeratorCoefficients, toCheckInput = true), - NumberedPolynomial(denominatorCoefficients, toCheckInput = true) - ) -@Suppress("FunctionName") -public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numerator: NumberedPolynomial): NumberedRationalFunction = - NumberedRationalFunction(numerator, polynomialOne) -@Suppress("FunctionName") -public fun > A.NumberedRationalFunction(numerator: NumberedPolynomial): NumberedRationalFunction = - NumberedRationalFunction(numerator, NumberedPolynomial(mapOf(emptyList() to one), toCheckInput = false)) -@Suppress("FunctionName") -public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numeratorCoefficients: Map, C>): NumberedRationalFunction = - NumberedRationalFunction( - NumberedPolynomial(numeratorCoefficients, toCheckInput = true), - polynomialOne - ) -@Suppress("FunctionName") -public fun > A.NumberedRationalFunction(numeratorCoefficients: Map, C>): NumberedRationalFunction = - NumberedRationalFunction( - NumberedPolynomial(numeratorCoefficients, toCheckInput = true), - NumberedPolynomial(mapOf(emptyList() to one), toCheckInput = false) - ) - -//context(A) -//public fun > C.asNumberedRationalFunction() : NumberedRationalFunction = NumberedRationalFunction(asLabeledPolynomial()) -//context(NumberedRationalFunctionSpace) -//public fun > C.asNumberedRationalFunction() : NumberedRationalFunction = NumberedRationalFunction(asLabeledPolynomial()) \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt deleted file mode 100644 index ad817c7ba..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt +++ /dev/null @@ -1,528 +0,0 @@ -package space.kscience.kmath.functions - -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.* -import kotlin.contracts.* -import kotlin.jvm.JvmName -import kotlin.math.max - - -// TODO: Docs - -/** - * Creates a [NumberedPolynomialSpace] over a received ring. - */ -public fun > A.numberedPolynomial(): NumberedPolynomialSpace = - NumberedPolynomialSpace(this) - -/** - * Creates a [NumberedPolynomialSpace]'s scope over a received ring. - */ -@OptIn(ExperimentalContracts::class) -public inline fun , R> A.numberedPolynomial(block: NumberedPolynomialSpace.() -> R): R { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return NumberedPolynomialSpace(this).block() -} - -///** -// * Represents the polynomial as a [String] where name of variable with index `i` is [withVariableName] + `"_${i+1}"`. -// * Consider that monomials are sorted in lexicographic order. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial.represent(withVariableName: String = NumberedPolynomial.defaultVariableName): String = -// coefficients.entries -// .sortedWith { o1, o2 -> NumberedPolynomial.monomialComparator.compare(o1.key, o2.key) } -// .asSequence() -// .map { (degs, t) -> -// if (degs.isEmpty()) "$t" -// else { -// when { -// t.isOne() -> "" -// t.isMinusOne() -> "-" -// else -> "$t " -// } + -// degs -// .mapIndexed { index, deg -> -// when (deg) { -// 0U -> "" -// 1U -> "${withVariableName}_${index+1}" -// else -> "${withVariableName}_${index+1}^$deg" -// } -// } -// .filter { it.isNotEmpty() } -// .joinToString(separator = " ") { it } -// } -// } -// .joinToString(separator = " + ") { it } -// .ifEmpty { "0" } -// -///** -// * Represents the polynomial as a [String] naming variables by [namer]. -// * Consider that monomials are sorted in lexicographic order. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial.represent(namer: (Int) -> String): String = -// coefficients.entries -// .sortedWith { o1, o2 -> NumberedPolynomial.monomialComparator.compare(o1.key, o2.key) } -// .asSequence() -// .map { (degs, t) -> -// if (degs.isEmpty()) "$t" -// else { -// when { -// t.isOne() -> "" -// t.isMinusOne() -> "-" -// else -> "$t " -// } + -// degs -// .mapIndexed { index, deg -> -// when (deg) { -// 0U -> "" -// 1U -> namer(index) -// else -> "${namer(index)}^$deg" -// } -// } -// .filter { it.isNotEmpty() } -// .joinToString(separator = " ") { it } -// } -// } -// .joinToString(separator = " + ") { it } -// .ifEmpty { "0" } -// -///** -// * Represents the polynomial as a [String] where name of variable with index `i` is [withVariableName] + `"_${i+1}"` -// * and with brackets around the string if needed (i.e. when there are at least two addends in the representation). -// * Consider that monomials are sorted in lexicographic order. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial.representWithBrackets(withVariableName: String = NumberedPolynomial.defaultVariableName): String = -// with(represent(withVariableName)) { if (coefficients.count() == 1) this else "($this)" } -// -///** -// * Represents the polynomial as a [String] naming variables by [namer] and with brackets around the string if needed -// * (i.e. when there are at least two addends in the representation). -// * Consider that monomials are sorted in lexicographic order. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial.representWithBrackets(namer: (Int) -> String): String = -// with(represent(namer)) { if (coefficients.count() == 1) this else "($this)" } -// -///** -// * Represents the polynomial as a [String] where name of variable with index `i` is [withVariableName] + `"_${i+1}"`. -// * Consider that monomials are sorted in **reversed** lexicographic order. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial.representReversed(withVariableName: String = NumberedPolynomial.defaultVariableName): String = -// coefficients.entries -// .sortedWith { o1, o2 -> -NumberedPolynomial.monomialComparator.compare(o1.key, o2.key) } -// .asSequence() -// .map { (degs, t) -> -// if (degs.isEmpty()) "$t" -// else { -// when { -// t.isOne() -> "" -// t.isMinusOne() -> "-" -// else -> "$t " -// } + -// degs -// .mapIndexed { index, deg -> -// when (deg) { -// 0U -> "" -// 1U -> "${withVariableName}_${index+1}" -// else -> "${withVariableName}_${index+1}^$deg" -// } -// } -// .filter { it.isNotEmpty() } -// .joinToString(separator = " ") { it } -// } -// } -// .joinToString(separator = " + ") { it } -// .ifEmpty { "0" } -// -///** -// * Represents the polynomial as a [String] naming variables by [namer]. -// * Consider that monomials are sorted in **reversed** lexicographic order. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial.representReversed(namer: (Int) -> String): String = -// coefficients.entries -// .sortedWith { o1, o2 -> -NumberedPolynomial.monomialComparator.compare(o1.key, o2.key) } -// .asSequence() -// .map { (degs, t) -> -// if (degs.isEmpty()) "$t" -// else { -// when { -// t.isOne() -> "" -// t.isMinusOne() -> "-" -// else -> "$t " -// } + -// degs -// .mapIndexed { index, deg -> -// when (deg) { -// 0U -> "" -// 1U -> namer(index) -// else -> "${namer(index)}^$deg" -// } -// } -// .filter { it.isNotEmpty() } -// .joinToString(separator = " ") { it } -// } -// } -// .joinToString(separator = " + ") { it } -// .ifEmpty { "0" } -// -///** -// * Represents the polynomial as a [String] where name of variable with index `i` is [withVariableName] + `"_${i+1}"` -// * and with brackets around the string if needed (i.e. when there are at least two addends in the representation). -// * Consider that monomials are sorted in **reversed** lexicographic order. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial.representReversedWithBrackets(withVariableName: String = NumberedPolynomial.defaultVariableName): String = -// with(representReversed(withVariableName)) { if (coefficients.count() == 1) this else "($this)" } -// -///** -// * Represents the polynomial as a [String] naming variables by [namer] and with brackets around the string if needed -// * (i.e. when there are at least two addends in the representation). -// * Consider that monomials are sorted in **reversed** lexicographic order. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial.representReversedWithBrackets(namer: (Int) -> String): String = -// with(representReversed(namer)) { if (coefficients.count() == 1) this else "($this)" } - -//public fun NumberedPolynomial.substitute(ring: Ring, args: Map): NumberedPolynomial = ring { -// if (coefficients.isEmpty()) return this@substitute -// NumberedPolynomial( -// buildMap { -// coefficients.forEach { (degs, c) -> -// val newDegs = degs.mapIndexed { index, deg -> if (index in args) 0U else deg }.cleanUp() -// val newC = degs.foldIndexed(c) { index, acc, deg -> -// if (index in args) multiplyWithPower(acc, args[index]!!, deg) -// else acc -// } -// this[newDegs] = if (newDegs in this) this[newDegs]!! + newC else newC -// } -// } -// ) -//} -// -//// TODO: Replace with optimisation: the [result] may be unboxed, and all operations may be performed as soon as -//// possible on it -//@JvmName("substitutePolynomial") -//public fun NumberedPolynomial.substitute(ring: Ring, arg: Map>) : NumberedPolynomial = -// ring.numberedPolynomialSpace { -// if (coefficients.isEmpty()) return zero -// coefficients -// .asSequence() -// .map { (degs, c) -> -// degs.foldIndexed( -// NumberedPolynomial( -// degs.mapIndexed { index, deg -> if (index in arg) 0U else deg } to c -// ) -// ) { index, acc, deg -> if (index in arg) multiplyWithPower(acc, arg[index]!!, deg) else acc } -// } -// .reduce { acc, polynomial -> acc + polynomial } // TODO: Rewrite. Might be slow. -// } -// -//// TODO: Substitute rational function -// -//public fun > NumberedPolynomial.asFunctionOver(ring: A): (Map) -> NumberedPolynomial = -// { substitute(ring, it) } -// -//public fun > NumberedPolynomial.asPolynomialFunctionOver(ring: A): (Map>) -> NumberedPolynomial = -// { substitute(ring, it) } - -//operator fun > Polynomial.div(other: T): Polynomial = -// if (other.isZero()) throw ArithmeticException("/ by zero") -// else -// Polynomial( -// coefficients -// .mapValues { it.value / other }, -// toCheckInput = false -// ) - -/** - * Evaluates the value of the given double polynomial for given double argument. - */ -public fun NumberedPolynomial.substitute(args: Map): NumberedPolynomial = Double.algebra { - val acc = LinkedHashMap, Double>(coefficients.size) - for ((degs, c) in coefficients) { - val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp() - val newC = args.entries.fold(c) { product, (variable, substitution) -> - val deg = degs.getOrElse(variable) { 0u } - if (deg == 0u) product else product * substitution.pow(deg.toInt()) - } - if (newDegs !in acc) acc[newDegs] = newC - else acc[newDegs] = acc[newDegs]!! + newC - } - return NumberedPolynomial(acc) -} - -/** - * Evaluates the value of the given polynomial for given argument. - * - * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). - */ -public fun NumberedPolynomial.substitute(ring: Ring, args: Map): NumberedPolynomial = ring { - val acc = LinkedHashMap, C>(coefficients.size) - for ((degs, c) in coefficients) { - val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp() - val newC = args.entries.fold(c) { product, (variable, substitution) -> - val deg = degs.getOrElse(variable) { 0u } - if (deg == 0u) product else product * power(substitution, deg) - } - if (newDegs !in acc) acc[newDegs] = newC - else acc[newDegs] = acc[newDegs]!! + newC - } - return NumberedPolynomial(acc) -} - -// TODO: (Waiting for hero) Replace with optimisation: the [result] may be unboxed, and all operations may be performed -// as soon as possible on it -@JvmName("substitutePolynomial") -public fun NumberedPolynomial.substitute(ring: Ring, args: Map>) : NumberedPolynomial = TODO() /*ring.numberedPolynomial { - val acc = LinkedHashMap, NumberedPolynomial>(coefficients.size) - for ((degs, c) in coefficients) { - val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp() - val newC = args.entries.fold(c.asNumberedPolynomial()) { product, (variable, substitution) -> - val deg = degs.getOrElse(variable) { 0u } - if (deg == 0u) product else product * power(substitution, deg) - } - if (newDegs !in acc) acc[newDegs] = c.asNumberedPolynomial() - else acc[newDegs] = acc[newDegs]!! + c - } -}*/ - -/** - * Represent the polynomial as a regular context-less function. - */ -public fun > NumberedPolynomial.asFunction(ring: A): (Map) -> NumberedPolynomial = { substitute(ring, it) } - -/** - * Represent the polynomial as a regular context-less function. - */ -public fun > NumberedPolynomial.asPolynomialFunctionOver(ring: A): (Map>) -> NumberedPolynomial = { substitute(ring, it) } - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > NumberedPolynomial.derivativeWithRespectTo( - algebra: A, - variable: Int, -): NumberedPolynomial = algebra { - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - if (degs.size > variable) return@forEach - put( - degs.mapIndexed { index, deg -> - when { - index != variable -> deg - deg > 0u -> deg - 1u - else -> return@forEach - } - }.cleanUp(), - multiplyByDoubling(c, degs[variable]) - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > NumberedPolynomial.derivativeWithRespectTo( - algebra: A, - variables: Collection, -): NumberedPolynomial = algebra { - val cleanedVariables = variables.toSet() - if (cleanedVariables.isEmpty()) return this@derivativeWithRespectTo - val maxRespectedVariable = cleanedVariables.maxOrNull()!! - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - if (degs.size > maxRespectedVariable) return@forEach - put( - degs.mapIndexed { index, deg -> - when { - index !in cleanedVariables -> deg - deg > 0u -> deg - 1u - else -> return@forEach - } - }.cleanUp(), - cleanedVariables.fold(c) { acc, variable -> multiplyByDoubling(acc, degs[variable]) } - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > NumberedPolynomial.nthDerivativeWithRespectTo( - algebra: A, - variable: Int, - order: UInt -): NumberedPolynomial = algebra { - if (order == 0u) return this@nthDerivativeWithRespectTo - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - if (degs.size > variable) return@forEach - put( - degs.mapIndexed { index, deg -> - when { - index != variable -> deg - deg >= order -> deg - order - else -> return@forEach - } - }.cleanUp(), - degs[variable].let { deg -> - (deg downTo deg - order + 1u) - .fold(c) { acc, ord -> multiplyByDoubling(acc, ord) } - } - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > NumberedPolynomial.nthDerivativeWithRespectTo( - algebra: A, - variablesAndOrders: Map, -): NumberedPolynomial = algebra { - val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u } - if (filteredVariablesAndOrders.isEmpty()) return this@nthDerivativeWithRespectTo - val maxRespectedVariable = filteredVariablesAndOrders.keys.maxOrNull()!! - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - if (degs.size > maxRespectedVariable) return@forEach - put( - degs.mapIndexed { index, deg -> - if (index !in filteredVariablesAndOrders) return@mapIndexed deg - val order = filteredVariablesAndOrders[index]!! - if (deg >= order) deg - order else return@forEach - }.cleanUp(), - filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> - degs[index].let { deg -> - (deg downTo deg - order + 1u) - .fold(acc1) { acc2, ord -> multiplyByDoubling(acc2, ord) } - } - } - ) - } - } - ) -} - -/** - * Returns algebraic antiderivative of received polynomial. - */ -@UnstableKMathAPI -public fun > NumberedPolynomial.antiderivativeWithRespectTo( - algebra: A, - variable: Int, -): NumberedPolynomial = algebra { - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - put( - List(max(variable + 1, degs.size)) { if (it != variable) degs[it] else degs[it] + 1u }, - c / multiplyByDoubling(one, degs[variable]) - ) - } - } - ) -} - -/** - * Returns algebraic antiderivative of received polynomial. - */ -@UnstableKMathAPI -public fun > NumberedPolynomial.antiderivativeWithRespectTo( - algebra: A, - variables: Collection, -): NumberedPolynomial = algebra { - val cleanedVariables = variables.toSet() - if (cleanedVariables.isEmpty()) return this@antiderivativeWithRespectTo - val maxRespectedVariable = cleanedVariables.maxOrNull()!! - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - put( - List(max(maxRespectedVariable + 1, degs.size)) { if (it !in variables) degs[it] else degs[it] + 1u }, - cleanedVariables.fold(c) { acc, variable -> acc / multiplyByDoubling(one, degs[variable]) } - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > NumberedPolynomial.nthAntiderivativeWithRespectTo( - algebra: A, - variable: Int, - order: UInt -): NumberedPolynomial = algebra { - if (order == 0u) return this@nthAntiderivativeWithRespectTo - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - put( - List(max(variable + 1, degs.size)) { if (it != variable) degs[it] else degs[it] + order }, - degs[variable].let { deg -> - (deg downTo deg - order + 1u) - .fold(c) { acc, ord -> acc / multiplyByDoubling(one, ord) } - } - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > NumberedPolynomial.nthAntiderivativeWithRespectTo( - algebra: A, - variablesAndOrders: Map, -): NumberedPolynomial = algebra { - val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u } - if (filteredVariablesAndOrders.isEmpty()) return this@nthAntiderivativeWithRespectTo - val maxRespectedVariable = filteredVariablesAndOrders.keys.maxOrNull()!! - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - put( - List(max(maxRespectedVariable + 1, degs.size)) { degs[it] + filteredVariablesAndOrders.getOrElse(it) { 0u } }, - filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> - degs[index].let { deg -> - (deg downTo deg - order + 1u) - .fold(acc1) { acc2, ord -> acc2 / multiplyByDoubling(one, ord) } - } - } - ) - } - } - ) -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt deleted file mode 100644 index 5cd0679ab..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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.functions - -import space.kscience.kmath.operations.Ring -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract - - -/** - * Creates a [NumberedRationalFunctionSpace] over a received ring. - */ -public fun > A.numberedRationalFunction(): NumberedRationalFunctionSpace = - NumberedRationalFunctionSpace(this) - -/** - * Creates a [NumberedRationalFunctionSpace]'s scope over a received ring. - */ -public inline fun , R> A.numberedRationalFunction(block: NumberedRationalFunctionSpace.() -> R): R { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return NumberedRationalFunctionSpace(this).block() -} - -//fun > NumberedRationalFunction.reduced(): NumberedRationalFunction { -// val greatestCommonDivider = polynomialGCD(numerator, denominator) -// return NumberedRationalFunction( -// numerator / greatestCommonDivider, -// denominator / greatestCommonDivider -// ) -//} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt deleted file mode 100644 index 0fcd4c6e5..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt +++ /dev/null @@ -1,107 +0,0 @@ -/* - * 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.integration - -import space.kscience.kmath.functions.PiecewisePolynomial -import space.kscience.kmath.functions.integrate -import space.kscience.kmath.functions.antiderivative -import space.kscience.kmath.interpolation.PolynomialInterpolator -import space.kscience.kmath.interpolation.SplineInterpolator -import space.kscience.kmath.interpolation.interpolatePolynomials -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.* -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.DoubleBuffer -import space.kscience.kmath.structures.MutableBufferFactory - -/** - * Compute analytical indefinite integral of this [PiecewisePolynomial], keeping all intervals intact - */ -@OptIn(PerformancePitfall::class) -@UnstableKMathAPI -public fun > PiecewisePolynomial.integrate(algebra: Field): PiecewisePolynomial = - PiecewisePolynomial(pieces.map { it.first to it.second.antiderivative(algebra) }) - -/** - * Compute definite integral of given [PiecewisePolynomial] piece by piece in a given [range] - * Requires [UnivariateIntegrationNodes] or [IntegrationRange] and [IntegrandMaxCalls] - * - * TODO use context receiver for algebra - */ -@UnstableKMathAPI -public fun > PiecewisePolynomial.integrate( - algebra: Field, range: ClosedRange, -): T = algebra.sum( - pieces.map { (region, poly) -> - val intersectedRange = maxOf(range.start, region.start)..minOf(range.endInclusive, region.endInclusive) - //Check if polynomial range is not used - if (intersectedRange.start == intersectedRange.endInclusive) algebra.zero - else poly.integrate(algebra, intersectedRange) - } -) - -/** - * A generic spline-interpolation-based analytic integration - * * [IntegrationRange]—the univariate range of integration. By default, uses `0..1` interval. - * * [IntegrandMaxCalls]—the maximum number of function calls during integration. For non-iterative rules, always uses - * the maximum number of points. By default, uses 10 points. - */ -@UnstableKMathAPI -public class SplineIntegrator>( - public val algebra: Field, - public val bufferFactory: MutableBufferFactory, -) : UnivariateIntegrator { - override fun process(integrand: UnivariateIntegrand): UnivariateIntegrand = algebra { - val range = integrand.getFeature()?.range ?: 0.0..1.0 - - val interpolator: PolynomialInterpolator = SplineInterpolator(algebra, bufferFactory) - - val nodes: Buffer = integrand.getFeature()?.nodes ?: run { - val numPoints = integrand.getFeature()?.maxCalls ?: 100 - val step = (range.endInclusive - range.start) / (numPoints - 1) - DoubleBuffer(numPoints) { i -> range.start + i * step } - } - - val values = nodes.map(bufferFactory) { integrand.function(it) } - val polynomials = interpolator.interpolatePolynomials( - nodes.map(bufferFactory) { number(it) }, - values - ) - val res = polynomials.integrate(algebra, number(range.start)..number(range.endInclusive)) - integrand + IntegrandValue(res) + IntegrandCallsPerformed(integrand.calls + nodes.size) - } -} - -/** - * A simplified double-based spline-interpolation-based analytic integration - * * [IntegrationRange]—the univariate range of integration. By default, uses `0.0..1.0` interval. - * * [IntegrandMaxCalls]—the maximum number of function calls during integration. For non-iterative rules, always - * uses the maximum number of points. By default, uses 10 points. - */ -@UnstableKMathAPI -public object DoubleSplineIntegrator : UnivariateIntegrator { - override fun process(integrand: UnivariateIntegrand): UnivariateIntegrand { - val range = integrand.getFeature()?.range ?: 0.0..1.0 - val interpolator: PolynomialInterpolator = SplineInterpolator(DoubleField, ::DoubleBuffer) - - val nodes: Buffer = integrand.getFeature()?.nodes ?: run { - val numPoints = integrand.getFeature()?.maxCalls ?: 100 - val step = (range.endInclusive - range.start) / (numPoints - 1) - DoubleBuffer(numPoints) { i -> range.start + i * step } - } - - val values = nodes.map { integrand.function(it) } - val polynomials = interpolator.interpolatePolynomials(nodes, values) - val res = polynomials.integrate(DoubleField, range) - return integrand + IntegrandValue(res) + IntegrandCallsPerformed(integrand.calls + nodes.size) - } -} - -@Suppress("unused") -@UnstableKMathAPI -public inline val DoubleField.splineIntegrator: UnivariateIntegrator - get() = DoubleSplineIntegrator \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt deleted file mode 100644 index 62819be0c..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt +++ /dev/null @@ -1,92 +0,0 @@ -/* - * 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. - */ - -@file:OptIn(UnstableKMathAPI::class) - -package space.kscience.kmath.interpolation - -import space.kscience.kmath.data.XYColumnarData -import space.kscience.kmath.functions.PiecewisePolynomial -import space.kscience.kmath.functions.asFunction -import space.kscience.kmath.functions.substitute -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.asBuffer - -/** - * And interpolator for data with x column type [X], y column type [Y]. - */ -public fun interface Interpolator { - public fun interpolate(points: XYColumnarData): (X) -> Y -} - -/** - * And interpolator returning [PiecewisePolynomial] function - */ -public interface PolynomialInterpolator> : Interpolator { - public val algebra: Ring - - public fun getDefaultValue(): T = error("Out of bounds") - - public fun interpolatePolynomials(points: XYColumnarData): PiecewisePolynomial - - override fun interpolate(points: XYColumnarData): (T) -> T = { x -> - interpolatePolynomials(points).substitute(algebra, x) ?: getDefaultValue() - } -} - - -public fun > PolynomialInterpolator.interpolatePolynomials( - x: Buffer, - y: Buffer, -): PiecewisePolynomial { - val pointSet = XYColumnarData.of(x, y) - return interpolatePolynomials(pointSet) -} - -public fun > PolynomialInterpolator.interpolatePolynomials( - data: Map, -): PiecewisePolynomial { - val pointSet = XYColumnarData.of(data.keys.toList().asBuffer(), data.values.toList().asBuffer()) - return interpolatePolynomials(pointSet) -} - -public fun > PolynomialInterpolator.interpolatePolynomials( - data: List>, -): PiecewisePolynomial { - val pointSet = XYColumnarData.of(data.map { it.first }.asBuffer(), data.map { it.second }.asBuffer()) - return interpolatePolynomials(pointSet) -} - -public fun > PolynomialInterpolator.interpolate( - x: Buffer, - y: Buffer, -): (T) -> T? = interpolatePolynomials(x, y).asFunction(algebra) - -public fun > PolynomialInterpolator.interpolate( - data: Map, -): (T) -> T? = interpolatePolynomials(data).asFunction(algebra) - -public fun > PolynomialInterpolator.interpolate( - data: List>, -): (T) -> T? = interpolatePolynomials(data).asFunction(algebra) - - -public fun > PolynomialInterpolator.interpolate( - x: Buffer, - y: Buffer, - defaultValue: T, -): (T) -> T = interpolatePolynomials(x, y).asFunction(algebra, defaultValue) - -public fun > PolynomialInterpolator.interpolate( - data: Map, - defaultValue: T, -): (T) -> T = interpolatePolynomials(data).asFunction(algebra, defaultValue) - -public fun > PolynomialInterpolator.interpolate( - data: List>, - defaultValue: T, -): (T) -> T = interpolatePolynomials(data).asFunction(algebra, defaultValue) \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt deleted file mode 100644 index b55f16cf2..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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.interpolation - -import space.kscience.kmath.data.XYColumnarData -import space.kscience.kmath.functions.PiecewisePolynomial -import space.kscience.kmath.functions.ListPolynomial -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.Field -import space.kscience.kmath.operations.invoke - -@OptIn(UnstableKMathAPI::class) -internal fun > insureSorted(points: XYColumnarData<*, T, *>) { - for (i in 0 until points.size - 1) - require(points.x[i + 1] > points.x[i]) { "Input data is not sorted at index $i" } -} - -/** - * Reference JVM implementation: https://github.com/apache/commons-math/blob/master/src/main/java/org/apache/commons/math4/analysis/interpolation/LinearInterpolator.java - */ -public class LinearInterpolator>(override val algebra: Field) : PolynomialInterpolator { - - @OptIn(UnstableKMathAPI::class) - override fun interpolatePolynomials(points: XYColumnarData): PiecewisePolynomial = algebra { - require(points.size > 0) { "Point array should not be empty" } - insureSorted(points) - - PiecewisePolynomial(points.x[0]) { - for (i in 0 until points.size - 1) { - val slope = (points.y[i + 1] - points.y[i]) / (points.x[i + 1] - points.x[i]) - val const = points.y[i] - slope * points.x[i] - val polynomial = ListPolynomial(const, slope) - putRight(points.x[i + 1], polynomial) - } - } - } -} - -public val > Field.linearInterpolator: LinearInterpolator - get() = LinearInterpolator(this) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt deleted file mode 100644 index 48c90ff23..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt +++ /dev/null @@ -1,83 +0,0 @@ -/* - * 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.interpolation - -import space.kscience.kmath.data.XYColumnarData -import space.kscience.kmath.functions.PiecewisePolynomial -import space.kscience.kmath.functions.ListPolynomial -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.Field -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.structures.DoubleBuffer -import space.kscience.kmath.structures.MutableBufferFactory - -/** - * Generic spline interpolator. Not recommended for performance critical places, use platform-specific and type - * specific ones. - * - * Based on - * https://github.com/apache/commons-math/blob/eb57d6d457002a0bb5336d789a3381a24599affe/src/main/java/org/apache/commons/math4/analysis/interpolation/SplineInterpolator.java - */ -public class SplineInterpolator>( - override val algebra: Field, - public val bufferFactory: MutableBufferFactory, -) : PolynomialInterpolator { - //TODO possibly optimize zeroed buffers - - @OptIn(UnstableKMathAPI::class) - override fun interpolatePolynomials(points: XYColumnarData): PiecewisePolynomial = algebra { - require(points.size >= 3) { "Can't use spline interpolator with less than 3 points" } - insureSorted(points) - // Number of intervals. The number of data points is n + 1. - val n = points.size - 1 - // Differences between knot points - val h = bufferFactory(n) { i -> points.x[i + 1] - points.x[i] } - val mu = bufferFactory(n) { zero } - val z = bufferFactory(n + 1) { zero } - - for (i in 1 until n) { - val g = 2.0 * (points.x[i + 1] - points.x[i - 1]) - h[i - 1] * mu[i - 1] - mu[i] = h[i] / g - z[i] = - ((points.y[i + 1] * h[i - 1] - points.y[i] * (points.x[i + 1] - points.x[i - 1]) + points.y[i - 1] * h[i]) * 3.0 / - (h[i - 1] * h[i]) - h[i - 1] * z[i - 1]) / g - } - - // cubic spline coefficients -- b is linear, c quadratic, d is cubic (original y's are constants) - - PiecewisePolynomial(points.x[points.size - 1]) { - var cOld = zero - - for (j in n - 1 downTo 0) { - val c = z[j] - mu[j] * cOld - val a = points.y[j] - val b = (points.y[j + 1] - points.y[j]) / h[j] - h[j] * (cOld + 2.0 * c) / 3.0 - val d = (cOld - c) / (3.0 * h[j]) - val x0 = points.x[j] - val x02 = x0 * x0 - val x03 = x02 * x0 - //Shift coefficients to represent absolute polynomial instead of one with an offset - val polynomial = ListPolynomial( - a - b * x0 + c * x02 - d * x03, - b - 2 * c * x0 + 3 * d * x02, - c - 3 * d * x0, - d - ) - cOld = c - putLeft(x0, polynomial) - } - } - } -} - - -public fun > Field.splineInterpolator( - bufferFactory: MutableBufferFactory, -): SplineInterpolator = SplineInterpolator(this, bufferFactory) - -public val DoubleField.splineInterpolator: SplineInterpolator - get() = SplineInterpolator(this, ::DoubleBuffer) \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt deleted file mode 100644 index aae0ad017..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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.integration - -import space.kscience.kmath.functions.ListPolynomial -import space.kscience.kmath.functions.integrate -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.DoubleField -import kotlin.math.PI -import kotlin.math.sin -import kotlin.test.Test -import kotlin.test.assertEquals - -@OptIn(UnstableKMathAPI::class) -class SplineIntegralTest { - - @Test - fun integratePolynomial(){ - val polynomial = ListPolynomial(1.0, 2.0, 3.0) - val integral = polynomial.integrate(DoubleField,1.0..2.0) - assertEquals(11.0, integral, 0.001) - } - - @Test - fun gaussSin() { - val res = DoubleField.splineIntegrator.integrate(0.0..2 * PI, IntegrandMaxCalls(5)) { x -> - sin(x) - } - assertEquals(0.0, res.value, 1e-2) - } - - @Test - fun gaussUniform() { - val res = DoubleField.splineIntegrator.integrate(35.0..100.0, IntegrandMaxCalls(20)) { x -> - if(x in 30.0..50.0){ - 1.0 - } else { - 0.0 - } - } - assertEquals(15.0, res.value, 0.5) - } - - -} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt deleted file mode 100644 index 1143036d4..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt +++ /dev/null @@ -1,29 +0,0 @@ -/* - * 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.interpolation - -import space.kscience.kmath.operations.DoubleField -import kotlin.test.Test -import kotlin.test.assertEquals - -internal class LinearInterpolatorTest { - @Test - fun testInterpolation() { - val data = listOf( - 0.0 to 0.0, - 1.0 to 1.0, - 2.0 to 3.0, - 3.0 to 4.0 - ) - - //val polynomial: PiecewisePolynomial = DoubleField.linearInterpolator.interpolatePolynomials(data) - val function = DoubleField.linearInterpolator.interpolate(data) - assertEquals(null, function(-1.0)) - assertEquals(0.5, function(0.5)) - assertEquals(2.0, function(1.5)) - assertEquals(3.0, function(2.0)) - } -} diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt deleted file mode 100644 index 4c7d816d4..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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.interpolation - -import space.kscience.kmath.operations.DoubleField -import kotlin.math.PI -import kotlin.math.sin -import kotlin.test.Test -import kotlin.test.assertEquals - -internal class SplineInterpolatorTest { - @Test - fun testInterpolation() { - val data = (0..10).map { - val x = it.toDouble() / 5 * PI - x to sin(x) - } - - //val polynomial: PiecewisePolynomial = DoubleField.splineInterpolator.interpolatePolynomials(data) - - val function = DoubleField.splineInterpolator.interpolate(data, Double.NaN) - - assertEquals(Double.NaN, function(-1.0)) - assertEquals(sin(0.5), function(0.5), 0.1) - assertEquals(sin(1.5), function(1.5), 0.1) - assertEquals(sin(2.0), function(2.0), 0.1) - } -} diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt deleted file mode 100644 index 2353beee6..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt +++ /dev/null @@ -1,142 +0,0 @@ -/* - * 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.functions.ListPolynomial -import space.kscience.kmath.functions.ListPolynomialSpace -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.Ring - - -class IntModulo { - val residue: Int - val modulus: Int - - @PublishedApi - internal constructor(residue: Int, modulus: Int, toCheckInput: Boolean = true) { - if (toCheckInput) { - require(modulus != 0) { "modulus can not be zero" } - this.modulus = if (modulus < 0) -modulus else modulus - this.residue = residue.mod(modulus) - } else { - this.residue = residue - this.modulus = modulus - } - } - - constructor(residue: Int, modulus: Int) : this(residue, modulus, true) - - operator fun unaryPlus(): IntModulo = this - operator fun unaryMinus(): IntModulo = - IntModulo( - if (residue == 0) 0 else modulus - residue, - modulus, - toCheckInput = false - ) - operator fun plus(other: IntModulo): IntModulo { - require(modulus == other.modulus) { "can not add two residue different modulo" } - return IntModulo( - (residue + other.residue) % modulus, - modulus, - toCheckInput = false - ) - } - operator fun plus(other: Int): IntModulo = - IntModulo( - (residue + other) % modulus, - modulus, - toCheckInput = false - ) - operator fun minus(other: IntModulo): IntModulo { - require(modulus == other.modulus) { "can not subtract two residue different modulo" } - return IntModulo( - (residue - other.residue) % modulus, - modulus, - toCheckInput = false - ) - } - operator fun minus(other: Int): IntModulo = - IntModulo( - (residue - other) % modulus, - modulus, - toCheckInput = false - ) - operator fun times(other: IntModulo): IntModulo { - require(modulus == other.modulus) { "can not multiply two residue different modulo" } - return IntModulo( - (residue * other.residue) % modulus, - modulus, - toCheckInput = false - ) - } - operator fun times(other: Int): IntModulo = - IntModulo( - (residue * other) % modulus, - modulus, - toCheckInput = false - ) - operator fun div(other: IntModulo): IntModulo { - require(modulus == other.modulus) { "can not divide two residue different modulo" } - val (reciprocalCandidate, gcdOfOtherResidueAndModulus) = bezoutIdentityWithGCD(other.residue, modulus) - require(gcdOfOtherResidueAndModulus == 1) { "can not divide to residue that has non-trivial GCD with modulo" } - return IntModulo( - (residue * reciprocalCandidate) % modulus, - modulus, - toCheckInput = false - ) - } - operator fun div(other: Int): IntModulo { - val (reciprocalCandidate, gcdOfOtherResidueAndModulus) = bezoutIdentityWithGCD(other, modulus) - require(gcdOfOtherResidueAndModulus == 1) { "can not divide to residue that has non-trivial GCD with modulo" } - return IntModulo( - (residue * reciprocalCandidate) % modulus, - modulus, - toCheckInput = false - ) - } - override fun equals(other: Any?): Boolean = - when (other) { - is IntModulo -> residue == other.residue && modulus == other.modulus - else -> false - } - - override fun hashCode(): Int = residue.hashCode() - - override fun toString(): String = "$residue mod $modulus" -} - -@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") -@OptIn(UnstableKMathAPI::class) -class IntModuloRing : Ring { - - val modulus: Int - - constructor(modulus: Int) { - require(modulus != 0) { "modulus can not be zero" } - this.modulus = if (modulus < 0) -modulus else modulus - } - - override inline val zero: IntModulo get() = IntModulo(0, modulus, toCheckInput = false) - override inline val one: IntModulo get() = IntModulo(1, modulus, toCheckInput = false) - - fun number(arg: Int) = IntModulo(arg, modulus, toCheckInput = false) - - override inline fun add(left: IntModulo, right: IntModulo): IntModulo = left + right - override inline fun multiply(left: IntModulo, right: IntModulo): IntModulo = left * right - - override inline fun IntModulo.unaryMinus(): IntModulo = -this - override inline fun IntModulo.plus(arg: IntModulo): IntModulo = this + arg - override inline fun IntModulo.minus(arg: IntModulo): IntModulo = this - arg - override inline fun IntModulo.times(arg: IntModulo): IntModulo = this * arg - inline fun IntModulo.div(arg: IntModulo): IntModulo = this / arg -} - -fun ListPolynomialSpace.number(arg: Int) = IntModulo(arg, ring.modulus, toCheckInput = false) - -fun ListPolynomialSpace.ListPolynomial(vararg coefs: Int): ListPolynomial = - ListPolynomial(coefs.map { IntModulo(it, ring.modulus) }) -fun IntModuloRing.ListPolynomial(vararg coefs: Int): ListPolynomial = - ListPolynomial(coefs.map { IntModulo(it, modulus) }) \ No newline at end of file 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 deleted file mode 100644 index 72bb5942c..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt +++ /dev/null @@ -1,135 +0,0 @@ -/* - * 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.Field -import space.kscience.kmath.operations.NumbersAddOps - -class Rational { - companion object { - val ZERO: Rational = Rational(0L) - val ONE: Rational = Rational(1L) - } - - val numerator: Long - val denominator: Long - - internal constructor(numerator: Long, denominator: Long, toCheckInput: Boolean = true) { - if (toCheckInput) { - if (denominator == 0L) throw ArithmeticException("/ by zero") - - val greatestCommonDivider = gcd(numerator, denominator).let { if (denominator < 0L) -it else it } - - this.numerator = numerator / greatestCommonDivider - this.denominator = denominator / greatestCommonDivider - } else { - this.numerator = numerator - this.denominator = denominator - } - } - - constructor(numerator: Int, denominator: Int) : this(numerator.toLong(), denominator.toLong(), true) - constructor(numerator: Int, denominator: Long) : this(numerator.toLong(), denominator, true) - constructor(numerator: Long, denominator: Int) : this(numerator, denominator.toLong(), true) - constructor(numerator: Long, denominator: Long) : this(numerator, denominator, true) - constructor(numerator: Int) : this(numerator.toLong(), 1L, false) - constructor(numerator: Long) : this(numerator, 1L, false) - - operator fun unaryPlus(): Rational = this - operator fun unaryMinus(): Rational = Rational(-this.numerator, this.denominator) - operator fun plus(other: Rational): Rational = - Rational( - numerator * other.denominator + denominator * other.numerator, - denominator * other.denominator - ) - operator fun plus(other: Int): Rational = - Rational( - numerator + denominator * other.toLong(), - denominator - ) - operator fun plus(other: Long): Rational = - Rational( - numerator + denominator * other, - denominator - ) - operator fun minus(other: Rational): Rational = - Rational( - numerator * other.denominator - denominator * other.numerator, - denominator * other.denominator - ) - operator fun minus(other: Int): Rational = - Rational( - numerator - denominator * other.toLong(), - denominator - ) - operator fun minus(other: Long): Rational = - Rational( - numerator - denominator * other, - denominator - ) - operator fun times(other: Rational): Rational = - Rational( - numerator * other.numerator, - denominator * other.denominator - ) - operator fun times(other: Int): Rational = - Rational( - numerator * other.toLong(), - denominator - ) - operator fun times(other: Long): Rational = - Rational( - numerator * other, - denominator - ) - operator fun div(other: Rational): Rational = - Rational( - numerator * other.denominator, - denominator * other.numerator - ) - operator fun div(other: Int): Rational = - Rational( - numerator, - denominator * other.toLong() - ) - operator fun div(other: Long): Rational = - Rational( - numerator, - denominator * other - ) - override fun equals(other: Any?): Boolean = - when (other) { - is Rational -> numerator == other.numerator && denominator == other.denominator - is Int -> numerator == other && denominator == 1L - is Long -> numerator == other && denominator == 1L - else -> false - } - - override fun hashCode(): Int = 31 * numerator.hashCode() + denominator.hashCode() - - override fun toString(): String = if (denominator == 1L) "$numerator" else "$numerator/$denominator" -} - -@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") -@OptIn(UnstableKMathAPI::class) -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 deleted file mode 100644 index 05d9115fa..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/RationalWithMemorization.kt +++ /dev/null @@ -1,107 +0,0 @@ -/* - * 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 { - 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 {}) - } - constructor(numerator: Int, denominator: Int) : this(Rational(numerator, denominator), object : Endpoint {}) - constructor(numerator: Int, denominator: Long) : this(Rational(numerator, denominator), object : Endpoint {}) - constructor(numerator: Long, denominator: Int) : this(Rational(numerator, denominator), object : Endpoint {}) - constructor(numerator: Long, denominator: Long) : this(Rational(numerator, denominator), object : Endpoint {}) - constructor(numerator: Int) : this(Rational(numerator), object : Endpoint {}) - constructor(numerator: Long) : this(Rational(numerator), object : Endpoint {}) - - operator fun unaryPlus(): RationalWithMemorization = this - operator fun unaryMinus(): RationalWithMemorization = RationalWithMemorization( - -value, - object : Negation { - override val negated: OperationsMemory = memory - } - ) - operator fun plus(other: RationalWithMemorization): RationalWithMemorization = RationalWithMemorization( - value + other.value, - object : Sum { - override val augend: OperationsMemory = memory - override val addend: OperationsMemory = other.memory - } - ) - operator fun minus(other: RationalWithMemorization): RationalWithMemorization = RationalWithMemorization( - value - other.value, - object : Difference { - override val minuend: OperationsMemory = memory - override val subtrahend: OperationsMemory = other.memory - } - ) - operator fun times(other: RationalWithMemorization): RationalWithMemorization = RationalWithMemorization( - value * other.value, - object : Product { - override val multiplicand: OperationsMemory = memory - override val multiplier: OperationsMemory = other.memory - } - ) - operator fun div(other: RationalWithMemorization): RationalWithMemorization = RationalWithMemorization( - value / other.value, - object : Quotient { - override val dividend: OperationsMemory = memory - override val divisor: OperationsMemory = other.memory - } - ) - - override fun equals(other: Any?): Boolean = - other is RationalWithMemorization && value == other.value - - override fun hashCode(): Int = value.hashCode() - - override fun toString(): String = value.toString() -} - -@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") -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") -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 deleted file mode 100644 index a4fb81274..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/memorization.kt +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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 deleted file mode 100644 index cc647fa2c..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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 - -// TODO: Move to corresponding module "kmath-number-theory" - -import kotlin.math.abs - - -data class BezoutIdentityWithGCD(val first: T, val second: T, val gcd: T) - -tailrec fun gcd(a: Long, b: Long): Long = if (a == 0L) abs(b) else gcd(b % a, a) - -fun bezoutIdentityWithGCD(a: Int, b: Int): BezoutIdentityWithGCD = - when { - a < 0 && b < 0 -> with(bezoutIdentityWithGCDInternalLogic(-a, -b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(-first, -second, gcd) } - a < 0 -> with(bezoutIdentityWithGCDInternalLogic(-a, b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(-first, second, gcd) } - b < 0 -> with(bezoutIdentityWithGCDInternalLogic(a, -b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(first, -second, gcd) } - else -> bezoutIdentityWithGCDInternalLogic(a, b, 1, 0, 0, 1) - } - -internal tailrec fun bezoutIdentityWithGCDInternalLogic(a: Int, b: Int, m1: Int, m2: Int, m3: Int, m4: Int): BezoutIdentityWithGCD = - if (b == 0) BezoutIdentityWithGCD(m1, m3, a) - else { - val quotient = a / b - val reminder = a % b - bezoutIdentityWithGCDInternalLogic(b, reminder, m2, m1 - quotient * m2, m4, m3 - quotient * m4) - } \ No newline at end of file -- 2.34.1 From a6b86eeee122ce42229ccef2fb3372828e36b3bc Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sat, 11 Jun 2022 19:31:01 +0300 Subject: [PATCH 065/123] Cleaned out useless code. --- .../kscience/kmath/test/misc/IntModulo.kt | 142 ------------------ .../kscience/kmath/test/misc/Rational.kt | 135 ----------------- .../test/misc/RationalWithMemorization.kt | 107 ------------- .../kscience/kmath/test/misc/memorization.kt | 51 ------- .../space/kscience/kmath/test/misc/misc.kt | 31 ---- 5 files changed, 466 deletions(-) delete mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt delete mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt delete mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/RationalWithMemorization.kt delete mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/memorization.kt delete mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt deleted file mode 100644 index 2353beee6..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt +++ /dev/null @@ -1,142 +0,0 @@ -/* - * 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.functions.ListPolynomial -import space.kscience.kmath.functions.ListPolynomialSpace -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.Ring - - -class IntModulo { - val residue: Int - val modulus: Int - - @PublishedApi - internal constructor(residue: Int, modulus: Int, toCheckInput: Boolean = true) { - if (toCheckInput) { - require(modulus != 0) { "modulus can not be zero" } - this.modulus = if (modulus < 0) -modulus else modulus - this.residue = residue.mod(modulus) - } else { - this.residue = residue - this.modulus = modulus - } - } - - constructor(residue: Int, modulus: Int) : this(residue, modulus, true) - - operator fun unaryPlus(): IntModulo = this - operator fun unaryMinus(): IntModulo = - IntModulo( - if (residue == 0) 0 else modulus - residue, - modulus, - toCheckInput = false - ) - operator fun plus(other: IntModulo): IntModulo { - require(modulus == other.modulus) { "can not add two residue different modulo" } - return IntModulo( - (residue + other.residue) % modulus, - modulus, - toCheckInput = false - ) - } - operator fun plus(other: Int): IntModulo = - IntModulo( - (residue + other) % modulus, - modulus, - toCheckInput = false - ) - operator fun minus(other: IntModulo): IntModulo { - require(modulus == other.modulus) { "can not subtract two residue different modulo" } - return IntModulo( - (residue - other.residue) % modulus, - modulus, - toCheckInput = false - ) - } - operator fun minus(other: Int): IntModulo = - IntModulo( - (residue - other) % modulus, - modulus, - toCheckInput = false - ) - operator fun times(other: IntModulo): IntModulo { - require(modulus == other.modulus) { "can not multiply two residue different modulo" } - return IntModulo( - (residue * other.residue) % modulus, - modulus, - toCheckInput = false - ) - } - operator fun times(other: Int): IntModulo = - IntModulo( - (residue * other) % modulus, - modulus, - toCheckInput = false - ) - operator fun div(other: IntModulo): IntModulo { - require(modulus == other.modulus) { "can not divide two residue different modulo" } - val (reciprocalCandidate, gcdOfOtherResidueAndModulus) = bezoutIdentityWithGCD(other.residue, modulus) - require(gcdOfOtherResidueAndModulus == 1) { "can not divide to residue that has non-trivial GCD with modulo" } - return IntModulo( - (residue * reciprocalCandidate) % modulus, - modulus, - toCheckInput = false - ) - } - operator fun div(other: Int): IntModulo { - val (reciprocalCandidate, gcdOfOtherResidueAndModulus) = bezoutIdentityWithGCD(other, modulus) - require(gcdOfOtherResidueAndModulus == 1) { "can not divide to residue that has non-trivial GCD with modulo" } - return IntModulo( - (residue * reciprocalCandidate) % modulus, - modulus, - toCheckInput = false - ) - } - override fun equals(other: Any?): Boolean = - when (other) { - is IntModulo -> residue == other.residue && modulus == other.modulus - else -> false - } - - override fun hashCode(): Int = residue.hashCode() - - override fun toString(): String = "$residue mod $modulus" -} - -@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") -@OptIn(UnstableKMathAPI::class) -class IntModuloRing : Ring { - - val modulus: Int - - constructor(modulus: Int) { - require(modulus != 0) { "modulus can not be zero" } - this.modulus = if (modulus < 0) -modulus else modulus - } - - override inline val zero: IntModulo get() = IntModulo(0, modulus, toCheckInput = false) - override inline val one: IntModulo get() = IntModulo(1, modulus, toCheckInput = false) - - fun number(arg: Int) = IntModulo(arg, modulus, toCheckInput = false) - - override inline fun add(left: IntModulo, right: IntModulo): IntModulo = left + right - override inline fun multiply(left: IntModulo, right: IntModulo): IntModulo = left * right - - override inline fun IntModulo.unaryMinus(): IntModulo = -this - override inline fun IntModulo.plus(arg: IntModulo): IntModulo = this + arg - override inline fun IntModulo.minus(arg: IntModulo): IntModulo = this - arg - override inline fun IntModulo.times(arg: IntModulo): IntModulo = this * arg - inline fun IntModulo.div(arg: IntModulo): IntModulo = this / arg -} - -fun ListPolynomialSpace.number(arg: Int) = IntModulo(arg, ring.modulus, toCheckInput = false) - -fun ListPolynomialSpace.ListPolynomial(vararg coefs: Int): ListPolynomial = - ListPolynomial(coefs.map { IntModulo(it, ring.modulus) }) -fun IntModuloRing.ListPolynomial(vararg coefs: Int): ListPolynomial = - ListPolynomial(coefs.map { IntModulo(it, modulus) }) \ No newline at end of file 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 deleted file mode 100644 index 72bb5942c..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt +++ /dev/null @@ -1,135 +0,0 @@ -/* - * 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.Field -import space.kscience.kmath.operations.NumbersAddOps - -class Rational { - companion object { - val ZERO: Rational = Rational(0L) - val ONE: Rational = Rational(1L) - } - - val numerator: Long - val denominator: Long - - internal constructor(numerator: Long, denominator: Long, toCheckInput: Boolean = true) { - if (toCheckInput) { - if (denominator == 0L) throw ArithmeticException("/ by zero") - - val greatestCommonDivider = gcd(numerator, denominator).let { if (denominator < 0L) -it else it } - - this.numerator = numerator / greatestCommonDivider - this.denominator = denominator / greatestCommonDivider - } else { - this.numerator = numerator - this.denominator = denominator - } - } - - constructor(numerator: Int, denominator: Int) : this(numerator.toLong(), denominator.toLong(), true) - constructor(numerator: Int, denominator: Long) : this(numerator.toLong(), denominator, true) - constructor(numerator: Long, denominator: Int) : this(numerator, denominator.toLong(), true) - constructor(numerator: Long, denominator: Long) : this(numerator, denominator, true) - constructor(numerator: Int) : this(numerator.toLong(), 1L, false) - constructor(numerator: Long) : this(numerator, 1L, false) - - operator fun unaryPlus(): Rational = this - operator fun unaryMinus(): Rational = Rational(-this.numerator, this.denominator) - operator fun plus(other: Rational): Rational = - Rational( - numerator * other.denominator + denominator * other.numerator, - denominator * other.denominator - ) - operator fun plus(other: Int): Rational = - Rational( - numerator + denominator * other.toLong(), - denominator - ) - operator fun plus(other: Long): Rational = - Rational( - numerator + denominator * other, - denominator - ) - operator fun minus(other: Rational): Rational = - Rational( - numerator * other.denominator - denominator * other.numerator, - denominator * other.denominator - ) - operator fun minus(other: Int): Rational = - Rational( - numerator - denominator * other.toLong(), - denominator - ) - operator fun minus(other: Long): Rational = - Rational( - numerator - denominator * other, - denominator - ) - operator fun times(other: Rational): Rational = - Rational( - numerator * other.numerator, - denominator * other.denominator - ) - operator fun times(other: Int): Rational = - Rational( - numerator * other.toLong(), - denominator - ) - operator fun times(other: Long): Rational = - Rational( - numerator * other, - denominator - ) - operator fun div(other: Rational): Rational = - Rational( - numerator * other.denominator, - denominator * other.numerator - ) - operator fun div(other: Int): Rational = - Rational( - numerator, - denominator * other.toLong() - ) - operator fun div(other: Long): Rational = - Rational( - numerator, - denominator * other - ) - override fun equals(other: Any?): Boolean = - when (other) { - is Rational -> numerator == other.numerator && denominator == other.denominator - is Int -> numerator == other && denominator == 1L - is Long -> numerator == other && denominator == 1L - else -> false - } - - override fun hashCode(): Int = 31 * numerator.hashCode() + denominator.hashCode() - - override fun toString(): String = if (denominator == 1L) "$numerator" else "$numerator/$denominator" -} - -@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") -@OptIn(UnstableKMathAPI::class) -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 deleted file mode 100644 index 05d9115fa..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/RationalWithMemorization.kt +++ /dev/null @@ -1,107 +0,0 @@ -/* - * 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 { - 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 {}) - } - constructor(numerator: Int, denominator: Int) : this(Rational(numerator, denominator), object : Endpoint {}) - constructor(numerator: Int, denominator: Long) : this(Rational(numerator, denominator), object : Endpoint {}) - constructor(numerator: Long, denominator: Int) : this(Rational(numerator, denominator), object : Endpoint {}) - constructor(numerator: Long, denominator: Long) : this(Rational(numerator, denominator), object : Endpoint {}) - constructor(numerator: Int) : this(Rational(numerator), object : Endpoint {}) - constructor(numerator: Long) : this(Rational(numerator), object : Endpoint {}) - - operator fun unaryPlus(): RationalWithMemorization = this - operator fun unaryMinus(): RationalWithMemorization = RationalWithMemorization( - -value, - object : Negation { - override val negated: OperationsMemory = memory - } - ) - operator fun plus(other: RationalWithMemorization): RationalWithMemorization = RationalWithMemorization( - value + other.value, - object : Sum { - override val augend: OperationsMemory = memory - override val addend: OperationsMemory = other.memory - } - ) - operator fun minus(other: RationalWithMemorization): RationalWithMemorization = RationalWithMemorization( - value - other.value, - object : Difference { - override val minuend: OperationsMemory = memory - override val subtrahend: OperationsMemory = other.memory - } - ) - operator fun times(other: RationalWithMemorization): RationalWithMemorization = RationalWithMemorization( - value * other.value, - object : Product { - override val multiplicand: OperationsMemory = memory - override val multiplier: OperationsMemory = other.memory - } - ) - operator fun div(other: RationalWithMemorization): RationalWithMemorization = RationalWithMemorization( - value / other.value, - object : Quotient { - override val dividend: OperationsMemory = memory - override val divisor: OperationsMemory = other.memory - } - ) - - override fun equals(other: Any?): Boolean = - other is RationalWithMemorization && value == other.value - - override fun hashCode(): Int = value.hashCode() - - override fun toString(): String = value.toString() -} - -@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") -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") -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 deleted file mode 100644 index a4fb81274..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/memorization.kt +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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 deleted file mode 100644 index cc647fa2c..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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 - -// TODO: Move to corresponding module "kmath-number-theory" - -import kotlin.math.abs - - -data class BezoutIdentityWithGCD(val first: T, val second: T, val gcd: T) - -tailrec fun gcd(a: Long, b: Long): Long = if (a == 0L) abs(b) else gcd(b % a, a) - -fun bezoutIdentityWithGCD(a: Int, b: Int): BezoutIdentityWithGCD = - when { - a < 0 && b < 0 -> with(bezoutIdentityWithGCDInternalLogic(-a, -b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(-first, -second, gcd) } - a < 0 -> with(bezoutIdentityWithGCDInternalLogic(-a, b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(-first, second, gcd) } - b < 0 -> with(bezoutIdentityWithGCDInternalLogic(a, -b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(first, -second, gcd) } - else -> bezoutIdentityWithGCDInternalLogic(a, b, 1, 0, 0, 1) - } - -internal tailrec fun bezoutIdentityWithGCDInternalLogic(a: Int, b: Int, m1: Int, m2: Int, m3: Int, m4: Int): BezoutIdentityWithGCD = - if (b == 0) BezoutIdentityWithGCD(m1, m3, a) - else { - val quotient = a / b - val reminder = a % b - bezoutIdentityWithGCDInternalLogic(b, reminder, m2, m1 - quotient * m2, m4, m3 - quotient * m4) - } \ No newline at end of file -- 2.34.1 From 17703e407dd33dcddff3608c9a8fa06c052af8d7 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sun, 12 Jun 2022 00:24:23 +0300 Subject: [PATCH 066/123] Applied changes from previous sift. --- .../kscience/kmath/functions/Polynomial.kt | 150 ++++-- .../kmath/functions/RationalFunction.kt | 467 +++++++++++++----- 2 files changed, 468 insertions(+), 149 deletions(-) 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 e201f1f6e..f2eba10d5 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 @@ -25,38 +25,38 @@ public interface Polynomial @Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") // FIXME: Waiting for KT-31420 public interface PolynomialSpace> : Ring

{ /** - * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * Returns sum of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. */ public operator fun C.plus(other: Int): C /** - * Returns difference between the constant and the integer represented as constant (member of underlying ring). + * Returns difference between the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. */ public operator fun C.minus(other: Int): C /** - * Returns product of the constant and the integer represented as constant (member of underlying ring). + * Returns product of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to sum of [other] copies of [this]. */ public operator fun C.times(other: Int): C /** - * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * Returns sum of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. */ public operator fun Int.plus(other: C): C /** - * Returns difference between the integer represented as constant (member of underlying ring) and the constant. + * Returns difference between the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. */ public operator fun Int.minus(other: C): C /** - * Returns product of the integer represented as constant (member of underlying ring) and the constant. + * Returns product of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -72,38 +72,38 @@ public interface PolynomialSpace> : Ring

{ public fun Int.asConstant(): C = constantNumber(this) /** - * Returns sum of the polynomial and the integer represented as polynomial. + * Returns sum of the polynomial and the integer represented as a polynomial. * * The operation is equivalent to adding [other] copies of unit polynomial to [this]. */ public operator fun P.plus(other: Int): P = addMultipliedByDoubling(this, one, other) /** - * Returns difference between the polynomial and the integer represented as polynomial. + * Returns difference between the polynomial and the integer represented as a polynomial. * * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. */ public operator fun P.minus(other: Int): P = addMultipliedByDoubling(this, one, -other) /** - * Returns product of the polynomial and the integer represented as polynomial. + * Returns product of the polynomial and the integer represented as a polynomial. * * The operation is equivalent to sum of [other] copies of [this]. */ public operator fun P.times(other: Int): P = multiplyByDoubling(this, other) /** - * Returns sum of the integer represented as polynomial and the polynomial. + * Returns sum of the integer represented as a polynomial and the polynomial. * * The operation is equivalent to adding [this] copies of unit polynomial to [other]. */ public operator fun Int.plus(other: P): P = addMultipliedByDoubling(other, one, this) /** - * Returns difference between the integer represented as polynomial and the polynomial. + * Returns difference between the integer represented as a polynomial and the polynomial. * * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. */ public operator fun Int.minus(other: P): P = addMultipliedByDoubling(-other, one, this) /** - * Returns product of the integer represented as polynomial and the polynomial. + * Returns product of the integer represented as a polynomial and the polynomial. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -165,28 +165,28 @@ public interface PolynomialSpace> : Ring

{ public val constantOne: C /** - * Returns sum of the constant represented as polynomial and the polynomial. + * Returns sum of the constant represented as a polynomial and the polynomial. */ public operator fun C.plus(other: P): P /** - * Returns difference between the constant represented as polynomial and the polynomial. + * Returns difference between the constant represented as a polynomial and the polynomial. */ public operator fun C.minus(other: P): P /** - * Returns product of the constant represented as polynomial and the polynomial. + * Returns product of the constant represented as a polynomial and the polynomial. */ public operator fun C.times(other: P): P /** - * Returns sum of the constant represented as polynomial and the polynomial. + * Returns sum of the constant represented as a polynomial and the polynomial. */ public operator fun P.plus(other: C): P /** - * Returns difference between the constant represented as polynomial and the polynomial. + * Returns difference between the constant represented as a polynomial and the polynomial. */ public operator fun P.minus(other: C): P /** - * Returns product of the constant represented as polynomial and the polynomial. + * Returns product of the constant represented as a polynomial and the polynomial. */ public operator fun P.times(other: C): P @@ -254,41 +254,44 @@ public interface PolynomialSpace> : Ring

{ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public interface PolynomialSpaceOverRing, A: Ring> : PolynomialSpace { + /** + * Underlying ring of constants. Its operations on constants are inherited by local operations on constants. + */ public val ring: A /** - * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * Returns sum of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. */ public override operator fun C.plus(other: Int): C = ring { addMultipliedByDoubling(this@plus, one, other) } /** - * Returns difference between the constant and the integer represented as constant (member of underlying ring). + * Returns difference between the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. */ public override operator fun C.minus(other: Int): C = ring { addMultipliedByDoubling(this@minus, one, -other) } /** - * Returns product of the constant and the integer represented as constant (member of underlying ring). + * Returns product of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to sum of [other] copies of [this]. */ public override operator fun C.times(other: Int): C = ring { multiplyByDoubling(this@times, other) } /** - * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * Returns sum of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. */ public override operator fun Int.plus(other: C): C = ring { addMultipliedByDoubling(other, one, this@plus) } /** - * Returns difference between the integer represented as constant (member of underlying ring) and the constant. + * Returns difference between the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. */ public override operator fun Int.minus(other: C): C = ring { addMultipliedByDoubling(-other, one, this@minus) } /** - * Returns product of the integer represented as constant (member of underlying ring) and the constant. + * Returns product of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -330,58 +333,143 @@ public interface PolynomialSpaceOverRing, A: Ring> : Poly public override val constantOne: C get() = ring.one } +/** + * Abstraction of ring of polynomials of type [P] of variables of type [V] and over ring of constants of type [C]. + * + * @param C the type of constants. Polynomials have them as coefficients in their terms. + * @param V the type of variables. Polynomials have them in representations of terms. + * @param P the type of polynomials. + */ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public interface MultivariatePolynomialSpace>: PolynomialSpace { + /** + * Returns sum of the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("plusVariableInt") public operator fun V.plus(other: Int): P + /** + * Returns difference between the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("minusVariableInt") public operator fun V.minus(other: Int): P + /** + * Returns product of the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("timesVariableInt") public operator fun V.times(other: Int): P + /** + * Returns sum of the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("plusIntVariable") public operator fun Int.plus(other: V): P + /** + * Returns difference between the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("minusIntVariable") public operator fun Int.minus(other: V): P + /** + * Returns product of the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("timesIntVariable") public operator fun Int.times(other: V): P - @JvmName("plusConstantVariable") - public operator fun C.plus(other: V): P - @JvmName("minusConstantVariable") - public operator fun C.minus(other: V): P - @JvmName("timesConstantVariable") - public operator fun C.times(other: V): P - + /** + * Returns sum of the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("plusVariableConstant") public operator fun V.plus(other: C): P + /** + * Returns difference between the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("minusVariableConstant") public operator fun V.minus(other: C): P + /** + * Returns product of the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("timesVariableConstant") public operator fun V.times(other: C): P + /** + * Returns sum of the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("plusConstantVariable") + public operator fun C.plus(other: V): P + /** + * Returns difference between the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("minusConstantVariable") + public operator fun C.minus(other: V): P + /** + * Returns product of the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("timesConstantVariable") + public operator fun C.times(other: V): P + + /** + * Represents the variable as a monic monomial. + */ @JvmName("unaryPlusVariable") public operator fun V.unaryPlus(): P + /** + * Returns negation of representation of the variable as a monic monomial. + */ @JvmName("unaryMinusVariable") public operator fun V.unaryMinus(): P + /** + * Returns sum of the variables represented as monic monomials. + */ @JvmName("plusVariableVariable") public operator fun V.plus(other: V): P + /** + * Returns difference between the variables represented as monic monomials. + */ @JvmName("minusVariableVariable") public operator fun V.minus(other: V): P + /** + * Returns product of the variables represented as monic monomials. + */ @JvmName("timesVariableVariable") public operator fun V.times(other: V): P + /** + * Represents the [variable] as a monic monomial. + */ + public fun number(variable: V): P = +variable + /** + * Represents the variable as a monic monomial. + */ + public fun V.asPolynomial(): P = number(this) + + /** + * Returns sum of the variable represented as a monic monomial and the polynomial. + */ @JvmName("plusVariablePolynomial") public operator fun V.plus(other: P): P + /** + * Returns difference between the variable represented as a monic monomial and the polynomial. + */ @JvmName("minusVariablePolynomial") public operator fun V.minus(other: P): P + /** + * Returns product of the variable represented as a monic monomial and the polynomial. + */ @JvmName("timesVariablePolynomial") public operator fun V.times(other: P): P + /** + * Returns sum of the polynomial and the variable represented as a monic monomial. + */ @JvmName("plusPolynomialVariable") public operator fun P.plus(other: V): P + /** + * Returns difference between the polynomial and the variable represented as a monic monomial. + */ @JvmName("minusPolynomialVariable") public operator fun P.minus(other: V): P + /** + * Returns product of the polynomial and the variable represented as a monic monomial. + */ @JvmName("timesPolynomialVariable") public operator fun P.times(other: V): P diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt index dfec126f3..edc9dfa5c 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt @@ -25,44 +25,44 @@ public interface RationalFunction> { * [C]. * * @param C the type of constants. Polynomials have them as coefficients in their terms. - * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. + * @param P the type of polynomials. Rational functions have them as numerators and denominators. * @param R the type of rational functions. */ @Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") // FIXME: Waiting for KT-31420 public interface RationalFunctionalSpace, R: RationalFunction> : Ring { /** - * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * Returns sum of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. */ public operator fun C.plus(other: Int): C /** - * Returns difference between the constant and the integer represented as constant (member of underlying ring). + * Returns difference between the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. */ public operator fun C.minus(other: Int): C /** - * Returns product of the constant and the integer represented as constant (member of underlying ring). + * Returns product of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to sum of [other] copies of [this]. */ public operator fun C.times(other: Int): C /** - * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * Returns sum of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. */ public operator fun Int.plus(other: C): C /** - * Returns difference between the integer represented as constant (member of underlying ring) and the constant. + * Returns difference between the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. */ public operator fun Int.minus(other: C): C /** - * Returns product of the integer represented as constant (member of underlying ring) and the constant. + * Returns product of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -78,38 +78,38 @@ public interface RationalFunctionalSpace, R: RationalFunctio public fun Int.asConstant(): C = constantNumber(this) /** - * Returns sum of the constant and the integer represented as polynomial. + * Returns sum of the constant and the integer represented as a polynomial. * * The operation is equivalent to adding [other] copies of unit polynomial to [this]. */ public operator fun P.plus(other: Int): P /** - * Returns difference between the constant and the integer represented as polynomial. + * Returns difference between the constant and the integer represented as a polynomial. * * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. */ public operator fun P.minus(other: Int): P /** - * Returns product of the constant and the integer represented as polynomial. + * Returns product of the constant and the integer represented as a polynomial. * * The operation is equivalent to sum of [other] copies of [this]. */ public operator fun P.times(other: Int): P /** - * Returns sum of the integer represented as polynomial and the constant. + * Returns sum of the integer represented as a polynomial and the constant. * * The operation is equivalent to adding [this] copies of unit polynomial to [other]. */ public operator fun Int.plus(other: P): P /** - * Returns difference between the integer represented as polynomial and the constant. + * Returns difference between the integer represented as a polynomial and the constant. * * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. */ public operator fun Int.minus(other: P): P /** - * Returns product of the integer represented as polynomial and the constant. + * Returns product of the integer represented as a polynomial and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -125,25 +125,25 @@ public interface RationalFunctionalSpace, R: RationalFunctio public fun Int.asPolynomial(): P = polynomialNumber(this) /** - * Returns sum of the rational function and the integer represented as rational function. + * Returns sum of the rational function and the integer represented as a rational function. * * The operation is equivalent to adding [other] copies of unit polynomial to [this]. */ public operator fun R.plus(other: Int): R = addMultipliedByDoubling(this, one, other) /** - * Returns difference between the rational function and the integer represented as rational function. + * Returns difference between the rational function and the integer represented as a rational function. * * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. */ public operator fun R.minus(other: Int): R = addMultipliedByDoubling(this, one, -other) /** - * Returns product of the rational function and the integer represented as rational function. + * Returns product of the rational function and the integer represented as a rational function. * * The operation is equivalent to sum of [other] copies of [this]. */ public operator fun R.times(other: Int): R = multiplyByDoubling(this, other) /** - * Returns quotient of the rational function and the integer represented as rational function. + * Returns quotient of the rational function and the integer represented as a rational function. * * The operation is equivalent to creating a new rational function by preserving numerator of [this] and * multiplication denominator of [this] to [other]. @@ -151,25 +151,25 @@ public interface RationalFunctionalSpace, R: RationalFunctio public operator fun R.div(other: Int): R = this / multiplyByDoubling(one, other) /** - * Returns sum of the integer represented as rational function and the rational function. + * Returns sum of the integer represented as a rational function and the rational function. * * The operation is equivalent to adding [this] copies of unit polynomial to [other]. */ public operator fun Int.plus(other: R): R = addMultipliedByDoubling(other, one, this) /** - * Returns difference between the integer represented as rational function and the rational function. + * Returns difference between the integer represented as a rational function and the rational function. * * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. */ public operator fun Int.minus(other: R): R = addMultipliedByDoubling(-other, one, this) /** - * Returns product of the integer represented as rational function and the rational function. + * Returns product of the integer represented as a rational function and the rational function. * * The operation is equivalent to sum of [this] copies of [other]. */ public operator fun Int.times(other: R): R = multiplyByDoubling(other, this) /** - * Returns quotient of the integer represented as rational function and the rational function. + * Returns quotient of the integer represented as a rational function and the rational function. * * The operation is equivalent to creating a new rational function which numerator is [this] times denominator of * [other] and which denominator is [other]'s numerator. @@ -232,28 +232,28 @@ public interface RationalFunctionalSpace, R: RationalFunctio public val constantOne: C /** - * Returns sum of the constant represented as polynomial and the polynomial. + * Returns sum of the constant represented as a polynomial and the polynomial. */ public operator fun C.plus(other: P): P /** - * Returns difference between the constant represented as polynomial and the polynomial. + * Returns difference between the constant represented as a polynomial and the polynomial. */ public operator fun C.minus(other: P): P /** - * Returns product of the constant represented as polynomial and the polynomial. + * Returns product of the constant represented as a polynomial and the polynomial. */ public operator fun C.times(other: P): P /** - * Returns sum of the constant represented as polynomial and the polynomial. + * Returns sum of the constant represented as a polynomial and the polynomial. */ public operator fun P.plus(other: C): P /** - * Returns difference between the constant represented as polynomial and the polynomial. + * Returns difference between the constant represented as a polynomial and the polynomial. */ public operator fun P.minus(other: C): P /** - * Returns product of the constant represented as polynomial and the polynomial. + * Returns product of the constant represented as a polynomial and the polynomial. */ public operator fun P.times(other: C): P @@ -305,36 +305,36 @@ public interface RationalFunctionalSpace, R: RationalFunctio public val polynomialOne: P /** - * Returns sum of the constant represented as rational function and the rational function. + * Returns sum of the constant represented as a rational function and the rational function. */ public operator fun C.plus(other: R): R /** - * Returns difference between the constant represented as polynomial and the rational function. + * Returns difference between the constant represented as a polynomial and the rational function. */ public operator fun C.minus(other: R): R /** - * Returns product of the constant represented as polynomial and the rational function. + * Returns product of the constant represented as a polynomial and the rational function. */ public operator fun C.times(other: R): R /** - * Returns quotient of the constant represented as polynomial and the rational function. + * Returns quotient of the constant represented as a polynomial and the rational function. */ public operator fun C.div(other: R): R /** - * Returns sum of the rational function and the constant represented as rational function. + * Returns sum of the rational function and the constant represented as a rational function. */ public operator fun R.plus(other: C): R /** - * Returns difference between the rational function and the constant represented as rational function. + * Returns difference between the rational function and the constant represented as a rational function. */ public operator fun R.minus(other: C): R /** - * Returns product of the rational function and the constant represented as rational function. + * Returns product of the rational function and the constant represented as a rational function. */ public operator fun R.times(other: C): R /** - * Returns quotient of the rational function and the constant represented as rational function. + * Returns quotient of the rational function and the constant represented as a rational function. */ public operator fun R.div(other: C): R @@ -348,36 +348,36 @@ public interface RationalFunctionalSpace, R: RationalFunctio public fun C.asRationalFunction(): R = number(this) /** - * Returns sum of the polynomial represented as rational function and the rational function. + * Returns sum of the polynomial represented as a rational function and the rational function. */ public operator fun P.plus(other: R): R /** - * Returns difference between the polynomial represented as polynomial and the rational function. + * Returns difference between the polynomial represented as a polynomial and the rational function. */ public operator fun P.minus(other: R): R /** - * Returns product of the polynomial represented as polynomial and the rational function. + * Returns product of the polynomial represented as a polynomial and the rational function. */ public operator fun P.times(other: R): R /** - * Returns quotient of the polynomial represented as polynomial and the rational function. + * Returns quotient of the polynomial represented as a polynomial and the rational function. */ public operator fun P.div(other: R): R /** - * Returns sum of the rational function and the polynomial represented as rational function. + * Returns sum of the rational function and the polynomial represented as a rational function. */ public operator fun R.plus(other: P): R /** - * Returns difference between the rational function and the polynomial represented as rational function. + * Returns difference between the rational function and the polynomial represented as a rational function. */ public operator fun R.minus(other: P): R /** - * Returns product of the rational function and the polynomial represented as rational function. + * Returns product of the rational function and the polynomial represented as a rational function. */ public operator fun R.times(other: P): R /** - * Returns quotient of the rational function and the polynomial represented as rational function. + * Returns quotient of the rational function and the polynomial represented as a rational function. */ public operator fun R.div(other: P): R @@ -459,43 +459,51 @@ public interface RationalFunctionalSpace, R: RationalFunctio * @param A the type of algebraic structure (precisely, of ring) provided for constants. */ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 -public interface RationalFunctionalSpaceOverRing, R: RationalFunction, A: Ring> : RationalFunctionalSpace { +public interface RationalFunctionalSpaceOverRing< + C, + P: Polynomial, + R: RationalFunction, + A: Ring + > : RationalFunctionalSpace { + /** + * Underlying ring of constants. Its operations on constants are inherited by local operations on constants. + */ public val ring: A /** - * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * Returns sum of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. */ public override operator fun C.plus(other: Int): C = ring { addMultipliedByDoubling(this@plus, one, other) } /** - * Returns difference between the constant and the integer represented as constant (member of underlying ring). + * Returns difference between the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. */ public override operator fun C.minus(other: Int): C = ring { addMultipliedByDoubling(this@minus, one, -other) } /** - * Returns product of the constant and the integer represented as constant (member of underlying ring). + * Returns product of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to sum of [other] copies of [this]. */ public override operator fun C.times(other: Int): C = ring { multiplyByDoubling(this@times, other) } /** - * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * Returns sum of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. */ public override operator fun Int.plus(other: C): C = ring { addMultipliedByDoubling(other, one, this@plus) } /** - * Returns difference between the integer represented as constant (member of underlying ring) and the constant. + * Returns difference between the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. */ public override operator fun Int.minus(other: C): C = ring { addMultipliedByDoubling(-other, one, this@minus) } /** - * Returns product of the integer represented as constant (member of underlying ring) and the constant. + * Returns product of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -560,41 +568,44 @@ public interface RationalFunctionalSpaceOverPolynomialSpace< AP: PolynomialSpace, > : RationalFunctionalSpace { + /** + * Underlying polynomial ring. Its polynomial operations are inherited by local polynomial operations. + */ public val polynomialRing: AP /** - * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * Returns sum of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. */ public override operator fun C.plus(other: Int): C = polynomialRing { this@plus + other } /** - * Returns difference between the constant and the integer represented as constant (member of underlying ring). + * Returns difference between the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. */ public override operator fun C.minus(other: Int): C = polynomialRing { this@minus - other } /** - * Returns product of the constant and the integer represented as constant (member of underlying ring). + * Returns product of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to sum of [other] copies of [this]. */ public override operator fun C.times(other: Int): C = polynomialRing { this@times * other } /** - * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * Returns sum of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. */ public override operator fun Int.plus(other: C): C = polynomialRing { this@plus + other } /** - * Returns difference between the integer represented as constant (member of underlying ring) and the constant. + * Returns difference between the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. */ public override operator fun Int.minus(other: C): C = polynomialRing { this@minus - other } /** - * Returns product of the integer represented as constant (member of underlying ring) and the constant. + * Returns product of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -610,38 +621,38 @@ public interface RationalFunctionalSpaceOverPolynomialSpace< override fun Int.asConstant(): C = polynomialRing { asConstant() } /** - * Returns sum of the constant and the integer represented as polynomial. + * Returns sum of the constant and the integer represented as a polynomial. * * The operation is equivalent to adding [other] copies of unit polynomial to [this]. */ public override operator fun P.plus(other: Int): P = polynomialRing { this@plus + other } /** - * Returns difference between the constant and the integer represented as polynomial. + * Returns difference between the constant and the integer represented as a polynomial. * * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. */ public override operator fun P.minus(other: Int): P = polynomialRing { this@minus - other } /** - * Returns product of the constant and the integer represented as polynomial. + * Returns product of the constant and the integer represented as a polynomial. * * The operation is equivalent to sum of [other] copies of [this]. */ public override operator fun P.times(other: Int): P = polynomialRing { this@times * other } /** - * Returns sum of the integer represented as polynomial and the constant. + * Returns sum of the integer represented as a polynomial and the constant. * * The operation is equivalent to adding [this] copies of unit polynomial to [other]. */ public override operator fun Int.plus(other: P): P = polynomialRing { this@plus + other } /** - * Returns difference between the integer represented as polynomial and the constant. + * Returns difference between the integer represented as a polynomial and the constant. * * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. */ public override operator fun Int.minus(other: P): P = polynomialRing { this@minus - other } /** - * Returns product of the integer represented as polynomial and the constant. + * Returns product of the integer represented as a polynomial and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -697,28 +708,28 @@ public interface RationalFunctionalSpaceOverPolynomialSpace< public override val constantOne: C get() = polynomialRing.constantOne /** - * Returns sum of the constant represented as polynomial and the polynomial. + * Returns sum of the constant represented as a polynomial and the polynomial. */ public override operator fun C.plus(other: P): P = polynomialRing { this@plus + other } /** - * Returns difference between the constant represented as polynomial and the polynomial. + * Returns difference between the constant represented as a polynomial and the polynomial. */ public override operator fun C.minus(other: P): P = polynomialRing { this@minus - other } /** - * Returns product of the constant represented as polynomial and the polynomial. + * Returns product of the constant represented as a polynomial and the polynomial. */ public override operator fun C.times(other: P): P = polynomialRing { this@times * other } /** - * Returns sum of the constant represented as polynomial and the polynomial. + * Returns sum of the constant represented as a polynomial and the polynomial. */ public override operator fun P.plus(other: C): P = polynomialRing { this@plus + other } /** - * Returns difference between the constant represented as polynomial and the polynomial. + * Returns difference between the constant represented as a polynomial and the polynomial. */ public override operator fun P.minus(other: C): P = polynomialRing { this@minus - other } /** - * Returns product of the constant represented as polynomial and the polynomial. + * Returns product of the constant represented as a polynomial and the polynomial. */ public override operator fun P.times(other: C): P = polynomialRing { this@times * other } @@ -774,7 +785,8 @@ public interface RationalFunctionalSpaceOverPolynomialSpace< /** * Abstraction of field of rational functions of type [R] with respect to polynomials of type [P] and constants of type - * [C]. It also assumes that there is provided constructor + * [C]. It also assumes that there is provided constructor [constructRationalFunction] of rational functions from + * polynomial numerator and denominator. * * @param C the type of constants. Polynomials have them as coefficients in their terms. * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. @@ -786,10 +798,14 @@ public abstract class PolynomialSpaceOfFractions< P: Polynomial, R: RationalFunction, > : RationalFunctionalSpace { + + /** + * Constructor of rational functions (of type [R]) from numerator and denominator (of type [P]). + */ protected abstract fun constructRationalFunction(numerator: P, denominator: P = polynomialOne) : R /** - * Returns sum of the rational function and the integer represented as rational function. + * Returns sum of the rational function and the integer represented as a rational function. * * The operation is equivalent to adding [other] copies of unit polynomial to [this]. */ @@ -799,7 +815,7 @@ public abstract class PolynomialSpaceOfFractions< denominator ) /** - * Returns difference between the rational function and the integer represented as rational function. + * Returns difference between the rational function and the integer represented as a rational function. * * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. */ @@ -809,7 +825,7 @@ public abstract class PolynomialSpaceOfFractions< denominator ) /** - * Returns product of the rational function and the integer represented as rational function. + * Returns product of the rational function and the integer represented as a rational function. * * The operation is equivalent to sum of [other] copies of [this]. */ @@ -826,7 +842,7 @@ public abstract class PolynomialSpaceOfFractions< ) /** - * Returns sum of the integer represented as rational function and the rational function. + * Returns sum of the integer represented as a rational function and the rational function. * * The operation is equivalent to adding [this] copies of unit polynomial to [other]. */ @@ -836,7 +852,7 @@ public abstract class PolynomialSpaceOfFractions< other.denominator ) /** - * Returns difference between the integer represented as rational function and the rational function. + * Returns difference between the integer represented as a rational function and the rational function. * * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. */ @@ -846,7 +862,7 @@ public abstract class PolynomialSpaceOfFractions< other.denominator ) /** - * Returns product of the integer represented as rational function and the rational function. + * Returns product of the integer represented as a rational function and the rational function. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -873,7 +889,7 @@ public abstract class PolynomialSpaceOfFractions< public override operator fun P.div(other: P): R = constructRationalFunction(this, other) /** - * Returns sum of the constant represented as rational function and the rational function. + * Returns sum of the constant represented as a rational function and the rational function. */ public override operator fun C.plus(other: R): R = constructRationalFunction( @@ -881,7 +897,7 @@ public abstract class PolynomialSpaceOfFractions< other.denominator ) /** - * Returns difference between the constant represented as polynomial and the rational function. + * Returns difference between the constant represented as a polynomial and the rational function. */ public override operator fun C.minus(other: R): R = constructRationalFunction( @@ -889,7 +905,7 @@ public abstract class PolynomialSpaceOfFractions< other.denominator ) /** - * Returns product of the constant represented as polynomial and the rational function. + * Returns product of the constant represented as a polynomial and the rational function. */ public override operator fun C.times(other: R): R = constructRationalFunction( @@ -904,7 +920,7 @@ public abstract class PolynomialSpaceOfFractions< ) /** - * Returns sum of the constant represented as rational function and the rational function. + * Returns sum of the constant represented as a rational function and the rational function. */ public override operator fun R.plus(other: C): R = constructRationalFunction( @@ -912,7 +928,7 @@ public abstract class PolynomialSpaceOfFractions< denominator ) /** - * Returns difference between the constant represented as rational function and the rational function. + * Returns difference between the constant represented as a rational function and the rational function. */ public override operator fun R.minus(other: C): R = constructRationalFunction( @@ -920,7 +936,7 @@ public abstract class PolynomialSpaceOfFractions< denominator ) /** - * Returns product of the constant represented as rational function and the rational function. + * Returns product of the constant represented as a rational function and the rational function. */ public override operator fun R.times(other: C): R = constructRationalFunction( @@ -940,7 +956,7 @@ public abstract class PolynomialSpaceOfFractions< public override fun number(value: C): R = constructRationalFunction(polynomialNumber(value)) /** - * Returns sum of the polynomial represented as rational function and the rational function. + * Returns sum of the polynomial represented as a rational function and the rational function. */ public override operator fun P.plus(other: R): R = constructRationalFunction( @@ -948,7 +964,7 @@ public abstract class PolynomialSpaceOfFractions< other.denominator ) /** - * Returns difference between the polynomial represented as polynomial and the rational function. + * Returns difference between the polynomial represented as a polynomial and the rational function. */ public override operator fun P.minus(other: R): R = constructRationalFunction( @@ -956,7 +972,7 @@ public abstract class PolynomialSpaceOfFractions< other.denominator ) /** - * Returns product of the polynomial represented as polynomial and the rational function. + * Returns product of the polynomial represented as a polynomial and the rational function. */ public override operator fun P.times(other: R): R = constructRationalFunction( @@ -971,7 +987,7 @@ public abstract class PolynomialSpaceOfFractions< ) /** - * Returns sum of the polynomial represented as rational function and the rational function. + * Returns sum of the polynomial represented as a rational function and the rational function. */ public override operator fun R.plus(other: P): R = constructRationalFunction( @@ -979,7 +995,7 @@ public abstract class PolynomialSpaceOfFractions< denominator ) /** - * Returns difference between the polynomial represented as rational function and the rational function. + * Returns difference between the polynomial represented as a rational function and the rational function. */ public override operator fun R.minus(other: P): R = constructRationalFunction( @@ -987,7 +1003,7 @@ public abstract class PolynomialSpaceOfFractions< denominator ) /** - * Returns product of the polynomial represented as rational function and the rational function. + * Returns product of the polynomial represented as a rational function and the rational function. */ public override operator fun R.times(other: P): R = constructRationalFunction( @@ -1052,6 +1068,15 @@ public abstract class PolynomialSpaceOfFractions< public override val one: R get() = constructRationalFunction(polynomialOne) } +/** + * Abstraction of field of rational functions of type [R] with respect to polynomials of type [P] of variables of type + * [V] and over ring of constants of type [C]. + * + * @param C the type of constants. Polynomials have them as coefficients in their terms. + * @param V the type of variables. Polynomials have them in representations of terms. + * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. + * @param R the type of rational functions. + */ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public interface MultivariateRationalFunctionalSpace< C, @@ -1059,70 +1084,175 @@ public interface MultivariateRationalFunctionalSpace< P: Polynomial, R: RationalFunction >: RationalFunctionalSpace { + /** + * Returns sum of the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("plusVariableInt") public operator fun V.plus(other: Int): P + /** + * Returns difference between the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("minusVariableInt") public operator fun V.minus(other: Int): P + /** + * Returns product of the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("timesVariableInt") public operator fun V.times(other: Int): P + /** + * Returns sum of the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("plusIntVariable") public operator fun Int.plus(other: V): P + /** + * Returns difference between the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("minusIntVariable") public operator fun Int.minus(other: V): P + /** + * Returns product of the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("timesIntVariable") public operator fun Int.times(other: V): P - @JvmName("plusConstantVariable") - public operator fun C.plus(other: V): P - @JvmName("minusConstantVariable") - public operator fun C.minus(other: V): P - @JvmName("timesConstantVariable") - public operator fun C.times(other: V): P - + /** + * Returns sum of the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("plusVariableConstant") public operator fun V.plus(other: C): P + /** + * Returns difference between the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("minusVariableConstant") public operator fun V.minus(other: C): P + /** + * Returns product of the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("timesVariableConstant") public operator fun V.times(other: C): P + /** + * Returns sum of the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("plusConstantVariable") + public operator fun C.plus(other: V): P + /** + * Returns difference between the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("minusConstantVariable") + public operator fun C.minus(other: V): P + /** + * Returns product of the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("timesConstantVariable") + public operator fun C.times(other: V): P + + /** + * Represents the variable as a monic monomial. + */ @JvmName("unaryPlusVariable") public operator fun V.unaryPlus(): P + /** + * Returns negation of representation of the variable as a monic monomial. + */ @JvmName("unaryMinusVariable") public operator fun V.unaryMinus(): P + /** + * Returns sum of the variables represented as monic monomials. + */ @JvmName("plusVariableVariable") public operator fun V.plus(other: V): P + /** + * Returns difference between the variables represented as monic monomials. + */ @JvmName("minusVariableVariable") public operator fun V.minus(other: V): P + /** + * Returns product of the variables represented as monic monomials. + */ @JvmName("timesVariableVariable") public operator fun V.times(other: V): P + /** + * Represents the [variable] as a monic monomial. + */ + public fun polynomialNumber(variable: V): P = +variable + /** + * Represents the variable as a monic monomial. + */ + public fun V.asPolynomial(): P = polynomialNumber(this) + + /** + * Represents the [variable] as a rational function. + */ + public fun number(variable: V): R = number(polynomialNumber(variable)) + /** + * Represents the variable as a rational function. + */ + public fun V.asRationalFunction(): R = number(this) + + /** + * Returns sum of the variable represented as a monic monomial and the polynomial. + */ @JvmName("plusVariablePolynomial") public operator fun V.plus(other: P): P + /** + * Returns difference between the variable represented as a monic monomial and the polynomial. + */ @JvmName("minusVariablePolynomial") public operator fun V.minus(other: P): P + /** + * Returns product of the variable represented as a monic monomial and the polynomial. + */ @JvmName("timesVariablePolynomial") public operator fun V.times(other: P): P + /** + * Returns sum of the polynomial and the variable represented as a monic monomial. + */ @JvmName("plusPolynomialVariable") public operator fun P.plus(other: V): P + /** + * Returns difference between the polynomial and the variable represented as a monic monomial. + */ @JvmName("minusPolynomialVariable") public operator fun P.minus(other: V): P + /** + * Returns product of the polynomial and the variable represented as a monic monomial. + */ @JvmName("timesPolynomialVariable") public operator fun P.times(other: V): P + /** + * Returns sum of the variable represented as a rational function and the rational function. + */ @JvmName("plusVariableRational") public operator fun V.plus(other: R): R + /** + * Returns difference between the variable represented as a rational function and the rational function. + */ @JvmName("minusVariableRational") public operator fun V.minus(other: R): R + /** + * Returns product of the variable represented as a rational function and the rational function. + */ @JvmName("timesVariableRational") public operator fun V.times(other: R): R + /** + * Returns sum of the rational function and the variable represented as a rational function. + */ @JvmName("plusRationalVariable") public operator fun R.plus(other: V): R + /** + * Returns difference between the rational function and the variable represented as a rational function. + */ @JvmName("minusRationalVariable") public operator fun R.minus(other: V): R + /** + * Returns product of the rational function and the variable represented as a rational function. + */ @JvmName("timesRationalVariable") public operator fun R.times(other: V): R @@ -1161,22 +1291,17 @@ public interface MultivariateRationalFunctionalSpace< public val R.countOfVariables: Int get() = variables.size } -public interface MultivariateRationalFunctionalSpaceOverRing< - C, - V, - P: Polynomial, - R: RationalFunction, - A: Ring - > : RationalFunctionalSpaceOverRing, MultivariateRationalFunctionalSpace - -public interface MultivariateRationalFunctionalSpaceOverPolynomialSpace< - C, - V, - P: Polynomial, - R: RationalFunction, - AP: PolynomialSpace, - > : RationalFunctionalSpaceOverPolynomialSpace, MultivariateRationalFunctionalSpace - +/** + * Abstraction of field of rational functions of type [R] with respect to polynomials of type [P] of variables of type + * [V] and over ring of constants of type [C]. It also assumes that there is provided [polynomialRing] (of type [AP]), + * that provides constant-, variable- and polynomial-wise operations. + * + * @param C the type of constants. Polynomials have them as coefficients in their terms. + * @param V the type of variables. Polynomials have them in representations of terms. + * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. + * @param R the type of rational functions. + * @param AP the type of algebraic structure (precisely, of ring) provided for polynomials. + */ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public interface MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSpace< C, @@ -1184,57 +1309,135 @@ public interface MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSp P: Polynomial, R: RationalFunction, AP: MultivariatePolynomialSpace, - > : MultivariateRationalFunctionalSpaceOverPolynomialSpace { + > : RationalFunctionalSpaceOverPolynomialSpace, MultivariateRationalFunctionalSpace { + /** + * Returns sum of the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("plusVariableInt") public override operator fun V.plus(other: Int): P = polynomialRing { this@plus + other } + /** + * Returns difference between the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("minusVariableInt") public override operator fun V.minus(other: Int): P = polynomialRing { this@minus - other } + /** + * Returns product of the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("timesVariableInt") public override operator fun V.times(other: Int): P = polynomialRing { this@times * other } + /** + * Returns sum of the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("plusIntVariable") public override operator fun Int.plus(other: V): P = polynomialRing { this@plus + other } + /** + * Returns difference between the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("minusIntVariable") public override operator fun Int.minus(other: V): P = polynomialRing { this@minus - other } + /** + * Returns product of the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("timesIntVariable") public override operator fun Int.times(other: V): P = polynomialRing { this@times * other } - @JvmName("plusConstantVariable") - public override operator fun C.plus(other: V): P = polynomialRing { this@plus + other } - @JvmName("minusConstantVariable") - public override operator fun C.minus(other: V): P = polynomialRing { this@minus - other } - @JvmName("timesConstantVariable") - public override operator fun C.times(other: V): P = polynomialRing { this@times * other } - + /** + * Returns sum of the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("plusVariableConstant") public override operator fun V.plus(other: C): P = polynomialRing { this@plus + other } + /** + * Returns difference between the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("minusVariableConstant") public override operator fun V.minus(other: C): P = polynomialRing { this@minus - other } + /** + * Returns product of the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("timesVariableConstant") public override operator fun V.times(other: C): P = polynomialRing { this@times * other } + /** + * Returns sum of the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("plusConstantVariable") + public override operator fun C.plus(other: V): P = polynomialRing { this@plus + other } + /** + * Returns difference between the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("minusConstantVariable") + public override operator fun C.minus(other: V): P = polynomialRing { this@minus - other } + /** + * Returns product of the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("timesConstantVariable") + public override operator fun C.times(other: V): P = polynomialRing { this@times * other } + + /** + * Represents the variable as a monic monomial. + */ @JvmName("unaryPlusVariable") public override operator fun V.unaryPlus(): P = polynomialRing { +this@unaryPlus } + /** + * Returns negation of representation of the variable as a monic monomial. + */ @JvmName("unaryMinusVariable") public override operator fun V.unaryMinus(): P = polynomialRing { -this@unaryMinus } + /** + * Returns sum of the variables represented as monic monomials. + */ @JvmName("plusVariableVariable") public override operator fun V.plus(other: V): P = polynomialRing { this@plus + other } + /** + * Returns difference between the variables represented as monic monomials. + */ @JvmName("minusVariableVariable") public override operator fun V.minus(other: V): P = polynomialRing { this@minus - other } + /** + * Returns product of the variables represented as monic monomials. + */ @JvmName("timesVariableVariable") public override operator fun V.times(other: V): P = polynomialRing { this@times * other } + /** + * Represents the [variable] as a monic monomial. + */ + public override fun polynomialNumber(variable: V): P = polynomialRing { number(variable) } + /** + * Represents the variable as a monic monomial. + */ + public override fun V.asPolynomial(): P = polynomialRing { this@asPolynomial.asPolynomial() } + + /** + * Returns sum of the variable represented as a monic monomial and the polynomial. + */ @JvmName("plusVariablePolynomial") public override operator fun V.plus(other: P): P = polynomialRing { this@plus + other } + /** + * Returns difference between the variable represented as a monic monomial and the polynomial. + */ @JvmName("minusVariablePolynomial") public override operator fun V.minus(other: P): P = polynomialRing { this@minus - other } + /** + * Returns product of the variable represented as a monic monomial and the polynomial. + */ @JvmName("timesVariablePolynomial") public override operator fun V.times(other: P): P = polynomialRing { this@times * other } + /** + * Returns sum of the polynomial and the variable represented as a monic monomial. + */ @JvmName("plusPolynomialVariable") public override operator fun P.plus(other: V): P = polynomialRing { this@plus + other } + /** + * Returns difference between the polynomial and the variable represented as a monic monomial. + */ @JvmName("minusPolynomialVariable") public override operator fun P.minus(other: V): P = polynomialRing { this@minus - other } + /** + * Returns product of the polynomial and the variable represented as a monic monomial. + */ @JvmName("timesPolynomialVariable") public override operator fun P.times(other: V): P = polynomialRing { this@times * other } @@ -1264,6 +1467,16 @@ public interface MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSp public override val P.countOfVariables: Int get() = polynomialRing { countOfVariables } } +/** + * Abstraction of field of rational functions of type [R] with respect to polynomials of type [P] of variables of type + * [V] and over ring of constants of type [C]. It also assumes that there is provided constructor + * [constructRationalFunction] of rational functions from polynomial numerator and denominator. + * + * @param C the type of constants. Polynomials have them as coefficients in their terms. + * @param V the type of variables. Polynomials have them in representations of terms. + * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. + * @param R the type of rational functions. + */ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public abstract class MultivariatePolynomialSpaceOfFractions< C, @@ -1271,18 +1484,27 @@ public abstract class MultivariatePolynomialSpaceOfFractions< P: Polynomial, R: RationalFunction, > : MultivariateRationalFunctionalSpace, PolynomialSpaceOfFractions() { + /** + * Returns sum of the variable represented as a rational function and the rational function. + */ @JvmName("plusVariableRational") public override operator fun V.plus(other: R): R = constructRationalFunction( this * other.denominator + other.numerator, other.denominator ) + /** + * Returns difference between the variable represented as a rational function and the rational function. + */ @JvmName("minusVariableRational") public override operator fun V.minus(other: R): R = constructRationalFunction( this * other.denominator - other.numerator, other.denominator ) + /** + * Returns product of the variable represented as a rational function and the rational function. + */ @JvmName("timesVariableRational") public override operator fun V.times(other: R): R = constructRationalFunction( @@ -1290,18 +1512,27 @@ public abstract class MultivariatePolynomialSpaceOfFractions< other.denominator ) + /** + * Returns sum of the rational function and the variable represented as a rational function. + */ @JvmName("plusRationalVariable") public override operator fun R.plus(other: V): R = constructRationalFunction( numerator + denominator * other, denominator ) + /** + * Returns difference between the rational function and the variable represented as a rational function. + */ @JvmName("minusRationalVariable") public override operator fun R.minus(other: V): R = constructRationalFunction( numerator - denominator * other, denominator ) + /** + * Returns product of the rational function and the variable represented as a rational function. + */ @JvmName("timesRationalVariable") public override operator fun R.times(other: V): R = constructRationalFunction( -- 2.34.1 From 3a6aa1432094c6803ac026593e3035c14a51111d Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sun, 12 Jun 2022 22:52:08 +0300 Subject: [PATCH 067/123] Cleaned up ListPolynomials and ListRationalFunctions: - Added/updated docs. - Fully (but in a simple way) implemented invocation, substitution, functional representation, derivatives and antiderivatives. Optimized reimplementation is in progress. - Upgraded `PolynomialSpaceOfFractions` by adding a bit of laziness. - Other little things... --- .../kmath/functions/ListPolynomial.kt | 80 ++++-- .../kmath/functions/ListRationalFunction.kt | 159 +++++++---- .../kscience/kmath/functions/Polynomial.kt | 2 + .../kmath/functions/RationalFunction.kt | 10 +- .../kmath/functions/listPolynomialUtil.kt | 233 --------------- .../kscience/kmath/functions/listUtil.kt | 268 ++++++++++++++++++ ...alFunctionUtil.kt => listUtilOptimized.kt} | 129 +++++---- .../space/kscience/kmath/functions/misc.kt | 13 + .../kmath/functions/ListPolynomialUtilTest.kt | 2 + .../kscience/kmath/test/misc/Rational.kt | 135 +++++++++ .../space/kscience/kmath/test/misc/misc.kt | 11 + 11 files changed, 667 insertions(+), 375 deletions(-) delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listPolynomialUtil.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt rename kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/{listRationalFunctionUtil.kt => listUtilOptimized.kt} (72%) create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt index 585da95ea..fce179fc8 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt @@ -8,23 +8,19 @@ package space.kscience.kmath.functions import space.kscience.kmath.operations.Ring import space.kscience.kmath.operations.ScaleOperations import space.kscience.kmath.operations.invoke -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract -import kotlin.experimental.ExperimentalTypeInference -import kotlin.jvm.JvmName import kotlin.math.max import kotlin.math.min /** - * Polynomial model without fixation on specific context they are applied to. + * Represents univariate polynomial that stores its coefficients in a [List]. * * @param coefficients constant is the leftmost coefficient. */ public data class ListPolynomial( /** - * List that collects coefficients of the polynomial. Every monomial `a x^d` is represented as a coefficients - * `a` placed into the list with index `d`. For example coefficients of polynomial `5 x^2 - 6` can be represented as + * List that contains coefficients of the polynomial. Every monomial `a x^d` is stored as a coefficient `a` placed + * into the list at index `d`. For example, coefficients of a polynomial `5 x^2 - 6` can be represented as * ``` * listOf( * -6, // -6 + @@ -42,26 +38,28 @@ public data class ListPolynomial( * 0, // 0 x^4 * ) * ``` - * It is recommended not to put extra zeros at end of the list (as for `0x^3` and `0x^4` in the example), but is not - * prohibited. + * It is not prohibited to put extra zeros at end of the list (as for `0x^3` and `0x^4` in the example). But the + * longer the coefficients list the worse performance of arithmetical operations performed on it. Thus, it is + * recommended not to put (or even to remove) extra (or useless) coefficients at the end of the coefficients list. */ public val coefficients: List ) : Polynomial { - override fun toString(): String = "Polynomial$coefficients" + override fun toString(): String = "ListPolynomial$coefficients" } /** - * Space of univariate polynomials constructed over ring. + * Arithmetic context for univariate polynomials with coefficients stored as a [List] constructed with the given [ring] + * of constants. * - * @param C the type of constants. Polynomials have them as a coefficients in their terms. - * @param A type of underlying ring of constants. It's [Ring] of [C]. + * @param C the type of constants. Polynomials have them a coefficients in their terms. + * @param A type of provided underlying ring of constants. It's [Ring] of [C]. * @param ring underlying ring of constants of type [A]. */ public open class ListPolynomialSpace>( public override val ring: A, ) : PolynomialSpaceOverRing, A> { /** - * Returns sum of the polynomial and the integer represented as polynomial. + * Returns sum of the polynomial and the integer represented as a polynomial. * * The operation is equivalent to adding [other] copies of unit polynomial to [this]. */ @@ -79,7 +77,7 @@ public open class ListPolynomialSpace>( } ) /** - * Returns difference between the polynomial and the integer represented as polynomial. + * Returns difference between the polynomial and the integer represented as a polynomial. * * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. */ @@ -97,7 +95,7 @@ public open class ListPolynomialSpace>( } ) /** - * Returns product of the polynomial and the integer represented as polynomial. + * Returns product of the polynomial and the integer represented as a polynomial. * * The operation is equivalent to sum of [other] copies of [this]. */ @@ -112,7 +110,7 @@ public open class ListPolynomialSpace>( ) /** - * Returns sum of the integer represented as polynomial and the polynomial. + * Returns sum of the integer represented as a polynomial and the polynomial. * * The operation is equivalent to adding [this] copies of unit polynomial to [other]. */ @@ -130,7 +128,7 @@ public open class ListPolynomialSpace>( } ) /** - * Returns difference between the integer represented as polynomial and the polynomial. + * Returns difference between the integer represented as a polynomial and the polynomial. * * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. */ @@ -150,7 +148,7 @@ public open class ListPolynomialSpace>( } ) /** - * Returns product of the integer represented as polynomial and the polynomial. + * Returns product of the integer represented as a polynomial and the polynomial. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -170,7 +168,7 @@ public open class ListPolynomialSpace>( public override fun number(value: Int): ListPolynomial = number(constantNumber(value)) /** - * Returns sum of the constant represented as polynomial and the polynomial. + * Returns sum of the constant represented as a polynomial and the polynomial. */ public override operator fun C.plus(other: ListPolynomial): ListPolynomial = with(other.coefficients) { @@ -186,7 +184,7 @@ public open class ListPolynomialSpace>( ) } /** - * Returns difference between the constant represented as polynomial and the polynomial. + * Returns difference between the constant represented as a polynomial and the polynomial. */ public override operator fun C.minus(other: ListPolynomial): ListPolynomial = with(other.coefficients) { @@ -204,7 +202,7 @@ public open class ListPolynomialSpace>( ) } /** - * Returns product of the constant represented as polynomial and the polynomial. + * Returns product of the constant represented as a polynomial and the polynomial. */ public override operator fun C.times(other: ListPolynomial): ListPolynomial = ListPolynomial( @@ -216,7 +214,7 @@ public open class ListPolynomialSpace>( ) /** - * Returns sum of the constant represented as polynomial and the polynomial. + * Returns sum of the constant represented as a polynomial and the polynomial. */ public override operator fun ListPolynomial.plus(other: C): ListPolynomial = with(coefficients) { @@ -232,7 +230,7 @@ public open class ListPolynomialSpace>( ) } /** - * Returns difference between the constant represented as polynomial and the polynomial. + * Returns difference between the constant represented as a polynomial and the polynomial. */ public override operator fun ListPolynomial.minus(other: C): ListPolynomial = with(coefficients) { @@ -248,7 +246,7 @@ public open class ListPolynomialSpace>( ) } /** - * Returns product of the constant represented as polynomial and the polynomial. + * Returns product of the constant represented as a polynomial and the polynomial. */ public override operator fun ListPolynomial.times(other: C): ListPolynomial = ListPolynomial( @@ -262,7 +260,7 @@ public open class ListPolynomialSpace>( /** * Converts the constant [value] to polynomial. */ - public override fun number(value: C): ListPolynomial = ListPolynomial(value) + public override fun number(value: C): ListPolynomial = ListPolynomial(listOf(value)) /** * Returns negation of the polynomial. @@ -321,9 +319,9 @@ public open class ListPolynomialSpace>( */ override val zero: ListPolynomial = ListPolynomial(emptyList()) /** - * Instance of unit constant (unit of the underlying ring). + * Instance of unit polynomial (unit of the polynomial ring). */ - override val one: ListPolynomial = ListPolynomial(listOf(constantOne)) + override val one: ListPolynomial by lazy { ListPolynomial(listOf(constantOne)) } /** * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is @@ -331,23 +329,43 @@ public open class ListPolynomialSpace>( */ public override val ListPolynomial.degree: Int get() = coefficients.lastIndex + // TODO: When context receivers will be ready move all of this substitutions and invocations to utilities with + // [ListPolynomialSpace] as a context receiver + /** + * Evaluates value of [this] polynomial on provided argument. + */ @Suppress("NOTHING_TO_INLINE") public inline fun ListPolynomial.substitute(argument: C): C = this.substitute(ring, argument) + /** + * Substitutes provided polynomial [argument] into [this] polynomial. + */ @Suppress("NOTHING_TO_INLINE") public inline fun ListPolynomial.substitute(argument: ListPolynomial): ListPolynomial = this.substitute(ring, argument) + /** + * Represent [this] polynomial as a regular context-less function. + */ @Suppress("NOTHING_TO_INLINE") public inline fun ListPolynomial.asFunction(): (C) -> C = { this.substitute(ring, it) } + /** + * Represent [this] polynomial as a regular context-less function. + */ @Suppress("NOTHING_TO_INLINE") - public inline fun ListPolynomial.asFunctionOnConstants(): (C) -> C = { this.substitute(ring, it) } + public inline fun ListPolynomial.asFunctionOfConstant(): (C) -> C = { this.substitute(ring, it) } + /** + * Represent [this] polynomial as a regular context-less function. + */ @Suppress("NOTHING_TO_INLINE") - public inline fun ListPolynomial.asFunctionOnPolynomials(): (ListPolynomial) -> ListPolynomial = { this.substitute(ring, it) } + public inline fun ListPolynomial.asFunctionOfPolynomial(): (ListPolynomial) -> ListPolynomial = { this.substitute(ring, it) } /** - * Evaluates the polynomial for the given value [argument]. + * Evaluates value of [this] polynomial on provided [argument]. */ @Suppress("NOTHING_TO_INLINE") public inline operator fun ListPolynomial.invoke(argument: C): C = this.substitute(ring, argument) + /** + * Evaluates value of [this] polynomial on provided [argument]. + */ @Suppress("NOTHING_TO_INLINE") public inline operator fun ListPolynomial.invoke(argument: ListPolynomial): ListPolynomial = this.substitute(ring, argument) } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt index 7b6c23ac3..45ea99fb0 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt @@ -8,13 +8,23 @@ package space.kscience.kmath.functions import space.kscience.kmath.operations.Ring +/** + * Represents rational function that stores its numerator and denominator as [ListPolynomial]s. + */ public data class ListRationalFunction( public override val numerator: ListPolynomial, public override val denominator: ListPolynomial ) : RationalFunction> { - override fun toString(): String = "RationalFunction${numerator.coefficients}/${denominator.coefficients}" + override fun toString(): String = "ListRationalFunction${numerator.coefficients}/${denominator.coefficients}" } +/** + * Arithmetic context for univariate rational functions with numerator and denominator represented as [ListPolynomial]s. + * + * @param C the type of constants. Polynomials have them a coefficients in their terms. + * @param A type of provided underlying ring of constants. It's [Ring] of [C]. + * @param ring underlying ring of constants of type [A]. + */ public class ListRationalFunctionSpace> ( public val ring: A, ) : @@ -30,7 +40,13 @@ public class ListRationalFunctionSpace> ( ListRationalFunction, >() { + /** + * Underlying polynomial ring. Its polynomial operations are inherited by local polynomial operations. + */ override val polynomialRing : ListPolynomialSpace = ListPolynomialSpace(ring) + /** + * Constructor of [ListRationalFunction] from numerator and denominator [ListPolynomial]. + */ override fun constructRationalFunction(numerator: ListPolynomial, denominator: ListPolynomial): ListRationalFunction = ListRationalFunction(numerator, denominator) @@ -43,63 +59,88 @@ public class ListRationalFunctionSpace> ( */ public override val one: ListRationalFunction = ListRationalFunction(polynomialOne, polynomialOne) - // TODO: Разобрать + // TODO: When context receivers will be ready move all of this substitutions and invocations to utilities with + // [ListPolynomialSpace] as a context receiver + /** + * Evaluates value of [this] polynomial on provided argument. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun ListPolynomial.substitute(argument: C): C = this.substitute(ring, argument) + /** + * Substitutes provided polynomial [argument] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun ListPolynomial.substitute(argument: ListPolynomial): ListPolynomial = this.substitute(ring, argument) + /** + * Substitutes provided rational function [argument] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun ListPolynomial.substitute(argument: ListRationalFunction): ListRationalFunction = this.substitute(ring, argument) + /** + * Substitutes provided polynomial [argument] into [this] rational function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun ListRationalFunction.substitute(argument: ListPolynomial): ListRationalFunction = this.substitute(ring, argument) + /** + * Substitutes provided rational function [argument] into [this] rational function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun ListRationalFunction.substitute(argument: ListRationalFunction): ListRationalFunction = this.substitute(ring, argument) -// operator fun invoke(arg: UnivariatePolynomial): RationalFunction = -// RationalFunction( -// numerator(arg), -// denominator(arg) -// ) -// -// operator fun invoke(arg: RationalFunction): RationalFunction { -// val num = numerator invokeRFTakeNumerator arg -// val den = denominator invokeRFTakeNumerator arg -// val degreeDif = numeratorDegree - denominatorDegree -// return if (degreeDif > 0) -// RationalFunction( -// num, -// multiplyByPower(den, arg.denominator, degreeDif) -// ) -// else -// RationalFunction( -// multiplyByPower(num, arg.denominator, -degreeDif), -// den -// ) -// } -// -// override fun toString(): String = toString(UnivariatePolynomial.variableName) -// -// fun toString(withVariableName: String = UnivariatePolynomial.variableName): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toString(withVariableName) -// else -> "${numerator.toStringWithBrackets(withVariableName)}/${denominator.toStringWithBrackets(withVariableName)}" -// } -// -// fun toStringWithBrackets(withVariableName: String = UnivariatePolynomial.variableName): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toStringWithBrackets(withVariableName) -// else -> "(${numerator.toStringWithBrackets(withVariableName)}/${denominator.toStringWithBrackets(withVariableName)})" -// } -// -// fun toReversedString(withVariableName: String = UnivariatePolynomial.variableName): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedString(withVariableName) -// else -> "${numerator.toReversedStringWithBrackets(withVariableName)}/${denominator.toReversedStringWithBrackets(withVariableName)}" -// } -// -// fun toReversedStringWithBrackets(withVariableName: String = UnivariatePolynomial.variableName): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedStringWithBrackets(withVariableName) -// else -> "(${numerator.toReversedStringWithBrackets(withVariableName)}/${denominator.toReversedStringWithBrackets(withVariableName)})" -// } -// -// fun removeZeros() = -// RationalFunction( -// numerator.removeZeros(), -// denominator.removeZeros() -// ) + /** + * Represent [this] polynomial as a regular context-less function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun ListPolynomial.asFunction(): (C) -> C = { this.substitute(ring, it) } + /** + * Represent [this] polynomial as a regular context-less function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun ListPolynomial.asFunctionOfConstant(): (C) -> C = { this.substitute(ring, it) } + /** + * Represent [this] polynomial as a regular context-less function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun ListPolynomial.asFunctionOfPolynomial(): (ListPolynomial) -> ListPolynomial = { this.substitute(ring, it) } + /** + * Represent [this] polynomial as a regular context-less function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun ListPolynomial.asFunctionOfRationalFunction(): (ListRationalFunction) -> ListRationalFunction = { this.substitute(ring, it) } + /** + * Represent [this] rational function as a regular context-less function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun ListRationalFunction.asFunctionOfPolynomial(): (ListPolynomial) -> ListRationalFunction = { this.substitute(ring, it) } + /** + * Represent [this] rational function as a regular context-less function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun ListRationalFunction.asFunctionOfRationalFunction(): (ListRationalFunction) -> ListRationalFunction = { this.substitute(ring, it) } + + /** + * Evaluates value of [this] polynomial on provided argument. + */ + @Suppress("NOTHING_TO_INLINE") + public inline operator fun ListPolynomial.invoke(argument: C): C = this.substitute(ring, argument) + /** + * Evaluates value of [this] polynomial on provided argument. + */ + @Suppress("NOTHING_TO_INLINE") + public inline operator fun ListPolynomial.invoke(argument: ListPolynomial): ListPolynomial = this.substitute(ring, argument) + /** + * Evaluates value of [this] polynomial on provided argument. + */ + @Suppress("NOTHING_TO_INLINE") + public inline operator fun ListPolynomial.invoke(argument: ListRationalFunction): ListRationalFunction = this.substitute(ring, argument) + /** + * Evaluates value of [this] rational function on provided argument. + */ + @Suppress("NOTHING_TO_INLINE") + public inline operator fun ListRationalFunction.invoke(argument: ListPolynomial): ListRationalFunction = this.substitute(ring, argument) + /** + * Evaluates value of [this] rational function on provided argument. + */ + @Suppress("NOTHING_TO_INLINE") + public inline operator fun ListRationalFunction.invoke(argument: ListRationalFunction): ListRationalFunction = this.substitute(ring, argument) } \ No newline at end of file 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 f2eba10d5..12490d133 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 @@ -435,10 +435,12 @@ public interface MultivariatePolynomialSpace>: Polynomial /** * Represents the [variable] as a monic monomial. */ + @JvmName("numberVariable") public fun number(variable: V): P = +variable /** * Represents the variable as a monic monomial. */ + @JvmName("asPolynomialVariable") public fun V.asPolynomial(): P = number(this) /** diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt index edc9dfa5c..4ce6c7c26 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt @@ -1060,12 +1060,12 @@ public abstract class PolynomialSpaceOfFractions< /** * Instance of zero rational function (zero of the rational functions ring). */ - public override val zero: R get() = constructRationalFunction(polynomialZero) + public override val zero: R by lazy { constructRationalFunction(polynomialZero) } /** * Instance of unit polynomial (unit of the rational functions ring). */ - public override val one: R get() = constructRationalFunction(polynomialOne) + public override val one: R by lazy { constructRationalFunction(polynomialOne) } } /** @@ -1177,19 +1177,23 @@ public interface MultivariateRationalFunctionalSpace< /** * Represents the [variable] as a monic monomial. */ + @JvmName("polynomialNumberVariable") public fun polynomialNumber(variable: V): P = +variable /** * Represents the variable as a monic monomial. */ + @JvmName("asPolynomialVariable") public fun V.asPolynomial(): P = polynomialNumber(this) /** * Represents the [variable] as a rational function. */ + @JvmName("numberVariable") public fun number(variable: V): R = number(polynomialNumber(variable)) /** * Represents the variable as a rational function. */ + @JvmName("asRationalFunctionVariable") public fun V.asRationalFunction(): R = number(this) /** @@ -1403,10 +1407,12 @@ public interface MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSp /** * Represents the [variable] as a monic monomial. */ + @JvmName("polynomialNumberVariable") public override fun polynomialNumber(variable: V): P = polynomialRing { number(variable) } /** * Represents the variable as a monic monomial. */ + @JvmName("asPolynomialVariable") public override fun V.asPolynomial(): P = polynomialRing { this@asPolynomial.asPolynomial() } /** diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listPolynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listPolynomialUtil.kt deleted file mode 100644 index 50313cab9..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listPolynomialUtil.kt +++ /dev/null @@ -1,233 +0,0 @@ -/* - * 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.functions - -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.* -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract -import kotlin.math.max -import kotlin.math.min -import kotlin.math.pow - - -/** - * Removes zeros on the end of the coefficient list of polynomial. - */ -//context(PolynomialSpace) -//fun > Polynomial.removeZeros() : Polynomial = -// if (degree > -1) Polynomial(coefficients.subList(0, degree + 1)) else zero - -/** - * Creates a [ListPolynomialSpace] over a received ring. - */ -public fun > A.listPolynomial(): ListPolynomialSpace = - ListPolynomialSpace(this) - -/** - * Creates a [ListPolynomialSpace]'s scope over a received ring. - */ -public inline fun , R> A.listPolynomial(block: ListPolynomialSpace.() -> R): R { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return ListPolynomialSpace(this).block() -} - -/** - * Creates a [ScalableListPolynomialSpace] over a received scalable ring. - */ -public fun A.scalableListPolynomial(): ScalableListPolynomialSpace where A : Ring, A : ScaleOperations = - ScalableListPolynomialSpace(this) - -/** - * Creates a [ScalableListPolynomialSpace]'s scope over a received scalable ring. - */ -public inline fun A.scalableListPolynomial(block: ScalableListPolynomialSpace.() -> R): R where A : Ring, A : ScaleOperations { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return ScalableListPolynomialSpace(this).block() -} - -@Suppress("NOTHING_TO_INLINE") -internal inline fun copyTo( - origin: List, - originDegree: Int, - target: MutableList, -) { - for (deg in 0 .. originDegree) target[deg] = origin[deg] -} - -@Suppress("NOTHING_TO_INLINE") -internal inline fun multiplyAddingToUpdater( - ring: Ring, - multiplicand: MutableList, - multiplicandDegree: Int, - multiplier: List, - multiplierDegree: Int, - updater: MutableList, - zero: C, -) { - multiplyAddingTo( - ring = ring, - multiplicand = multiplicand, - multiplicandDegree = multiplicandDegree, - multiplier = multiplier, - multiplierDegree = multiplierDegree, - target = updater - ) - for (updateDeg in 0 .. multiplicandDegree + multiplierDegree) { - multiplicand[updateDeg] = updater[updateDeg] - updater[updateDeg] = zero - } -} - -@Suppress("NOTHING_TO_INLINE") -internal inline fun multiplyAddingTo( - ring: Ring, - multiplicand: List, - multiplicandDegree: Int, - multiplier: List, - multiplierDegree: Int, - target: MutableList -) = ring { - for (d in 0 .. multiplicandDegree + multiplierDegree) - for (k in max(0, d - multiplierDegree)..min(multiplicandDegree, d)) - target[d] += multiplicand[k] * multiplier[d - k] -} - -/** - * Evaluates the value of the given double polynomial for given double argument. - */ -public fun ListPolynomial.substitute(arg: Double): Double = - coefficients.reduceIndexedOrNull { index, acc, c -> - acc + c * arg.pow(index) - } ?: .0 - -/** - * Evaluates the value of the given polynomial for given argument. - * - * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). - */ -public fun ListPolynomial.substitute(ring: Ring, arg: C): C = ring { - if (coefficients.isEmpty()) return@ring zero - var result: C = coefficients.last() - for (j in coefficients.size - 2 downTo 0) { - result = (arg * result) + coefficients[j] - } - return result -} - -public fun ListPolynomial.substitute(ring: Ring, arg: ListPolynomial) : ListPolynomial = ring { - if (coefficients.isEmpty()) return ListPolynomial(emptyList()) - - val thisDegree = coefficients.lastIndex - if (thisDegree == -1) return ListPolynomial(emptyList()) - val argDegree = arg.coefficients.lastIndex - if (argDegree == -1) return coefficients[0].asListPolynomial() - val constantZero = zero - val resultCoefs: MutableList = MutableList(thisDegree * argDegree + 1) { constantZero } - resultCoefs[0] = coefficients[thisDegree] - val resultCoefsUpdate: MutableList = MutableList(thisDegree * argDegree + 1) { constantZero } - var resultDegree = 0 - for (deg in thisDegree - 1 downTo 0) { - resultCoefsUpdate[0] = coefficients[deg] - multiplyAddingToUpdater( - ring = ring, - multiplicand = resultCoefs, - multiplicandDegree = resultDegree, - multiplier = arg.coefficients, - multiplierDegree = argDegree, - updater = resultCoefsUpdate, - zero = constantZero - ) - resultDegree += argDegree - } - - return ListPolynomial(resultCoefs) -} - -/** - * Represent the polynomial as a regular context-less function. - */ -public fun > ListPolynomial.asFunction(ring: A): (C) -> C = { substitute(ring, it) } - -/** - * Represent the polynomial as a regular context-less function. - */ -public fun > ListPolynomial.asPolynomialFunctionOver(ring: A): (ListPolynomial) -> ListPolynomial = { substitute(ring, it) } - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun ListPolynomial.derivative( - algebra: A, -): ListPolynomial where A : Ring, A : NumericAlgebra = algebra { - ListPolynomial( - buildList(max(0, coefficients.size - 1)) { - for (deg in 1 .. coefficients.lastIndex) add(number(deg) * coefficients[deg]) - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun ListPolynomial.nthDerivative( - algebra: A, - order: Int, -): ListPolynomial where A : Ring, A : NumericAlgebra = algebra { - require(order >= 0) { "Order of derivative must be non-negative" } - ListPolynomial( - buildList(max(0, coefficients.size - order)) { - for (deg in order.. coefficients.lastIndex) - add((deg - order + 1 .. deg).fold(coefficients[deg]) { acc, d -> acc * number(d) }) - } - ) -} - -/** - * Returns algebraic antiderivative of received polynomial. - */ -@UnstableKMathAPI -public fun ListPolynomial.antiderivative( - algebra: A, -): ListPolynomial where A : Field, A : NumericAlgebra = algebra { - ListPolynomial( - buildList(coefficients.size + 1) { - add(zero) - coefficients.mapIndexedTo(this) { index, t -> t / number(index + 1) } - } - ) -} - -/** - * Returns algebraic antiderivative of received polynomial. - */ -@UnstableKMathAPI -public fun ListPolynomial.nthAntiderivative( - algebra: A, - order: Int, -): ListPolynomial where A : Field, A : NumericAlgebra = algebra { - require(order >= 0) { "Order of antiderivative must be non-negative" } - ListPolynomial( - buildList(coefficients.size + order) { - repeat(order) { add(zero) } - coefficients.mapIndexedTo(this) { index, c -> (1..order).fold(c) { acc, i -> acc / number(index + i) } } - } - ) -} - -/** - * Compute a definite integral of a given polynomial in a [range] - */ -@UnstableKMathAPI -public fun > ListPolynomial.integrate( - algebra: Field, - range: ClosedRange, -): C = algebra { - val integral = antiderivative(algebra) - integral.substitute(algebra, range.endInclusive) - integral.substitute(algebra, range.start) -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt new file mode 100644 index 000000000..127dd8c7a --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt @@ -0,0 +1,268 @@ +/* + * 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.functions + +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.* +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract +import kotlin.math.max +import kotlin.math.pow + + +/** + * Creates a [ListPolynomialSpace] over a received ring. + */ +public fun > A.listPolynomialSpace(): ListPolynomialSpace = + ListPolynomialSpace(this) + +/** + * Creates a [ListPolynomialSpace]'s scope over a received ring. + */ // TODO: When context will be ready move [ListPolynomialSpace] and add [A] to context receivers of [block] +public inline fun , R> A.listPolynomialSpace(block: ListPolynomialSpace.() -> R): R { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return ListPolynomialSpace(this).block() +} + +/** + * Creates a [ScalableListPolynomialSpace] over a received scalable ring. + */ +public fun A.scalableListPolynomialSpace(): ScalableListPolynomialSpace where A : Ring, A : ScaleOperations = + ScalableListPolynomialSpace(this) + +/** + * Creates a [ScalableListPolynomialSpace]'s scope over a received scalable ring. + */ // TODO: When context will be ready move [ListPolynomialSpace] and add [A] to context receivers of [block] +public inline fun A.scalableListPolynomialSpace(block: ScalableListPolynomialSpace.() -> R): R where A : Ring, A : ScaleOperations { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return ScalableListPolynomialSpace(this).block() +} + +/** + * Creates a [ListRationalFunctionSpace] over a received ring. + */ +public fun > A.listRationalFunctionSpace(): ListRationalFunctionSpace = + ListRationalFunctionSpace(this) + +/** + * Creates a [ListRationalFunctionSpace]'s scope over a received ring. + */ // TODO: When context will be ready move [ListRationalFunctionSpace] and add [A] to context receivers of [block] +public inline fun , R> A.listRationalFunctionSpace(block: ListRationalFunctionSpace.() -> R): R { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return ListRationalFunctionSpace(this).block() +} + + +/** + * Evaluates value of [this] Double polynomial on provided Double argument. + */ +public fun ListPolynomial.substitute(arg: Double): Double = + coefficients.reduceIndexedOrNull { index, acc, c -> + acc + c * arg.pow(index) + } ?: .0 + +/** + * Evaluates value of [this] polynomial on provided argument. + * + * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). + */ +public fun ListPolynomial.substitute(ring: Ring, arg: C): C = ring { + if (coefficients.isEmpty()) return zero + var result: C = coefficients.last() + for (j in coefficients.size - 2 downTo 0) { + result = (arg * result) + coefficients[j] + } + return result +} + +/** + * Substitutes provided polynomial [arg] into [this] polynomial. + * + * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). + */ // TODO: To optimize boxing +public fun ListPolynomial.substitute(ring: Ring, arg: ListPolynomial) : ListPolynomial = + ring.listPolynomialSpace { + if (coefficients.isEmpty()) return zero + var result: ListPolynomial = coefficients.last().asPolynomial() + for (j in coefficients.size - 2 downTo 0) { + result = (arg * result) + coefficients[j] + } + return result + } + +/** + * Substitutes provided rational function [arg] into [this] polynomial. + * + * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). + */ // TODO: To optimize boxing +public fun ListPolynomial.substitute(ring: Ring, arg: ListRationalFunction) : ListRationalFunction = + ring.listRationalFunctionSpace { + if (coefficients.isEmpty()) return zero + var result: ListRationalFunction = coefficients.last().asRationalFunction() + for (j in coefficients.size - 2 downTo 0) { + result = (arg * result) + coefficients[j] + } + return result + } + +/** + * Evaluates value of [this] Double rational function in provided Double argument. + */ +public fun ListRationalFunction.substitute(arg: Double): Double = + numerator.substitute(arg) / denominator.substitute(arg) + +/** + * Evaluates value of [this] polynomial for provided argument. + * + * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). + */ +public fun ListRationalFunction.substitute(ring: Field, arg: C): C = ring { + numerator.substitute(ring, arg) / denominator.substitute(ring, arg) +} + +/** + * Substitutes provided polynomial [arg] into [this] rational function. + */ // TODO: To optimize boxing +public fun ListRationalFunction.substitute(ring: Ring, arg: ListPolynomial) : ListRationalFunction = + ring.listRationalFunctionSpace { + numerator.substitute(ring, arg) / denominator.substitute(ring, arg) + } + +/** + * Substitutes provided rational function [arg] into [this] rational function. + */ // TODO: To optimize boxing +public fun ListRationalFunction.substitute(ring: Ring, arg: ListRationalFunction) : ListRationalFunction = + ring.listRationalFunctionSpace { + numerator.substitute(ring, arg) / denominator.substitute(ring, arg) + } + +/** + * Represent [this] polynomial as a regular context-less function. + */ +public fun > ListPolynomial.asFunctionOver(ring: A): (C) -> C = { substitute(ring, it) } + +/** + * Represent [this] polynomial as a regular context-less function. + */ +public fun > ListPolynomial.asPolynomialFunctionOver(ring: A): (ListPolynomial) -> ListPolynomial = { substitute(ring, it) } + +/** + * Represent [this] polynomial as a regular context-less function. + */ +public fun > ListPolynomial.asFunctionOfRationalFunctionOver(ring: A): (ListPolynomial) -> ListPolynomial = { substitute(ring, it) } + +/** + * Represent [this] rational function as a regular context-less function. + */ +public fun > ListRationalFunction.asFunctionOver(ring: A): (C) -> C = { substitute(ring, it) } + +/** + * Represent [this] rational function as a regular context-less function. + */ +public fun > ListRationalFunction.asPolynomialFunctionOver(ring: A): (ListPolynomial) -> ListRationalFunction = { substitute(ring, it) } + +/** + * Represent [this] rational function as a regular context-less function. + */ +public fun > ListRationalFunction.asFunctionOfRationalFunctionOver(ring: A): (ListPolynomial) -> ListRationalFunction = { substitute(ring, it) } + +/** + * Returns algebraic derivative of received polynomial. + */ +@UnstableKMathAPI +public fun ListPolynomial.derivative( + ring: A, +): ListPolynomial where A : Ring, A : NumericAlgebra = ring { + ListPolynomial( + buildList(max(0, coefficients.size - 1)) { + for (deg in 1 .. coefficients.lastIndex) add(number(deg) * coefficients[deg]) + } + ) +} + +/** + * Returns algebraic derivative of received polynomial of specified [order]. The [order] should be non-negative integer. + */ +@UnstableKMathAPI +public fun ListPolynomial.nthDerivative( + ring: A, + order: Int, +): ListPolynomial where A : Ring, A : NumericAlgebra = ring { + require(order >= 0) { "Order of derivative must be non-negative" } + ListPolynomial( + buildList(max(0, coefficients.size - order)) { + for (deg in order.. coefficients.lastIndex) + add((deg - order + 1 .. deg).fold(coefficients[deg]) { acc, d -> acc * number(d) }) + } + ) +} + +/** + * Returns algebraic antiderivative of received polynomial. + */ +@UnstableKMathAPI +public fun ListPolynomial.antiderivative( + ring: A, +): ListPolynomial where A : Field, A : NumericAlgebra = ring { + ListPolynomial( + buildList(coefficients.size + 1) { + add(zero) + coefficients.mapIndexedTo(this) { index, t -> t / number(index + 1) } + } + ) +} + +/** + * Returns algebraic antiderivative of received polynomial of specified [order]. The [order] should be non-negative integer. + */ +@UnstableKMathAPI +public fun ListPolynomial.nthAntiderivative( + ring: A, + order: Int, +): ListPolynomial where A : Field, A : NumericAlgebra = ring { + require(order >= 0) { "Order of antiderivative must be non-negative" } + ListPolynomial( + buildList(coefficients.size + order) { + repeat(order) { add(zero) } + coefficients.mapIndexedTo(this) { index, c -> (1..order).fold(c) { acc, i -> acc / number(index + i) } } + } + ) +} + +/** + * Computes a definite integral of [this] polynomial in the specified [range]. + */ +@UnstableKMathAPI +public fun > ListPolynomial.integrate( + ring: Field, + range: ClosedRange, +): C = ring { + val antiderivative = antiderivative(ring) + antiderivative.substitute(ring, range.endInclusive) - antiderivative.substitute(ring, range.start) +} + +/** + * Returns algebraic derivative of received rational function. + */ +@UnstableKMathAPI +public fun ListRationalFunction.derivative( + ring: A, +): ListRationalFunction where A : Ring, A : NumericAlgebra = ring.listRationalFunctionSpace { + ListRationalFunction( + numerator.derivative(ring) * denominator - numerator * denominator.derivative(ring), + denominator * denominator + ) +} + +/** + * Returns algebraic derivative of received rational function of specified [order]. The [order] should be non-negative integer. + */ +@UnstableKMathAPI +public tailrec fun ListRationalFunction.nthDerivative( + ring: A, + order: Int, +): ListRationalFunction where A : Ring, A : NumericAlgebra = + if (order == 0) this else derivative(ring).nthDerivative(ring, order - 1) \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listRationalFunctionUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtilOptimized.kt similarity index 72% rename from kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listRationalFunctionUtil.kt rename to kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtilOptimized.kt index 367212588..6eb3a1dc7 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listRationalFunctionUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtilOptimized.kt @@ -5,41 +5,91 @@ package space.kscience.kmath.functions -import space.kscience.kmath.operations.Field import space.kscience.kmath.operations.Ring import space.kscience.kmath.operations.invoke -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract import kotlin.math.max +import kotlin.math.min -/** - * Creates a [ListRationalFunctionSpace] over a received ring. - */ -public fun > A.listRationalFunction(): ListRationalFunctionSpace = - ListRationalFunctionSpace(this) - -/** - * Creates a [ListRationalFunctionSpace]'s scope over a received ring. - */ -public inline fun , R> A.listRationalFunction(block: ListRationalFunctionSpace.() -> R): R { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return ListRationalFunctionSpace(this).block() +// TODO: Optimized copies of substitution and invocation +@UnstablePolynomialBoxingOptimization +@Suppress("NOTHING_TO_INLINE") +internal inline fun copyTo( + origin: List, + originDegree: Int, + target: MutableList, +) { + for (deg in 0 .. originDegree) target[deg] = origin[deg] } -/** - * Evaluates the value of the given double polynomial for given double argument. - */ -public fun ListRationalFunction.substitute(arg: Double): Double = - numerator.substitute(arg) / denominator.substitute(arg) +@UnstablePolynomialBoxingOptimization +@Suppress("NOTHING_TO_INLINE") +internal inline fun multiplyAddingToUpdater( + ring: Ring, + multiplicand: MutableList, + multiplicandDegree: Int, + multiplier: List, + multiplierDegree: Int, + updater: MutableList, + zero: C, +) { + multiplyAddingTo( + ring = ring, + multiplicand = multiplicand, + multiplicandDegree = multiplicandDegree, + multiplier = multiplier, + multiplierDegree = multiplierDegree, + target = updater + ) + for (updateDeg in 0 .. multiplicandDegree + multiplierDegree) { + multiplicand[updateDeg] = updater[updateDeg] + updater[updateDeg] = zero + } +} -/** - * Evaluates the value of the given polynomial for given argument. - * - * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). - */ -public fun ListRationalFunction.substitute(ring: Field, arg: C): C = ring { - numerator.substitute(ring, arg) / denominator.substitute(ring, arg) +@UnstablePolynomialBoxingOptimization +@Suppress("NOTHING_TO_INLINE") +internal inline fun multiplyAddingTo( + ring: Ring, + multiplicand: List, + multiplicandDegree: Int, + multiplier: List, + multiplierDegree: Int, + target: MutableList +) = ring { + for (d in 0 .. multiplicandDegree + multiplierDegree) + for (k in max(0, d - multiplierDegree)..min(multiplicandDegree, d)) + target[d] += multiplicand[k] * multiplier[d - k] +} + +@UnstablePolynomialBoxingOptimization +public fun ListPolynomial.substitute2(ring: Ring, arg: ListPolynomial) : ListPolynomial = ring { + if (coefficients.isEmpty()) return ListPolynomial(emptyList()) + + val thisDegree = coefficients.lastIndex + if (thisDegree == -1) return ListPolynomial(emptyList()) + val argDegree = arg.coefficients.lastIndex + if (argDegree == -1) return coefficients[0].asListPolynomial() + val constantZero = zero + val resultCoefs: MutableList = MutableList(thisDegree * argDegree + 1) { constantZero } + resultCoefs[0] = coefficients[thisDegree] + val resultCoefsUpdate: MutableList = MutableList(thisDegree * argDegree + 1) { constantZero } + var resultDegree = 0 + for (deg in thisDegree - 1 downTo 0) { + resultCoefsUpdate[0] = coefficients[deg] + multiplyAddingToUpdater( + ring = ring, + multiplicand = resultCoefs, + multiplicandDegree = resultDegree, + multiplier = arg.coefficients, + multiplierDegree = argDegree, + updater = resultCoefsUpdate, + zero = constantZero + ) + resultDegree += argDegree + } + + return ListPolynomial(resultCoefs) } /** @@ -52,6 +102,7 @@ public fun ListRationalFunction.substitute(ring: Field, arg: C): C = r * * Used in [ListPolynomial.substitute] and [ListRationalFunction.substitute] for performance optimisation. */ // TODO: Дописать +@UnstablePolynomialBoxingOptimization internal fun ListPolynomial.substituteRationalFunctionTakeNumerator(ring: Ring, arg: ListRationalFunction): ListPolynomial = ring { if (coefficients.isEmpty()) return ListPolynomial(emptyList()) @@ -196,26 +247,4 @@ internal fun ListPolynomial.substituteRationalFunctionTakeNumerator(ring: end = thisDegree + 1 ) ) -} - -//operator fun > RationalFunction.invoke(arg: T): T = numerator(arg) / denominator(arg) -// -//fun > RationalFunction.reduced(): RationalFunction = -// polynomialGCD(numerator, denominator).let { -// RationalFunction( -// numerator / it, -// denominator / it -// ) -// } - -///** -// * Returns result of applying formal derivative to the polynomial. -// * -// * @param T Field where we are working now. -// * @return Result of the operator. -// */ -//fun > RationalFunction.derivative() = -// RationalFunction( -// numerator.derivative() * denominator - denominator.derivative() * numerator, -// denominator * denominator -// ) \ No newline at end of file +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt new file mode 100644 index 000000000..8b6fac39e --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt @@ -0,0 +1,13 @@ +/* + * 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.functions + + +@RequiresOptIn( + message = "It's copy of operation with optimized boxing. It's currently unstable.", + level = RequiresOptIn.Level.ERROR +) +internal annotation class UnstablePolynomialBoxingOptimization \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt index c5eb8fb81..69c1611f3 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt @@ -5,6 +5,7 @@ package space.kscience.kmath.functions +import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.test.misc.Rational import space.kscience.kmath.test.misc.RationalField import kotlin.test.Test @@ -12,6 +13,7 @@ import kotlin.test.assertEquals import kotlin.test.assertFailsWith +@OptIn(UnstableKMathAPI::class) class ListPolynomialUtilTest { @Test fun test_substitute_Double() { 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..72bb5942c --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt @@ -0,0 +1,135 @@ +/* + * 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.Field +import space.kscience.kmath.operations.NumbersAddOps + +class Rational { + companion object { + val ZERO: Rational = Rational(0L) + val ONE: Rational = Rational(1L) + } + + val numerator: Long + val denominator: Long + + internal constructor(numerator: Long, denominator: Long, toCheckInput: Boolean = true) { + if (toCheckInput) { + if (denominator == 0L) throw ArithmeticException("/ by zero") + + val greatestCommonDivider = gcd(numerator, denominator).let { if (denominator < 0L) -it else it } + + this.numerator = numerator / greatestCommonDivider + this.denominator = denominator / greatestCommonDivider + } else { + this.numerator = numerator + this.denominator = denominator + } + } + + constructor(numerator: Int, denominator: Int) : this(numerator.toLong(), denominator.toLong(), true) + constructor(numerator: Int, denominator: Long) : this(numerator.toLong(), denominator, true) + constructor(numerator: Long, denominator: Int) : this(numerator, denominator.toLong(), true) + constructor(numerator: Long, denominator: Long) : this(numerator, denominator, true) + constructor(numerator: Int) : this(numerator.toLong(), 1L, false) + constructor(numerator: Long) : this(numerator, 1L, false) + + operator fun unaryPlus(): Rational = this + operator fun unaryMinus(): Rational = Rational(-this.numerator, this.denominator) + operator fun plus(other: Rational): Rational = + Rational( + numerator * other.denominator + denominator * other.numerator, + denominator * other.denominator + ) + operator fun plus(other: Int): Rational = + Rational( + numerator + denominator * other.toLong(), + denominator + ) + operator fun plus(other: Long): Rational = + Rational( + numerator + denominator * other, + denominator + ) + operator fun minus(other: Rational): Rational = + Rational( + numerator * other.denominator - denominator * other.numerator, + denominator * other.denominator + ) + operator fun minus(other: Int): Rational = + Rational( + numerator - denominator * other.toLong(), + denominator + ) + operator fun minus(other: Long): Rational = + Rational( + numerator - denominator * other, + denominator + ) + operator fun times(other: Rational): Rational = + Rational( + numerator * other.numerator, + denominator * other.denominator + ) + operator fun times(other: Int): Rational = + Rational( + numerator * other.toLong(), + denominator + ) + operator fun times(other: Long): Rational = + Rational( + numerator * other, + denominator + ) + operator fun div(other: Rational): Rational = + Rational( + numerator * other.denominator, + denominator * other.numerator + ) + operator fun div(other: Int): Rational = + Rational( + numerator, + denominator * other.toLong() + ) + operator fun div(other: Long): Rational = + Rational( + numerator, + denominator * other + ) + override fun equals(other: Any?): Boolean = + when (other) { + is Rational -> numerator == other.numerator && denominator == other.denominator + is Int -> numerator == other && denominator == 1L + is Long -> numerator == other && denominator == 1L + else -> false + } + + override fun hashCode(): Int = 31 * numerator.hashCode() + denominator.hashCode() + + override fun toString(): String = if (denominator == 1L) "$numerator" else "$numerator/$denominator" +} + +@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") +@OptIn(UnstableKMathAPI::class) +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/misc.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt new file mode 100644 index 000000000..873162a1b --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt @@ -0,0 +1,11 @@ +/* + * 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 kotlin.math.abs + + +tailrec fun gcd(a: Long, b: Long): Long = if (a == 0L) abs(b) else gcd(b % a, a) \ No newline at end of file -- 2.34.1 From e7100138006c0b7f91ee40135a40498b09ddeebe Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sun, 12 Jun 2022 23:02:26 +0300 Subject: [PATCH 068/123] Fixed tests. --- .../kmath/functions/ListPolynomialTest.kt | 32 ++-- .../kscience/kmath/test/misc/IntModulo.kt | 140 ++++++++++++++++++ .../space/kscience/kmath/test/misc/misc.kt | 20 ++- 3 files changed, 175 insertions(+), 17 deletions(-) create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt index 5401be707..c9950fac5 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt @@ -12,7 +12,7 @@ import kotlin.test.* class ListPolynomialTest { @Test fun test_Polynomial_Int_plus() { - RationalField.listPolynomial { + RationalField.listPolynomialSpace { assertEquals( ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + -3, @@ -52,7 +52,7 @@ class ListPolynomialTest { } @Test fun test_Polynomial_Int_minus() { - RationalField.listPolynomial { + RationalField.listPolynomialSpace { assertEquals( ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - -3, @@ -92,7 +92,7 @@ class ListPolynomialTest { } @Test fun test_Polynomial_Int_times() { - IntModuloRing(35).listPolynomial { + IntModuloRing(35).listPolynomialSpace { assertEquals( ListPolynomial(34, 2, 1, 20, 2), ListPolynomial(22, 26, 13, 15, 26) * 27, @@ -107,7 +107,7 @@ class ListPolynomialTest { } @Test fun test_Int_Polynomial_plus() { - RationalField.listPolynomial { + RationalField.listPolynomialSpace { assertEquals( ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), -3 + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)), @@ -147,7 +147,7 @@ class ListPolynomialTest { } @Test fun test_Int_Polynomial_minus() { - RationalField.listPolynomial { + RationalField.listPolynomialSpace { assertEquals( ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), 3 - ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), @@ -187,7 +187,7 @@ class ListPolynomialTest { } @Test fun test_Int_Polynomial_times() { - IntModuloRing(35).listPolynomial { + IntModuloRing(35).listPolynomialSpace { assertEquals( ListPolynomial(34, 2, 1, 20, 2), 27 * ListPolynomial(22, 26, 13, 15, 26), @@ -202,7 +202,7 @@ class ListPolynomialTest { } @Test fun test_Polynomial_Constant_plus() { - RationalField.listPolynomial { + RationalField.listPolynomialSpace { assertEquals( ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + Rational(-3), @@ -242,7 +242,7 @@ class ListPolynomialTest { } @Test fun test_Polynomial_Constant_minus() { - RationalField.listPolynomial { + RationalField.listPolynomialSpace { assertEquals( ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - Rational(-3), @@ -282,7 +282,7 @@ class ListPolynomialTest { } @Test fun test_Polynomial_Constant_times() { - IntModuloRing(35).listPolynomial { + IntModuloRing(35).listPolynomialSpace { assertEquals( ListPolynomial(34, 2, 1, 20, 2), ListPolynomial(22, 26, 13, 15, 26) * 27.asConstant(), @@ -297,7 +297,7 @@ class ListPolynomialTest { } @Test fun test_Constant_Polynomial_plus() { - RationalField.listPolynomial { + RationalField.listPolynomialSpace { assertEquals( ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), Rational(-3) + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)), @@ -337,7 +337,7 @@ class ListPolynomialTest { } @Test fun test_Constant_Polynomial_minus() { - RationalField.listPolynomial { + RationalField.listPolynomialSpace { assertEquals( ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), Rational(3) - ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), @@ -377,7 +377,7 @@ class ListPolynomialTest { } @Test fun test_Constant_Polynomial_times() { - IntModuloRing(35).listPolynomial { + IntModuloRing(35).listPolynomialSpace { assertEquals( ListPolynomial(34, 2, 1, 20, 2), 27 * ListPolynomial(22, 26, 13, 15, 26), @@ -392,7 +392,7 @@ class ListPolynomialTest { } @Test fun test_Polynomial_unaryMinus() { - RationalField.listPolynomial { + RationalField.listPolynomialSpace { assertEquals( ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), -ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)), @@ -407,7 +407,7 @@ class ListPolynomialTest { } @Test fun test_Polynomial_Polynomial_plus() { - RationalField.listPolynomial { + RationalField.listPolynomialSpace { // (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( ListPolynomial(Rational(-10, 63), Rational(37, 9), Rational(-29, 56)), @@ -440,7 +440,7 @@ class ListPolynomialTest { } @Test fun test_Polynomial_Polynomial_minus() { - RationalField.listPolynomial { + RationalField.listPolynomialSpace { // (5/9 - 8/9 x - 8/7 x^2) - (-5/7 + 5/1 x + 5/8 x^2) ?= 80/63 - 53/9 x - 99/56 x^2 assertEquals( ListPolynomial(Rational(80, 63), Rational(-53, 9), Rational(-99, 56)), @@ -473,7 +473,7 @@ class ListPolynomialTest { } @Test fun test_Polynomial_Polynomial_times() { - IntModuloRing(35).listPolynomial { + IntModuloRing(35).listPolynomialSpace { // (1 + x + x^2) * (1 - x + x^2) ?= 1 + x^2 + x^4 assertEquals( ListPolynomial(1, 0, 1, 0, 1), diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt new file mode 100644 index 000000000..36a0d8be5 --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt @@ -0,0 +1,140 @@ +/* + * 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.functions.ListPolynomial +import space.kscience.kmath.functions.ListPolynomialSpace +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.Ring + + +class IntModulo { + val residue: Int + val modulus: Int + + @PublishedApi + internal constructor(residue: Int, modulus: Int, toCheckInput: Boolean = true) { + if (toCheckInput) { + require(modulus != 0) { "modulus can not be zero" } + this.modulus = if (modulus < 0) -modulus else modulus + this.residue = residue.mod(modulus) + } else { + this.residue = residue + this.modulus = modulus + } + } + + constructor(residue: Int, modulus: Int) : this(residue, modulus, true) + + operator fun unaryPlus(): IntModulo = this + operator fun unaryMinus(): IntModulo = + IntModulo( + if (residue == 0) 0 else modulus - residue, + modulus, + toCheckInput = false + ) + operator fun plus(other: IntModulo): IntModulo { + require(modulus == other.modulus) { "can not add two residue different modulo" } + return IntModulo( + (residue + other.residue) % modulus, + modulus, + toCheckInput = false + ) + } + operator fun plus(other: Int): IntModulo = + IntModulo( + (residue + other) % modulus, + modulus, + toCheckInput = false + ) + operator fun minus(other: IntModulo): IntModulo { + require(modulus == other.modulus) { "can not subtract two residue different modulo" } + return IntModulo( + (residue - other.residue) % modulus, + modulus, + toCheckInput = false + ) + } + operator fun minus(other: Int): IntModulo = + IntModulo( + (residue - other) % modulus, + modulus, + toCheckInput = false + ) + operator fun times(other: IntModulo): IntModulo { + require(modulus == other.modulus) { "can not multiply two residue different modulo" } + return IntModulo( + (residue * other.residue) % modulus, + modulus, + toCheckInput = false + ) + } + operator fun times(other: Int): IntModulo = + IntModulo( + (residue * other) % modulus, + modulus, + toCheckInput = false + ) + operator fun div(other: IntModulo): IntModulo { + require(modulus == other.modulus) { "can not divide two residue different modulo" } + val (reciprocalCandidate, gcdOfOtherResidueAndModulus) = bezoutIdentityWithGCD(other.residue, modulus) + require(gcdOfOtherResidueAndModulus == 1) { "can not divide to residue that has non-trivial GCD with modulo" } + return IntModulo( + (residue * reciprocalCandidate) % modulus, + modulus, + toCheckInput = false + ) + } + operator fun div(other: Int): IntModulo { + val (reciprocalCandidate, gcdOfOtherResidueAndModulus) = bezoutIdentityWithGCD(other, modulus) + require(gcdOfOtherResidueAndModulus == 1) { "can not divide to residue that has non-trivial GCD with modulo" } + return IntModulo( + (residue * reciprocalCandidate) % modulus, + modulus, + toCheckInput = false + ) + } + override fun equals(other: Any?): Boolean = + when (other) { + is IntModulo -> residue == other.residue && modulus == other.modulus + else -> false + } + + override fun hashCode(): Int = residue.hashCode() + + override fun toString(): String = "$residue mod $modulus" +} + +@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") +@OptIn(UnstableKMathAPI::class) +class IntModuloRing : Ring { + + val modulus: Int + + constructor(modulus: Int) { + require(modulus != 0) { "modulus can not be zero" } + this.modulus = if (modulus < 0) -modulus else modulus + } + + override inline val zero: IntModulo get() = IntModulo(0, modulus, toCheckInput = false) + override inline val one: IntModulo get() = IntModulo(1, modulus, toCheckInput = false) + + fun number(arg: Int) = IntModulo(arg, modulus, toCheckInput = false) + + override inline fun add(left: IntModulo, right: IntModulo): IntModulo = left + right + override inline fun multiply(left: IntModulo, right: IntModulo): IntModulo = left * right + + override inline fun IntModulo.unaryMinus(): IntModulo = -this + override inline fun IntModulo.plus(arg: IntModulo): IntModulo = this + arg + override inline fun IntModulo.minus(arg: IntModulo): IntModulo = this - arg + override inline fun IntModulo.times(arg: IntModulo): IntModulo = this * arg + inline fun IntModulo.div(arg: IntModulo): IntModulo = this / arg +} + +fun ListPolynomialSpace.ListPolynomial(vararg coefs: Int): ListPolynomial = + ListPolynomial(coefs.map { IntModulo(it, ring.modulus) }) +fun IntModuloRing.ListPolynomial(vararg coefs: Int): ListPolynomial = + ListPolynomial(coefs.map { IntModulo(it, modulus) }) \ 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 index 873162a1b..ed41b9245 100644 --- 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 @@ -8,4 +8,22 @@ package space.kscience.kmath.test.misc import kotlin.math.abs -tailrec fun gcd(a: Long, b: Long): Long = if (a == 0L) abs(b) else gcd(b % a, a) \ No newline at end of file +data class BezoutIdentityWithGCD(val first: T, val second: T, val gcd: T) + +tailrec fun gcd(a: Long, b: Long): Long = if (a == 0L) abs(b) else gcd(b % a, a) + +fun bezoutIdentityWithGCD(a: Int, b: Int): BezoutIdentityWithGCD = + when { + a < 0 && b < 0 -> with(bezoutIdentityWithGCDInternalLogic(-a, -b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(-first, -second, gcd) } + a < 0 -> with(bezoutIdentityWithGCDInternalLogic(-a, b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(-first, second, gcd) } + b < 0 -> with(bezoutIdentityWithGCDInternalLogic(a, -b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(first, -second, gcd) } + else -> bezoutIdentityWithGCDInternalLogic(a, b, 1, 0, 0, 1) + } + +internal tailrec fun bezoutIdentityWithGCDInternalLogic(a: Int, b: Int, m1: Int, m2: Int, m3: Int, m4: Int): BezoutIdentityWithGCD = + if (b == 0) BezoutIdentityWithGCD(m1, m3, a) + else { + val quotient = a / b + val reminder = a % b + bezoutIdentityWithGCDInternalLogic(b, reminder, m2, m1 - quotient * m2, m4, m3 - quotient * m4) + } \ No newline at end of file -- 2.34.1 From 94fd24d8524140c945412b980df8e5252a10e811 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sun, 12 Jun 2022 23:49:44 +0300 Subject: [PATCH 069/123] Fixed some tests and docstrings. Removed `zero` and `one` overridings because overrided fields are already lazily initialized. --- .../kmath/functions/ListRationalFunction.kt | 9 ----- .../kmath/functions/RationalFunction.kt | 34 +++++++++++++++---- .../kscience/kmath/test/misc/IntModulo.kt | 2 -- 3 files changed, 27 insertions(+), 18 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt index 45ea99fb0..f3e352bcd 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt @@ -50,15 +50,6 @@ public class ListRationalFunctionSpace> ( override fun constructRationalFunction(numerator: ListPolynomial, denominator: ListPolynomial): ListRationalFunction = ListRationalFunction(numerator, denominator) - /** - * Instance of zero rational function (zero of the rational functions ring). - */ - public override val zero: ListRationalFunction = ListRationalFunction(polynomialZero, polynomialOne) - /** - * Instance of unit polynomial (unit of the rational functions ring). - */ - public override val one: ListRationalFunction = ListRationalFunction(polynomialOne, polynomialOne) - // TODO: When context receivers will be ready move all of this substitutions and invocations to utilities with // [ListPolynomialSpace] as a context receiver /** diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt index 4ce6c7c26..01911f980 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt @@ -834,7 +834,12 @@ public abstract class PolynomialSpaceOfFractions< numerator * other, denominator ) - + /** + * Returns quotient of the rational function and the integer represented as a rational function. + * + * The operation is equivalent to creating a new rational function by preserving numerator of [this] and + * multiplication denominator of [this] to [other]. + */ public override operator fun R.div(other: Int): R = constructRationalFunction( numerator, @@ -871,7 +876,12 @@ public abstract class PolynomialSpaceOfFractions< this * other.numerator, other.denominator ) - + /** + * Returns quotient of the integer represented as a rational function and the rational function. + * + * The operation is equivalent to creating a new rational function which numerator is [this] times denominator of + * [other] and which denominator is [other]'s numerator. + */ public override operator fun Int.div(other: R): R = constructRationalFunction( this * other.denominator, @@ -912,7 +922,9 @@ public abstract class PolynomialSpaceOfFractions< this * other.numerator, other.denominator ) - + /** + * Returns quotient of the constant represented as a polynomial and the rational function. + */ public override operator fun C.div(other: R): R = constructRationalFunction( this * other.denominator, @@ -943,7 +955,9 @@ public abstract class PolynomialSpaceOfFractions< numerator * other, denominator ) - + /** + * Returns quotient of the rational function and the constant represented as a rational function. + */ public override operator fun R.div(other: C): R = constructRationalFunction( numerator, @@ -979,7 +993,9 @@ public abstract class PolynomialSpaceOfFractions< this * other.numerator, other.denominator ) - + /** + * Returns quotient of the polynomial represented as a polynomial and the rational function. + */ public override operator fun P.div(other: R): R = constructRationalFunction( this * other.denominator, @@ -1010,7 +1026,9 @@ public abstract class PolynomialSpaceOfFractions< numerator * other, denominator ) - + /** + * Returns quotient of the rational function and the polynomial represented as a rational function. + */ public override operator fun R.div(other: P): R = constructRationalFunction( numerator, @@ -1050,7 +1068,9 @@ public abstract class PolynomialSpaceOfFractions< numerator * other.numerator, denominator * other.denominator ) - + /** + * Returns quotient of the rational functions. + */ public override operator fun R.div(other: R): R = constructRationalFunction( numerator * other.denominator, diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt index 36a0d8be5..89764db46 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt @@ -7,7 +7,6 @@ package space.kscience.kmath.test.misc import space.kscience.kmath.functions.ListPolynomial import space.kscience.kmath.functions.ListPolynomialSpace -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.Ring @@ -109,7 +108,6 @@ class IntModulo { } @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") -@OptIn(UnstableKMathAPI::class) class IntModuloRing : Ring { val modulus: Int -- 2.34.1 From ab9bba22022187b0437e9fc085b16cd8cbf232fe Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Mon, 13 Jun 2022 00:16:22 +0300 Subject: [PATCH 070/123] Put suddenly disappeared files back. --- .../kmath/functions/listConstructors.kt | 65 +++++++++ .../kscience/kmath/test/misc/Rational.kt | 135 ++++++++++++++++++ 2 files changed, 200 insertions(+) create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt new file mode 100644 index 000000000..fc55ba310 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt @@ -0,0 +1,65 @@ +/* + * 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. + */ + +/* + * 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.functions + +import space.kscience.kmath.operations.Ring + + +/** + * Returns a [ListPolynomial] instance with given [coefficients]. The collection of coefficients will be reversed if + * [reverse] parameter is true. + */ +@Suppress("FunctionName") +public fun ListPolynomial(coefficients: List, reverse: Boolean = false): ListPolynomial = + ListPolynomial(with(coefficients) { if (reverse) reversed() else this }) + +/** + * Returns a [ListPolynomial] instance with given [coefficients]. The collection of coefficients will be reversed if + * [reverse] parameter is true. + */ +@Suppress("FunctionName") +public fun ListPolynomial(vararg coefficients: C, reverse: Boolean = false): ListPolynomial = + ListPolynomial(with(coefficients) { if (reverse) reversed() else toList() }) + +public fun C.asListPolynomial() : ListPolynomial = ListPolynomial(listOf(this)) + + +// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available + +@Suppress("FunctionName") +public fun ListRationalFunction(numeratorCoefficients: List, denominatorCoefficients: List, reverse: Boolean = false): ListRationalFunction = + ListRationalFunction( + ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), + ListPolynomial( with(denominatorCoefficients) { if (reverse) reversed() else this } ) + ) +@Suppress("FunctionName") +public fun > ListRationalFunctionSpace.ListRationalFunction(numerator: ListPolynomial): ListRationalFunction = + ListRationalFunction(numerator, polynomialOne) +@Suppress("FunctionName") +public fun > A.ListRationalFunction(numerator: ListPolynomial): ListRationalFunction = + ListRationalFunction(numerator, ListPolynomial(listOf(one))) +@Suppress("FunctionName") +public fun > ListRationalFunctionSpace.ListRationalFunction(numeratorCoefficients: List, reverse: Boolean = false): ListRationalFunction = + ListRationalFunction( + ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), + polynomialOne + ) +@Suppress("FunctionName") +public fun > A.ListRationalFunction(numeratorCoefficients: List, reverse: Boolean = false): ListRationalFunction = + ListRationalFunction( + ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), + ListPolynomial(listOf(one)) + ) + +//context(A) +//public fun > C.asListRationalFunction() : ListRationalFunction = ListRationalFunction(asListPolynomial()) +//context(ListRationalFunctionSpace) +//public fun > C.asListRationalFunction() : ListRationalFunction = ListRationalFunction(asListPolynomial()) \ No newline at end of file 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..72bb5942c --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt @@ -0,0 +1,135 @@ +/* + * 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.Field +import space.kscience.kmath.operations.NumbersAddOps + +class Rational { + companion object { + val ZERO: Rational = Rational(0L) + val ONE: Rational = Rational(1L) + } + + val numerator: Long + val denominator: Long + + internal constructor(numerator: Long, denominator: Long, toCheckInput: Boolean = true) { + if (toCheckInput) { + if (denominator == 0L) throw ArithmeticException("/ by zero") + + val greatestCommonDivider = gcd(numerator, denominator).let { if (denominator < 0L) -it else it } + + this.numerator = numerator / greatestCommonDivider + this.denominator = denominator / greatestCommonDivider + } else { + this.numerator = numerator + this.denominator = denominator + } + } + + constructor(numerator: Int, denominator: Int) : this(numerator.toLong(), denominator.toLong(), true) + constructor(numerator: Int, denominator: Long) : this(numerator.toLong(), denominator, true) + constructor(numerator: Long, denominator: Int) : this(numerator, denominator.toLong(), true) + constructor(numerator: Long, denominator: Long) : this(numerator, denominator, true) + constructor(numerator: Int) : this(numerator.toLong(), 1L, false) + constructor(numerator: Long) : this(numerator, 1L, false) + + operator fun unaryPlus(): Rational = this + operator fun unaryMinus(): Rational = Rational(-this.numerator, this.denominator) + operator fun plus(other: Rational): Rational = + Rational( + numerator * other.denominator + denominator * other.numerator, + denominator * other.denominator + ) + operator fun plus(other: Int): Rational = + Rational( + numerator + denominator * other.toLong(), + denominator + ) + operator fun plus(other: Long): Rational = + Rational( + numerator + denominator * other, + denominator + ) + operator fun minus(other: Rational): Rational = + Rational( + numerator * other.denominator - denominator * other.numerator, + denominator * other.denominator + ) + operator fun minus(other: Int): Rational = + Rational( + numerator - denominator * other.toLong(), + denominator + ) + operator fun minus(other: Long): Rational = + Rational( + numerator - denominator * other, + denominator + ) + operator fun times(other: Rational): Rational = + Rational( + numerator * other.numerator, + denominator * other.denominator + ) + operator fun times(other: Int): Rational = + Rational( + numerator * other.toLong(), + denominator + ) + operator fun times(other: Long): Rational = + Rational( + numerator * other, + denominator + ) + operator fun div(other: Rational): Rational = + Rational( + numerator * other.denominator, + denominator * other.numerator + ) + operator fun div(other: Int): Rational = + Rational( + numerator, + denominator * other.toLong() + ) + operator fun div(other: Long): Rational = + Rational( + numerator, + denominator * other + ) + override fun equals(other: Any?): Boolean = + when (other) { + is Rational -> numerator == other.numerator && denominator == other.denominator + is Int -> numerator == other && denominator == 1L + is Long -> numerator == other && denominator == 1L + else -> false + } + + override fun hashCode(): Int = 31 * numerator.hashCode() + denominator.hashCode() + + override fun toString(): String = if (denominator == 1L) "$numerator" else "$numerator/$denominator" +} + +@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") +@OptIn(UnstableKMathAPI::class) +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 -- 2.34.1 From dbb48a2a9f3ecabc0eb0aeb7e7c72d589aba0c4f Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Mon, 13 Jun 2022 01:41:04 +0300 Subject: [PATCH 071/123] Added docstrings to ListPolynomial and ListRationalFunction fabric functions. --- .../kmath/functions/listConstructors.kt | 56 +++++++++++++++---- 1 file changed, 44 insertions(+), 12 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt index fc55ba310..35c736914 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt @@ -14,52 +14,84 @@ import space.kscience.kmath.operations.Ring /** - * Returns a [ListPolynomial] instance with given [coefficients]. The collection of coefficients will be reversed if - * [reverse] parameter is true. + * Constructs a [ListPolynomial] instance with provided [coefficients]. The collection of coefficients will be reversed + * if [reverse] parameter is true. */ @Suppress("FunctionName") public fun ListPolynomial(coefficients: List, reverse: Boolean = false): ListPolynomial = ListPolynomial(with(coefficients) { if (reverse) reversed() else this }) /** - * Returns a [ListPolynomial] instance with given [coefficients]. The collection of coefficients will be reversed if - * [reverse] parameter is true. + * Constructs a [ListPolynomial] instance with provided [coefficients]. The collection of coefficients will be reversed + * if [reverse] parameter is true. */ @Suppress("FunctionName") public fun ListPolynomial(vararg coefficients: C, reverse: Boolean = false): ListPolynomial = ListPolynomial(with(coefficients) { if (reverse) reversed() else toList() }) +/** + * Represents [this] constant as a [ListPolynomial]. + */ public fun C.asListPolynomial() : ListPolynomial = ListPolynomial(listOf(this)) // Waiting for context receivers :( FIXME: Replace with context receivers when they will be available +/** + * Constructs [ListRationalFunction] instance with numerator and denominator constructed with provided + * [numeratorCoefficients] and [denominatorCoefficients]. The both collections of coefficients will be reversed if + * [reverse] parameter is true. + */ @Suppress("FunctionName") public fun ListRationalFunction(numeratorCoefficients: List, denominatorCoefficients: List, reverse: Boolean = false): ListRationalFunction = ListRationalFunction( ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), ListPolynomial( with(denominatorCoefficients) { if (reverse) reversed() else this } ) ) -@Suppress("FunctionName") -public fun > ListRationalFunctionSpace.ListRationalFunction(numerator: ListPolynomial): ListRationalFunction = - ListRationalFunction(numerator, polynomialOne) +/** + * Constructs [ListRationalFunction] instance with provided [numerator] and unit denominator. + */ @Suppress("FunctionName") public fun > A.ListRationalFunction(numerator: ListPolynomial): ListRationalFunction = ListRationalFunction(numerator, ListPolynomial(listOf(one))) +/** + * Constructs [ListRationalFunction] instance with provided [numerator] and unit denominator. + */ @Suppress("FunctionName") -public fun > ListRationalFunctionSpace.ListRationalFunction(numeratorCoefficients: List, reverse: Boolean = false): ListRationalFunction = - ListRationalFunction( - ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), - polynomialOne - ) +public fun > ListRationalFunctionSpace.ListRationalFunction(numerator: ListPolynomial): ListRationalFunction = + ListRationalFunction(numerator, polynomialOne) +/** + * Constructs [ListRationalFunction] instance with numerator constructed with provided [numeratorCoefficients] and unit + * denominator. The collection of numerator coefficients will be reversed if [reverse] parameter is true. + */ @Suppress("FunctionName") public fun > A.ListRationalFunction(numeratorCoefficients: List, reverse: Boolean = false): ListRationalFunction = ListRationalFunction( ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), ListPolynomial(listOf(one)) ) +/** + * Constructs [ListRationalFunction] instance with numerator constructed with provided [numeratorCoefficients] and unit + * denominator. The collection of numerator coefficients will be reversed if [reverse] parameter is true. + */ +@Suppress("FunctionName") +public fun > ListRationalFunctionSpace.ListRationalFunction(numeratorCoefficients: List, reverse: Boolean = false): ListRationalFunction = + ListRationalFunction( + ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), + polynomialOne + ) +/** + * Represents [this] constant as a rational function. + */ // FIXME: When context receivers will be ready, delete this function and uncomment the following two +public fun > C.asListRationalFunction(ring: A) : ListRationalFunction = ring.ListRationalFunction(asListPolynomial()) +///** +// * Represents [this] constant as a rational function. +// */ //context(A) //public fun > C.asListRationalFunction() : ListRationalFunction = ListRationalFunction(asListPolynomial()) +///** +// * Represents [this] constant as a rational function. +// */ //context(ListRationalFunctionSpace) //public fun > C.asListRationalFunction() : ListRationalFunction = ListRationalFunction(asListPolynomial()) \ No newline at end of file -- 2.34.1 From 37ad48e820cde271ba93d1249b84b0abfd033f21 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Mon, 13 Jun 2022 02:06:15 +0300 Subject: [PATCH 072/123] Sift # 3. Filtered last sift and usages of [ListPolynomial]s. --- .../kmath/functions/LabeledPolynomial.kt | 539 ------------------ .../functions/LabeledRationalFunction.kt | 139 ----- .../kmath/functions/ListPolynomial.kt | 80 ++- .../kmath/functions/ListRationalFunction.kt | 158 +++-- .../kmath/functions/NumberedPolynomial.kt | 389 ------------- .../functions/NumberedRationalFunction.kt | 188 ------ .../kscience/kmath/functions/Polynomial.kt | 152 ++++- .../kmath/functions/RationalFunction.kt | 511 ++++++++++++----- .../kmath/functions/labeledConstructors.kt | 203 ------- .../kmath/functions/labeledPolynomialUtil.kt | 495 ---------------- .../functions/labeledRationalFunctionUtil.kt | 33 -- .../kmath/functions/listConstructors.kt | 61 +- .../kmath/functions/listPolynomialUtil.kt | 233 -------- .../kscience/kmath/functions/listUtil.kt | 268 +++++++++ ...alFunctionUtil.kt => listUtilOptimized.kt} | 129 +++-- .../space/kscience/kmath/functions/misc.kt | 13 + .../kmath/functions/numberedConstructors.kt | 195 ------- .../kmath/functions/numberedPolynomialUtil.kt | 528 ----------------- .../functions/numberedRationalFunctionUtil.kt | 33 -- .../kmath/functions/ListPolynomialTest.kt | 32 +- .../kmath/functions/ListPolynomialUtilTest.kt | 2 + .../kscience/kmath/test/misc/IntModulo.kt | 138 +++++ .../kscience/kmath/test/misc/Rational.kt | 135 +++++ .../space/kscience/kmath/test/misc/misc.kt | 29 + 24 files changed, 1378 insertions(+), 3305 deletions(-) delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listPolynomialUtil.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt rename kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/{listRationalFunctionUtil.kt => listUtilOptimized.kt} (72%) create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt deleted file mode 100644 index b904f7331..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt +++ /dev/null @@ -1,539 +0,0 @@ -/* - * 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.functions - -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.ScaleOperations -import kotlin.math.max - - -/** - * Represents multivariate polynomials with labeled variables. - * - * @param C Ring in which the polynomial is considered. - */ -public data class LabeledPolynomial -internal constructor( - /** - * Map that collects coefficients of the polynomial. Every non-zero monomial - * `a x_1^{d_1} ... x_n^{d_n}` is represented as pair "key-value" in the map, where value is coefficients `a` and - * key is map that associates variables in the monomial with multiplicity of them occurring in the monomial. - * For example polynomial - * ``` - * 5 a^2 c^3 - 6 b + 0 b c - * ``` - * has coefficients represented as - * ``` - * mapOf( - * mapOf( - * a to 2, - * c to 3 - * ) to 5, - * mapOf( - * b to 1 - * ) to (-6) - * ) - * ``` - * where `a`, `b` and `c` are corresponding [Symbol] objects. - */ - public val coefficients: Map, C> -) : Polynomial { - override fun toString(): String = "LabeledPolynomial$coefficients" -} - -/** - * Space of polynomials. - * - * @param C the type of operated polynomials. - * @param A the intersection of [Ring] of [C] and [ScaleOperations] of [C]. - * @param ring the [A] instance. - */ -public class LabeledPolynomialSpace>( - public override val ring: A, -) : MultivariatePolynomialSpace>, PolynomialSpaceOverRing, A> { - public override operator fun Symbol.plus(other: Int): LabeledPolynomial = - if (other == 0) LabeledPolynomial(mapOf( - mapOf(this@plus to 1U) to constantOne, - )) - else LabeledPolynomial(mapOf( - mapOf(this@plus to 1U) to constantOne, - emptyMap() to constantOne * other, - )) - public override operator fun Symbol.minus(other: Int): LabeledPolynomial = - if (other == 0) LabeledPolynomial(mapOf( - mapOf(this@minus to 1U) to -constantOne, - )) - else LabeledPolynomial(mapOf( - mapOf(this@minus to 1U) to -constantOne, - emptyMap() to constantOne * other, - )) - public override operator fun Symbol.times(other: Int): LabeledPolynomial = - if (other == 0) zero - else LabeledPolynomial(mapOf( - mapOf(this to 1U) to constantOne * other, - )) - - public override operator fun Int.plus(other: Symbol): LabeledPolynomial = - if (this == 0) LabeledPolynomial(mapOf( - mapOf(other to 1U) to constantOne, - )) - else LabeledPolynomial(mapOf( - mapOf(other to 1U) to constantOne, - emptyMap() to constantOne * this@plus, - )) - public override operator fun Int.minus(other: Symbol): LabeledPolynomial = - if (this == 0) LabeledPolynomial(mapOf( - mapOf(other to 1U) to -constantOne, - )) - else LabeledPolynomial(mapOf( - mapOf(other to 1U) to -constantOne, - emptyMap() to constantOne * this@minus, - )) - public override operator fun Int.times(other: Symbol): LabeledPolynomial = - if (this == 0) zero - else LabeledPolynomial(mapOf( - mapOf(other to 1U) to constantOne * this@times, - )) - - /** - * Returns sum of the polynomial and the integer represented as polynomial. - * - * The operation is equivalent to adding [other] copies of unit polynomial to [this]. - */ - public override operator fun LabeledPolynomial.plus(other: Int): LabeledPolynomial = - if (other == 0) this - else with(coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to other.asConstant())) - else LabeledPolynomial( - toMutableMap() - .apply { - val degs = emptyMap() - - this[degs] = getOrElse(degs) { constantZero } + other - } - ) - } - /** - * Returns difference between the polynomial and the integer represented as polynomial. - * - * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. - */ - public override operator fun LabeledPolynomial.minus(other: Int): LabeledPolynomial = - if (other == 0) this - else with(coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to (-other).asConstant())) - else LabeledPolynomial( - toMutableMap() - .apply { - val degs = emptyMap() - - this[degs] = getOrElse(degs) { constantZero } - other - } - ) - } - /** - * Returns product of the polynomial and the integer represented as polynomial. - * - * The operation is equivalent to sum of [other] copies of [this]. - */ - public override operator fun LabeledPolynomial.times(other: Int): LabeledPolynomial = - if (other == 0) zero - else LabeledPolynomial( - coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this[degs]!! * other - } - ) - - /** - * Returns sum of the integer represented as polynomial and the polynomial. - * - * The operation is equivalent to adding [this] copies of unit polynomial to [other]. - */ - public override operator fun Int.plus(other: LabeledPolynomial): LabeledPolynomial = - if (this == 0) other - else with(other.coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to this@plus.asConstant())) - else LabeledPolynomial( - toMutableMap() - .apply { - val degs = emptyMap() - - this[degs] = this@plus + getOrElse(degs) { constantZero } - } - ) - } - /** - * Returns difference between the integer represented as polynomial and the polynomial. - * - * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. - */ - public override operator fun Int.minus(other: LabeledPolynomial): LabeledPolynomial = - if (this == 0) other - else with(other.coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to this@minus.asConstant())) - else LabeledPolynomial( - toMutableMap() - .apply { - val degs = emptyMap() - - this[degs] = this@minus - getOrElse(degs) { constantZero } - } - ) - } - /** - * Returns product of the integer represented as polynomial and the polynomial. - * - * The operation is equivalent to sum of [this] copies of [other]. - */ - public override operator fun Int.times(other: LabeledPolynomial): LabeledPolynomial = - if (this == 0) zero - else LabeledPolynomial( - other.coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this@times * this[degs]!! - } - ) - - /** - * Converts the integer [value] to polynomial. - */ - public override fun number(value: Int): LabeledPolynomial = number(constantNumber(value)) - - public override operator fun C.plus(other: Symbol): LabeledPolynomial = - LabeledPolynomial(mapOf( - mapOf(other to 1U) to constantOne, - emptyMap() to this@plus, - )) - public override operator fun C.minus(other: Symbol): LabeledPolynomial = - LabeledPolynomial(mapOf( - mapOf(other to 1U) to -constantOne, - emptyMap() to this@minus, - )) - public override operator fun C.times(other: Symbol): LabeledPolynomial = - LabeledPolynomial(mapOf( - mapOf(other to 1U) to this@times, - )) - - public override operator fun Symbol.plus(other: C): LabeledPolynomial = - LabeledPolynomial(mapOf( - mapOf(this@plus to 1U) to constantOne, - emptyMap() to other, - )) - public override operator fun Symbol.minus(other: C): LabeledPolynomial = - LabeledPolynomial(mapOf( - mapOf(this@minus to 1U) to -constantOne, - emptyMap() to other, - )) - public override operator fun Symbol.times(other: C): LabeledPolynomial = - LabeledPolynomial(mapOf( - mapOf(this@times to 1U) to other, - )) - - /** - * Returns sum of the constant represented as polynomial and the polynomial. - */ - override operator fun C.plus(other: LabeledPolynomial): LabeledPolynomial = - with(other.coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to this@plus)) - else LabeledPolynomial( - toMutableMap() - .apply { - val degs = emptyMap() - - this[degs] = this@plus + getOrElse(degs) { constantZero } - } - ) - } - /** - * Returns difference between the constant represented as polynomial and the polynomial. - */ - override operator fun C.minus(other: LabeledPolynomial): LabeledPolynomial = - with(other.coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to this@minus)) - else LabeledPolynomial( - toMutableMap() - .apply { - forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } - - val degs = emptyMap() - - this[degs] = this@minus - getOrElse(degs) { constantZero } - } - ) - } - /** - * Returns product of the constant represented as polynomial and the polynomial. - */ - override operator fun C.times(other: LabeledPolynomial): LabeledPolynomial = - LabeledPolynomial( - other.coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this@times * this[degs]!! - } - ) - - /** - * Returns sum of the constant represented as polynomial and the polynomial. - */ - override operator fun LabeledPolynomial.plus(other: C): LabeledPolynomial = - with(coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to other)) - else LabeledPolynomial( - toMutableMap() - .apply { - val degs = emptyMap() - - this[degs] = getOrElse(degs) { constantZero } + other - } - ) - } - /** - * Returns difference between the constant represented as polynomial and the polynomial. - */ - override operator fun LabeledPolynomial.minus(other: C): LabeledPolynomial = - with(coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to other)) - else LabeledPolynomial( - toMutableMap() - .apply { - forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } - - val degs = emptyMap() - - this[degs] = getOrElse(degs) { constantZero } - other - } - ) - } - /** - * Returns product of the constant represented as polynomial and the polynomial. - */ - override operator fun LabeledPolynomial.times(other: C): LabeledPolynomial = - LabeledPolynomial( - coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this[degs]!! * other - } - ) - - /** - * Converts the constant [value] to polynomial. - */ - public override fun number(value: C): LabeledPolynomial = - LabeledPolynomial(mapOf(emptyMap() to value)) - - public override operator fun Symbol.unaryPlus(): LabeledPolynomial = - LabeledPolynomial(mapOf( - mapOf(this to 1U) to constantOne, - )) - public override operator fun Symbol.unaryMinus(): LabeledPolynomial = - LabeledPolynomial(mapOf( - mapOf(this to 1U) to -constantOne, - )) - public override operator fun Symbol.plus(other: Symbol): LabeledPolynomial = - if (this == other) LabeledPolynomial(mapOf( - mapOf(this to 1U) to constantOne * 2 - )) - else LabeledPolynomial(mapOf( - mapOf(this to 1U) to constantOne, - mapOf(other to 1U) to constantOne, - )) - public override operator fun Symbol.minus(other: Symbol): LabeledPolynomial = - if (this == other) zero - else LabeledPolynomial(mapOf( - mapOf(this to 1U) to constantOne, - mapOf(other to 1U) to -constantOne, - )) - public override operator fun Symbol.times(other: Symbol): LabeledPolynomial = - if (this == other) LabeledPolynomial(mapOf( - mapOf(this to 2U) to constantOne - )) - else LabeledPolynomial(mapOf( - mapOf(this to 1U, other to 1U) to constantOne, - )) - - public override operator fun Symbol.plus(other: LabeledPolynomial): LabeledPolynomial = - with(other.coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(mapOf(this@plus to 1u) to constantOne)) - else LabeledPolynomial( - toMutableMap() - .apply { - val degs = mapOf(this@plus to 1U) - - this[degs] = constantOne + getOrElse(degs) { constantZero } - } - ) - } - public override operator fun Symbol.minus(other: LabeledPolynomial): LabeledPolynomial = - with(other.coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(mapOf(this@minus to 1u) to constantOne)) - else LabeledPolynomial( - toMutableMap() - .apply { - forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } - - val degs = mapOf(this@minus to 1U) - - this[degs] = constantOne - getOrElse(degs) { constantZero } - } - ) - } - public override operator fun Symbol.times(other: LabeledPolynomial): LabeledPolynomial = - LabeledPolynomial( - other.coefficients - .mapKeys { (degs, _) -> degs.toMutableMap().also{ it[this] = if (this in it) it[this]!! + 1U else 1U } } - ) - - public override operator fun LabeledPolynomial.plus(other: Symbol): LabeledPolynomial = - with(coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(mapOf(other to 1u) to constantOne)) - else LabeledPolynomial( - toMutableMap() - .apply { - val degs = mapOf(other to 1U) - - this[degs] = constantOne + getOrElse(degs) { constantZero } - } - ) - } - public override operator fun LabeledPolynomial.minus(other: Symbol): LabeledPolynomial = - with(coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(mapOf(other to 1u) to constantOne)) - else LabeledPolynomial( - toMutableMap() - .apply { - val degs = mapOf(other to 1U) - - this[degs] = constantOne - getOrElse(degs) { constantZero } - } - ) - } - public override operator fun LabeledPolynomial.times(other: Symbol): LabeledPolynomial = - LabeledPolynomial( - coefficients - .mapKeys { (degs, _) -> degs.toMutableMap().also{ it[other] = if (other in it) it[other]!! + 1U else 1U } } - ) - - /** - * Returns negation of the polynomial. - */ - override fun LabeledPolynomial.unaryMinus(): LabeledPolynomial = - LabeledPolynomial( - coefficients.mapValues { -it.value } - ) - /** - * Returns sum of the polynomials. - */ - override operator fun LabeledPolynomial.plus(other: LabeledPolynomial): LabeledPolynomial = - LabeledPolynomial( - buildMap(coefficients.size + other.coefficients.size) { - other.coefficients.mapValuesTo(this) { it.value } - other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! + value else value } - } - ) - /** - * Returns difference of the polynomials. - */ - override operator fun LabeledPolynomial.minus(other: LabeledPolynomial): LabeledPolynomial = - LabeledPolynomial( - buildMap(coefficients.size + other.coefficients.size) { - other.coefficients.mapValuesTo(this) { it.value } - other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! - value else -value } - } - ) - /** - * Returns product of the polynomials. - */ - override operator fun LabeledPolynomial.times(other: LabeledPolynomial): LabeledPolynomial = - LabeledPolynomial( - buildMap(coefficients.size * other.coefficients.size) { - for ((degs1, c1) in coefficients) for ((degs2, c2) in other.coefficients) { - val degs = degs1.toMutableMap() - degs2.mapValuesTo(degs) { (variable, deg) -> degs.getOrElse(variable) { 0u } + deg } - val c = c1 * c2 - this[degs] = if (degs in this) this[degs]!! + c else c - } - } - ) - - /** - * Instance of zero polynomial (zero of the polynomial ring). - */ - override val zero: LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to constantZero)) - /** - * Instance of unit polynomial (unit of the polynomial ring). - */ - override val one: LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to constantOne)) - - /** - * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is - * zero, degree is -1. - */ - override val LabeledPolynomial.degree: Int - get() = coefficients.entries.maxOfOrNull { (degs, c) -> degs.values.sum().toInt() } ?: -1 - /** - * Map that associates variables (that appear in the polynomial in positive exponents) with their most exponents - * in which they are appeared in the polynomial. - * - * As consequence all values in the map are positive integers. Also, if the polynomial is constant, the map is empty. - * And keys of the map is the same as in [variables]. - */ - public override val LabeledPolynomial.degrees: Map - get() = - buildMap { - coefficients.entries.forEach { (degs, _) -> - degs.mapValuesTo(this) { (variable, deg) -> - max(getOrElse(variable) { 0u }, deg) - } - } - } - /** - * Counts degree of the polynomial by the specified [variable]. - */ - public override fun LabeledPolynomial.degreeBy(variable: Symbol): UInt = - coefficients.entries.maxOfOrNull { (degs, _) -> degs.getOrElse(variable) { 0u } } ?: 0u - /** - * Counts degree of the polynomial by the specified [variables]. - */ - public override fun LabeledPolynomial.degreeBy(variables: Collection): UInt = - coefficients.entries.maxOfOrNull { (degs, _) -> degs.filterKeys { it in variables }.values.sum() } ?: 0u - /** - * Set of all variables that appear in the polynomial in positive exponents. - */ - public override val LabeledPolynomial.variables: Set - get() = - buildSet { - coefficients.entries.forEach { (degs, _) -> addAll(degs.keys) } - } - /** - * Count of all variables that appear in the polynomial in positive exponents. - */ - public override val LabeledPolynomial.countOfVariables: Int get() = variables.size - -// @Suppress("NOTHING_TO_INLINE") -// public inline fun LabeledPolynomial.substitute(argument: Map): LabeledPolynomial = this.substitute(ring, argument) -// @Suppress("NOTHING_TO_INLINE") -// @JvmName("substitutePolynomial") -// public inline fun LabeledPolynomial.substitute(argument: Map>): LabeledPolynomial = this.substitute(ring, argument) -// -// @Suppress("NOTHING_TO_INLINE") -// public inline fun LabeledPolynomial.asFunction(): (Map) -> LabeledPolynomial = { this.substitute(ring, it) } -// @Suppress("NOTHING_TO_INLINE") -// public inline fun LabeledPolynomial.asFunctionOnConstants(): (Map) -> LabeledPolynomial = { this.substitute(ring, it) } -// @Suppress("NOTHING_TO_INLINE") -// public inline fun LabeledPolynomial.asFunctionOnPolynomials(): (Map>) -> LabeledPolynomial = { this.substitute(ring, it) } -// -// @Suppress("NOTHING_TO_INLINE") -// public inline operator fun LabeledPolynomial.invoke(argument: Map): LabeledPolynomial = this.substitute(ring, argument) -// @Suppress("NOTHING_TO_INLINE") -// @JvmName("invokePolynomial") -// public inline operator fun LabeledPolynomial.invoke(argument: Map>): LabeledPolynomial = this.substitute(ring, argument) -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt deleted file mode 100644 index 76c6874f5..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt +++ /dev/null @@ -1,139 +0,0 @@ -/* - * 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.functions - -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.invoke - - -public class LabeledRationalFunction( - public override val numerator: LabeledPolynomial, - public override val denominator: LabeledPolynomial -) : RationalFunction> { - override fun toString(): String = "LabeledRationalFunction${numerator.coefficients}/${denominator.coefficients}" -} - -public class LabeledRationalFunctionSpace>( - public val ring: A, -) : - MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSpace< - C, - Symbol, - LabeledPolynomial, - LabeledRationalFunction, - LabeledPolynomialSpace, - >, - MultivariatePolynomialSpaceOfFractions< - C, - Symbol, - LabeledPolynomial, - LabeledRationalFunction, - >() { - - override val polynomialRing : LabeledPolynomialSpace = LabeledPolynomialSpace(ring) - override fun constructRationalFunction( - numerator: LabeledPolynomial, - denominator: LabeledPolynomial - ): LabeledRationalFunction = - LabeledRationalFunction(numerator, denominator) - - /** - * Instance of zero rational function (zero of the rational functions ring). - */ - public override val zero: LabeledRationalFunction = LabeledRationalFunction(polynomialZero, polynomialOne) - /** - * Instance of unit polynomial (unit of the rational functions ring). - */ - public override val one: LabeledRationalFunction = LabeledRationalFunction(polynomialOne, polynomialOne) - - // TODO: Разобрать - -// operator fun invoke(arg: Map): LabeledRationalFunction = -// LabeledRationalFunction( -// numerator(arg), -// denominator(arg) -// ) -// -// @JvmName("invokeLabeledPolynomial") -// operator fun invoke(arg: Map>): LabeledRationalFunction = -// LabeledRationalFunction( -// numerator(arg), -// denominator(arg) -// ) -// -// @JvmName("invokeLabeledRationalFunction") -// operator fun invoke(arg: Map>): LabeledRationalFunction { -// var num = numerator invokeRFTakeNumerator arg -// var den = denominator invokeRFTakeNumerator arg -// for (variable in variables) if (variable in arg) { -// val degreeDif = degrees[variable]!! -// if (degreeDif > 0) -// den = multiplyByPower(den, arg[variable]!!.denominator, degreeDif) -// else -// num = multiplyByPower(num, arg[variable]!!.denominator, -degreeDif) -// } -// return LabeledRationalFunction(num, den) -// } -// -// override fun toString(): String = toString(emptyMap()) -// -// fun toString(names: Map = emptyMap()): String = -// when (true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toString(names) -// else -> "${numerator.toStringWithBrackets(names)}/${denominator.toStringWithBrackets(names)}" -// } -// -// fun toString(namer: (Symbol) -> String): String = -// when (true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toString(namer) -// else -> "${numerator.toStringWithBrackets(namer)}/${denominator.toStringWithBrackets(namer)}" -// } -// -// fun toStringWithBrackets(names: Map = emptyMap()): String = -// when (true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toStringWithBrackets(names) -// else -> "(${numerator.toStringWithBrackets(names)}/${denominator.toStringWithBrackets(names)})" -// } -// -// fun toStringWithBrackets(namer: (Symbol) -> String): String = -// when (true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toStringWithBrackets(namer) -// else -> "(${numerator.toStringWithBrackets(namer)}/${denominator.toStringWithBrackets(namer)})" -// } -// -// fun toReversedString(names: Map = emptyMap()): String = -// when (true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedString(names) -// else -> "${numerator.toReversedStringWithBrackets(names)}/${denominator.toReversedStringWithBrackets(names)}" -// } -// -// fun toReversedString(namer: (Symbol) -> String): String = -// when (true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedString(namer) -// else -> "${numerator.toReversedStringWithBrackets(namer)}/${denominator.toReversedStringWithBrackets(namer)}" -// } -// -// fun toReversedStringWithBrackets(names: Map = emptyMap()): String = -// when (true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedStringWithBrackets(names) -// else -> "(${numerator.toReversedStringWithBrackets(names)}/${denominator.toReversedStringWithBrackets(names)})" -// } -// -// fun toReversedStringWithBrackets(namer: (Symbol) -> String): String = -// when (true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedStringWithBrackets(namer) -// else -> "(${numerator.toReversedStringWithBrackets(namer)}/${denominator.toReversedStringWithBrackets(namer)})" -// } -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt index 585da95ea..fce179fc8 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt @@ -8,23 +8,19 @@ package space.kscience.kmath.functions import space.kscience.kmath.operations.Ring import space.kscience.kmath.operations.ScaleOperations import space.kscience.kmath.operations.invoke -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract -import kotlin.experimental.ExperimentalTypeInference -import kotlin.jvm.JvmName import kotlin.math.max import kotlin.math.min /** - * Polynomial model without fixation on specific context they are applied to. + * Represents univariate polynomial that stores its coefficients in a [List]. * * @param coefficients constant is the leftmost coefficient. */ public data class ListPolynomial( /** - * List that collects coefficients of the polynomial. Every monomial `a x^d` is represented as a coefficients - * `a` placed into the list with index `d`. For example coefficients of polynomial `5 x^2 - 6` can be represented as + * List that contains coefficients of the polynomial. Every monomial `a x^d` is stored as a coefficient `a` placed + * into the list at index `d`. For example, coefficients of a polynomial `5 x^2 - 6` can be represented as * ``` * listOf( * -6, // -6 + @@ -42,26 +38,28 @@ public data class ListPolynomial( * 0, // 0 x^4 * ) * ``` - * It is recommended not to put extra zeros at end of the list (as for `0x^3` and `0x^4` in the example), but is not - * prohibited. + * It is not prohibited to put extra zeros at end of the list (as for `0x^3` and `0x^4` in the example). But the + * longer the coefficients list the worse performance of arithmetical operations performed on it. Thus, it is + * recommended not to put (or even to remove) extra (or useless) coefficients at the end of the coefficients list. */ public val coefficients: List ) : Polynomial { - override fun toString(): String = "Polynomial$coefficients" + override fun toString(): String = "ListPolynomial$coefficients" } /** - * Space of univariate polynomials constructed over ring. + * Arithmetic context for univariate polynomials with coefficients stored as a [List] constructed with the given [ring] + * of constants. * - * @param C the type of constants. Polynomials have them as a coefficients in their terms. - * @param A type of underlying ring of constants. It's [Ring] of [C]. + * @param C the type of constants. Polynomials have them a coefficients in their terms. + * @param A type of provided underlying ring of constants. It's [Ring] of [C]. * @param ring underlying ring of constants of type [A]. */ public open class ListPolynomialSpace>( public override val ring: A, ) : PolynomialSpaceOverRing, A> { /** - * Returns sum of the polynomial and the integer represented as polynomial. + * Returns sum of the polynomial and the integer represented as a polynomial. * * The operation is equivalent to adding [other] copies of unit polynomial to [this]. */ @@ -79,7 +77,7 @@ public open class ListPolynomialSpace>( } ) /** - * Returns difference between the polynomial and the integer represented as polynomial. + * Returns difference between the polynomial and the integer represented as a polynomial. * * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. */ @@ -97,7 +95,7 @@ public open class ListPolynomialSpace>( } ) /** - * Returns product of the polynomial and the integer represented as polynomial. + * Returns product of the polynomial and the integer represented as a polynomial. * * The operation is equivalent to sum of [other] copies of [this]. */ @@ -112,7 +110,7 @@ public open class ListPolynomialSpace>( ) /** - * Returns sum of the integer represented as polynomial and the polynomial. + * Returns sum of the integer represented as a polynomial and the polynomial. * * The operation is equivalent to adding [this] copies of unit polynomial to [other]. */ @@ -130,7 +128,7 @@ public open class ListPolynomialSpace>( } ) /** - * Returns difference between the integer represented as polynomial and the polynomial. + * Returns difference between the integer represented as a polynomial and the polynomial. * * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. */ @@ -150,7 +148,7 @@ public open class ListPolynomialSpace>( } ) /** - * Returns product of the integer represented as polynomial and the polynomial. + * Returns product of the integer represented as a polynomial and the polynomial. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -170,7 +168,7 @@ public open class ListPolynomialSpace>( public override fun number(value: Int): ListPolynomial = number(constantNumber(value)) /** - * Returns sum of the constant represented as polynomial and the polynomial. + * Returns sum of the constant represented as a polynomial and the polynomial. */ public override operator fun C.plus(other: ListPolynomial): ListPolynomial = with(other.coefficients) { @@ -186,7 +184,7 @@ public open class ListPolynomialSpace>( ) } /** - * Returns difference between the constant represented as polynomial and the polynomial. + * Returns difference between the constant represented as a polynomial and the polynomial. */ public override operator fun C.minus(other: ListPolynomial): ListPolynomial = with(other.coefficients) { @@ -204,7 +202,7 @@ public open class ListPolynomialSpace>( ) } /** - * Returns product of the constant represented as polynomial and the polynomial. + * Returns product of the constant represented as a polynomial and the polynomial. */ public override operator fun C.times(other: ListPolynomial): ListPolynomial = ListPolynomial( @@ -216,7 +214,7 @@ public open class ListPolynomialSpace>( ) /** - * Returns sum of the constant represented as polynomial and the polynomial. + * Returns sum of the constant represented as a polynomial and the polynomial. */ public override operator fun ListPolynomial.plus(other: C): ListPolynomial = with(coefficients) { @@ -232,7 +230,7 @@ public open class ListPolynomialSpace>( ) } /** - * Returns difference between the constant represented as polynomial and the polynomial. + * Returns difference between the constant represented as a polynomial and the polynomial. */ public override operator fun ListPolynomial.minus(other: C): ListPolynomial = with(coefficients) { @@ -248,7 +246,7 @@ public open class ListPolynomialSpace>( ) } /** - * Returns product of the constant represented as polynomial and the polynomial. + * Returns product of the constant represented as a polynomial and the polynomial. */ public override operator fun ListPolynomial.times(other: C): ListPolynomial = ListPolynomial( @@ -262,7 +260,7 @@ public open class ListPolynomialSpace>( /** * Converts the constant [value] to polynomial. */ - public override fun number(value: C): ListPolynomial = ListPolynomial(value) + public override fun number(value: C): ListPolynomial = ListPolynomial(listOf(value)) /** * Returns negation of the polynomial. @@ -321,9 +319,9 @@ public open class ListPolynomialSpace>( */ override val zero: ListPolynomial = ListPolynomial(emptyList()) /** - * Instance of unit constant (unit of the underlying ring). + * Instance of unit polynomial (unit of the polynomial ring). */ - override val one: ListPolynomial = ListPolynomial(listOf(constantOne)) + override val one: ListPolynomial by lazy { ListPolynomial(listOf(constantOne)) } /** * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is @@ -331,23 +329,43 @@ public open class ListPolynomialSpace>( */ public override val ListPolynomial.degree: Int get() = coefficients.lastIndex + // TODO: When context receivers will be ready move all of this substitutions and invocations to utilities with + // [ListPolynomialSpace] as a context receiver + /** + * Evaluates value of [this] polynomial on provided argument. + */ @Suppress("NOTHING_TO_INLINE") public inline fun ListPolynomial.substitute(argument: C): C = this.substitute(ring, argument) + /** + * Substitutes provided polynomial [argument] into [this] polynomial. + */ @Suppress("NOTHING_TO_INLINE") public inline fun ListPolynomial.substitute(argument: ListPolynomial): ListPolynomial = this.substitute(ring, argument) + /** + * Represent [this] polynomial as a regular context-less function. + */ @Suppress("NOTHING_TO_INLINE") public inline fun ListPolynomial.asFunction(): (C) -> C = { this.substitute(ring, it) } + /** + * Represent [this] polynomial as a regular context-less function. + */ @Suppress("NOTHING_TO_INLINE") - public inline fun ListPolynomial.asFunctionOnConstants(): (C) -> C = { this.substitute(ring, it) } + public inline fun ListPolynomial.asFunctionOfConstant(): (C) -> C = { this.substitute(ring, it) } + /** + * Represent [this] polynomial as a regular context-less function. + */ @Suppress("NOTHING_TO_INLINE") - public inline fun ListPolynomial.asFunctionOnPolynomials(): (ListPolynomial) -> ListPolynomial = { this.substitute(ring, it) } + public inline fun ListPolynomial.asFunctionOfPolynomial(): (ListPolynomial) -> ListPolynomial = { this.substitute(ring, it) } /** - * Evaluates the polynomial for the given value [argument]. + * Evaluates value of [this] polynomial on provided [argument]. */ @Suppress("NOTHING_TO_INLINE") public inline operator fun ListPolynomial.invoke(argument: C): C = this.substitute(ring, argument) + /** + * Evaluates value of [this] polynomial on provided [argument]. + */ @Suppress("NOTHING_TO_INLINE") public inline operator fun ListPolynomial.invoke(argument: ListPolynomial): ListPolynomial = this.substitute(ring, argument) } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt index 7b6c23ac3..f3e352bcd 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt @@ -8,13 +8,23 @@ package space.kscience.kmath.functions import space.kscience.kmath.operations.Ring +/** + * Represents rational function that stores its numerator and denominator as [ListPolynomial]s. + */ public data class ListRationalFunction( public override val numerator: ListPolynomial, public override val denominator: ListPolynomial ) : RationalFunction> { - override fun toString(): String = "RationalFunction${numerator.coefficients}/${denominator.coefficients}" + override fun toString(): String = "ListRationalFunction${numerator.coefficients}/${denominator.coefficients}" } +/** + * Arithmetic context for univariate rational functions with numerator and denominator represented as [ListPolynomial]s. + * + * @param C the type of constants. Polynomials have them a coefficients in their terms. + * @param A type of provided underlying ring of constants. It's [Ring] of [C]. + * @param ring underlying ring of constants of type [A]. + */ public class ListRationalFunctionSpace> ( public val ring: A, ) : @@ -30,76 +40,98 @@ public class ListRationalFunctionSpace> ( ListRationalFunction, >() { + /** + * Underlying polynomial ring. Its polynomial operations are inherited by local polynomial operations. + */ override val polynomialRing : ListPolynomialSpace = ListPolynomialSpace(ring) + /** + * Constructor of [ListRationalFunction] from numerator and denominator [ListPolynomial]. + */ override fun constructRationalFunction(numerator: ListPolynomial, denominator: ListPolynomial): ListRationalFunction = ListRationalFunction(numerator, denominator) + // TODO: When context receivers will be ready move all of this substitutions and invocations to utilities with + // [ListPolynomialSpace] as a context receiver /** - * Instance of zero rational function (zero of the rational functions ring). + * Evaluates value of [this] polynomial on provided argument. */ - public override val zero: ListRationalFunction = ListRationalFunction(polynomialZero, polynomialOne) + @Suppress("NOTHING_TO_INLINE") + public inline fun ListPolynomial.substitute(argument: C): C = this.substitute(ring, argument) /** - * Instance of unit polynomial (unit of the rational functions ring). + * Substitutes provided polynomial [argument] into [this] polynomial. */ - public override val one: ListRationalFunction = ListRationalFunction(polynomialOne, polynomialOne) + @Suppress("NOTHING_TO_INLINE") + public inline fun ListPolynomial.substitute(argument: ListPolynomial): ListPolynomial = this.substitute(ring, argument) + /** + * Substitutes provided rational function [argument] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun ListPolynomial.substitute(argument: ListRationalFunction): ListRationalFunction = this.substitute(ring, argument) + /** + * Substitutes provided polynomial [argument] into [this] rational function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun ListRationalFunction.substitute(argument: ListPolynomial): ListRationalFunction = this.substitute(ring, argument) + /** + * Substitutes provided rational function [argument] into [this] rational function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun ListRationalFunction.substitute(argument: ListRationalFunction): ListRationalFunction = this.substitute(ring, argument) - // TODO: Разобрать + /** + * Represent [this] polynomial as a regular context-less function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun ListPolynomial.asFunction(): (C) -> C = { this.substitute(ring, it) } + /** + * Represent [this] polynomial as a regular context-less function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun ListPolynomial.asFunctionOfConstant(): (C) -> C = { this.substitute(ring, it) } + /** + * Represent [this] polynomial as a regular context-less function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun ListPolynomial.asFunctionOfPolynomial(): (ListPolynomial) -> ListPolynomial = { this.substitute(ring, it) } + /** + * Represent [this] polynomial as a regular context-less function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun ListPolynomial.asFunctionOfRationalFunction(): (ListRationalFunction) -> ListRationalFunction = { this.substitute(ring, it) } + /** + * Represent [this] rational function as a regular context-less function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun ListRationalFunction.asFunctionOfPolynomial(): (ListPolynomial) -> ListRationalFunction = { this.substitute(ring, it) } + /** + * Represent [this] rational function as a regular context-less function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun ListRationalFunction.asFunctionOfRationalFunction(): (ListRationalFunction) -> ListRationalFunction = { this.substitute(ring, it) } -// operator fun invoke(arg: UnivariatePolynomial): RationalFunction = -// RationalFunction( -// numerator(arg), -// denominator(arg) -// ) -// -// operator fun invoke(arg: RationalFunction): RationalFunction { -// val num = numerator invokeRFTakeNumerator arg -// val den = denominator invokeRFTakeNumerator arg -// val degreeDif = numeratorDegree - denominatorDegree -// return if (degreeDif > 0) -// RationalFunction( -// num, -// multiplyByPower(den, arg.denominator, degreeDif) -// ) -// else -// RationalFunction( -// multiplyByPower(num, arg.denominator, -degreeDif), -// den -// ) -// } -// -// override fun toString(): String = toString(UnivariatePolynomial.variableName) -// -// fun toString(withVariableName: String = UnivariatePolynomial.variableName): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toString(withVariableName) -// else -> "${numerator.toStringWithBrackets(withVariableName)}/${denominator.toStringWithBrackets(withVariableName)}" -// } -// -// fun toStringWithBrackets(withVariableName: String = UnivariatePolynomial.variableName): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toStringWithBrackets(withVariableName) -// else -> "(${numerator.toStringWithBrackets(withVariableName)}/${denominator.toStringWithBrackets(withVariableName)})" -// } -// -// fun toReversedString(withVariableName: String = UnivariatePolynomial.variableName): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedString(withVariableName) -// else -> "${numerator.toReversedStringWithBrackets(withVariableName)}/${denominator.toReversedStringWithBrackets(withVariableName)}" -// } -// -// fun toReversedStringWithBrackets(withVariableName: String = UnivariatePolynomial.variableName): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedStringWithBrackets(withVariableName) -// else -> "(${numerator.toReversedStringWithBrackets(withVariableName)}/${denominator.toReversedStringWithBrackets(withVariableName)})" -// } -// -// fun removeZeros() = -// RationalFunction( -// numerator.removeZeros(), -// denominator.removeZeros() -// ) + /** + * Evaluates value of [this] polynomial on provided argument. + */ + @Suppress("NOTHING_TO_INLINE") + public inline operator fun ListPolynomial.invoke(argument: C): C = this.substitute(ring, argument) + /** + * Evaluates value of [this] polynomial on provided argument. + */ + @Suppress("NOTHING_TO_INLINE") + public inline operator fun ListPolynomial.invoke(argument: ListPolynomial): ListPolynomial = this.substitute(ring, argument) + /** + * Evaluates value of [this] polynomial on provided argument. + */ + @Suppress("NOTHING_TO_INLINE") + public inline operator fun ListPolynomial.invoke(argument: ListRationalFunction): ListRationalFunction = this.substitute(ring, argument) + /** + * Evaluates value of [this] rational function on provided argument. + */ + @Suppress("NOTHING_TO_INLINE") + public inline operator fun ListRationalFunction.invoke(argument: ListPolynomial): ListRationalFunction = this.substitute(ring, argument) + /** + * Evaluates value of [this] rational function on provided argument. + */ + @Suppress("NOTHING_TO_INLINE") + public inline operator fun ListRationalFunction.invoke(argument: ListRationalFunction): ListRationalFunction = this.substitute(ring, argument) } \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt deleted file mode 100644 index e75373819..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ /dev/null @@ -1,389 +0,0 @@ -/* - * 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.functions - -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.ScaleOperations -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract -import kotlin.experimental.ExperimentalTypeInference -import kotlin.jvm.JvmName -import kotlin.math.max - - -/** - * Polynomial model without fixation on specific context they are applied to. - * - * @param C the type of constants. - */ -public data class NumberedPolynomial -internal constructor( - /** - * Map that collects coefficients of the polynomial. Every monomial `a x_1^{d_1} ... x_n^{d_n}` is represented as - * pair "key-value" in the map, where value is coefficients `a` and - * key is list that associates index of every variable in the monomial with multiplicity of the variable occurring - * in the monomial. For example coefficients of polynomial `5 x_1^2 x_3^3 - 6 x_2` can be represented as - * ``` - * mapOf( - * listOf(2, 0, 3) to 5, - * listOf(0, 1) to (-6), - * ) - * ``` - * and also as - * ``` - * mapOf( - * listOf(2, 0, 3) to 5, - * listOf(0, 1) to (-6), - * listOf(0, 1, 1) to 0, - * ) - * ``` - * It is recommended not to put zero monomials into the map, but is not prohibited. Lists of degrees always do not - * contain any zeros on end, but can contain zeros on start or anywhere in middle. - */ - public val coefficients: Map, C> -) : Polynomial { - override fun toString(): String = "NumberedPolynomial$coefficients" -} - -/** - * Space of polynomials. - * - * @param C the type of operated polynomials. - * @param A the intersection of [Ring] of [C] and [ScaleOperations] of [C]. - * @param ring the [A] instance. - */ -public open class NumberedPolynomialSpace>( - public final override val ring: A, -) : PolynomialSpaceOverRing, A> { - /** - * Returns sum of the polynomial and the integer represented as polynomial. - * - * The operation is equivalent to adding [other] copies of unit polynomial to [this]. - */ - public override operator fun NumberedPolynomial.plus(other: Int): NumberedPolynomial = - if (other == 0) this - else - NumberedPolynomial( - coefficients - .toMutableMap() - .apply { - val degs = emptyList() - - this[degs] = getOrElse(degs) { constantZero } + other - } - ) - /** - * Returns difference between the polynomial and the integer represented as polynomial. - * - * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. - */ - public override operator fun NumberedPolynomial.minus(other: Int): NumberedPolynomial = - if (other == 0) this - else - NumberedPolynomial( - coefficients - .toMutableMap() - .apply { - val degs = emptyList() - - this[degs] = getOrElse(degs) { constantZero } - other - } - ) - /** - * Returns product of the polynomial and the integer represented as polynomial. - * - * The operation is equivalent to sum of [other] copies of [this]. - */ - public override operator fun NumberedPolynomial.times(other: Int): NumberedPolynomial = - if (other == 0) zero - else NumberedPolynomial( - coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this[degs]!! * other - } - ) - - /** - * Returns sum of the integer represented as polynomial and the polynomial. - * - * The operation is equivalent to adding [this] copies of unit polynomial to [other]. - */ - public override operator fun Int.plus(other: NumberedPolynomial): NumberedPolynomial = - if (this == 0) other - else - NumberedPolynomial( - other.coefficients - .toMutableMap() - .apply { - val degs = emptyList() - - this[degs] = this@plus + getOrElse(degs) { constantZero } - } - ) - /** - * Returns difference between the integer represented as polynomial and the polynomial. - * - * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. - */ - public override operator fun Int.minus(other: NumberedPolynomial): NumberedPolynomial = - if (this == 0) other - else - NumberedPolynomial( - other.coefficients - .toMutableMap() - .apply { - val degs = emptyList() - - this[degs] = this@minus - getOrElse(degs) { constantZero } - } - ) - /** - * Returns product of the integer represented as polynomial and the polynomial. - * - * The operation is equivalent to sum of [this] copies of [other]. - */ - public override operator fun Int.times(other: NumberedPolynomial): NumberedPolynomial = - if (this == 0) zero - else NumberedPolynomial( - other.coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this@times * this[degs]!! - } - ) - - /** - * Converts the integer [value] to polynomial. - */ - public override fun number(value: Int): NumberedPolynomial = number(constantNumber(value)) - - /** - * Returns sum of the constant represented as polynomial and the polynomial. - */ - override operator fun C.plus(other: NumberedPolynomial): NumberedPolynomial = - with(other.coefficients) { - if (isEmpty()) NumberedPolynomial(mapOf(emptyList() to this@plus)) - else NumberedPolynomial( - toMutableMap() - .apply { - val degs = emptyList() - - this[degs] = this@plus + getOrElse(degs) { constantZero } - } - ) - } - /** - * Returns difference between the constant represented as polynomial and the polynomial. - */ - override operator fun C.minus(other: NumberedPolynomial): NumberedPolynomial = - with(other.coefficients) { - if (isEmpty()) NumberedPolynomial(mapOf(emptyList() to this@minus)) - else NumberedPolynomial( - toMutableMap() - .apply { - forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } - - val degs = emptyList() - - this[degs] = this@minus - getOrElse(degs) { constantZero } - } - ) - } - /** - * Returns product of the constant represented as polynomial and the polynomial. - */ - override operator fun C.times(other: NumberedPolynomial): NumberedPolynomial = - NumberedPolynomial( - other.coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this@times * this[degs]!! - } - ) - - /** - * Returns sum of the constant represented as polynomial and the polynomial. - */ - override operator fun NumberedPolynomial.plus(other: C): NumberedPolynomial = - with(coefficients) { - if (isEmpty()) NumberedPolynomial(mapOf(emptyList() to other)) - else NumberedPolynomial( - toMutableMap() - .apply { - val degs = emptyList() - - this[degs] = getOrElse(degs) { constantZero } + other - } - ) - } - /** - * Returns difference between the constant represented as polynomial and the polynomial. - */ - override operator fun NumberedPolynomial.minus(other: C): NumberedPolynomial = - with(coefficients) { - if (isEmpty()) NumberedPolynomial(mapOf(emptyList() to other)) - else NumberedPolynomial( - toMutableMap() - .apply { - val degs = emptyList() - - this[degs] = getOrElse(degs) { constantZero } - other - } - ) - } - /** - * Returns product of the constant represented as polynomial and the polynomial. - */ - override operator fun NumberedPolynomial.times(other: C): NumberedPolynomial = - NumberedPolynomial( - coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this[degs]!! * other - } - ) - - /** - * Converts the constant [value] to polynomial. - */ - public override fun number(value: C): NumberedPolynomial = - NumberedPolynomial(mapOf(emptyList() to value)) - - /** - * Returns negation of the polynomial. - */ - override fun NumberedPolynomial.unaryMinus(): NumberedPolynomial = - NumberedPolynomial( - coefficients.mapValues { -it.value } - ) - /** - * Returns sum of the polynomials. - */ - override operator fun NumberedPolynomial.plus(other: NumberedPolynomial): NumberedPolynomial = - NumberedPolynomial( - buildMap(coefficients.size + other.coefficients.size) { - other.coefficients.mapValuesTo(this) { it.value } - other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! + value else value } - } - ) - /** - * Returns difference of the polynomials. - */ - override operator fun NumberedPolynomial.minus(other: NumberedPolynomial): NumberedPolynomial = - NumberedPolynomial( - buildMap(coefficients.size + other.coefficients.size) { - other.coefficients.mapValuesTo(this) { it.value } - other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! - value else -value } - } - ) - /** - * Returns product of the polynomials. - */ - override operator fun NumberedPolynomial.times(other: NumberedPolynomial): NumberedPolynomial = - NumberedPolynomial( - buildMap(coefficients.size * other.coefficients.size) { - for ((degs1, c1) in coefficients) for ((degs2, c2) in other.coefficients) { - val degs = - (0..max(degs1.lastIndex, degs2.lastIndex)) - .map { degs1.getOrElse(it) { 0U } + degs2.getOrElse(it) { 0U } } - val c = c1 * c2 - this[degs] = if (degs in this) this[degs]!! + c else c - } - } - ) - - /** - * Instance of zero polynomial (zero of the polynomial ring). - */ - override val zero: NumberedPolynomial = NumberedPolynomial(emptyMap()) - /** - * Instance of unit polynomial (unit of the polynomial ring). - */ - override val one: NumberedPolynomial = - NumberedPolynomial( - mapOf( - emptyList() to constantOne // 1 * x_1^0 * x_2^0 * ... - ) - ) - - /** - * Maximal index (ID) of variable occurring in the polynomial with positive power. If there is no such variable, - * the result is `-1`. - */ - public val NumberedPolynomial.lastVariable: Int - get() = coefficients.entries.maxOfOrNull { (degs, _) -> degs.lastIndex } ?: -1 - /** - * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is - * zero, degree is -1. - */ - override val NumberedPolynomial.degree: Int - get() = coefficients.entries.maxOfOrNull { (degs, _) -> degs.sum().toInt() } ?: -1 - /** - * List that associates indices of variables (that appear in the polynomial in positive exponents) with their most - * exponents in which the variables are appeared in the polynomial. - * - * As consequence all values in the list are non-negative integers. Also, if the polynomial is constant, the list is empty. - * And last index of the list is [lastVariable]. - */ - public val NumberedPolynomial.degrees: List - get() = - MutableList(lastVariable + 1) { 0u }.apply { - coefficients.entries.forEach { (degs, _) -> - degs.forEachIndexed { index, deg -> - this[index] = max(this[index], deg) - } - } - } - /** - * Counts degree of the polynomial by the specified [variable]. - */ - public fun NumberedPolynomial.degreeBy(variable: Int): UInt = - coefficients.entries.maxOfOrNull { (degs, _) -> degs.getOrElse(variable) { 0u } } ?: 0u - /** - * Counts degree of the polynomial by the specified [variables]. - */ - public fun NumberedPolynomial.degreeBy(variables: Collection): UInt = - coefficients.entries.maxOfOrNull { (degs, _) -> - degs.withIndex().filter { (index, _) -> index in variables }.sumOf { it.value } - } ?: 0u - /** - * Count of variables occurring in the polynomial with positive power. If there is no such variable, - * the result is `0`. - */ - public val NumberedPolynomial.countOfVariables: Int - get() = - MutableList(lastVariable + 1) { false }.apply { - coefficients.entries.forEach { (degs, _) -> - degs.forEachIndexed { index, deg -> - if (deg != 0u) this[index] = true - } - } - }.count { it } - - @Suppress("NOTHING_TO_INLINE") - public inline fun NumberedPolynomial.substitute(argument: Map): NumberedPolynomial = this.substitute(ring, argument) - @Suppress("NOTHING_TO_INLINE") - @JvmName("substitutePolynomial") - public inline fun NumberedPolynomial.substitute(argument: Map>): NumberedPolynomial = this.substitute(ring, argument) - - @Suppress("NOTHING_TO_INLINE") - public inline fun NumberedPolynomial.asFunction(): (Map) -> NumberedPolynomial = { this.substitute(ring, it) } - @Suppress("NOTHING_TO_INLINE") - public inline fun NumberedPolynomial.asFunctionOnConstants(): (Map) -> NumberedPolynomial = { this.substitute(ring, it) } - @Suppress("NOTHING_TO_INLINE") - public inline fun NumberedPolynomial.asFunctionOnPolynomials(): (Map>) -> NumberedPolynomial = { this.substitute(ring, it) } - - @Suppress("NOTHING_TO_INLINE") - public inline operator fun NumberedPolynomial.invoke(argument: Map): NumberedPolynomial = this.substitute(ring, argument) - @Suppress("NOTHING_TO_INLINE") - @JvmName("invokePolynomial") - public inline operator fun NumberedPolynomial.invoke(argument: Map>): NumberedPolynomial = this.substitute(ring, argument) - - // FIXME: Move to other constructors with context receiver - public fun C.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomial(mapOf(emptyList() to this)) -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt deleted file mode 100644 index 30c7f0188..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt +++ /dev/null @@ -1,188 +0,0 @@ -/* - * 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.functions - -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.invoke -import kotlin.math.max - - -public class NumberedRationalFunction internal constructor( - public override val numerator: NumberedPolynomial, - public override val denominator: NumberedPolynomial -) : RationalFunction> { - override fun toString(): String = "NumberedRationalFunction${numerator.coefficients}/${denominator.coefficients}" -} - -public class NumberedRationalFunctionSpace> ( - public val ring: A, -) : - RationalFunctionalSpaceOverPolynomialSpace< - C, - NumberedPolynomial, - NumberedRationalFunction, - NumberedPolynomialSpace, - >, - PolynomialSpaceOfFractions< - C, - NumberedPolynomial, - NumberedRationalFunction, - >() { - - override val polynomialRing : NumberedPolynomialSpace = NumberedPolynomialSpace(ring) - override fun constructRationalFunction( - numerator: NumberedPolynomial, - denominator: NumberedPolynomial - ): NumberedRationalFunction = - NumberedRationalFunction(numerator, denominator) - - /** - * Instance of zero rational function (zero of the rational functions ring). - */ - public override val zero: NumberedRationalFunction = NumberedRationalFunction(polynomialZero, polynomialOne) - /** - * Instance of unit polynomial (unit of the rational functions ring). - */ - public override val one: NumberedRationalFunction = NumberedRationalFunction(polynomialOne, polynomialOne) - - /** - * Maximal index (ID) of variable occurring in the polynomial with positive power. If there is no such variable, - * the result is `-1`. - */ - public val NumberedPolynomial.lastVariable: Int get() = polynomialRing { lastVariable } - /** - * List that associates indices of variables (that appear in the polynomial in positive exponents) with their most - * exponents in which the variables are appeared in the polynomial. - * - * As consequence all values in the list are non-negative integers. Also, if the polynomial is constant, the list is empty. - * And last index of the list is [lastVariable]. - */ - public val NumberedPolynomial.degrees: List get() = polynomialRing { degrees } - /** - * Counts degree of the polynomial by the specified [variable]. - */ - public fun NumberedPolynomial.degreeBy(variable: Int): UInt = polynomialRing { degreeBy(variable) } - /** - * Counts degree of the polynomial by the specified [variables]. - */ - public fun NumberedPolynomial.degreeBy(variables: Collection): UInt = polynomialRing { degreeBy(variables) } - /** - * Count of variables occurring in the polynomial with positive power. If there is no such variable, - * the result is `0`. - */ - public val NumberedPolynomial.countOfVariables: Int get() = polynomialRing { countOfVariables } - - /** - * Count of all variables that appear in the polynomial in positive exponents. - */ - public val NumberedRationalFunction.lastVariable: Int - get() = polynomialRing { max(numerator.lastVariable, denominator.lastVariable) } - /** - * Count of variables occurring in the rational function with positive power. If there is no such variable, - * the result is `0`. - */ - public val NumberedRationalFunction.countOfVariables: Int - get() = - MutableList(lastVariable + 1) { false }.apply { - numerator.coefficients.entries.forEach { (degs, _) -> - degs.forEachIndexed { index, deg -> - if (deg != 0u) this[index] = true - } - } - denominator.coefficients.entries.forEach { (degs, _) -> - degs.forEachIndexed { index, deg -> - if (deg != 0u) this[index] = true - } - } - }.count { it } - - // TODO: Разобрать - -// operator fun invoke(arg: Map): NumberedRationalFunction = -// NumberedRationalFunction( -// numerator(arg), -// denominator(arg) -// ) -// -// @JvmName("invokePolynomial") -// operator fun invoke(arg: Map>): NumberedRationalFunction = -// NumberedRationalFunction( -// numerator(arg), -// denominator(arg) -// ) -// -// @JvmName("invokeRationalFunction") -// operator fun invoke(arg: Map>): NumberedRationalFunction { -// var num = numerator invokeRFTakeNumerator arg -// var den = denominator invokeRFTakeNumerator arg -// for (variable in 0 until max(numerator.countOfVariables, denominator.countOfVariables)) if (variable in arg) { -// val degreeDif = numerator.degrees.getOrElse(variable) { 0 } - denominator.degrees.getOrElse(variable) { 0 } -// if (degreeDif > 0) -// den = multiplyByPower(den, arg[variable]!!.denominator, degreeDif) -// else -// num = multiplyByPower(num, arg[variable]!!.denominator, -degreeDif) -// } -// return NumberedRationalFunction(num, den) -// } -// -// override fun toString(): String = toString(Polynomial.variableName) -// -// fun toString(withVariableName: String = Polynomial.variableName): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toString(withVariableName) -// else -> "${numerator.toStringWithBrackets(withVariableName)}/${denominator.toStringWithBrackets(withVariableName)}" -// } -// -// fun toString(namer: (Int) -> String): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toString(namer) -// else -> "${numerator.toStringWithBrackets(namer)}/${denominator.toStringWithBrackets(namer)}" -// } -// -// fun toStringWithBrackets(withVariableName: String = Polynomial.variableName): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toStringWithBrackets(withVariableName) -// else -> "(${numerator.toStringWithBrackets(withVariableName)}/${denominator.toStringWithBrackets(withVariableName)})" -// } -// -// fun toStringWithBrackets(namer: (Int) -> String): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toStringWithBrackets(namer) -// else -> "(${numerator.toStringWithBrackets(namer)}/${denominator.toStringWithBrackets(namer)})" -// } -// -// fun toReversedString(withVariableName: String = Polynomial.variableName): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedString(withVariableName) -// else -> "${numerator.toReversedStringWithBrackets(withVariableName)}/${denominator.toReversedStringWithBrackets(withVariableName)}" -// } -// -// fun toReversedString(namer: (Int) -> String): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedString(namer) -// else -> "${numerator.toReversedStringWithBrackets(namer)}/${denominator.toReversedStringWithBrackets(namer)}" -// } -// -// fun toReversedStringWithBrackets(withVariableName: String = Polynomial.variableName): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedStringWithBrackets(withVariableName) -// else -> "(${numerator.toReversedStringWithBrackets(withVariableName)}/${denominator.toReversedStringWithBrackets(withVariableName)})" -// } -// -// fun toReversedStringWithBrackets(namer: (Int) -> String): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedStringWithBrackets(namer) -// else -> "(${numerator.toReversedStringWithBrackets(namer)}/${denominator.toReversedStringWithBrackets(namer)})" -// } -} \ No newline at end of file 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 e201f1f6e..12490d133 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 @@ -25,38 +25,38 @@ public interface Polynomial @Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") // FIXME: Waiting for KT-31420 public interface PolynomialSpace> : Ring

{ /** - * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * Returns sum of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. */ public operator fun C.plus(other: Int): C /** - * Returns difference between the constant and the integer represented as constant (member of underlying ring). + * Returns difference between the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. */ public operator fun C.minus(other: Int): C /** - * Returns product of the constant and the integer represented as constant (member of underlying ring). + * Returns product of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to sum of [other] copies of [this]. */ public operator fun C.times(other: Int): C /** - * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * Returns sum of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. */ public operator fun Int.plus(other: C): C /** - * Returns difference between the integer represented as constant (member of underlying ring) and the constant. + * Returns difference between the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. */ public operator fun Int.minus(other: C): C /** - * Returns product of the integer represented as constant (member of underlying ring) and the constant. + * Returns product of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -72,38 +72,38 @@ public interface PolynomialSpace> : Ring

{ public fun Int.asConstant(): C = constantNumber(this) /** - * Returns sum of the polynomial and the integer represented as polynomial. + * Returns sum of the polynomial and the integer represented as a polynomial. * * The operation is equivalent to adding [other] copies of unit polynomial to [this]. */ public operator fun P.plus(other: Int): P = addMultipliedByDoubling(this, one, other) /** - * Returns difference between the polynomial and the integer represented as polynomial. + * Returns difference between the polynomial and the integer represented as a polynomial. * * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. */ public operator fun P.minus(other: Int): P = addMultipliedByDoubling(this, one, -other) /** - * Returns product of the polynomial and the integer represented as polynomial. + * Returns product of the polynomial and the integer represented as a polynomial. * * The operation is equivalent to sum of [other] copies of [this]. */ public operator fun P.times(other: Int): P = multiplyByDoubling(this, other) /** - * Returns sum of the integer represented as polynomial and the polynomial. + * Returns sum of the integer represented as a polynomial and the polynomial. * * The operation is equivalent to adding [this] copies of unit polynomial to [other]. */ public operator fun Int.plus(other: P): P = addMultipliedByDoubling(other, one, this) /** - * Returns difference between the integer represented as polynomial and the polynomial. + * Returns difference between the integer represented as a polynomial and the polynomial. * * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. */ public operator fun Int.minus(other: P): P = addMultipliedByDoubling(-other, one, this) /** - * Returns product of the integer represented as polynomial and the polynomial. + * Returns product of the integer represented as a polynomial and the polynomial. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -165,28 +165,28 @@ public interface PolynomialSpace> : Ring

{ public val constantOne: C /** - * Returns sum of the constant represented as polynomial and the polynomial. + * Returns sum of the constant represented as a polynomial and the polynomial. */ public operator fun C.plus(other: P): P /** - * Returns difference between the constant represented as polynomial and the polynomial. + * Returns difference between the constant represented as a polynomial and the polynomial. */ public operator fun C.minus(other: P): P /** - * Returns product of the constant represented as polynomial and the polynomial. + * Returns product of the constant represented as a polynomial and the polynomial. */ public operator fun C.times(other: P): P /** - * Returns sum of the constant represented as polynomial and the polynomial. + * Returns sum of the constant represented as a polynomial and the polynomial. */ public operator fun P.plus(other: C): P /** - * Returns difference between the constant represented as polynomial and the polynomial. + * Returns difference between the constant represented as a polynomial and the polynomial. */ public operator fun P.minus(other: C): P /** - * Returns product of the constant represented as polynomial and the polynomial. + * Returns product of the constant represented as a polynomial and the polynomial. */ public operator fun P.times(other: C): P @@ -254,41 +254,44 @@ public interface PolynomialSpace> : Ring

{ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public interface PolynomialSpaceOverRing, A: Ring> : PolynomialSpace { + /** + * Underlying ring of constants. Its operations on constants are inherited by local operations on constants. + */ public val ring: A /** - * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * Returns sum of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. */ public override operator fun C.plus(other: Int): C = ring { addMultipliedByDoubling(this@plus, one, other) } /** - * Returns difference between the constant and the integer represented as constant (member of underlying ring). + * Returns difference between the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. */ public override operator fun C.minus(other: Int): C = ring { addMultipliedByDoubling(this@minus, one, -other) } /** - * Returns product of the constant and the integer represented as constant (member of underlying ring). + * Returns product of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to sum of [other] copies of [this]. */ public override operator fun C.times(other: Int): C = ring { multiplyByDoubling(this@times, other) } /** - * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * Returns sum of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. */ public override operator fun Int.plus(other: C): C = ring { addMultipliedByDoubling(other, one, this@plus) } /** - * Returns difference between the integer represented as constant (member of underlying ring) and the constant. + * Returns difference between the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. */ public override operator fun Int.minus(other: C): C = ring { addMultipliedByDoubling(-other, one, this@minus) } /** - * Returns product of the integer represented as constant (member of underlying ring) and the constant. + * Returns product of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -330,58 +333,145 @@ public interface PolynomialSpaceOverRing, A: Ring> : Poly public override val constantOne: C get() = ring.one } +/** + * Abstraction of ring of polynomials of type [P] of variables of type [V] and over ring of constants of type [C]. + * + * @param C the type of constants. Polynomials have them as coefficients in their terms. + * @param V the type of variables. Polynomials have them in representations of terms. + * @param P the type of polynomials. + */ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public interface MultivariatePolynomialSpace>: PolynomialSpace { + /** + * Returns sum of the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("plusVariableInt") public operator fun V.plus(other: Int): P + /** + * Returns difference between the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("minusVariableInt") public operator fun V.minus(other: Int): P + /** + * Returns product of the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("timesVariableInt") public operator fun V.times(other: Int): P + /** + * Returns sum of the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("plusIntVariable") public operator fun Int.plus(other: V): P + /** + * Returns difference between the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("minusIntVariable") public operator fun Int.minus(other: V): P + /** + * Returns product of the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("timesIntVariable") public operator fun Int.times(other: V): P - @JvmName("plusConstantVariable") - public operator fun C.plus(other: V): P - @JvmName("minusConstantVariable") - public operator fun C.minus(other: V): P - @JvmName("timesConstantVariable") - public operator fun C.times(other: V): P - + /** + * Returns sum of the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("plusVariableConstant") public operator fun V.plus(other: C): P + /** + * Returns difference between the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("minusVariableConstant") public operator fun V.minus(other: C): P + /** + * Returns product of the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("timesVariableConstant") public operator fun V.times(other: C): P + /** + * Returns sum of the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("plusConstantVariable") + public operator fun C.plus(other: V): P + /** + * Returns difference between the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("minusConstantVariable") + public operator fun C.minus(other: V): P + /** + * Returns product of the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("timesConstantVariable") + public operator fun C.times(other: V): P + + /** + * Represents the variable as a monic monomial. + */ @JvmName("unaryPlusVariable") public operator fun V.unaryPlus(): P + /** + * Returns negation of representation of the variable as a monic monomial. + */ @JvmName("unaryMinusVariable") public operator fun V.unaryMinus(): P + /** + * Returns sum of the variables represented as monic monomials. + */ @JvmName("plusVariableVariable") public operator fun V.plus(other: V): P + /** + * Returns difference between the variables represented as monic monomials. + */ @JvmName("minusVariableVariable") public operator fun V.minus(other: V): P + /** + * Returns product of the variables represented as monic monomials. + */ @JvmName("timesVariableVariable") public operator fun V.times(other: V): P + /** + * Represents the [variable] as a monic monomial. + */ + @JvmName("numberVariable") + public fun number(variable: V): P = +variable + /** + * Represents the variable as a monic monomial. + */ + @JvmName("asPolynomialVariable") + public fun V.asPolynomial(): P = number(this) + + /** + * Returns sum of the variable represented as a monic monomial and the polynomial. + */ @JvmName("plusVariablePolynomial") public operator fun V.plus(other: P): P + /** + * Returns difference between the variable represented as a monic monomial and the polynomial. + */ @JvmName("minusVariablePolynomial") public operator fun V.minus(other: P): P + /** + * Returns product of the variable represented as a monic monomial and the polynomial. + */ @JvmName("timesVariablePolynomial") public operator fun V.times(other: P): P + /** + * Returns sum of the polynomial and the variable represented as a monic monomial. + */ @JvmName("plusPolynomialVariable") public operator fun P.plus(other: V): P + /** + * Returns difference between the polynomial and the variable represented as a monic monomial. + */ @JvmName("minusPolynomialVariable") public operator fun P.minus(other: V): P + /** + * Returns product of the polynomial and the variable represented as a monic monomial. + */ @JvmName("timesPolynomialVariable") public operator fun P.times(other: V): P diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt index dfec126f3..01911f980 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt @@ -25,44 +25,44 @@ public interface RationalFunction> { * [C]. * * @param C the type of constants. Polynomials have them as coefficients in their terms. - * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. + * @param P the type of polynomials. Rational functions have them as numerators and denominators. * @param R the type of rational functions. */ @Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") // FIXME: Waiting for KT-31420 public interface RationalFunctionalSpace, R: RationalFunction> : Ring { /** - * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * Returns sum of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. */ public operator fun C.plus(other: Int): C /** - * Returns difference between the constant and the integer represented as constant (member of underlying ring). + * Returns difference between the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. */ public operator fun C.minus(other: Int): C /** - * Returns product of the constant and the integer represented as constant (member of underlying ring). + * Returns product of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to sum of [other] copies of [this]. */ public operator fun C.times(other: Int): C /** - * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * Returns sum of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. */ public operator fun Int.plus(other: C): C /** - * Returns difference between the integer represented as constant (member of underlying ring) and the constant. + * Returns difference between the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. */ public operator fun Int.minus(other: C): C /** - * Returns product of the integer represented as constant (member of underlying ring) and the constant. + * Returns product of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -78,38 +78,38 @@ public interface RationalFunctionalSpace, R: RationalFunctio public fun Int.asConstant(): C = constantNumber(this) /** - * Returns sum of the constant and the integer represented as polynomial. + * Returns sum of the constant and the integer represented as a polynomial. * * The operation is equivalent to adding [other] copies of unit polynomial to [this]. */ public operator fun P.plus(other: Int): P /** - * Returns difference between the constant and the integer represented as polynomial. + * Returns difference between the constant and the integer represented as a polynomial. * * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. */ public operator fun P.minus(other: Int): P /** - * Returns product of the constant and the integer represented as polynomial. + * Returns product of the constant and the integer represented as a polynomial. * * The operation is equivalent to sum of [other] copies of [this]. */ public operator fun P.times(other: Int): P /** - * Returns sum of the integer represented as polynomial and the constant. + * Returns sum of the integer represented as a polynomial and the constant. * * The operation is equivalent to adding [this] copies of unit polynomial to [other]. */ public operator fun Int.plus(other: P): P /** - * Returns difference between the integer represented as polynomial and the constant. + * Returns difference between the integer represented as a polynomial and the constant. * * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. */ public operator fun Int.minus(other: P): P /** - * Returns product of the integer represented as polynomial and the constant. + * Returns product of the integer represented as a polynomial and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -125,25 +125,25 @@ public interface RationalFunctionalSpace, R: RationalFunctio public fun Int.asPolynomial(): P = polynomialNumber(this) /** - * Returns sum of the rational function and the integer represented as rational function. + * Returns sum of the rational function and the integer represented as a rational function. * * The operation is equivalent to adding [other] copies of unit polynomial to [this]. */ public operator fun R.plus(other: Int): R = addMultipliedByDoubling(this, one, other) /** - * Returns difference between the rational function and the integer represented as rational function. + * Returns difference between the rational function and the integer represented as a rational function. * * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. */ public operator fun R.minus(other: Int): R = addMultipliedByDoubling(this, one, -other) /** - * Returns product of the rational function and the integer represented as rational function. + * Returns product of the rational function and the integer represented as a rational function. * * The operation is equivalent to sum of [other] copies of [this]. */ public operator fun R.times(other: Int): R = multiplyByDoubling(this, other) /** - * Returns quotient of the rational function and the integer represented as rational function. + * Returns quotient of the rational function and the integer represented as a rational function. * * The operation is equivalent to creating a new rational function by preserving numerator of [this] and * multiplication denominator of [this] to [other]. @@ -151,25 +151,25 @@ public interface RationalFunctionalSpace, R: RationalFunctio public operator fun R.div(other: Int): R = this / multiplyByDoubling(one, other) /** - * Returns sum of the integer represented as rational function and the rational function. + * Returns sum of the integer represented as a rational function and the rational function. * * The operation is equivalent to adding [this] copies of unit polynomial to [other]. */ public operator fun Int.plus(other: R): R = addMultipliedByDoubling(other, one, this) /** - * Returns difference between the integer represented as rational function and the rational function. + * Returns difference between the integer represented as a rational function and the rational function. * * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. */ public operator fun Int.minus(other: R): R = addMultipliedByDoubling(-other, one, this) /** - * Returns product of the integer represented as rational function and the rational function. + * Returns product of the integer represented as a rational function and the rational function. * * The operation is equivalent to sum of [this] copies of [other]. */ public operator fun Int.times(other: R): R = multiplyByDoubling(other, this) /** - * Returns quotient of the integer represented as rational function and the rational function. + * Returns quotient of the integer represented as a rational function and the rational function. * * The operation is equivalent to creating a new rational function which numerator is [this] times denominator of * [other] and which denominator is [other]'s numerator. @@ -232,28 +232,28 @@ public interface RationalFunctionalSpace, R: RationalFunctio public val constantOne: C /** - * Returns sum of the constant represented as polynomial and the polynomial. + * Returns sum of the constant represented as a polynomial and the polynomial. */ public operator fun C.plus(other: P): P /** - * Returns difference between the constant represented as polynomial and the polynomial. + * Returns difference between the constant represented as a polynomial and the polynomial. */ public operator fun C.minus(other: P): P /** - * Returns product of the constant represented as polynomial and the polynomial. + * Returns product of the constant represented as a polynomial and the polynomial. */ public operator fun C.times(other: P): P /** - * Returns sum of the constant represented as polynomial and the polynomial. + * Returns sum of the constant represented as a polynomial and the polynomial. */ public operator fun P.plus(other: C): P /** - * Returns difference between the constant represented as polynomial and the polynomial. + * Returns difference between the constant represented as a polynomial and the polynomial. */ public operator fun P.minus(other: C): P /** - * Returns product of the constant represented as polynomial and the polynomial. + * Returns product of the constant represented as a polynomial and the polynomial. */ public operator fun P.times(other: C): P @@ -305,36 +305,36 @@ public interface RationalFunctionalSpace, R: RationalFunctio public val polynomialOne: P /** - * Returns sum of the constant represented as rational function and the rational function. + * Returns sum of the constant represented as a rational function and the rational function. */ public operator fun C.plus(other: R): R /** - * Returns difference between the constant represented as polynomial and the rational function. + * Returns difference between the constant represented as a polynomial and the rational function. */ public operator fun C.minus(other: R): R /** - * Returns product of the constant represented as polynomial and the rational function. + * Returns product of the constant represented as a polynomial and the rational function. */ public operator fun C.times(other: R): R /** - * Returns quotient of the constant represented as polynomial and the rational function. + * Returns quotient of the constant represented as a polynomial and the rational function. */ public operator fun C.div(other: R): R /** - * Returns sum of the rational function and the constant represented as rational function. + * Returns sum of the rational function and the constant represented as a rational function. */ public operator fun R.plus(other: C): R /** - * Returns difference between the rational function and the constant represented as rational function. + * Returns difference between the rational function and the constant represented as a rational function. */ public operator fun R.minus(other: C): R /** - * Returns product of the rational function and the constant represented as rational function. + * Returns product of the rational function and the constant represented as a rational function. */ public operator fun R.times(other: C): R /** - * Returns quotient of the rational function and the constant represented as rational function. + * Returns quotient of the rational function and the constant represented as a rational function. */ public operator fun R.div(other: C): R @@ -348,36 +348,36 @@ public interface RationalFunctionalSpace, R: RationalFunctio public fun C.asRationalFunction(): R = number(this) /** - * Returns sum of the polynomial represented as rational function and the rational function. + * Returns sum of the polynomial represented as a rational function and the rational function. */ public operator fun P.plus(other: R): R /** - * Returns difference between the polynomial represented as polynomial and the rational function. + * Returns difference between the polynomial represented as a polynomial and the rational function. */ public operator fun P.minus(other: R): R /** - * Returns product of the polynomial represented as polynomial and the rational function. + * Returns product of the polynomial represented as a polynomial and the rational function. */ public operator fun P.times(other: R): R /** - * Returns quotient of the polynomial represented as polynomial and the rational function. + * Returns quotient of the polynomial represented as a polynomial and the rational function. */ public operator fun P.div(other: R): R /** - * Returns sum of the rational function and the polynomial represented as rational function. + * Returns sum of the rational function and the polynomial represented as a rational function. */ public operator fun R.plus(other: P): R /** - * Returns difference between the rational function and the polynomial represented as rational function. + * Returns difference between the rational function and the polynomial represented as a rational function. */ public operator fun R.minus(other: P): R /** - * Returns product of the rational function and the polynomial represented as rational function. + * Returns product of the rational function and the polynomial represented as a rational function. */ public operator fun R.times(other: P): R /** - * Returns quotient of the rational function and the polynomial represented as rational function. + * Returns quotient of the rational function and the polynomial represented as a rational function. */ public operator fun R.div(other: P): R @@ -459,43 +459,51 @@ public interface RationalFunctionalSpace, R: RationalFunctio * @param A the type of algebraic structure (precisely, of ring) provided for constants. */ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 -public interface RationalFunctionalSpaceOverRing, R: RationalFunction, A: Ring> : RationalFunctionalSpace { +public interface RationalFunctionalSpaceOverRing< + C, + P: Polynomial, + R: RationalFunction, + A: Ring + > : RationalFunctionalSpace { + /** + * Underlying ring of constants. Its operations on constants are inherited by local operations on constants. + */ public val ring: A /** - * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * Returns sum of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. */ public override operator fun C.plus(other: Int): C = ring { addMultipliedByDoubling(this@plus, one, other) } /** - * Returns difference between the constant and the integer represented as constant (member of underlying ring). + * Returns difference between the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. */ public override operator fun C.minus(other: Int): C = ring { addMultipliedByDoubling(this@minus, one, -other) } /** - * Returns product of the constant and the integer represented as constant (member of underlying ring). + * Returns product of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to sum of [other] copies of [this]. */ public override operator fun C.times(other: Int): C = ring { multiplyByDoubling(this@times, other) } /** - * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * Returns sum of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. */ public override operator fun Int.plus(other: C): C = ring { addMultipliedByDoubling(other, one, this@plus) } /** - * Returns difference between the integer represented as constant (member of underlying ring) and the constant. + * Returns difference between the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. */ public override operator fun Int.minus(other: C): C = ring { addMultipliedByDoubling(-other, one, this@minus) } /** - * Returns product of the integer represented as constant (member of underlying ring) and the constant. + * Returns product of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -560,41 +568,44 @@ public interface RationalFunctionalSpaceOverPolynomialSpace< AP: PolynomialSpace, > : RationalFunctionalSpace { + /** + * Underlying polynomial ring. Its polynomial operations are inherited by local polynomial operations. + */ public val polynomialRing: AP /** - * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * Returns sum of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. */ public override operator fun C.plus(other: Int): C = polynomialRing { this@plus + other } /** - * Returns difference between the constant and the integer represented as constant (member of underlying ring). + * Returns difference between the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. */ public override operator fun C.minus(other: Int): C = polynomialRing { this@minus - other } /** - * Returns product of the constant and the integer represented as constant (member of underlying ring). + * Returns product of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to sum of [other] copies of [this]. */ public override operator fun C.times(other: Int): C = polynomialRing { this@times * other } /** - * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * Returns sum of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. */ public override operator fun Int.plus(other: C): C = polynomialRing { this@plus + other } /** - * Returns difference between the integer represented as constant (member of underlying ring) and the constant. + * Returns difference between the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. */ public override operator fun Int.minus(other: C): C = polynomialRing { this@minus - other } /** - * Returns product of the integer represented as constant (member of underlying ring) and the constant. + * Returns product of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -610,38 +621,38 @@ public interface RationalFunctionalSpaceOverPolynomialSpace< override fun Int.asConstant(): C = polynomialRing { asConstant() } /** - * Returns sum of the constant and the integer represented as polynomial. + * Returns sum of the constant and the integer represented as a polynomial. * * The operation is equivalent to adding [other] copies of unit polynomial to [this]. */ public override operator fun P.plus(other: Int): P = polynomialRing { this@plus + other } /** - * Returns difference between the constant and the integer represented as polynomial. + * Returns difference between the constant and the integer represented as a polynomial. * * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. */ public override operator fun P.minus(other: Int): P = polynomialRing { this@minus - other } /** - * Returns product of the constant and the integer represented as polynomial. + * Returns product of the constant and the integer represented as a polynomial. * * The operation is equivalent to sum of [other] copies of [this]. */ public override operator fun P.times(other: Int): P = polynomialRing { this@times * other } /** - * Returns sum of the integer represented as polynomial and the constant. + * Returns sum of the integer represented as a polynomial and the constant. * * The operation is equivalent to adding [this] copies of unit polynomial to [other]. */ public override operator fun Int.plus(other: P): P = polynomialRing { this@plus + other } /** - * Returns difference between the integer represented as polynomial and the constant. + * Returns difference between the integer represented as a polynomial and the constant. * * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. */ public override operator fun Int.minus(other: P): P = polynomialRing { this@minus - other } /** - * Returns product of the integer represented as polynomial and the constant. + * Returns product of the integer represented as a polynomial and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -697,28 +708,28 @@ public interface RationalFunctionalSpaceOverPolynomialSpace< public override val constantOne: C get() = polynomialRing.constantOne /** - * Returns sum of the constant represented as polynomial and the polynomial. + * Returns sum of the constant represented as a polynomial and the polynomial. */ public override operator fun C.plus(other: P): P = polynomialRing { this@plus + other } /** - * Returns difference between the constant represented as polynomial and the polynomial. + * Returns difference between the constant represented as a polynomial and the polynomial. */ public override operator fun C.minus(other: P): P = polynomialRing { this@minus - other } /** - * Returns product of the constant represented as polynomial and the polynomial. + * Returns product of the constant represented as a polynomial and the polynomial. */ public override operator fun C.times(other: P): P = polynomialRing { this@times * other } /** - * Returns sum of the constant represented as polynomial and the polynomial. + * Returns sum of the constant represented as a polynomial and the polynomial. */ public override operator fun P.plus(other: C): P = polynomialRing { this@plus + other } /** - * Returns difference between the constant represented as polynomial and the polynomial. + * Returns difference between the constant represented as a polynomial and the polynomial. */ public override operator fun P.minus(other: C): P = polynomialRing { this@minus - other } /** - * Returns product of the constant represented as polynomial and the polynomial. + * Returns product of the constant represented as a polynomial and the polynomial. */ public override operator fun P.times(other: C): P = polynomialRing { this@times * other } @@ -774,7 +785,8 @@ public interface RationalFunctionalSpaceOverPolynomialSpace< /** * Abstraction of field of rational functions of type [R] with respect to polynomials of type [P] and constants of type - * [C]. It also assumes that there is provided constructor + * [C]. It also assumes that there is provided constructor [constructRationalFunction] of rational functions from + * polynomial numerator and denominator. * * @param C the type of constants. Polynomials have them as coefficients in their terms. * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. @@ -786,10 +798,14 @@ public abstract class PolynomialSpaceOfFractions< P: Polynomial, R: RationalFunction, > : RationalFunctionalSpace { + + /** + * Constructor of rational functions (of type [R]) from numerator and denominator (of type [P]). + */ protected abstract fun constructRationalFunction(numerator: P, denominator: P = polynomialOne) : R /** - * Returns sum of the rational function and the integer represented as rational function. + * Returns sum of the rational function and the integer represented as a rational function. * * The operation is equivalent to adding [other] copies of unit polynomial to [this]. */ @@ -799,7 +815,7 @@ public abstract class PolynomialSpaceOfFractions< denominator ) /** - * Returns difference between the rational function and the integer represented as rational function. + * Returns difference between the rational function and the integer represented as a rational function. * * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. */ @@ -809,7 +825,7 @@ public abstract class PolynomialSpaceOfFractions< denominator ) /** - * Returns product of the rational function and the integer represented as rational function. + * Returns product of the rational function and the integer represented as a rational function. * * The operation is equivalent to sum of [other] copies of [this]. */ @@ -818,7 +834,12 @@ public abstract class PolynomialSpaceOfFractions< numerator * other, denominator ) - + /** + * Returns quotient of the rational function and the integer represented as a rational function. + * + * The operation is equivalent to creating a new rational function by preserving numerator of [this] and + * multiplication denominator of [this] to [other]. + */ public override operator fun R.div(other: Int): R = constructRationalFunction( numerator, @@ -826,7 +847,7 @@ public abstract class PolynomialSpaceOfFractions< ) /** - * Returns sum of the integer represented as rational function and the rational function. + * Returns sum of the integer represented as a rational function and the rational function. * * The operation is equivalent to adding [this] copies of unit polynomial to [other]. */ @@ -836,7 +857,7 @@ public abstract class PolynomialSpaceOfFractions< other.denominator ) /** - * Returns difference between the integer represented as rational function and the rational function. + * Returns difference between the integer represented as a rational function and the rational function. * * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. */ @@ -846,7 +867,7 @@ public abstract class PolynomialSpaceOfFractions< other.denominator ) /** - * Returns product of the integer represented as rational function and the rational function. + * Returns product of the integer represented as a rational function and the rational function. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -855,7 +876,12 @@ public abstract class PolynomialSpaceOfFractions< this * other.numerator, other.denominator ) - + /** + * Returns quotient of the integer represented as a rational function and the rational function. + * + * The operation is equivalent to creating a new rational function which numerator is [this] times denominator of + * [other] and which denominator is [other]'s numerator. + */ public override operator fun Int.div(other: R): R = constructRationalFunction( this * other.denominator, @@ -873,7 +899,7 @@ public abstract class PolynomialSpaceOfFractions< public override operator fun P.div(other: P): R = constructRationalFunction(this, other) /** - * Returns sum of the constant represented as rational function and the rational function. + * Returns sum of the constant represented as a rational function and the rational function. */ public override operator fun C.plus(other: R): R = constructRationalFunction( @@ -881,7 +907,7 @@ public abstract class PolynomialSpaceOfFractions< other.denominator ) /** - * Returns difference between the constant represented as polynomial and the rational function. + * Returns difference between the constant represented as a polynomial and the rational function. */ public override operator fun C.minus(other: R): R = constructRationalFunction( @@ -889,14 +915,16 @@ public abstract class PolynomialSpaceOfFractions< other.denominator ) /** - * Returns product of the constant represented as polynomial and the rational function. + * Returns product of the constant represented as a polynomial and the rational function. */ public override operator fun C.times(other: R): R = constructRationalFunction( this * other.numerator, other.denominator ) - + /** + * Returns quotient of the constant represented as a polynomial and the rational function. + */ public override operator fun C.div(other: R): R = constructRationalFunction( this * other.denominator, @@ -904,7 +932,7 @@ public abstract class PolynomialSpaceOfFractions< ) /** - * Returns sum of the constant represented as rational function and the rational function. + * Returns sum of the constant represented as a rational function and the rational function. */ public override operator fun R.plus(other: C): R = constructRationalFunction( @@ -912,7 +940,7 @@ public abstract class PolynomialSpaceOfFractions< denominator ) /** - * Returns difference between the constant represented as rational function and the rational function. + * Returns difference between the constant represented as a rational function and the rational function. */ public override operator fun R.minus(other: C): R = constructRationalFunction( @@ -920,14 +948,16 @@ public abstract class PolynomialSpaceOfFractions< denominator ) /** - * Returns product of the constant represented as rational function and the rational function. + * Returns product of the constant represented as a rational function and the rational function. */ public override operator fun R.times(other: C): R = constructRationalFunction( numerator * other, denominator ) - + /** + * Returns quotient of the rational function and the constant represented as a rational function. + */ public override operator fun R.div(other: C): R = constructRationalFunction( numerator, @@ -940,7 +970,7 @@ public abstract class PolynomialSpaceOfFractions< public override fun number(value: C): R = constructRationalFunction(polynomialNumber(value)) /** - * Returns sum of the polynomial represented as rational function and the rational function. + * Returns sum of the polynomial represented as a rational function and the rational function. */ public override operator fun P.plus(other: R): R = constructRationalFunction( @@ -948,7 +978,7 @@ public abstract class PolynomialSpaceOfFractions< other.denominator ) /** - * Returns difference between the polynomial represented as polynomial and the rational function. + * Returns difference between the polynomial represented as a polynomial and the rational function. */ public override operator fun P.minus(other: R): R = constructRationalFunction( @@ -956,14 +986,16 @@ public abstract class PolynomialSpaceOfFractions< other.denominator ) /** - * Returns product of the polynomial represented as polynomial and the rational function. + * Returns product of the polynomial represented as a polynomial and the rational function. */ public override operator fun P.times(other: R): R = constructRationalFunction( this * other.numerator, other.denominator ) - + /** + * Returns quotient of the polynomial represented as a polynomial and the rational function. + */ public override operator fun P.div(other: R): R = constructRationalFunction( this * other.denominator, @@ -971,7 +1003,7 @@ public abstract class PolynomialSpaceOfFractions< ) /** - * Returns sum of the polynomial represented as rational function and the rational function. + * Returns sum of the polynomial represented as a rational function and the rational function. */ public override operator fun R.plus(other: P): R = constructRationalFunction( @@ -979,7 +1011,7 @@ public abstract class PolynomialSpaceOfFractions< denominator ) /** - * Returns difference between the polynomial represented as rational function and the rational function. + * Returns difference between the polynomial represented as a rational function and the rational function. */ public override operator fun R.minus(other: P): R = constructRationalFunction( @@ -987,14 +1019,16 @@ public abstract class PolynomialSpaceOfFractions< denominator ) /** - * Returns product of the polynomial represented as rational function and the rational function. + * Returns product of the polynomial represented as a rational function and the rational function. */ public override operator fun R.times(other: P): R = constructRationalFunction( numerator * other, denominator ) - + /** + * Returns quotient of the rational function and the polynomial represented as a rational function. + */ public override operator fun R.div(other: P): R = constructRationalFunction( numerator, @@ -1034,7 +1068,9 @@ public abstract class PolynomialSpaceOfFractions< numerator * other.numerator, denominator * other.denominator ) - + /** + * Returns quotient of the rational functions. + */ public override operator fun R.div(other: R): R = constructRationalFunction( numerator * other.denominator, @@ -1044,14 +1080,23 @@ public abstract class PolynomialSpaceOfFractions< /** * Instance of zero rational function (zero of the rational functions ring). */ - public override val zero: R get() = constructRationalFunction(polynomialZero) + public override val zero: R by lazy { constructRationalFunction(polynomialZero) } /** * Instance of unit polynomial (unit of the rational functions ring). */ - public override val one: R get() = constructRationalFunction(polynomialOne) + public override val one: R by lazy { constructRationalFunction(polynomialOne) } } +/** + * Abstraction of field of rational functions of type [R] with respect to polynomials of type [P] of variables of type + * [V] and over ring of constants of type [C]. + * + * @param C the type of constants. Polynomials have them as coefficients in their terms. + * @param V the type of variables. Polynomials have them in representations of terms. + * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. + * @param R the type of rational functions. + */ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public interface MultivariateRationalFunctionalSpace< C, @@ -1059,70 +1104,179 @@ public interface MultivariateRationalFunctionalSpace< P: Polynomial, R: RationalFunction >: RationalFunctionalSpace { + /** + * Returns sum of the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("plusVariableInt") public operator fun V.plus(other: Int): P + /** + * Returns difference between the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("minusVariableInt") public operator fun V.minus(other: Int): P + /** + * Returns product of the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("timesVariableInt") public operator fun V.times(other: Int): P + /** + * Returns sum of the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("plusIntVariable") public operator fun Int.plus(other: V): P + /** + * Returns difference between the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("minusIntVariable") public operator fun Int.minus(other: V): P + /** + * Returns product of the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("timesIntVariable") public operator fun Int.times(other: V): P - @JvmName("plusConstantVariable") - public operator fun C.plus(other: V): P - @JvmName("minusConstantVariable") - public operator fun C.minus(other: V): P - @JvmName("timesConstantVariable") - public operator fun C.times(other: V): P - + /** + * Returns sum of the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("plusVariableConstant") public operator fun V.plus(other: C): P + /** + * Returns difference between the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("minusVariableConstant") public operator fun V.minus(other: C): P + /** + * Returns product of the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("timesVariableConstant") public operator fun V.times(other: C): P + /** + * Returns sum of the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("plusConstantVariable") + public operator fun C.plus(other: V): P + /** + * Returns difference between the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("minusConstantVariable") + public operator fun C.minus(other: V): P + /** + * Returns product of the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("timesConstantVariable") + public operator fun C.times(other: V): P + + /** + * Represents the variable as a monic monomial. + */ @JvmName("unaryPlusVariable") public operator fun V.unaryPlus(): P + /** + * Returns negation of representation of the variable as a monic monomial. + */ @JvmName("unaryMinusVariable") public operator fun V.unaryMinus(): P + /** + * Returns sum of the variables represented as monic monomials. + */ @JvmName("plusVariableVariable") public operator fun V.plus(other: V): P + /** + * Returns difference between the variables represented as monic monomials. + */ @JvmName("minusVariableVariable") public operator fun V.minus(other: V): P + /** + * Returns product of the variables represented as monic monomials. + */ @JvmName("timesVariableVariable") public operator fun V.times(other: V): P + /** + * Represents the [variable] as a monic monomial. + */ + @JvmName("polynomialNumberVariable") + public fun polynomialNumber(variable: V): P = +variable + /** + * Represents the variable as a monic monomial. + */ + @JvmName("asPolynomialVariable") + public fun V.asPolynomial(): P = polynomialNumber(this) + + /** + * Represents the [variable] as a rational function. + */ + @JvmName("numberVariable") + public fun number(variable: V): R = number(polynomialNumber(variable)) + /** + * Represents the variable as a rational function. + */ + @JvmName("asRationalFunctionVariable") + public fun V.asRationalFunction(): R = number(this) + + /** + * Returns sum of the variable represented as a monic monomial and the polynomial. + */ @JvmName("plusVariablePolynomial") public operator fun V.plus(other: P): P + /** + * Returns difference between the variable represented as a monic monomial and the polynomial. + */ @JvmName("minusVariablePolynomial") public operator fun V.minus(other: P): P + /** + * Returns product of the variable represented as a monic monomial and the polynomial. + */ @JvmName("timesVariablePolynomial") public operator fun V.times(other: P): P + /** + * Returns sum of the polynomial and the variable represented as a monic monomial. + */ @JvmName("plusPolynomialVariable") public operator fun P.plus(other: V): P + /** + * Returns difference between the polynomial and the variable represented as a monic monomial. + */ @JvmName("minusPolynomialVariable") public operator fun P.minus(other: V): P + /** + * Returns product of the polynomial and the variable represented as a monic monomial. + */ @JvmName("timesPolynomialVariable") public operator fun P.times(other: V): P + /** + * Returns sum of the variable represented as a rational function and the rational function. + */ @JvmName("plusVariableRational") public operator fun V.plus(other: R): R + /** + * Returns difference between the variable represented as a rational function and the rational function. + */ @JvmName("minusVariableRational") public operator fun V.minus(other: R): R + /** + * Returns product of the variable represented as a rational function and the rational function. + */ @JvmName("timesVariableRational") public operator fun V.times(other: R): R + /** + * Returns sum of the rational function and the variable represented as a rational function. + */ @JvmName("plusRationalVariable") public operator fun R.plus(other: V): R + /** + * Returns difference between the rational function and the variable represented as a rational function. + */ @JvmName("minusRationalVariable") public operator fun R.minus(other: V): R + /** + * Returns product of the rational function and the variable represented as a rational function. + */ @JvmName("timesRationalVariable") public operator fun R.times(other: V): R @@ -1161,22 +1315,17 @@ public interface MultivariateRationalFunctionalSpace< public val R.countOfVariables: Int get() = variables.size } -public interface MultivariateRationalFunctionalSpaceOverRing< - C, - V, - P: Polynomial, - R: RationalFunction, - A: Ring - > : RationalFunctionalSpaceOverRing, MultivariateRationalFunctionalSpace - -public interface MultivariateRationalFunctionalSpaceOverPolynomialSpace< - C, - V, - P: Polynomial, - R: RationalFunction, - AP: PolynomialSpace, - > : RationalFunctionalSpaceOverPolynomialSpace, MultivariateRationalFunctionalSpace - +/** + * Abstraction of field of rational functions of type [R] with respect to polynomials of type [P] of variables of type + * [V] and over ring of constants of type [C]. It also assumes that there is provided [polynomialRing] (of type [AP]), + * that provides constant-, variable- and polynomial-wise operations. + * + * @param C the type of constants. Polynomials have them as coefficients in their terms. + * @param V the type of variables. Polynomials have them in representations of terms. + * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. + * @param R the type of rational functions. + * @param AP the type of algebraic structure (precisely, of ring) provided for polynomials. + */ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public interface MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSpace< C, @@ -1184,57 +1333,137 @@ public interface MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSp P: Polynomial, R: RationalFunction, AP: MultivariatePolynomialSpace, - > : MultivariateRationalFunctionalSpaceOverPolynomialSpace { + > : RationalFunctionalSpaceOverPolynomialSpace, MultivariateRationalFunctionalSpace { + /** + * Returns sum of the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("plusVariableInt") public override operator fun V.plus(other: Int): P = polynomialRing { this@plus + other } + /** + * Returns difference between the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("minusVariableInt") public override operator fun V.minus(other: Int): P = polynomialRing { this@minus - other } + /** + * Returns product of the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("timesVariableInt") public override operator fun V.times(other: Int): P = polynomialRing { this@times * other } + /** + * Returns sum of the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("plusIntVariable") public override operator fun Int.plus(other: V): P = polynomialRing { this@plus + other } + /** + * Returns difference between the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("minusIntVariable") public override operator fun Int.minus(other: V): P = polynomialRing { this@minus - other } + /** + * Returns product of the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("timesIntVariable") public override operator fun Int.times(other: V): P = polynomialRing { this@times * other } - @JvmName("plusConstantVariable") - public override operator fun C.plus(other: V): P = polynomialRing { this@plus + other } - @JvmName("minusConstantVariable") - public override operator fun C.minus(other: V): P = polynomialRing { this@minus - other } - @JvmName("timesConstantVariable") - public override operator fun C.times(other: V): P = polynomialRing { this@times * other } - + /** + * Returns sum of the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("plusVariableConstant") public override operator fun V.plus(other: C): P = polynomialRing { this@plus + other } + /** + * Returns difference between the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("minusVariableConstant") public override operator fun V.minus(other: C): P = polynomialRing { this@minus - other } + /** + * Returns product of the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("timesVariableConstant") public override operator fun V.times(other: C): P = polynomialRing { this@times * other } + /** + * Returns sum of the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("plusConstantVariable") + public override operator fun C.plus(other: V): P = polynomialRing { this@plus + other } + /** + * Returns difference between the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("minusConstantVariable") + public override operator fun C.minus(other: V): P = polynomialRing { this@minus - other } + /** + * Returns product of the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("timesConstantVariable") + public override operator fun C.times(other: V): P = polynomialRing { this@times * other } + + /** + * Represents the variable as a monic monomial. + */ @JvmName("unaryPlusVariable") public override operator fun V.unaryPlus(): P = polynomialRing { +this@unaryPlus } + /** + * Returns negation of representation of the variable as a monic monomial. + */ @JvmName("unaryMinusVariable") public override operator fun V.unaryMinus(): P = polynomialRing { -this@unaryMinus } + /** + * Returns sum of the variables represented as monic monomials. + */ @JvmName("plusVariableVariable") public override operator fun V.plus(other: V): P = polynomialRing { this@plus + other } + /** + * Returns difference between the variables represented as monic monomials. + */ @JvmName("minusVariableVariable") public override operator fun V.minus(other: V): P = polynomialRing { this@minus - other } + /** + * Returns product of the variables represented as monic monomials. + */ @JvmName("timesVariableVariable") public override operator fun V.times(other: V): P = polynomialRing { this@times * other } + /** + * Represents the [variable] as a monic monomial. + */ + @JvmName("polynomialNumberVariable") + public override fun polynomialNumber(variable: V): P = polynomialRing { number(variable) } + /** + * Represents the variable as a monic monomial. + */ + @JvmName("asPolynomialVariable") + public override fun V.asPolynomial(): P = polynomialRing { this@asPolynomial.asPolynomial() } + + /** + * Returns sum of the variable represented as a monic monomial and the polynomial. + */ @JvmName("plusVariablePolynomial") public override operator fun V.plus(other: P): P = polynomialRing { this@plus + other } + /** + * Returns difference between the variable represented as a monic monomial and the polynomial. + */ @JvmName("minusVariablePolynomial") public override operator fun V.minus(other: P): P = polynomialRing { this@minus - other } + /** + * Returns product of the variable represented as a monic monomial and the polynomial. + */ @JvmName("timesVariablePolynomial") public override operator fun V.times(other: P): P = polynomialRing { this@times * other } + /** + * Returns sum of the polynomial and the variable represented as a monic monomial. + */ @JvmName("plusPolynomialVariable") public override operator fun P.plus(other: V): P = polynomialRing { this@plus + other } + /** + * Returns difference between the polynomial and the variable represented as a monic monomial. + */ @JvmName("minusPolynomialVariable") public override operator fun P.minus(other: V): P = polynomialRing { this@minus - other } + /** + * Returns product of the polynomial and the variable represented as a monic monomial. + */ @JvmName("timesPolynomialVariable") public override operator fun P.times(other: V): P = polynomialRing { this@times * other } @@ -1264,6 +1493,16 @@ public interface MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSp public override val P.countOfVariables: Int get() = polynomialRing { countOfVariables } } +/** + * Abstraction of field of rational functions of type [R] with respect to polynomials of type [P] of variables of type + * [V] and over ring of constants of type [C]. It also assumes that there is provided constructor + * [constructRationalFunction] of rational functions from polynomial numerator and denominator. + * + * @param C the type of constants. Polynomials have them as coefficients in their terms. + * @param V the type of variables. Polynomials have them in representations of terms. + * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. + * @param R the type of rational functions. + */ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public abstract class MultivariatePolynomialSpaceOfFractions< C, @@ -1271,18 +1510,27 @@ public abstract class MultivariatePolynomialSpaceOfFractions< P: Polynomial, R: RationalFunction, > : MultivariateRationalFunctionalSpace, PolynomialSpaceOfFractions() { + /** + * Returns sum of the variable represented as a rational function and the rational function. + */ @JvmName("plusVariableRational") public override operator fun V.plus(other: R): R = constructRationalFunction( this * other.denominator + other.numerator, other.denominator ) + /** + * Returns difference between the variable represented as a rational function and the rational function. + */ @JvmName("minusVariableRational") public override operator fun V.minus(other: R): R = constructRationalFunction( this * other.denominator - other.numerator, other.denominator ) + /** + * Returns product of the variable represented as a rational function and the rational function. + */ @JvmName("timesVariableRational") public override operator fun V.times(other: R): R = constructRationalFunction( @@ -1290,18 +1538,27 @@ public abstract class MultivariatePolynomialSpaceOfFractions< other.denominator ) + /** + * Returns sum of the rational function and the variable represented as a rational function. + */ @JvmName("plusRationalVariable") public override operator fun R.plus(other: V): R = constructRationalFunction( numerator + denominator * other, denominator ) + /** + * Returns difference between the rational function and the variable represented as a rational function. + */ @JvmName("minusRationalVariable") public override operator fun R.minus(other: V): R = constructRationalFunction( numerator - denominator * other, denominator ) + /** + * Returns product of the rational function and the variable represented as a rational function. + */ @JvmName("timesRationalVariable") public override operator fun R.times(other: V): R = constructRationalFunction( diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt deleted file mode 100644 index e81a9388e..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt +++ /dev/null @@ -1,203 +0,0 @@ -/* - * 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.functions - -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.Ring - - -/** - * Returns the same degrees' description of the monomial, but without zero degrees. - */ -internal fun Map.cleanUp() = filterValues { it > 0U } - -// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available - -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > LabeledPolynomialSpace.LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(coefs, toCheckInput) -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(coefs, toCheckInput) -@Suppress("FunctionName") -internal fun > A.LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : LabeledPolynomial { - if (!toCheckInput) return LabeledPolynomial(coefs) - - val fixedCoefs = LinkedHashMap, C>(coefs.size) - - for (entry in coefs) { - val key = entry.key.cleanUp() - val value = entry.value - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return LabeledPolynomial(fixedCoefs) -} - -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > LabeledPolynomialSpace.LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(pairs, toCheckInput) -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(pairs, toCheckInput) -@Suppress("FunctionName") -internal fun > A.LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : LabeledPolynomial { - if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) - - val fixedCoefs = LinkedHashMap, C>(pairs.size) - - for (entry in pairs) { - val key = entry.first.cleanUp() - val value = entry.second - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return LabeledPolynomial(fixedCoefs) -} - -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > LabeledPolynomialSpace.LabeledPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(pairs = pairs, toCheckInput = toCheckInput) -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(pairs = pairs, toCheckInput = toCheckInput) -@Suppress("FunctionName") -internal fun > A.LabeledPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : LabeledPolynomial { - if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) - - val fixedCoefs = LinkedHashMap, C>(pairs.size) - - for (entry in pairs) { - val key = entry.first.cleanUp() - val value = entry.second - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return LabeledPolynomial(fixedCoefs) -} - -@Suppress("FunctionName") -public fun > A.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) -@Suppress("FunctionName") -public fun > LabeledPolynomialSpace.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) -@Suppress("FunctionName") -public fun > LabeledRationalFunctionSpace.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) - -@Suppress("FunctionName") -public fun > A.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > LabeledPolynomialSpace.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > LabeledRationalFunctionSpace.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) - -@Suppress("FunctionName") -public fun > A.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > LabeledPolynomialSpace.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > LabeledRationalFunctionSpace.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs, toCheckInput = true) - -//context(A) -//public fun > Symbol.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1u) to one)) -//context(LabeledPolynomialSpace) -//public fun > Symbol.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1u) to constantOne)) -//context(LabeledRationalFunctionSpace) -//public fun > Symbol.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1u) to constantOne)) - -public fun C.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to this)) - -@DslMarker -@UnstableKMathAPI -internal annotation class LabeledPolynomialConstructorDSL - -@UnstableKMathAPI -@LabeledPolynomialConstructorDSL -public class LabeledPolynomialTermSignatureBuilder { - private val signature: MutableMap = LinkedHashMap() - public fun build(): Map = signature - public infix fun Symbol.inPowerOf(deg: UInt) { - signature[this] = deg - } - @Suppress("NOTHING_TO_INLINE") - public inline infix fun Symbol.pow(deg: UInt): Unit = this inPowerOf deg - @Suppress("NOTHING_TO_INLINE") - public inline infix fun Symbol.`in`(deg: UInt): Unit = this inPowerOf deg - @Suppress("NOTHING_TO_INLINE") - public inline infix fun Symbol.of(deg: UInt): Unit = this inPowerOf deg -} - -@UnstableKMathAPI -public class LabeledPolynomialBuilder(private val zero: C, private val add: (C, C) -> C, capacity: Int = 0) { - private val coefficients: MutableMap, C> = LinkedHashMap(capacity) - public fun build(): LabeledPolynomial = LabeledPolynomial(coefficients) - public operator fun C.invoke(block: LabeledPolynomialTermSignatureBuilder.() -> Unit) { - val signature = LabeledPolynomialTermSignatureBuilder().apply(block).build() - coefficients[signature] = add(coefficients.getOrElse(signature) { zero }, this@invoke) - } - @Suppress("NOTHING_TO_INLINE") - public inline infix fun C.with(noinline block: LabeledPolynomialTermSignatureBuilder.() -> Unit): Unit = this.invoke(block) - @Suppress("NOTHING_TO_INLINE") - public inline infix fun (LabeledPolynomialTermSignatureBuilder.() -> Unit).with(coef: C): Unit = coef.invoke(this) - @Suppress("NOTHING_TO_INLINE") - public infix fun sig(block: LabeledPolynomialTermSignatureBuilder.() -> Unit): LabeledPolynomialTermSignatureBuilder.() -> Unit = block -} - -// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available - -@UnstableKMathAPI -@LabeledPolynomialConstructorDSL -@Suppress("FunctionName") -public inline fun > A.LabeledPolynomial(block: LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = LabeledPolynomialBuilder(zero, ::add).apply(block).build() -@UnstableKMathAPI -@LabeledPolynomialConstructorDSL -@Suppress("FunctionName") -public inline fun > A.LabeledPolynomial(capacity: Int, block: LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = LabeledPolynomialBuilder(zero, ::add, capacity).apply(block).build() -@UnstableKMathAPI -@LabeledPolynomialConstructorDSL -@Suppress("FunctionName") -public inline fun > LabeledPolynomialSpace.LabeledPolynomial(block: LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = LabeledPolynomialBuilder(constantZero, { left: C, right: C -> left + right}).apply(block).build() -@UnstableKMathAPI -@LabeledPolynomialConstructorDSL -@Suppress("FunctionName") -public inline fun > LabeledPolynomialSpace.LabeledPolynomial(capacity: Int, block: LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = LabeledPolynomialBuilder(constantZero, { left: C, right: C -> left + right}, capacity).apply(block).build() - -// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available - -@Suppress("FunctionName") -public fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): LabeledRationalFunction = - LabeledRationalFunction( - LabeledPolynomial(numeratorCoefficients, toCheckInput = true), - LabeledPolynomial(denominatorCoefficients, toCheckInput = true) - ) -@Suppress("FunctionName") -public fun > A.LabeledRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): LabeledRationalFunction = - LabeledRationalFunction( - LabeledPolynomial(numeratorCoefficients, toCheckInput = true), - LabeledPolynomial(denominatorCoefficients, toCheckInput = true) - ) -@Suppress("FunctionName") -public fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numerator: LabeledPolynomial): LabeledRationalFunction = - LabeledRationalFunction(numerator, polynomialOne) -@Suppress("FunctionName") -public fun > A.LabeledRationalFunction(numerator: LabeledPolynomial): LabeledRationalFunction = - LabeledRationalFunction(numerator, LabeledPolynomial(mapOf(emptyMap() to one), toCheckInput = false)) -@Suppress("FunctionName") -public fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numeratorCoefficients: Map, C>): LabeledRationalFunction = - LabeledRationalFunction( - LabeledPolynomial(numeratorCoefficients, toCheckInput = true), - polynomialOne - ) -@Suppress("FunctionName") -public fun > A.LabeledRationalFunction(numeratorCoefficients: Map, C>): LabeledRationalFunction = - LabeledRationalFunction( - LabeledPolynomial(numeratorCoefficients, toCheckInput = true), - LabeledPolynomial(mapOf(emptyMap() to one), toCheckInput = false) - ) - -//context(A) -//public fun > Symbol.asLabeledRationalFunction() : LabeledRationalFunction = LabeledRationalFunction(asLabeledPolynomial()) -//context(LabeledRationalFunctionSpace) -//public fun > Symbol.asLabeledRationalFunction() : LabeledRationalFunction = LabeledRationalFunction(asLabeledPolynomial()) - -//context(A) -//public fun > C.asLabeledRationalFunction() : LabeledRationalFunction = LabeledRationalFunction(asLabeledPolynomial()) -//context(LabeledRationalFunctionSpace) -//public fun > C.asLabeledRationalFunction() : LabeledRationalFunction = LabeledRationalFunction(asLabeledPolynomial()) \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt deleted file mode 100644 index af918b9ae..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt +++ /dev/null @@ -1,495 +0,0 @@ -/* - * 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.functions - -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.Field -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.invoke -import kotlin.contracts.ExperimentalContracts -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract - - -// TODO: Docs - -/** - * Creates a [LabeledPolynomialSpace] over a received ring. - */ -public fun > A.labeledPolynomial(): LabeledPolynomialSpace = - LabeledPolynomialSpace(this) - -/** - * Creates a [LabeledPolynomialSpace]'s scope over a received ring. - */ -@OptIn(ExperimentalContracts::class) -public inline fun , R> A.labeledPolynomial(block: LabeledPolynomialSpace.() -> R): R { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return LabeledPolynomialSpace(this).block() -} - -///** -// * Represents the polynomial as a [String] with names of variables substituted with names from [names]. -// * Consider that monomials are sorted in lexicographic order. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.represent(names: Map = emptyMap()): String = -// coefficients.entries -// .sortedWith { o1, o2 -> LabeledPolynomial.monomialComparator.compare(o1.key, o2.key) } -// .asSequence() -// .map { (degs, t) -> -// if (degs.isEmpty()) "$t" -// else { -// when { -// t.isOne() -> "" -// t.isMinusOne() -> "-" -// else -> "$t " -// } + -// degs -// .toSortedMap() -// .filter { it.value > 0U } -// .map { (variable, deg) -> -// val variableName = names.getOrDefault(variable, variable.toString()) -// when (deg) { -// 1U -> variableName -// else -> "$variableName^$deg" -// } -// } -// .joinToString(separator = " ") { it } -// } -// } -// .joinToString(separator = " + ") { it } -// .ifEmpty { "0" } -// -///** -// * Represents the polynomial as a [String] naming variables by [namer]. -// * Consider that monomials are sorted in lexicographic order. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.represent(namer: (Symbol) -> String): String = -// coefficients.entries -// .sortedWith { o1, o2 -> LabeledPolynomial.monomialComparator.compare(o1.key, o2.key) } -// .asSequence() -// .map { (degs, t) -> -// if (degs.isEmpty()) "$t" -// else { -// when { -// t.isOne() -> "" -// t.isMinusOne() -> "-" -// else -> "$t " -// } + -// degs -// .toSortedMap() -// .filter { it.value > 0U } -// .map { (variable, deg) -> -// when (deg) { -// 1U -> namer(variable) -// else -> "${namer(variable)}^$deg" -// } -// } -// .joinToString(separator = " ") { it } -// } -// } -// .joinToString(separator = " + ") { it } -// .ifEmpty { "0" } -// -///** -// * Represents the polynomial as a [String] with names of variables substituted with names from [names] and with -// * brackets around the string if needed (i.e. when there are at least two addends in the representation). -// * Consider that monomials are sorted in lexicographic order. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.representWithBrackets(names: Map = emptyMap()): String = -// with(represent(names)) { if (coefficients.count() == 1) this else "($this)" } -// -///** -// * Represents the polynomial as a [String] naming variables by [namer] and with brackets around the string if needed -// * (i.e. when there are at least two addends in the representation). -// * Consider that monomials are sorted in lexicographic order. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.representWithBrackets(namer: (Symbol) -> String): String = -// with(represent(namer)) { if (coefficients.count() == 1) this else "($this)" } -// -///** -// * Represents the polynomial as a [String] with names of variables substituted with names from [names]. -// * Consider that monomials are sorted in **reversed** lexicographic order. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.representReversed(names: Map = emptyMap()): String = -// coefficients.entries -// .sortedWith { o1, o2 -> -LabeledPolynomial.monomialComparator.compare(o1.key, o2.key) } -// .asSequence() -// .map { (degs, t) -> -// if (degs.isEmpty()) "$t" -// else { -// when { -// t.isOne() -> "" -// t.isMinusOne() -> "-" -// else -> "$t " -// } + -// degs -// .toSortedMap() -// .filter { it.value > 0U } -// .map { (variable, deg) -> -// val variableName = names.getOrDefault(variable, variable.toString()) -// when (deg) { -// 1U -> variableName -// else -> "$variableName^$deg" -// } -// } -// .joinToString(separator = " ") { it } -// } -// } -// .joinToString(separator = " + ") { it } -// .ifEmpty { "0" } -// -///** -// * Represents the polynomial as a [String] naming variables by [namer]. -// * Consider that monomials are sorted in **reversed** lexicographic order. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.representReversed(namer: (Symbol) -> String): String = -// coefficients.entries -// .sortedWith { o1, o2 -> -LabeledPolynomial.monomialComparator.compare(o1.key, o2.key) } -// .asSequence() -// .map { (degs, t) -> -// if (degs.isEmpty()) "$t" -// else { -// when { -// t.isOne() -> "" -// t.isMinusOne() -> "-" -// else -> "$t " -// } + -// degs -// .toSortedMap() -// .filter { it.value > 0U } -// .map { (variable, deg) -> -// when (deg) { -// 1U -> namer(variable) -// else -> "${namer(variable)}^$deg" -// } -// } -// .joinToString(separator = " ") { it } -// } -// } -// .joinToString(separator = " + ") { it } -// .ifEmpty { "0" } -// -///** -// * Represents the polynomial as a [String] with names of variables substituted with names from [names] and with -// * brackets around the string if needed (i.e. when there are at least two addends in the representation). -// * Consider that monomials are sorted in **reversed** lexicographic order. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.representReversedWithBrackets(names: Map = emptyMap()): String = -// with(representReversed(names)) { if (coefficients.count() == 1) this else "($this)" } -// -///** -// * Represents the polynomial as a [String] naming variables by [namer] and with brackets around the string if needed -// * (i.e. when there are at least two addends in the representation). -// * Consider that monomials are sorted in **reversed** lexicographic order. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.representReversedWithBrackets(namer: (Symbol) -> String): String = -// with(representReversed(namer)) { if (coefficients.count() == 1) this else "($this)" } - -//operator fun > Polynomial.div(other: T): Polynomial = -// if (other.isZero()) throw ArithmeticException("/ by zero") -// else -// Polynomial( -// coefficients -// .mapValues { it.value / other }, -// toCheckInput = false -// ) - -//public fun LabeledPolynomial.substitute(ring: Ring, args: Map): LabeledPolynomial = ring { -// if (coefficients.isEmpty()) return this@substitute -// LabeledPolynomial( -// buildMap { -// coefficients.forEach { (degs, c) -> -// val newDegs = degs.filterKeys { it !in args } -// val newC = degs.entries.asSequence().filter { it.key in args }.fold(c) { acc, (variable, deg) -> -// multiplyWithPower(acc, args[variable]!!, deg) -// } -// this[newDegs] = if (newDegs in this) this[newDegs]!! + newC else newC -// } -// } -// ) -//} -// -//// TODO: Replace with optimisation: the [result] may be unboxed, and all operations may be performed as soon as -//// possible on it -//@JvmName("substitutePolynomial") -//fun LabeledPolynomial.substitute(ring: Ring, arg: Map>) : LabeledPolynomial = -// ring.labeledPolynomial { -// if (coefficients.isEmpty()) return zero -// coefficients -// .asSequence() -// .map { (degs, c) -> -// degs.entries -// .asSequence() -// .filter { it.key in arg } -// .fold(LabeledPolynomial(mapOf(degs.filterKeys { it !in arg } to c))) { acc, (index, deg) -> -// multiplyWithPower(acc, arg[index]!!, deg) -// } -// } -// .reduce { acc, polynomial -> acc + polynomial } // TODO: Rewrite. Might be slow. -// } -// -//// TODO: Substitute rational function -// -//fun > LabeledPolynomial.asFunctionOver(ring: A): (Map) -> LabeledPolynomial = -// { substitute(ring, it) } -// -//fun > LabeledPolynomial.asPolynomialFunctionOver(ring: A): (Map>) -> LabeledPolynomial = -// { substitute(ring, it) } - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > LabeledPolynomial.derivativeWithRespectTo( - algebra: A, - variable: Symbol, -): LabeledPolynomial = algebra { - LabeledPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - if (variable !in degs) return@forEach - put( - buildMap { - degs.forEach { (vari, deg) -> - when { - vari != variable -> put(vari, deg) - deg > 1u -> put(vari, deg - 1u) - } - } - }, - multiplyByDoubling(c, degs[variable]!!) - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > LabeledPolynomial.derivativeWithRespectTo( - algebra: A, - variables: Collection, -): LabeledPolynomial = algebra { - val cleanedVariables = variables.toSet() - if (cleanedVariables.isEmpty()) return this@derivativeWithRespectTo - LabeledPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - if (!degs.keys.containsAll(cleanedVariables)) return@forEach - put( - buildMap { - degs.forEach { (vari, deg) -> - when { - vari !in cleanedVariables -> put(vari, deg) - deg > 1u -> put(vari, deg - 1u) - } - } - }, - cleanedVariables.fold(c) { acc, variable -> multiplyByDoubling(acc, degs[variable]!!) } - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > LabeledPolynomial.nthDerivativeWithRespectTo( - algebra: A, - variable: Symbol, - order: UInt -): LabeledPolynomial = algebra { - if (order == 0u) return this@nthDerivativeWithRespectTo - LabeledPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - if (degs.getOrElse(variable) { 0u } < order) return@forEach - put( - buildMap { - degs.forEach { (vari, deg) -> - when { - vari != variable -> put(vari, deg) - deg > order -> put(vari, deg - order) - } - } - }, - degs[variable]!!.let { deg -> - (deg downTo deg - order + 1u) - .fold(c) { acc, ord -> multiplyByDoubling(acc, ord) } - } - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > LabeledPolynomial.nthDerivativeWithRespectTo( - algebra: A, - variablesAndOrders: Map, -): LabeledPolynomial = algebra { - val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u } - if (filteredVariablesAndOrders.isEmpty()) return this@nthDerivativeWithRespectTo - LabeledPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - if (filteredVariablesAndOrders.any { (variable, order) -> degs.getOrElse(variable) { 0u } < order }) return@forEach - put( - buildMap { - degs.forEach { (vari, deg) -> - if (vari !in filteredVariablesAndOrders) put(vari, deg) - else { - val order = filteredVariablesAndOrders[vari]!! - if (deg > order) put(vari, deg - order) - } - } - }, - filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> - degs[index]!!.let { deg -> - (deg downTo deg - order + 1u) - .fold(acc1) { acc2, ord -> multiplyByDoubling(acc2, ord) } - } - } - ) - } - } - ) -} - -/** - * Returns algebraic antiderivative of received polynomial. - */ -@UnstableKMathAPI -public fun > LabeledPolynomial.antiderivativeWithRespectTo( - algebra: A, - variable: Symbol, -): LabeledPolynomial = algebra { - LabeledPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - val newDegs = buildMap(degs.size + 1) { - put(variable, 1u) - for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) - } - put( - newDegs, - c / multiplyByDoubling(one, newDegs[variable]!!) - ) - } - } - ) -} - -/** - * Returns algebraic antiderivative of received polynomial. - */ -@UnstableKMathAPI -public fun > LabeledPolynomial.antiderivativeWithRespectTo( - algebra: A, - variables: Collection, -): LabeledPolynomial = algebra { - val cleanedVariables = variables.toSet() - if (cleanedVariables.isEmpty()) return this@antiderivativeWithRespectTo - LabeledPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - val newDegs = buildMap(degs.size + 1) { - for (variable in cleanedVariables) put(variable, 1u) - for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) - } - put( - newDegs, - cleanedVariables.fold(c) { acc, variable -> acc / multiplyByDoubling(one, newDegs[variable]!!) } - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > LabeledPolynomial.nthAntiderivativeWithRespectTo( - algebra: A, - variable: Symbol, - order: UInt -): LabeledPolynomial = algebra { - if (order == 0u) return this@nthAntiderivativeWithRespectTo - LabeledPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - val newDegs = buildMap(degs.size + 1) { - put(variable, order) - for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) - } - put( - newDegs, - newDegs[variable]!!.let { deg -> - (deg downTo deg - order + 1u) - .fold(c) { acc, ord -> acc / multiplyByDoubling(one, ord) } - } - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > LabeledPolynomial.nthAntiderivativeWithRespectTo( - algebra: A, - variablesAndOrders: Map, -): LabeledPolynomial = algebra { - val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u } - if (filteredVariablesAndOrders.isEmpty()) return this@nthAntiderivativeWithRespectTo - LabeledPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - val newDegs = buildMap(degs.size + 1) { - for ((variable, order) in filteredVariablesAndOrders) put(variable, order) - for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) - } - put( - newDegs, - filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> - newDegs[index]!!.let { deg -> - (deg downTo deg - order + 1u) - .fold(acc1) { acc2, ord -> acc2 / multiplyByDoubling(one, ord) } - } - } - ) - } - } - ) -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt deleted file mode 100644 index 583160cf4..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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.functions - -import space.kscience.kmath.operations.Ring -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract - - -/** - * Creates a [LabeledRationalFunctionSpace] over a received ring. - */ -public fun > A.labeledRationalFunction(): LabeledRationalFunctionSpace = - LabeledRationalFunctionSpace(this) - -/** - * Creates a [LabeledRationalFunctionSpace]'s scope over a received ring. - */ -public inline fun , R> A.labeledRationalFunction(block: LabeledRationalFunctionSpace.() -> R): R { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return LabeledRationalFunctionSpace(this).block() -} - -//fun > LabeledRationalFunction.reduced(): LabeledRationalFunction { -// val greatestCommonDivider = polynomialGCD(numerator, denominator) -// return LabeledRationalFunction( -// numerator / greatestCommonDivider, -// denominator / greatestCommonDivider -// ) -//} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt index 9498c77ca..35c736914 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt @@ -3,58 +3,95 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ +/* + * 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.functions import space.kscience.kmath.operations.Ring /** - * Returns a [ListPolynomial] instance with given [coefficients]. The collection of coefficients will be reversed if - * [reverse] parameter is true. + * Constructs a [ListPolynomial] instance with provided [coefficients]. The collection of coefficients will be reversed + * if [reverse] parameter is true. */ @Suppress("FunctionName") public fun ListPolynomial(coefficients: List, reverse: Boolean = false): ListPolynomial = ListPolynomial(with(coefficients) { if (reverse) reversed() else this }) /** - * Returns a [ListPolynomial] instance with given [coefficients]. The collection of coefficients will be reversed if - * [reverse] parameter is true. + * Constructs a [ListPolynomial] instance with provided [coefficients]. The collection of coefficients will be reversed + * if [reverse] parameter is true. */ @Suppress("FunctionName") public fun ListPolynomial(vararg coefficients: C, reverse: Boolean = false): ListPolynomial = ListPolynomial(with(coefficients) { if (reverse) reversed() else toList() }) +/** + * Represents [this] constant as a [ListPolynomial]. + */ public fun C.asListPolynomial() : ListPolynomial = ListPolynomial(listOf(this)) // Waiting for context receivers :( FIXME: Replace with context receivers when they will be available +/** + * Constructs [ListRationalFunction] instance with numerator and denominator constructed with provided + * [numeratorCoefficients] and [denominatorCoefficients]. The both collections of coefficients will be reversed if + * [reverse] parameter is true. + */ @Suppress("FunctionName") public fun ListRationalFunction(numeratorCoefficients: List, denominatorCoefficients: List, reverse: Boolean = false): ListRationalFunction = ListRationalFunction( ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), ListPolynomial( with(denominatorCoefficients) { if (reverse) reversed() else this } ) ) -@Suppress("FunctionName") -public fun > ListRationalFunctionSpace.ListRationalFunction(numerator: ListPolynomial): ListRationalFunction = - ListRationalFunction(numerator, polynomialOne) +/** + * Constructs [ListRationalFunction] instance with provided [numerator] and unit denominator. + */ @Suppress("FunctionName") public fun > A.ListRationalFunction(numerator: ListPolynomial): ListRationalFunction = ListRationalFunction(numerator, ListPolynomial(listOf(one))) +/** + * Constructs [ListRationalFunction] instance with provided [numerator] and unit denominator. + */ @Suppress("FunctionName") -public fun > ListRationalFunctionSpace.ListRationalFunction(numeratorCoefficients: List, reverse: Boolean = false): ListRationalFunction = - ListRationalFunction( - ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), - polynomialOne - ) +public fun > ListRationalFunctionSpace.ListRationalFunction(numerator: ListPolynomial): ListRationalFunction = + ListRationalFunction(numerator, polynomialOne) +/** + * Constructs [ListRationalFunction] instance with numerator constructed with provided [numeratorCoefficients] and unit + * denominator. The collection of numerator coefficients will be reversed if [reverse] parameter is true. + */ @Suppress("FunctionName") public fun > A.ListRationalFunction(numeratorCoefficients: List, reverse: Boolean = false): ListRationalFunction = ListRationalFunction( ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), ListPolynomial(listOf(one)) ) +/** + * Constructs [ListRationalFunction] instance with numerator constructed with provided [numeratorCoefficients] and unit + * denominator. The collection of numerator coefficients will be reversed if [reverse] parameter is true. + */ +@Suppress("FunctionName") +public fun > ListRationalFunctionSpace.ListRationalFunction(numeratorCoefficients: List, reverse: Boolean = false): ListRationalFunction = + ListRationalFunction( + ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), + polynomialOne + ) +/** + * Represents [this] constant as a rational function. + */ // FIXME: When context receivers will be ready, delete this function and uncomment the following two +public fun > C.asListRationalFunction(ring: A) : ListRationalFunction = ring.ListRationalFunction(asListPolynomial()) +///** +// * Represents [this] constant as a rational function. +// */ //context(A) //public fun > C.asListRationalFunction() : ListRationalFunction = ListRationalFunction(asListPolynomial()) +///** +// * Represents [this] constant as a rational function. +// */ //context(ListRationalFunctionSpace) //public fun > C.asListRationalFunction() : ListRationalFunction = ListRationalFunction(asListPolynomial()) \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listPolynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listPolynomialUtil.kt deleted file mode 100644 index 50313cab9..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listPolynomialUtil.kt +++ /dev/null @@ -1,233 +0,0 @@ -/* - * 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.functions - -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.* -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract -import kotlin.math.max -import kotlin.math.min -import kotlin.math.pow - - -/** - * Removes zeros on the end of the coefficient list of polynomial. - */ -//context(PolynomialSpace) -//fun > Polynomial.removeZeros() : Polynomial = -// if (degree > -1) Polynomial(coefficients.subList(0, degree + 1)) else zero - -/** - * Creates a [ListPolynomialSpace] over a received ring. - */ -public fun > A.listPolynomial(): ListPolynomialSpace = - ListPolynomialSpace(this) - -/** - * Creates a [ListPolynomialSpace]'s scope over a received ring. - */ -public inline fun , R> A.listPolynomial(block: ListPolynomialSpace.() -> R): R { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return ListPolynomialSpace(this).block() -} - -/** - * Creates a [ScalableListPolynomialSpace] over a received scalable ring. - */ -public fun A.scalableListPolynomial(): ScalableListPolynomialSpace where A : Ring, A : ScaleOperations = - ScalableListPolynomialSpace(this) - -/** - * Creates a [ScalableListPolynomialSpace]'s scope over a received scalable ring. - */ -public inline fun A.scalableListPolynomial(block: ScalableListPolynomialSpace.() -> R): R where A : Ring, A : ScaleOperations { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return ScalableListPolynomialSpace(this).block() -} - -@Suppress("NOTHING_TO_INLINE") -internal inline fun copyTo( - origin: List, - originDegree: Int, - target: MutableList, -) { - for (deg in 0 .. originDegree) target[deg] = origin[deg] -} - -@Suppress("NOTHING_TO_INLINE") -internal inline fun multiplyAddingToUpdater( - ring: Ring, - multiplicand: MutableList, - multiplicandDegree: Int, - multiplier: List, - multiplierDegree: Int, - updater: MutableList, - zero: C, -) { - multiplyAddingTo( - ring = ring, - multiplicand = multiplicand, - multiplicandDegree = multiplicandDegree, - multiplier = multiplier, - multiplierDegree = multiplierDegree, - target = updater - ) - for (updateDeg in 0 .. multiplicandDegree + multiplierDegree) { - multiplicand[updateDeg] = updater[updateDeg] - updater[updateDeg] = zero - } -} - -@Suppress("NOTHING_TO_INLINE") -internal inline fun multiplyAddingTo( - ring: Ring, - multiplicand: List, - multiplicandDegree: Int, - multiplier: List, - multiplierDegree: Int, - target: MutableList -) = ring { - for (d in 0 .. multiplicandDegree + multiplierDegree) - for (k in max(0, d - multiplierDegree)..min(multiplicandDegree, d)) - target[d] += multiplicand[k] * multiplier[d - k] -} - -/** - * Evaluates the value of the given double polynomial for given double argument. - */ -public fun ListPolynomial.substitute(arg: Double): Double = - coefficients.reduceIndexedOrNull { index, acc, c -> - acc + c * arg.pow(index) - } ?: .0 - -/** - * Evaluates the value of the given polynomial for given argument. - * - * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). - */ -public fun ListPolynomial.substitute(ring: Ring, arg: C): C = ring { - if (coefficients.isEmpty()) return@ring zero - var result: C = coefficients.last() - for (j in coefficients.size - 2 downTo 0) { - result = (arg * result) + coefficients[j] - } - return result -} - -public fun ListPolynomial.substitute(ring: Ring, arg: ListPolynomial) : ListPolynomial = ring { - if (coefficients.isEmpty()) return ListPolynomial(emptyList()) - - val thisDegree = coefficients.lastIndex - if (thisDegree == -1) return ListPolynomial(emptyList()) - val argDegree = arg.coefficients.lastIndex - if (argDegree == -1) return coefficients[0].asListPolynomial() - val constantZero = zero - val resultCoefs: MutableList = MutableList(thisDegree * argDegree + 1) { constantZero } - resultCoefs[0] = coefficients[thisDegree] - val resultCoefsUpdate: MutableList = MutableList(thisDegree * argDegree + 1) { constantZero } - var resultDegree = 0 - for (deg in thisDegree - 1 downTo 0) { - resultCoefsUpdate[0] = coefficients[deg] - multiplyAddingToUpdater( - ring = ring, - multiplicand = resultCoefs, - multiplicandDegree = resultDegree, - multiplier = arg.coefficients, - multiplierDegree = argDegree, - updater = resultCoefsUpdate, - zero = constantZero - ) - resultDegree += argDegree - } - - return ListPolynomial(resultCoefs) -} - -/** - * Represent the polynomial as a regular context-less function. - */ -public fun > ListPolynomial.asFunction(ring: A): (C) -> C = { substitute(ring, it) } - -/** - * Represent the polynomial as a regular context-less function. - */ -public fun > ListPolynomial.asPolynomialFunctionOver(ring: A): (ListPolynomial) -> ListPolynomial = { substitute(ring, it) } - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun ListPolynomial.derivative( - algebra: A, -): ListPolynomial where A : Ring, A : NumericAlgebra = algebra { - ListPolynomial( - buildList(max(0, coefficients.size - 1)) { - for (deg in 1 .. coefficients.lastIndex) add(number(deg) * coefficients[deg]) - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun ListPolynomial.nthDerivative( - algebra: A, - order: Int, -): ListPolynomial where A : Ring, A : NumericAlgebra = algebra { - require(order >= 0) { "Order of derivative must be non-negative" } - ListPolynomial( - buildList(max(0, coefficients.size - order)) { - for (deg in order.. coefficients.lastIndex) - add((deg - order + 1 .. deg).fold(coefficients[deg]) { acc, d -> acc * number(d) }) - } - ) -} - -/** - * Returns algebraic antiderivative of received polynomial. - */ -@UnstableKMathAPI -public fun ListPolynomial.antiderivative( - algebra: A, -): ListPolynomial where A : Field, A : NumericAlgebra = algebra { - ListPolynomial( - buildList(coefficients.size + 1) { - add(zero) - coefficients.mapIndexedTo(this) { index, t -> t / number(index + 1) } - } - ) -} - -/** - * Returns algebraic antiderivative of received polynomial. - */ -@UnstableKMathAPI -public fun ListPolynomial.nthAntiderivative( - algebra: A, - order: Int, -): ListPolynomial where A : Field, A : NumericAlgebra = algebra { - require(order >= 0) { "Order of antiderivative must be non-negative" } - ListPolynomial( - buildList(coefficients.size + order) { - repeat(order) { add(zero) } - coefficients.mapIndexedTo(this) { index, c -> (1..order).fold(c) { acc, i -> acc / number(index + i) } } - } - ) -} - -/** - * Compute a definite integral of a given polynomial in a [range] - */ -@UnstableKMathAPI -public fun > ListPolynomial.integrate( - algebra: Field, - range: ClosedRange, -): C = algebra { - val integral = antiderivative(algebra) - integral.substitute(algebra, range.endInclusive) - integral.substitute(algebra, range.start) -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt new file mode 100644 index 000000000..127dd8c7a --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt @@ -0,0 +1,268 @@ +/* + * 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.functions + +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.* +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract +import kotlin.math.max +import kotlin.math.pow + + +/** + * Creates a [ListPolynomialSpace] over a received ring. + */ +public fun > A.listPolynomialSpace(): ListPolynomialSpace = + ListPolynomialSpace(this) + +/** + * Creates a [ListPolynomialSpace]'s scope over a received ring. + */ // TODO: When context will be ready move [ListPolynomialSpace] and add [A] to context receivers of [block] +public inline fun , R> A.listPolynomialSpace(block: ListPolynomialSpace.() -> R): R { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return ListPolynomialSpace(this).block() +} + +/** + * Creates a [ScalableListPolynomialSpace] over a received scalable ring. + */ +public fun A.scalableListPolynomialSpace(): ScalableListPolynomialSpace where A : Ring, A : ScaleOperations = + ScalableListPolynomialSpace(this) + +/** + * Creates a [ScalableListPolynomialSpace]'s scope over a received scalable ring. + */ // TODO: When context will be ready move [ListPolynomialSpace] and add [A] to context receivers of [block] +public inline fun A.scalableListPolynomialSpace(block: ScalableListPolynomialSpace.() -> R): R where A : Ring, A : ScaleOperations { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return ScalableListPolynomialSpace(this).block() +} + +/** + * Creates a [ListRationalFunctionSpace] over a received ring. + */ +public fun > A.listRationalFunctionSpace(): ListRationalFunctionSpace = + ListRationalFunctionSpace(this) + +/** + * Creates a [ListRationalFunctionSpace]'s scope over a received ring. + */ // TODO: When context will be ready move [ListRationalFunctionSpace] and add [A] to context receivers of [block] +public inline fun , R> A.listRationalFunctionSpace(block: ListRationalFunctionSpace.() -> R): R { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return ListRationalFunctionSpace(this).block() +} + + +/** + * Evaluates value of [this] Double polynomial on provided Double argument. + */ +public fun ListPolynomial.substitute(arg: Double): Double = + coefficients.reduceIndexedOrNull { index, acc, c -> + acc + c * arg.pow(index) + } ?: .0 + +/** + * Evaluates value of [this] polynomial on provided argument. + * + * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). + */ +public fun ListPolynomial.substitute(ring: Ring, arg: C): C = ring { + if (coefficients.isEmpty()) return zero + var result: C = coefficients.last() + for (j in coefficients.size - 2 downTo 0) { + result = (arg * result) + coefficients[j] + } + return result +} + +/** + * Substitutes provided polynomial [arg] into [this] polynomial. + * + * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). + */ // TODO: To optimize boxing +public fun ListPolynomial.substitute(ring: Ring, arg: ListPolynomial) : ListPolynomial = + ring.listPolynomialSpace { + if (coefficients.isEmpty()) return zero + var result: ListPolynomial = coefficients.last().asPolynomial() + for (j in coefficients.size - 2 downTo 0) { + result = (arg * result) + coefficients[j] + } + return result + } + +/** + * Substitutes provided rational function [arg] into [this] polynomial. + * + * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). + */ // TODO: To optimize boxing +public fun ListPolynomial.substitute(ring: Ring, arg: ListRationalFunction) : ListRationalFunction = + ring.listRationalFunctionSpace { + if (coefficients.isEmpty()) return zero + var result: ListRationalFunction = coefficients.last().asRationalFunction() + for (j in coefficients.size - 2 downTo 0) { + result = (arg * result) + coefficients[j] + } + return result + } + +/** + * Evaluates value of [this] Double rational function in provided Double argument. + */ +public fun ListRationalFunction.substitute(arg: Double): Double = + numerator.substitute(arg) / denominator.substitute(arg) + +/** + * Evaluates value of [this] polynomial for provided argument. + * + * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). + */ +public fun ListRationalFunction.substitute(ring: Field, arg: C): C = ring { + numerator.substitute(ring, arg) / denominator.substitute(ring, arg) +} + +/** + * Substitutes provided polynomial [arg] into [this] rational function. + */ // TODO: To optimize boxing +public fun ListRationalFunction.substitute(ring: Ring, arg: ListPolynomial) : ListRationalFunction = + ring.listRationalFunctionSpace { + numerator.substitute(ring, arg) / denominator.substitute(ring, arg) + } + +/** + * Substitutes provided rational function [arg] into [this] rational function. + */ // TODO: To optimize boxing +public fun ListRationalFunction.substitute(ring: Ring, arg: ListRationalFunction) : ListRationalFunction = + ring.listRationalFunctionSpace { + numerator.substitute(ring, arg) / denominator.substitute(ring, arg) + } + +/** + * Represent [this] polynomial as a regular context-less function. + */ +public fun > ListPolynomial.asFunctionOver(ring: A): (C) -> C = { substitute(ring, it) } + +/** + * Represent [this] polynomial as a regular context-less function. + */ +public fun > ListPolynomial.asPolynomialFunctionOver(ring: A): (ListPolynomial) -> ListPolynomial = { substitute(ring, it) } + +/** + * Represent [this] polynomial as a regular context-less function. + */ +public fun > ListPolynomial.asFunctionOfRationalFunctionOver(ring: A): (ListPolynomial) -> ListPolynomial = { substitute(ring, it) } + +/** + * Represent [this] rational function as a regular context-less function. + */ +public fun > ListRationalFunction.asFunctionOver(ring: A): (C) -> C = { substitute(ring, it) } + +/** + * Represent [this] rational function as a regular context-less function. + */ +public fun > ListRationalFunction.asPolynomialFunctionOver(ring: A): (ListPolynomial) -> ListRationalFunction = { substitute(ring, it) } + +/** + * Represent [this] rational function as a regular context-less function. + */ +public fun > ListRationalFunction.asFunctionOfRationalFunctionOver(ring: A): (ListPolynomial) -> ListRationalFunction = { substitute(ring, it) } + +/** + * Returns algebraic derivative of received polynomial. + */ +@UnstableKMathAPI +public fun ListPolynomial.derivative( + ring: A, +): ListPolynomial where A : Ring, A : NumericAlgebra = ring { + ListPolynomial( + buildList(max(0, coefficients.size - 1)) { + for (deg in 1 .. coefficients.lastIndex) add(number(deg) * coefficients[deg]) + } + ) +} + +/** + * Returns algebraic derivative of received polynomial of specified [order]. The [order] should be non-negative integer. + */ +@UnstableKMathAPI +public fun ListPolynomial.nthDerivative( + ring: A, + order: Int, +): ListPolynomial where A : Ring, A : NumericAlgebra = ring { + require(order >= 0) { "Order of derivative must be non-negative" } + ListPolynomial( + buildList(max(0, coefficients.size - order)) { + for (deg in order.. coefficients.lastIndex) + add((deg - order + 1 .. deg).fold(coefficients[deg]) { acc, d -> acc * number(d) }) + } + ) +} + +/** + * Returns algebraic antiderivative of received polynomial. + */ +@UnstableKMathAPI +public fun ListPolynomial.antiderivative( + ring: A, +): ListPolynomial where A : Field, A : NumericAlgebra = ring { + ListPolynomial( + buildList(coefficients.size + 1) { + add(zero) + coefficients.mapIndexedTo(this) { index, t -> t / number(index + 1) } + } + ) +} + +/** + * Returns algebraic antiderivative of received polynomial of specified [order]. The [order] should be non-negative integer. + */ +@UnstableKMathAPI +public fun ListPolynomial.nthAntiderivative( + ring: A, + order: Int, +): ListPolynomial where A : Field, A : NumericAlgebra = ring { + require(order >= 0) { "Order of antiderivative must be non-negative" } + ListPolynomial( + buildList(coefficients.size + order) { + repeat(order) { add(zero) } + coefficients.mapIndexedTo(this) { index, c -> (1..order).fold(c) { acc, i -> acc / number(index + i) } } + } + ) +} + +/** + * Computes a definite integral of [this] polynomial in the specified [range]. + */ +@UnstableKMathAPI +public fun > ListPolynomial.integrate( + ring: Field, + range: ClosedRange, +): C = ring { + val antiderivative = antiderivative(ring) + antiderivative.substitute(ring, range.endInclusive) - antiderivative.substitute(ring, range.start) +} + +/** + * Returns algebraic derivative of received rational function. + */ +@UnstableKMathAPI +public fun ListRationalFunction.derivative( + ring: A, +): ListRationalFunction where A : Ring, A : NumericAlgebra = ring.listRationalFunctionSpace { + ListRationalFunction( + numerator.derivative(ring) * denominator - numerator * denominator.derivative(ring), + denominator * denominator + ) +} + +/** + * Returns algebraic derivative of received rational function of specified [order]. The [order] should be non-negative integer. + */ +@UnstableKMathAPI +public tailrec fun ListRationalFunction.nthDerivative( + ring: A, + order: Int, +): ListRationalFunction where A : Ring, A : NumericAlgebra = + if (order == 0) this else derivative(ring).nthDerivative(ring, order - 1) \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listRationalFunctionUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtilOptimized.kt similarity index 72% rename from kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listRationalFunctionUtil.kt rename to kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtilOptimized.kt index 367212588..6eb3a1dc7 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listRationalFunctionUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtilOptimized.kt @@ -5,41 +5,91 @@ package space.kscience.kmath.functions -import space.kscience.kmath.operations.Field import space.kscience.kmath.operations.Ring import space.kscience.kmath.operations.invoke -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract import kotlin.math.max +import kotlin.math.min -/** - * Creates a [ListRationalFunctionSpace] over a received ring. - */ -public fun > A.listRationalFunction(): ListRationalFunctionSpace = - ListRationalFunctionSpace(this) - -/** - * Creates a [ListRationalFunctionSpace]'s scope over a received ring. - */ -public inline fun , R> A.listRationalFunction(block: ListRationalFunctionSpace.() -> R): R { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return ListRationalFunctionSpace(this).block() +// TODO: Optimized copies of substitution and invocation +@UnstablePolynomialBoxingOptimization +@Suppress("NOTHING_TO_INLINE") +internal inline fun copyTo( + origin: List, + originDegree: Int, + target: MutableList, +) { + for (deg in 0 .. originDegree) target[deg] = origin[deg] } -/** - * Evaluates the value of the given double polynomial for given double argument. - */ -public fun ListRationalFunction.substitute(arg: Double): Double = - numerator.substitute(arg) / denominator.substitute(arg) +@UnstablePolynomialBoxingOptimization +@Suppress("NOTHING_TO_INLINE") +internal inline fun multiplyAddingToUpdater( + ring: Ring, + multiplicand: MutableList, + multiplicandDegree: Int, + multiplier: List, + multiplierDegree: Int, + updater: MutableList, + zero: C, +) { + multiplyAddingTo( + ring = ring, + multiplicand = multiplicand, + multiplicandDegree = multiplicandDegree, + multiplier = multiplier, + multiplierDegree = multiplierDegree, + target = updater + ) + for (updateDeg in 0 .. multiplicandDegree + multiplierDegree) { + multiplicand[updateDeg] = updater[updateDeg] + updater[updateDeg] = zero + } +} -/** - * Evaluates the value of the given polynomial for given argument. - * - * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). - */ -public fun ListRationalFunction.substitute(ring: Field, arg: C): C = ring { - numerator.substitute(ring, arg) / denominator.substitute(ring, arg) +@UnstablePolynomialBoxingOptimization +@Suppress("NOTHING_TO_INLINE") +internal inline fun multiplyAddingTo( + ring: Ring, + multiplicand: List, + multiplicandDegree: Int, + multiplier: List, + multiplierDegree: Int, + target: MutableList +) = ring { + for (d in 0 .. multiplicandDegree + multiplierDegree) + for (k in max(0, d - multiplierDegree)..min(multiplicandDegree, d)) + target[d] += multiplicand[k] * multiplier[d - k] +} + +@UnstablePolynomialBoxingOptimization +public fun ListPolynomial.substitute2(ring: Ring, arg: ListPolynomial) : ListPolynomial = ring { + if (coefficients.isEmpty()) return ListPolynomial(emptyList()) + + val thisDegree = coefficients.lastIndex + if (thisDegree == -1) return ListPolynomial(emptyList()) + val argDegree = arg.coefficients.lastIndex + if (argDegree == -1) return coefficients[0].asListPolynomial() + val constantZero = zero + val resultCoefs: MutableList = MutableList(thisDegree * argDegree + 1) { constantZero } + resultCoefs[0] = coefficients[thisDegree] + val resultCoefsUpdate: MutableList = MutableList(thisDegree * argDegree + 1) { constantZero } + var resultDegree = 0 + for (deg in thisDegree - 1 downTo 0) { + resultCoefsUpdate[0] = coefficients[deg] + multiplyAddingToUpdater( + ring = ring, + multiplicand = resultCoefs, + multiplicandDegree = resultDegree, + multiplier = arg.coefficients, + multiplierDegree = argDegree, + updater = resultCoefsUpdate, + zero = constantZero + ) + resultDegree += argDegree + } + + return ListPolynomial(resultCoefs) } /** @@ -52,6 +102,7 @@ public fun ListRationalFunction.substitute(ring: Field, arg: C): C = r * * Used in [ListPolynomial.substitute] and [ListRationalFunction.substitute] for performance optimisation. */ // TODO: Дописать +@UnstablePolynomialBoxingOptimization internal fun ListPolynomial.substituteRationalFunctionTakeNumerator(ring: Ring, arg: ListRationalFunction): ListPolynomial = ring { if (coefficients.isEmpty()) return ListPolynomial(emptyList()) @@ -196,26 +247,4 @@ internal fun ListPolynomial.substituteRationalFunctionTakeNumerator(ring: end = thisDegree + 1 ) ) -} - -//operator fun > RationalFunction.invoke(arg: T): T = numerator(arg) / denominator(arg) -// -//fun > RationalFunction.reduced(): RationalFunction = -// polynomialGCD(numerator, denominator).let { -// RationalFunction( -// numerator / it, -// denominator / it -// ) -// } - -///** -// * Returns result of applying formal derivative to the polynomial. -// * -// * @param T Field where we are working now. -// * @return Result of the operator. -// */ -//fun > RationalFunction.derivative() = -// RationalFunction( -// numerator.derivative() * denominator - denominator.derivative() * numerator, -// denominator * denominator -// ) \ No newline at end of file +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt new file mode 100644 index 000000000..8b6fac39e --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt @@ -0,0 +1,13 @@ +/* + * 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.functions + + +@RequiresOptIn( + message = "It's copy of operation with optimized boxing. It's currently unstable.", + level = RequiresOptIn.Level.ERROR +) +internal annotation class UnstablePolynomialBoxingOptimization \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt deleted file mode 100644 index dca8a0cff..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt +++ /dev/null @@ -1,195 +0,0 @@ -/* - * 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.functions - -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.Ring - - -/** - * Returns the same degrees' description of the monomial, but without extra zero degrees on the end. - */ -internal fun List.cleanUp() = subList(0, indexOfLast { it != 0U } + 1) - -// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available - -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > NumberedPolynomialSpace.NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(coefs, toCheckInput) -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(coefs, toCheckInput) -@Suppress("FunctionName") -internal fun > A.NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : NumberedPolynomial { - if (!toCheckInput) return NumberedPolynomial(coefs) - - val fixedCoefs = mutableMapOf, C>() - - for (entry in coefs) { - val key = entry.key.cleanUp() - val value = entry.value - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return NumberedPolynomial(fixedCoefs) -} - -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > NumberedPolynomialSpace.NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(pairs, toCheckInput) -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(pairs, toCheckInput) -@Suppress("FunctionName") -internal fun > A.NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : NumberedPolynomial { - if (!toCheckInput) return NumberedPolynomial(pairs.toMap()) - - val fixedCoefs = mutableMapOf, C>() - - for (entry in pairs) { - val key = entry.first.cleanUp() - val value = entry.second - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return NumberedPolynomial(fixedCoefs) -} - -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > NumberedPolynomialSpace.NumberedPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(pairs = pairs, toCheckInput = toCheckInput) -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(pairs = pairs, toCheckInput = toCheckInput) -@Suppress("FunctionName") -internal fun > A.NumberedPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : NumberedPolynomial { - if (!toCheckInput) return NumberedPolynomial(pairs.toMap()) - - val fixedCoefs = mutableMapOf, C>() - - for (entry in pairs) { - val key = entry.first.cleanUp() - val value = entry.second - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return NumberedPolynomial(fixedCoefs) -} - -@Suppress("FunctionName") -public fun > A.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, toCheckInput = true) -@Suppress("FunctionName") -public fun > NumberedPolynomialSpace.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, toCheckInput = true) -@Suppress("FunctionName") -public fun > NumberedRationalFunctionSpace.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, toCheckInput = true) - -@Suppress("FunctionName") -public fun > A.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > NumberedPolynomialSpace.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > NumberedRationalFunctionSpace.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, toCheckInput = true) - -@Suppress("FunctionName") -public fun > A.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > NumberedPolynomialSpace.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > NumberedRationalFunctionSpace.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs, toCheckInput = true) - -public fun C.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomial(mapOf(emptyList() to this)) - -@DslMarker -@UnstableKMathAPI -internal annotation class NumberedPolynomialConstructorDSL - -@UnstableKMathAPI -@NumberedPolynomialConstructorDSL -public class NumberedPolynomialTermSignatureBuilder { - private val signature: MutableList = ArrayList() - public fun build(): List = signature - public infix fun Int.inPowerOf(deg: UInt) { - if (this > signature.lastIndex) { - signature.addAll(List(this - signature.lastIndex - 1) { 0u }) - signature.add(deg) - } else { - signature[this] = deg - } - } - @Suppress("NOTHING_TO_INLINE") - public inline infix fun Int.pow(deg: UInt): Unit = this inPowerOf deg - @Suppress("NOTHING_TO_INLINE") - public inline infix fun Int.`in`(deg: UInt): Unit = this inPowerOf deg - @Suppress("NOTHING_TO_INLINE") - public inline infix fun Int.of(deg: UInt): Unit = this inPowerOf deg -} - -@UnstableKMathAPI -public class NumberedPolynomialBuilder(private val zero: C, private val add: (C, C) -> C, capacity: Int = 0) { - private val coefficients: MutableMap, C> = LinkedHashMap(capacity) - public fun build(): NumberedPolynomial = NumberedPolynomial(coefficients) - public operator fun C.invoke(block: NumberedPolynomialTermSignatureBuilder.() -> Unit) { - val signature = NumberedPolynomialTermSignatureBuilder().apply(block).build() - coefficients[signature] = add(coefficients.getOrElse(signature) { zero }, this@invoke) - } - @Suppress("NOTHING_TO_INLINE") - public inline infix fun C.with(noinline block: NumberedPolynomialTermSignatureBuilder.() -> Unit): Unit = this.invoke(block) - @Suppress("NOTHING_TO_INLINE") - public inline infix fun (NumberedPolynomialTermSignatureBuilder.() -> Unit).with(coef: C): Unit = coef.invoke(this) - @Suppress("NOTHING_TO_INLINE") - public infix fun sig(block: NumberedPolynomialTermSignatureBuilder.() -> Unit): NumberedPolynomialTermSignatureBuilder.() -> Unit = block -} - -// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available - -@UnstableKMathAPI -@NumberedPolynomialConstructorDSL -@Suppress("FunctionName") -public inline fun > A.NumberedPolynomial(block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder(zero, ::add).apply(block).build() -@UnstableKMathAPI -@NumberedPolynomialConstructorDSL -@Suppress("FunctionName") -public inline fun > A.NumberedPolynomial(capacity: Int, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder(zero, ::add, capacity).apply(block).build() -@UnstableKMathAPI -@NumberedPolynomialConstructorDSL -@Suppress("FunctionName") -public inline fun > NumberedPolynomialSpace.NumberedPolynomial(block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder(constantZero, { left: C, right: C -> left + right}).apply(block).build() -@UnstableKMathAPI -@NumberedPolynomialConstructorDSL -@Suppress("FunctionName") -public inline fun > NumberedPolynomialSpace.NumberedPolynomial(capacity: Int, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder(constantZero, { left: C, right: C -> left + right}, capacity).apply(block).build() - -// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available - -@Suppress("FunctionName") -public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): NumberedRationalFunction = - NumberedRationalFunction( - NumberedPolynomial(numeratorCoefficients, toCheckInput = true), - NumberedPolynomial(denominatorCoefficients, toCheckInput = true) - ) -@Suppress("FunctionName") -public fun > A.NumberedRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): NumberedRationalFunction = - NumberedRationalFunction( - NumberedPolynomial(numeratorCoefficients, toCheckInput = true), - NumberedPolynomial(denominatorCoefficients, toCheckInput = true) - ) -@Suppress("FunctionName") -public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numerator: NumberedPolynomial): NumberedRationalFunction = - NumberedRationalFunction(numerator, polynomialOne) -@Suppress("FunctionName") -public fun > A.NumberedRationalFunction(numerator: NumberedPolynomial): NumberedRationalFunction = - NumberedRationalFunction(numerator, NumberedPolynomial(mapOf(emptyList() to one), toCheckInput = false)) -@Suppress("FunctionName") -public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numeratorCoefficients: Map, C>): NumberedRationalFunction = - NumberedRationalFunction( - NumberedPolynomial(numeratorCoefficients, toCheckInput = true), - polynomialOne - ) -@Suppress("FunctionName") -public fun > A.NumberedRationalFunction(numeratorCoefficients: Map, C>): NumberedRationalFunction = - NumberedRationalFunction( - NumberedPolynomial(numeratorCoefficients, toCheckInput = true), - NumberedPolynomial(mapOf(emptyList() to one), toCheckInput = false) - ) - -//context(A) -//public fun > C.asNumberedRationalFunction() : NumberedRationalFunction = NumberedRationalFunction(asLabeledPolynomial()) -//context(NumberedRationalFunctionSpace) -//public fun > C.asNumberedRationalFunction() : NumberedRationalFunction = NumberedRationalFunction(asLabeledPolynomial()) \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt deleted file mode 100644 index ad817c7ba..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt +++ /dev/null @@ -1,528 +0,0 @@ -package space.kscience.kmath.functions - -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.* -import kotlin.contracts.* -import kotlin.jvm.JvmName -import kotlin.math.max - - -// TODO: Docs - -/** - * Creates a [NumberedPolynomialSpace] over a received ring. - */ -public fun > A.numberedPolynomial(): NumberedPolynomialSpace = - NumberedPolynomialSpace(this) - -/** - * Creates a [NumberedPolynomialSpace]'s scope over a received ring. - */ -@OptIn(ExperimentalContracts::class) -public inline fun , R> A.numberedPolynomial(block: NumberedPolynomialSpace.() -> R): R { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return NumberedPolynomialSpace(this).block() -} - -///** -// * Represents the polynomial as a [String] where name of variable with index `i` is [withVariableName] + `"_${i+1}"`. -// * Consider that monomials are sorted in lexicographic order. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial.represent(withVariableName: String = NumberedPolynomial.defaultVariableName): String = -// coefficients.entries -// .sortedWith { o1, o2 -> NumberedPolynomial.monomialComparator.compare(o1.key, o2.key) } -// .asSequence() -// .map { (degs, t) -> -// if (degs.isEmpty()) "$t" -// else { -// when { -// t.isOne() -> "" -// t.isMinusOne() -> "-" -// else -> "$t " -// } + -// degs -// .mapIndexed { index, deg -> -// when (deg) { -// 0U -> "" -// 1U -> "${withVariableName}_${index+1}" -// else -> "${withVariableName}_${index+1}^$deg" -// } -// } -// .filter { it.isNotEmpty() } -// .joinToString(separator = " ") { it } -// } -// } -// .joinToString(separator = " + ") { it } -// .ifEmpty { "0" } -// -///** -// * Represents the polynomial as a [String] naming variables by [namer]. -// * Consider that monomials are sorted in lexicographic order. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial.represent(namer: (Int) -> String): String = -// coefficients.entries -// .sortedWith { o1, o2 -> NumberedPolynomial.monomialComparator.compare(o1.key, o2.key) } -// .asSequence() -// .map { (degs, t) -> -// if (degs.isEmpty()) "$t" -// else { -// when { -// t.isOne() -> "" -// t.isMinusOne() -> "-" -// else -> "$t " -// } + -// degs -// .mapIndexed { index, deg -> -// when (deg) { -// 0U -> "" -// 1U -> namer(index) -// else -> "${namer(index)}^$deg" -// } -// } -// .filter { it.isNotEmpty() } -// .joinToString(separator = " ") { it } -// } -// } -// .joinToString(separator = " + ") { it } -// .ifEmpty { "0" } -// -///** -// * Represents the polynomial as a [String] where name of variable with index `i` is [withVariableName] + `"_${i+1}"` -// * and with brackets around the string if needed (i.e. when there are at least two addends in the representation). -// * Consider that monomials are sorted in lexicographic order. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial.representWithBrackets(withVariableName: String = NumberedPolynomial.defaultVariableName): String = -// with(represent(withVariableName)) { if (coefficients.count() == 1) this else "($this)" } -// -///** -// * Represents the polynomial as a [String] naming variables by [namer] and with brackets around the string if needed -// * (i.e. when there are at least two addends in the representation). -// * Consider that monomials are sorted in lexicographic order. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial.representWithBrackets(namer: (Int) -> String): String = -// with(represent(namer)) { if (coefficients.count() == 1) this else "($this)" } -// -///** -// * Represents the polynomial as a [String] where name of variable with index `i` is [withVariableName] + `"_${i+1}"`. -// * Consider that monomials are sorted in **reversed** lexicographic order. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial.representReversed(withVariableName: String = NumberedPolynomial.defaultVariableName): String = -// coefficients.entries -// .sortedWith { o1, o2 -> -NumberedPolynomial.monomialComparator.compare(o1.key, o2.key) } -// .asSequence() -// .map { (degs, t) -> -// if (degs.isEmpty()) "$t" -// else { -// when { -// t.isOne() -> "" -// t.isMinusOne() -> "-" -// else -> "$t " -// } + -// degs -// .mapIndexed { index, deg -> -// when (deg) { -// 0U -> "" -// 1U -> "${withVariableName}_${index+1}" -// else -> "${withVariableName}_${index+1}^$deg" -// } -// } -// .filter { it.isNotEmpty() } -// .joinToString(separator = " ") { it } -// } -// } -// .joinToString(separator = " + ") { it } -// .ifEmpty { "0" } -// -///** -// * Represents the polynomial as a [String] naming variables by [namer]. -// * Consider that monomials are sorted in **reversed** lexicographic order. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial.representReversed(namer: (Int) -> String): String = -// coefficients.entries -// .sortedWith { o1, o2 -> -NumberedPolynomial.monomialComparator.compare(o1.key, o2.key) } -// .asSequence() -// .map { (degs, t) -> -// if (degs.isEmpty()) "$t" -// else { -// when { -// t.isOne() -> "" -// t.isMinusOne() -> "-" -// else -> "$t " -// } + -// degs -// .mapIndexed { index, deg -> -// when (deg) { -// 0U -> "" -// 1U -> namer(index) -// else -> "${namer(index)}^$deg" -// } -// } -// .filter { it.isNotEmpty() } -// .joinToString(separator = " ") { it } -// } -// } -// .joinToString(separator = " + ") { it } -// .ifEmpty { "0" } -// -///** -// * Represents the polynomial as a [String] where name of variable with index `i` is [withVariableName] + `"_${i+1}"` -// * and with brackets around the string if needed (i.e. when there are at least two addends in the representation). -// * Consider that monomials are sorted in **reversed** lexicographic order. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial.representReversedWithBrackets(withVariableName: String = NumberedPolynomial.defaultVariableName): String = -// with(representReversed(withVariableName)) { if (coefficients.count() == 1) this else "($this)" } -// -///** -// * Represents the polynomial as a [String] naming variables by [namer] and with brackets around the string if needed -// * (i.e. when there are at least two addends in the representation). -// * Consider that monomials are sorted in **reversed** lexicographic order. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial.representReversedWithBrackets(namer: (Int) -> String): String = -// with(representReversed(namer)) { if (coefficients.count() == 1) this else "($this)" } - -//public fun NumberedPolynomial.substitute(ring: Ring, args: Map): NumberedPolynomial = ring { -// if (coefficients.isEmpty()) return this@substitute -// NumberedPolynomial( -// buildMap { -// coefficients.forEach { (degs, c) -> -// val newDegs = degs.mapIndexed { index, deg -> if (index in args) 0U else deg }.cleanUp() -// val newC = degs.foldIndexed(c) { index, acc, deg -> -// if (index in args) multiplyWithPower(acc, args[index]!!, deg) -// else acc -// } -// this[newDegs] = if (newDegs in this) this[newDegs]!! + newC else newC -// } -// } -// ) -//} -// -//// TODO: Replace with optimisation: the [result] may be unboxed, and all operations may be performed as soon as -//// possible on it -//@JvmName("substitutePolynomial") -//public fun NumberedPolynomial.substitute(ring: Ring, arg: Map>) : NumberedPolynomial = -// ring.numberedPolynomialSpace { -// if (coefficients.isEmpty()) return zero -// coefficients -// .asSequence() -// .map { (degs, c) -> -// degs.foldIndexed( -// NumberedPolynomial( -// degs.mapIndexed { index, deg -> if (index in arg) 0U else deg } to c -// ) -// ) { index, acc, deg -> if (index in arg) multiplyWithPower(acc, arg[index]!!, deg) else acc } -// } -// .reduce { acc, polynomial -> acc + polynomial } // TODO: Rewrite. Might be slow. -// } -// -//// TODO: Substitute rational function -// -//public fun > NumberedPolynomial.asFunctionOver(ring: A): (Map) -> NumberedPolynomial = -// { substitute(ring, it) } -// -//public fun > NumberedPolynomial.asPolynomialFunctionOver(ring: A): (Map>) -> NumberedPolynomial = -// { substitute(ring, it) } - -//operator fun > Polynomial.div(other: T): Polynomial = -// if (other.isZero()) throw ArithmeticException("/ by zero") -// else -// Polynomial( -// coefficients -// .mapValues { it.value / other }, -// toCheckInput = false -// ) - -/** - * Evaluates the value of the given double polynomial for given double argument. - */ -public fun NumberedPolynomial.substitute(args: Map): NumberedPolynomial = Double.algebra { - val acc = LinkedHashMap, Double>(coefficients.size) - for ((degs, c) in coefficients) { - val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp() - val newC = args.entries.fold(c) { product, (variable, substitution) -> - val deg = degs.getOrElse(variable) { 0u } - if (deg == 0u) product else product * substitution.pow(deg.toInt()) - } - if (newDegs !in acc) acc[newDegs] = newC - else acc[newDegs] = acc[newDegs]!! + newC - } - return NumberedPolynomial(acc) -} - -/** - * Evaluates the value of the given polynomial for given argument. - * - * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). - */ -public fun NumberedPolynomial.substitute(ring: Ring, args: Map): NumberedPolynomial = ring { - val acc = LinkedHashMap, C>(coefficients.size) - for ((degs, c) in coefficients) { - val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp() - val newC = args.entries.fold(c) { product, (variable, substitution) -> - val deg = degs.getOrElse(variable) { 0u } - if (deg == 0u) product else product * power(substitution, deg) - } - if (newDegs !in acc) acc[newDegs] = newC - else acc[newDegs] = acc[newDegs]!! + newC - } - return NumberedPolynomial(acc) -} - -// TODO: (Waiting for hero) Replace with optimisation: the [result] may be unboxed, and all operations may be performed -// as soon as possible on it -@JvmName("substitutePolynomial") -public fun NumberedPolynomial.substitute(ring: Ring, args: Map>) : NumberedPolynomial = TODO() /*ring.numberedPolynomial { - val acc = LinkedHashMap, NumberedPolynomial>(coefficients.size) - for ((degs, c) in coefficients) { - val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp() - val newC = args.entries.fold(c.asNumberedPolynomial()) { product, (variable, substitution) -> - val deg = degs.getOrElse(variable) { 0u } - if (deg == 0u) product else product * power(substitution, deg) - } - if (newDegs !in acc) acc[newDegs] = c.asNumberedPolynomial() - else acc[newDegs] = acc[newDegs]!! + c - } -}*/ - -/** - * Represent the polynomial as a regular context-less function. - */ -public fun > NumberedPolynomial.asFunction(ring: A): (Map) -> NumberedPolynomial = { substitute(ring, it) } - -/** - * Represent the polynomial as a regular context-less function. - */ -public fun > NumberedPolynomial.asPolynomialFunctionOver(ring: A): (Map>) -> NumberedPolynomial = { substitute(ring, it) } - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > NumberedPolynomial.derivativeWithRespectTo( - algebra: A, - variable: Int, -): NumberedPolynomial = algebra { - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - if (degs.size > variable) return@forEach - put( - degs.mapIndexed { index, deg -> - when { - index != variable -> deg - deg > 0u -> deg - 1u - else -> return@forEach - } - }.cleanUp(), - multiplyByDoubling(c, degs[variable]) - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > NumberedPolynomial.derivativeWithRespectTo( - algebra: A, - variables: Collection, -): NumberedPolynomial = algebra { - val cleanedVariables = variables.toSet() - if (cleanedVariables.isEmpty()) return this@derivativeWithRespectTo - val maxRespectedVariable = cleanedVariables.maxOrNull()!! - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - if (degs.size > maxRespectedVariable) return@forEach - put( - degs.mapIndexed { index, deg -> - when { - index !in cleanedVariables -> deg - deg > 0u -> deg - 1u - else -> return@forEach - } - }.cleanUp(), - cleanedVariables.fold(c) { acc, variable -> multiplyByDoubling(acc, degs[variable]) } - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > NumberedPolynomial.nthDerivativeWithRespectTo( - algebra: A, - variable: Int, - order: UInt -): NumberedPolynomial = algebra { - if (order == 0u) return this@nthDerivativeWithRespectTo - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - if (degs.size > variable) return@forEach - put( - degs.mapIndexed { index, deg -> - when { - index != variable -> deg - deg >= order -> deg - order - else -> return@forEach - } - }.cleanUp(), - degs[variable].let { deg -> - (deg downTo deg - order + 1u) - .fold(c) { acc, ord -> multiplyByDoubling(acc, ord) } - } - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > NumberedPolynomial.nthDerivativeWithRespectTo( - algebra: A, - variablesAndOrders: Map, -): NumberedPolynomial = algebra { - val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u } - if (filteredVariablesAndOrders.isEmpty()) return this@nthDerivativeWithRespectTo - val maxRespectedVariable = filteredVariablesAndOrders.keys.maxOrNull()!! - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - if (degs.size > maxRespectedVariable) return@forEach - put( - degs.mapIndexed { index, deg -> - if (index !in filteredVariablesAndOrders) return@mapIndexed deg - val order = filteredVariablesAndOrders[index]!! - if (deg >= order) deg - order else return@forEach - }.cleanUp(), - filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> - degs[index].let { deg -> - (deg downTo deg - order + 1u) - .fold(acc1) { acc2, ord -> multiplyByDoubling(acc2, ord) } - } - } - ) - } - } - ) -} - -/** - * Returns algebraic antiderivative of received polynomial. - */ -@UnstableKMathAPI -public fun > NumberedPolynomial.antiderivativeWithRespectTo( - algebra: A, - variable: Int, -): NumberedPolynomial = algebra { - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - put( - List(max(variable + 1, degs.size)) { if (it != variable) degs[it] else degs[it] + 1u }, - c / multiplyByDoubling(one, degs[variable]) - ) - } - } - ) -} - -/** - * Returns algebraic antiderivative of received polynomial. - */ -@UnstableKMathAPI -public fun > NumberedPolynomial.antiderivativeWithRespectTo( - algebra: A, - variables: Collection, -): NumberedPolynomial = algebra { - val cleanedVariables = variables.toSet() - if (cleanedVariables.isEmpty()) return this@antiderivativeWithRespectTo - val maxRespectedVariable = cleanedVariables.maxOrNull()!! - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - put( - List(max(maxRespectedVariable + 1, degs.size)) { if (it !in variables) degs[it] else degs[it] + 1u }, - cleanedVariables.fold(c) { acc, variable -> acc / multiplyByDoubling(one, degs[variable]) } - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > NumberedPolynomial.nthAntiderivativeWithRespectTo( - algebra: A, - variable: Int, - order: UInt -): NumberedPolynomial = algebra { - if (order == 0u) return this@nthAntiderivativeWithRespectTo - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - put( - List(max(variable + 1, degs.size)) { if (it != variable) degs[it] else degs[it] + order }, - degs[variable].let { deg -> - (deg downTo deg - order + 1u) - .fold(c) { acc, ord -> acc / multiplyByDoubling(one, ord) } - } - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > NumberedPolynomial.nthAntiderivativeWithRespectTo( - algebra: A, - variablesAndOrders: Map, -): NumberedPolynomial = algebra { - val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u } - if (filteredVariablesAndOrders.isEmpty()) return this@nthAntiderivativeWithRespectTo - val maxRespectedVariable = filteredVariablesAndOrders.keys.maxOrNull()!! - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - put( - List(max(maxRespectedVariable + 1, degs.size)) { degs[it] + filteredVariablesAndOrders.getOrElse(it) { 0u } }, - filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> - degs[index].let { deg -> - (deg downTo deg - order + 1u) - .fold(acc1) { acc2, ord -> acc2 / multiplyByDoubling(one, ord) } - } - } - ) - } - } - ) -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt deleted file mode 100644 index 5cd0679ab..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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.functions - -import space.kscience.kmath.operations.Ring -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract - - -/** - * Creates a [NumberedRationalFunctionSpace] over a received ring. - */ -public fun > A.numberedRationalFunction(): NumberedRationalFunctionSpace = - NumberedRationalFunctionSpace(this) - -/** - * Creates a [NumberedRationalFunctionSpace]'s scope over a received ring. - */ -public inline fun , R> A.numberedRationalFunction(block: NumberedRationalFunctionSpace.() -> R): R { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return NumberedRationalFunctionSpace(this).block() -} - -//fun > NumberedRationalFunction.reduced(): NumberedRationalFunction { -// val greatestCommonDivider = polynomialGCD(numerator, denominator) -// return NumberedRationalFunction( -// numerator / greatestCommonDivider, -// denominator / greatestCommonDivider -// ) -//} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt index 5401be707..c9950fac5 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt @@ -12,7 +12,7 @@ import kotlin.test.* class ListPolynomialTest { @Test fun test_Polynomial_Int_plus() { - RationalField.listPolynomial { + RationalField.listPolynomialSpace { assertEquals( ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + -3, @@ -52,7 +52,7 @@ class ListPolynomialTest { } @Test fun test_Polynomial_Int_minus() { - RationalField.listPolynomial { + RationalField.listPolynomialSpace { assertEquals( ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - -3, @@ -92,7 +92,7 @@ class ListPolynomialTest { } @Test fun test_Polynomial_Int_times() { - IntModuloRing(35).listPolynomial { + IntModuloRing(35).listPolynomialSpace { assertEquals( ListPolynomial(34, 2, 1, 20, 2), ListPolynomial(22, 26, 13, 15, 26) * 27, @@ -107,7 +107,7 @@ class ListPolynomialTest { } @Test fun test_Int_Polynomial_plus() { - RationalField.listPolynomial { + RationalField.listPolynomialSpace { assertEquals( ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), -3 + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)), @@ -147,7 +147,7 @@ class ListPolynomialTest { } @Test fun test_Int_Polynomial_minus() { - RationalField.listPolynomial { + RationalField.listPolynomialSpace { assertEquals( ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), 3 - ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), @@ -187,7 +187,7 @@ class ListPolynomialTest { } @Test fun test_Int_Polynomial_times() { - IntModuloRing(35).listPolynomial { + IntModuloRing(35).listPolynomialSpace { assertEquals( ListPolynomial(34, 2, 1, 20, 2), 27 * ListPolynomial(22, 26, 13, 15, 26), @@ -202,7 +202,7 @@ class ListPolynomialTest { } @Test fun test_Polynomial_Constant_plus() { - RationalField.listPolynomial { + RationalField.listPolynomialSpace { assertEquals( ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + Rational(-3), @@ -242,7 +242,7 @@ class ListPolynomialTest { } @Test fun test_Polynomial_Constant_minus() { - RationalField.listPolynomial { + RationalField.listPolynomialSpace { assertEquals( ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - Rational(-3), @@ -282,7 +282,7 @@ class ListPolynomialTest { } @Test fun test_Polynomial_Constant_times() { - IntModuloRing(35).listPolynomial { + IntModuloRing(35).listPolynomialSpace { assertEquals( ListPolynomial(34, 2, 1, 20, 2), ListPolynomial(22, 26, 13, 15, 26) * 27.asConstant(), @@ -297,7 +297,7 @@ class ListPolynomialTest { } @Test fun test_Constant_Polynomial_plus() { - RationalField.listPolynomial { + RationalField.listPolynomialSpace { assertEquals( ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), Rational(-3) + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)), @@ -337,7 +337,7 @@ class ListPolynomialTest { } @Test fun test_Constant_Polynomial_minus() { - RationalField.listPolynomial { + RationalField.listPolynomialSpace { assertEquals( ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), Rational(3) - ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), @@ -377,7 +377,7 @@ class ListPolynomialTest { } @Test fun test_Constant_Polynomial_times() { - IntModuloRing(35).listPolynomial { + IntModuloRing(35).listPolynomialSpace { assertEquals( ListPolynomial(34, 2, 1, 20, 2), 27 * ListPolynomial(22, 26, 13, 15, 26), @@ -392,7 +392,7 @@ class ListPolynomialTest { } @Test fun test_Polynomial_unaryMinus() { - RationalField.listPolynomial { + RationalField.listPolynomialSpace { assertEquals( ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), -ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)), @@ -407,7 +407,7 @@ class ListPolynomialTest { } @Test fun test_Polynomial_Polynomial_plus() { - RationalField.listPolynomial { + RationalField.listPolynomialSpace { // (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( ListPolynomial(Rational(-10, 63), Rational(37, 9), Rational(-29, 56)), @@ -440,7 +440,7 @@ class ListPolynomialTest { } @Test fun test_Polynomial_Polynomial_minus() { - RationalField.listPolynomial { + RationalField.listPolynomialSpace { // (5/9 - 8/9 x - 8/7 x^2) - (-5/7 + 5/1 x + 5/8 x^2) ?= 80/63 - 53/9 x - 99/56 x^2 assertEquals( ListPolynomial(Rational(80, 63), Rational(-53, 9), Rational(-99, 56)), @@ -473,7 +473,7 @@ class ListPolynomialTest { } @Test fun test_Polynomial_Polynomial_times() { - IntModuloRing(35).listPolynomial { + IntModuloRing(35).listPolynomialSpace { // (1 + x + x^2) * (1 - x + x^2) ?= 1 + x^2 + x^4 assertEquals( ListPolynomial(1, 0, 1, 0, 1), diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt index c5eb8fb81..69c1611f3 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt @@ -5,6 +5,7 @@ package space.kscience.kmath.functions +import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.test.misc.Rational import space.kscience.kmath.test.misc.RationalField import kotlin.test.Test @@ -12,6 +13,7 @@ import kotlin.test.assertEquals import kotlin.test.assertFailsWith +@OptIn(UnstableKMathAPI::class) class ListPolynomialUtilTest { @Test fun test_substitute_Double() { diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt new file mode 100644 index 000000000..89764db46 --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt @@ -0,0 +1,138 @@ +/* + * 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.functions.ListPolynomial +import space.kscience.kmath.functions.ListPolynomialSpace +import space.kscience.kmath.operations.Ring + + +class IntModulo { + val residue: Int + val modulus: Int + + @PublishedApi + internal constructor(residue: Int, modulus: Int, toCheckInput: Boolean = true) { + if (toCheckInput) { + require(modulus != 0) { "modulus can not be zero" } + this.modulus = if (modulus < 0) -modulus else modulus + this.residue = residue.mod(modulus) + } else { + this.residue = residue + this.modulus = modulus + } + } + + constructor(residue: Int, modulus: Int) : this(residue, modulus, true) + + operator fun unaryPlus(): IntModulo = this + operator fun unaryMinus(): IntModulo = + IntModulo( + if (residue == 0) 0 else modulus - residue, + modulus, + toCheckInput = false + ) + operator fun plus(other: IntModulo): IntModulo { + require(modulus == other.modulus) { "can not add two residue different modulo" } + return IntModulo( + (residue + other.residue) % modulus, + modulus, + toCheckInput = false + ) + } + operator fun plus(other: Int): IntModulo = + IntModulo( + (residue + other) % modulus, + modulus, + toCheckInput = false + ) + operator fun minus(other: IntModulo): IntModulo { + require(modulus == other.modulus) { "can not subtract two residue different modulo" } + return IntModulo( + (residue - other.residue) % modulus, + modulus, + toCheckInput = false + ) + } + operator fun minus(other: Int): IntModulo = + IntModulo( + (residue - other) % modulus, + modulus, + toCheckInput = false + ) + operator fun times(other: IntModulo): IntModulo { + require(modulus == other.modulus) { "can not multiply two residue different modulo" } + return IntModulo( + (residue * other.residue) % modulus, + modulus, + toCheckInput = false + ) + } + operator fun times(other: Int): IntModulo = + IntModulo( + (residue * other) % modulus, + modulus, + toCheckInput = false + ) + operator fun div(other: IntModulo): IntModulo { + require(modulus == other.modulus) { "can not divide two residue different modulo" } + val (reciprocalCandidate, gcdOfOtherResidueAndModulus) = bezoutIdentityWithGCD(other.residue, modulus) + require(gcdOfOtherResidueAndModulus == 1) { "can not divide to residue that has non-trivial GCD with modulo" } + return IntModulo( + (residue * reciprocalCandidate) % modulus, + modulus, + toCheckInput = false + ) + } + operator fun div(other: Int): IntModulo { + val (reciprocalCandidate, gcdOfOtherResidueAndModulus) = bezoutIdentityWithGCD(other, modulus) + require(gcdOfOtherResidueAndModulus == 1) { "can not divide to residue that has non-trivial GCD with modulo" } + return IntModulo( + (residue * reciprocalCandidate) % modulus, + modulus, + toCheckInput = false + ) + } + override fun equals(other: Any?): Boolean = + when (other) { + is IntModulo -> residue == other.residue && modulus == other.modulus + else -> false + } + + override fun hashCode(): Int = residue.hashCode() + + override fun toString(): String = "$residue mod $modulus" +} + +@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") +class IntModuloRing : Ring { + + val modulus: Int + + constructor(modulus: Int) { + require(modulus != 0) { "modulus can not be zero" } + this.modulus = if (modulus < 0) -modulus else modulus + } + + override inline val zero: IntModulo get() = IntModulo(0, modulus, toCheckInput = false) + override inline val one: IntModulo get() = IntModulo(1, modulus, toCheckInput = false) + + fun number(arg: Int) = IntModulo(arg, modulus, toCheckInput = false) + + override inline fun add(left: IntModulo, right: IntModulo): IntModulo = left + right + override inline fun multiply(left: IntModulo, right: IntModulo): IntModulo = left * right + + override inline fun IntModulo.unaryMinus(): IntModulo = -this + override inline fun IntModulo.plus(arg: IntModulo): IntModulo = this + arg + override inline fun IntModulo.minus(arg: IntModulo): IntModulo = this - arg + override inline fun IntModulo.times(arg: IntModulo): IntModulo = this * arg + inline fun IntModulo.div(arg: IntModulo): IntModulo = this / arg +} + +fun ListPolynomialSpace.ListPolynomial(vararg coefs: Int): ListPolynomial = + ListPolynomial(coefs.map { IntModulo(it, ring.modulus) }) +fun IntModuloRing.ListPolynomial(vararg coefs: Int): ListPolynomial = + ListPolynomial(coefs.map { IntModulo(it, modulus) }) \ No newline at end of file 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..72bb5942c --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt @@ -0,0 +1,135 @@ +/* + * 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.Field +import space.kscience.kmath.operations.NumbersAddOps + +class Rational { + companion object { + val ZERO: Rational = Rational(0L) + val ONE: Rational = Rational(1L) + } + + val numerator: Long + val denominator: Long + + internal constructor(numerator: Long, denominator: Long, toCheckInput: Boolean = true) { + if (toCheckInput) { + if (denominator == 0L) throw ArithmeticException("/ by zero") + + val greatestCommonDivider = gcd(numerator, denominator).let { if (denominator < 0L) -it else it } + + this.numerator = numerator / greatestCommonDivider + this.denominator = denominator / greatestCommonDivider + } else { + this.numerator = numerator + this.denominator = denominator + } + } + + constructor(numerator: Int, denominator: Int) : this(numerator.toLong(), denominator.toLong(), true) + constructor(numerator: Int, denominator: Long) : this(numerator.toLong(), denominator, true) + constructor(numerator: Long, denominator: Int) : this(numerator, denominator.toLong(), true) + constructor(numerator: Long, denominator: Long) : this(numerator, denominator, true) + constructor(numerator: Int) : this(numerator.toLong(), 1L, false) + constructor(numerator: Long) : this(numerator, 1L, false) + + operator fun unaryPlus(): Rational = this + operator fun unaryMinus(): Rational = Rational(-this.numerator, this.denominator) + operator fun plus(other: Rational): Rational = + Rational( + numerator * other.denominator + denominator * other.numerator, + denominator * other.denominator + ) + operator fun plus(other: Int): Rational = + Rational( + numerator + denominator * other.toLong(), + denominator + ) + operator fun plus(other: Long): Rational = + Rational( + numerator + denominator * other, + denominator + ) + operator fun minus(other: Rational): Rational = + Rational( + numerator * other.denominator - denominator * other.numerator, + denominator * other.denominator + ) + operator fun minus(other: Int): Rational = + Rational( + numerator - denominator * other.toLong(), + denominator + ) + operator fun minus(other: Long): Rational = + Rational( + numerator - denominator * other, + denominator + ) + operator fun times(other: Rational): Rational = + Rational( + numerator * other.numerator, + denominator * other.denominator + ) + operator fun times(other: Int): Rational = + Rational( + numerator * other.toLong(), + denominator + ) + operator fun times(other: Long): Rational = + Rational( + numerator * other, + denominator + ) + operator fun div(other: Rational): Rational = + Rational( + numerator * other.denominator, + denominator * other.numerator + ) + operator fun div(other: Int): Rational = + Rational( + numerator, + denominator * other.toLong() + ) + operator fun div(other: Long): Rational = + Rational( + numerator, + denominator * other + ) + override fun equals(other: Any?): Boolean = + when (other) { + is Rational -> numerator == other.numerator && denominator == other.denominator + is Int -> numerator == other && denominator == 1L + is Long -> numerator == other && denominator == 1L + else -> false + } + + override fun hashCode(): Int = 31 * numerator.hashCode() + denominator.hashCode() + + override fun toString(): String = if (denominator == 1L) "$numerator" else "$numerator/$denominator" +} + +@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") +@OptIn(UnstableKMathAPI::class) +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/misc.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt new file mode 100644 index 000000000..ed41b9245 --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt @@ -0,0 +1,29 @@ +/* + * 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 kotlin.math.abs + + +data class BezoutIdentityWithGCD(val first: T, val second: T, val gcd: T) + +tailrec fun gcd(a: Long, b: Long): Long = if (a == 0L) abs(b) else gcd(b % a, a) + +fun bezoutIdentityWithGCD(a: Int, b: Int): BezoutIdentityWithGCD = + when { + a < 0 && b < 0 -> with(bezoutIdentityWithGCDInternalLogic(-a, -b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(-first, -second, gcd) } + a < 0 -> with(bezoutIdentityWithGCDInternalLogic(-a, b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(-first, second, gcd) } + b < 0 -> with(bezoutIdentityWithGCDInternalLogic(a, -b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(first, -second, gcd) } + else -> bezoutIdentityWithGCDInternalLogic(a, b, 1, 0, 0, 1) + } + +internal tailrec fun bezoutIdentityWithGCDInternalLogic(a: Int, b: Int, m1: Int, m2: Int, m3: Int, m4: Int): BezoutIdentityWithGCD = + if (b == 0) BezoutIdentityWithGCD(m1, m3, a) + else { + val quotient = a / b + val reminder = a % b + bezoutIdentityWithGCDInternalLogic(b, reminder, m2, m1 - quotient * m2, m4, m3 - quotient * m4) + } \ No newline at end of file -- 2.34.1 From 5928adfe45fc4b1d608e94fb5b2c12c447377c24 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Mon, 13 Jun 2022 12:08:58 +0300 Subject: [PATCH 073/123] Fixed merging accidents. --- .../kscience/kmath/functions/Piecewise.kt | 132 ++++++++++++++++++ .../kmath/integration/SplineIntegrator.kt | 112 +++++++++++++++ .../kmath/interpolation/Interpolator.kt | 92 ++++++++++++ .../kmath/interpolation/LinearInterpolator.kt | 43 ++++++ .../kmath/interpolation/SplineInterpolator.kt | 88 ++++++++++++ .../kmath/integration/SplineIntegralTest.kt | 48 +++++++ .../interpolation/LinearInterpolatorTest.kt | 29 ++++ .../interpolation/SplineInterpolatorTest.kt | 36 +++++ 8 files changed, 580 insertions(+) create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt new file mode 100644 index 000000000..612b00535 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt @@ -0,0 +1,132 @@ +/* + * 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.functions + +import space.kscience.kmath.misc.PerformancePitfall +import space.kscience.kmath.operations.Ring + +/** + * Represents piecewise-defined function. + * + * @param T the piece key type. + * @param R the sub-function type. + */ +public fun interface Piecewise { + /** + * Returns the appropriate sub-function for given piece key. + */ + public fun findPiece(arg: T): R? +} + +/** + * Represents piecewise-defined function where all the sub-functions are polynomials. + * + * @property pieces An ordered list of range-polynomial pairs. The list does not in general guarantee that there are no + * "holes" in it. + */ +public interface PiecewisePolynomial> : Piecewise> { + public val pieces: Collection, ListPolynomial>> + + override fun findPiece(arg: T): ListPolynomial? +} + +/** + * A generic piecewise without constraints on how pieces are placed + */ +@PerformancePitfall("findPiece method of resulting piecewise is slow") +public fun > PiecewisePolynomial( + pieces: Collection, ListPolynomial>>, +): PiecewisePolynomial = object : PiecewisePolynomial { + override val pieces: Collection, ListPolynomial>> = pieces + + override fun findPiece(arg: T): ListPolynomial? = pieces.firstOrNull { arg in it.first }?.second +} + +/** + * An optimized piecewise that uses not separate pieces, but a range separated by delimiters. + * The pieces search is logarithmic. + */ +private class OrderedPiecewisePolynomial>( + override val pieces: List, ListPolynomial>>, +) : PiecewisePolynomial { + + override fun findPiece(arg: T): ListPolynomial? { + val index = pieces.binarySearch { (range, _) -> + when { + arg >= range.endInclusive -> -1 + arg < range.start -> +1 + else -> 0 + } + } + return if (index < 0) null else pieces[index].second + } + +} + +/** + * A [Piecewise] builder where all the pieces are ordered by the [Comparable] type instances. + * + * @param T the comparable piece key type. + * @param delimiter the initial piecewise separator + */ +public class PiecewiseBuilder>(delimiter: T) { + private val delimiters: MutableList = arrayListOf(delimiter) + private val pieces: MutableList> = arrayListOf() + + /** + * Dynamically adds a piece to the right side (beyond maximum argument value of previous piece) + * + * @param right new rightmost position. If is less than current rightmost position, an error is thrown. + * @param piece the sub-function. + */ + public fun putRight(right: T, piece: ListPolynomial) { + require(right > delimiters.last()) { "New delimiter should be to the right of old one" } + delimiters += right + pieces += piece + } + + /** + * Dynamically adds a piece to the left side (beyond maximum argument value of previous piece) + * + * @param left the new leftmost position. If is less than current rightmost position, an error is thrown. + * @param piece the sub-function. + */ + public fun putLeft(left: T, piece: ListPolynomial) { + require(left < delimiters.first()) { "New delimiter should be to the left of old one" } + delimiters.add(0, left) + pieces.add(0, piece) + } + + public fun build(): PiecewisePolynomial = OrderedPiecewisePolynomial(delimiters.zipWithNext { l, r -> + l..r + }.zip(pieces)) +} + +/** + * A builder for [PiecewisePolynomial] + */ +public fun > PiecewisePolynomial( + startingPoint: T, + builder: PiecewiseBuilder.() -> Unit, +): PiecewisePolynomial = PiecewiseBuilder(startingPoint).apply(builder).build() + +/** + * Return a value of polynomial function with given [ring] a given [arg] or null if argument is outside piecewise + * definition. + */ +public fun , C : Ring> PiecewisePolynomial.substitute(ring: C, arg: T): T? = + findPiece(arg)?.substitute(ring, arg) + +/** + * Convert this polynomial to a function returning nullable value (null if argument is outside piecewise range). + */ +public fun , C : Ring> PiecewisePolynomial.asFunction(ring: C): (T) -> T? = { substitute(ring, it) } + +/** + * Convert this polynomial to a function using [defaultValue] for arguments outside the piecewise range. + */ +public fun , C : Ring> PiecewisePolynomial.asFunction(ring: C, defaultValue: T): (T) -> T = + { substitute(ring, it) ?: defaultValue } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt new file mode 100644 index 000000000..80006c2de --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt @@ -0,0 +1,112 @@ +/* + * 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. + */ + +/* + * 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.integration + +import space.kscience.kmath.functions.PiecewisePolynomial +import space.kscience.kmath.functions.integrate +import space.kscience.kmath.functions.antiderivative +import space.kscience.kmath.interpolation.PolynomialInterpolator +import space.kscience.kmath.interpolation.SplineInterpolator +import space.kscience.kmath.interpolation.interpolatePolynomials +import space.kscience.kmath.misc.PerformancePitfall +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.* +import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.DoubleBuffer +import space.kscience.kmath.structures.MutableBufferFactory + +/** + * Compute analytical indefinite integral of this [PiecewisePolynomial], keeping all intervals intact + */ +@OptIn(PerformancePitfall::class) +@UnstableKMathAPI +public fun > PiecewisePolynomial.integrate(algebra: Field): PiecewisePolynomial = + PiecewisePolynomial(pieces.map { it.first to it.second.antiderivative(algebra) }) + +/** + * Compute definite integral of given [PiecewisePolynomial] piece by piece in a given [range] + * Requires [UnivariateIntegrationNodes] or [IntegrationRange] and [IntegrandMaxCalls] + * + * TODO use context receiver for algebra + */ +@UnstableKMathAPI +public fun > PiecewisePolynomial.integrate( + algebra: Field, range: ClosedRange, +): T = algebra.sum( + pieces.map { (region, poly) -> + val intersectedRange = maxOf(range.start, region.start)..minOf(range.endInclusive, region.endInclusive) + //Check if polynomial range is not used + if (intersectedRange.start == intersectedRange.endInclusive) algebra.zero + else poly.integrate(algebra, intersectedRange) + } +) + +/** + * A generic spline-interpolation-based analytic integration + * * [IntegrationRange]—the univariate range of integration. By default, uses `0..1` interval. + * * [IntegrandMaxCalls]—the maximum number of function calls during integration. For non-iterative rules, always uses + * the maximum number of points. By default, uses 10 points. + */ +@UnstableKMathAPI +public class SplineIntegrator>( + public val algebra: Field, + public val bufferFactory: MutableBufferFactory, +) : UnivariateIntegrator { + override fun process(integrand: UnivariateIntegrand): UnivariateIntegrand = algebra { + val range = integrand.getFeature()?.range ?: 0.0..1.0 + + val interpolator: PolynomialInterpolator = SplineInterpolator(algebra, bufferFactory) + + val nodes: Buffer = integrand.getFeature()?.nodes ?: run { + val numPoints = integrand.getFeature()?.maxCalls ?: 100 + val step = (range.endInclusive - range.start) / (numPoints - 1) + DoubleBuffer(numPoints) { i -> range.start + i * step } + } + + val values = nodes.map(bufferFactory) { integrand.function(it) } + val polynomials = interpolator.interpolatePolynomials( + nodes.map(bufferFactory) { number(it) }, + values + ) + val res = polynomials.integrate(algebra, number(range.start)..number(range.endInclusive)) + integrand + IntegrandValue(res) + IntegrandCallsPerformed(integrand.calls + nodes.size) + } +} + +/** + * A simplified double-based spline-interpolation-based analytic integration + * * [IntegrationRange]—the univariate range of integration. By default, uses `0.0..1.0` interval. + * * [IntegrandMaxCalls]—the maximum number of function calls during integration. For non-iterative rules, always + * uses the maximum number of points. By default, uses 10 points. + */ +@UnstableKMathAPI +public object DoubleSplineIntegrator : UnivariateIntegrator { + override fun process(integrand: UnivariateIntegrand): UnivariateIntegrand { + val range = integrand.getFeature()?.range ?: 0.0..1.0 + val interpolator: PolynomialInterpolator = SplineInterpolator(DoubleField, ::DoubleBuffer) + + val nodes: Buffer = integrand.getFeature()?.nodes ?: run { + val numPoints = integrand.getFeature()?.maxCalls ?: 100 + val step = (range.endInclusive - range.start) / (numPoints - 1) + DoubleBuffer(numPoints) { i -> range.start + i * step } + } + + val values = nodes.map { integrand.function(it) } + val polynomials = interpolator.interpolatePolynomials(nodes, values) + val res = polynomials.integrate(DoubleField, range) + return integrand + IntegrandValue(res) + IntegrandCallsPerformed(integrand.calls + nodes.size) + } +} + +@Suppress("unused") +@UnstableKMathAPI +public inline val DoubleField.splineIntegrator: UnivariateIntegrator + get() = DoubleSplineIntegrator \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt new file mode 100644 index 000000000..62819be0c --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt @@ -0,0 +1,92 @@ +/* + * 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. + */ + +@file:OptIn(UnstableKMathAPI::class) + +package space.kscience.kmath.interpolation + +import space.kscience.kmath.data.XYColumnarData +import space.kscience.kmath.functions.PiecewisePolynomial +import space.kscience.kmath.functions.asFunction +import space.kscience.kmath.functions.substitute +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.Ring +import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.asBuffer + +/** + * And interpolator for data with x column type [X], y column type [Y]. + */ +public fun interface Interpolator { + public fun interpolate(points: XYColumnarData): (X) -> Y +} + +/** + * And interpolator returning [PiecewisePolynomial] function + */ +public interface PolynomialInterpolator> : Interpolator { + public val algebra: Ring + + public fun getDefaultValue(): T = error("Out of bounds") + + public fun interpolatePolynomials(points: XYColumnarData): PiecewisePolynomial + + override fun interpolate(points: XYColumnarData): (T) -> T = { x -> + interpolatePolynomials(points).substitute(algebra, x) ?: getDefaultValue() + } +} + + +public fun > PolynomialInterpolator.interpolatePolynomials( + x: Buffer, + y: Buffer, +): PiecewisePolynomial { + val pointSet = XYColumnarData.of(x, y) + return interpolatePolynomials(pointSet) +} + +public fun > PolynomialInterpolator.interpolatePolynomials( + data: Map, +): PiecewisePolynomial { + val pointSet = XYColumnarData.of(data.keys.toList().asBuffer(), data.values.toList().asBuffer()) + return interpolatePolynomials(pointSet) +} + +public fun > PolynomialInterpolator.interpolatePolynomials( + data: List>, +): PiecewisePolynomial { + val pointSet = XYColumnarData.of(data.map { it.first }.asBuffer(), data.map { it.second }.asBuffer()) + return interpolatePolynomials(pointSet) +} + +public fun > PolynomialInterpolator.interpolate( + x: Buffer, + y: Buffer, +): (T) -> T? = interpolatePolynomials(x, y).asFunction(algebra) + +public fun > PolynomialInterpolator.interpolate( + data: Map, +): (T) -> T? = interpolatePolynomials(data).asFunction(algebra) + +public fun > PolynomialInterpolator.interpolate( + data: List>, +): (T) -> T? = interpolatePolynomials(data).asFunction(algebra) + + +public fun > PolynomialInterpolator.interpolate( + x: Buffer, + y: Buffer, + defaultValue: T, +): (T) -> T = interpolatePolynomials(x, y).asFunction(algebra, defaultValue) + +public fun > PolynomialInterpolator.interpolate( + data: Map, + defaultValue: T, +): (T) -> T = interpolatePolynomials(data).asFunction(algebra, defaultValue) + +public fun > PolynomialInterpolator.interpolate( + data: List>, + defaultValue: T, +): (T) -> T = interpolatePolynomials(data).asFunction(algebra, defaultValue) \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt new file mode 100644 index 000000000..b55f16cf2 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt @@ -0,0 +1,43 @@ +/* + * 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.interpolation + +import space.kscience.kmath.data.XYColumnarData +import space.kscience.kmath.functions.PiecewisePolynomial +import space.kscience.kmath.functions.ListPolynomial +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.Field +import space.kscience.kmath.operations.invoke + +@OptIn(UnstableKMathAPI::class) +internal fun > insureSorted(points: XYColumnarData<*, T, *>) { + for (i in 0 until points.size - 1) + require(points.x[i + 1] > points.x[i]) { "Input data is not sorted at index $i" } +} + +/** + * Reference JVM implementation: https://github.com/apache/commons-math/blob/master/src/main/java/org/apache/commons/math4/analysis/interpolation/LinearInterpolator.java + */ +public class LinearInterpolator>(override val algebra: Field) : PolynomialInterpolator { + + @OptIn(UnstableKMathAPI::class) + override fun interpolatePolynomials(points: XYColumnarData): PiecewisePolynomial = algebra { + require(points.size > 0) { "Point array should not be empty" } + insureSorted(points) + + PiecewisePolynomial(points.x[0]) { + for (i in 0 until points.size - 1) { + val slope = (points.y[i + 1] - points.y[i]) / (points.x[i + 1] - points.x[i]) + val const = points.y[i] - slope * points.x[i] + val polynomial = ListPolynomial(const, slope) + putRight(points.x[i + 1], polynomial) + } + } + } +} + +public val > Field.linearInterpolator: LinearInterpolator + get() = LinearInterpolator(this) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt new file mode 100644 index 000000000..0bcbfd0c6 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt @@ -0,0 +1,88 @@ +/* + * 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. + */ + +/* + * 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.interpolation + +import space.kscience.kmath.data.XYColumnarData +import space.kscience.kmath.functions.PiecewisePolynomial +import space.kscience.kmath.functions.ListPolynomial +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.operations.Field +import space.kscience.kmath.operations.invoke +import space.kscience.kmath.structures.DoubleBuffer +import space.kscience.kmath.structures.MutableBufferFactory + +/** + * Generic spline interpolator. Not recommended for performance critical places, use platform-specific and type + * specific ones. + * + * Based on + * https://github.com/apache/commons-math/blob/eb57d6d457002a0bb5336d789a3381a24599affe/src/main/java/org/apache/commons/math4/analysis/interpolation/SplineInterpolator.java + */ +public class SplineInterpolator>( + override val algebra: Field, + public val bufferFactory: MutableBufferFactory, +) : PolynomialInterpolator { + //TODO possibly optimize zeroed buffers + + @OptIn(UnstableKMathAPI::class) + override fun interpolatePolynomials(points: XYColumnarData): PiecewisePolynomial = algebra { + require(points.size >= 3) { "Can't use spline interpolator with less than 3 points" } + insureSorted(points) + // Number of intervals. The number of data points is n + 1. + val n = points.size - 1 + // Differences between knot points + val h = bufferFactory(n) { i -> points.x[i + 1] - points.x[i] } + val mu = bufferFactory(n) { zero } + val z = bufferFactory(n + 1) { zero } + + for (i in 1 until n) { + val g = 2.0 * (points.x[i + 1] - points.x[i - 1]) - h[i - 1] * mu[i - 1] + mu[i] = h[i] / g + z[i] = + ((points.y[i + 1] * h[i - 1] - points.y[i] * (points.x[i + 1] - points.x[i - 1]) + points.y[i - 1] * h[i]) * 3.0 / + (h[i - 1] * h[i]) - h[i - 1] * z[i - 1]) / g + } + + // cubic spline coefficients -- b is linear, c quadratic, d is cubic (original y's are constants) + + PiecewisePolynomial(points.x[points.size - 1]) { + var cOld = zero + + for (j in n - 1 downTo 0) { + val c = z[j] - mu[j] * cOld + val a = points.y[j] + val b = (points.y[j + 1] - points.y[j]) / h[j] - h[j] * (cOld + 2.0 * c) / 3.0 + val d = (cOld - c) / (3.0 * h[j]) + val x0 = points.x[j] + val x02 = x0 * x0 + val x03 = x02 * x0 + //Shift coefficients to represent absolute polynomial instead of one with an offset + val polynomial = ListPolynomial( + a - b * x0 + c * x02 - d * x03, + b - 2 * c * x0 + 3 * d * x02, + c - 3 * d * x0, + d + ) + cOld = c + putLeft(x0, polynomial) + } + } + } +} + + +public fun > Field.splineInterpolator( + bufferFactory: MutableBufferFactory, +): SplineInterpolator = SplineInterpolator(this, bufferFactory) + +public val DoubleField.splineInterpolator: SplineInterpolator + get() = SplineInterpolator(this, ::DoubleBuffer) \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt new file mode 100644 index 000000000..aae0ad017 --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt @@ -0,0 +1,48 @@ +/* + * 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.integration + +import space.kscience.kmath.functions.ListPolynomial +import space.kscience.kmath.functions.integrate +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.DoubleField +import kotlin.math.PI +import kotlin.math.sin +import kotlin.test.Test +import kotlin.test.assertEquals + +@OptIn(UnstableKMathAPI::class) +class SplineIntegralTest { + + @Test + fun integratePolynomial(){ + val polynomial = ListPolynomial(1.0, 2.0, 3.0) + val integral = polynomial.integrate(DoubleField,1.0..2.0) + assertEquals(11.0, integral, 0.001) + } + + @Test + fun gaussSin() { + val res = DoubleField.splineIntegrator.integrate(0.0..2 * PI, IntegrandMaxCalls(5)) { x -> + sin(x) + } + assertEquals(0.0, res.value, 1e-2) + } + + @Test + fun gaussUniform() { + val res = DoubleField.splineIntegrator.integrate(35.0..100.0, IntegrandMaxCalls(20)) { x -> + if(x in 30.0..50.0){ + 1.0 + } else { + 0.0 + } + } + assertEquals(15.0, res.value, 0.5) + } + + +} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt new file mode 100644 index 000000000..1143036d4 --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt @@ -0,0 +1,29 @@ +/* + * 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.interpolation + +import space.kscience.kmath.operations.DoubleField +import kotlin.test.Test +import kotlin.test.assertEquals + +internal class LinearInterpolatorTest { + @Test + fun testInterpolation() { + val data = listOf( + 0.0 to 0.0, + 1.0 to 1.0, + 2.0 to 3.0, + 3.0 to 4.0 + ) + + //val polynomial: PiecewisePolynomial = DoubleField.linearInterpolator.interpolatePolynomials(data) + val function = DoubleField.linearInterpolator.interpolate(data) + assertEquals(null, function(-1.0)) + assertEquals(0.5, function(0.5)) + assertEquals(2.0, function(1.5)) + assertEquals(3.0, function(2.0)) + } +} diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt new file mode 100644 index 000000000..f748535e2 --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt @@ -0,0 +1,36 @@ +/* + * 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. + */ + +/* + * 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.interpolation + +import space.kscience.kmath.operations.DoubleField +import kotlin.math.PI +import kotlin.math.sin +import kotlin.test.Test +import kotlin.test.assertEquals + +internal class SplineInterpolatorTest { + @Test + fun testInterpolation() { + val data = (0..10).map { + val x = it.toDouble() / 5 * PI + x to sin(x) + } + + //val polynomial: PiecewisePolynomial = DoubleField.splineInterpolator.interpolatePolynomials(data) + + val function = DoubleField.splineInterpolator.interpolate(data, Double.NaN) + + assertEquals(Double.NaN, function(-1.0)) + assertEquals(sin(0.5), function(0.5), 0.1) + assertEquals(sin(1.5), function(1.5), 0.1) + assertEquals(sin(2.0), function(2.0), 0.1) + } +} -- 2.34.1 From 58e0715714487323a46f5b86e121a46782d356c5 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Mon, 13 Jun 2022 12:15:14 +0300 Subject: [PATCH 074/123] Removed duplicates of copyright comments. --- .../space/kscience/kmath/integration/SplineIntegrator.kt | 5 ----- .../space/kscience/kmath/interpolation/SplineInterpolator.kt | 5 ----- .../kscience/kmath/interpolation/SplineInterpolatorTest.kt | 5 ----- 3 files changed, 15 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt index 80006c2de..0fcd4c6e5 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt @@ -3,11 +3,6 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -/* - * 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.integration import space.kscience.kmath.functions.PiecewisePolynomial diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt index 0bcbfd0c6..48c90ff23 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt @@ -3,11 +3,6 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -/* - * 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.interpolation import space.kscience.kmath.data.XYColumnarData diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt index f748535e2..4c7d816d4 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt @@ -3,11 +3,6 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -/* - * 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.interpolation import space.kscience.kmath.operations.DoubleField -- 2.34.1 From d0134bdbe9eb65b45f3764c775e657ee0186d163 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Tue, 14 Jun 2022 19:15:36 +0300 Subject: [PATCH 075/123] Sift 4. Cleaned up "numbered" case. Tests are in progress. --- .../kmath/operations/bufferOperation.kt | 9 + .../kmath/functions/ListPolynomial.kt | 24 +- .../kmath/functions/ListRationalFunction.kt | 34 +- .../kmath/functions/NumberedPolynomial.kt | 429 +++++++++++++++ .../functions/NumberedRationalFunction.kt | 239 ++++++++ .../kmath/functions/RationalFunction.kt | 8 + .../kscience/kmath/functions/listUtil.kt | 43 +- .../kmath/functions/numberedConstructors.kt | 478 ++++++++++++++++ .../kscience/kmath/functions/numberedUtil.kt | 515 ++++++++++++++++++ 9 files changed, 1724 insertions(+), 55 deletions(-) create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/bufferOperation.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/bufferOperation.kt index 31b0c2841..762f08be1 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/bufferOperation.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/bufferOperation.kt @@ -91,6 +91,15 @@ public inline fun Buffer.fold(initial: R, operation: (acc: R, T) return accumulator } +/** + * Fold given buffer according to indexed [operation] + */ +public inline fun Buffer.foldIndexed(initial: R, operation: (index: Int, acc: R, T) -> R): R { + var accumulator = initial + for (index in this.indices) accumulator = operation(index, accumulator, get(index)) + return accumulator +} + /** * Zip two buffers using given [transform]. */ diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt index fce179fc8..42e3f7301 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt @@ -48,8 +48,8 @@ public data class ListPolynomial( } /** - * Arithmetic context for univariate polynomials with coefficients stored as a [List] constructed with the given [ring] - * of constants. + * Arithmetic context for univariate polynomials with coefficients stored as a [List] constructed with the provided + * [ring] of constants. * * @param C the type of constants. Polynomials have them a coefficients in their terms. * @param A type of provided underlying ring of constants. It's [Ring] of [C]. @@ -313,6 +313,10 @@ public open class ListPolynomialSpace>( } ) } + /** + * Raises [arg] to the integer power [exponent]. + */ // TODO: To optimize boxing + override fun power(arg: ListPolynomial, exponent: UInt): ListPolynomial = super.power(arg, exponent) /** * Instance of zero polynomial (zero of the polynomial ring). @@ -332,42 +336,42 @@ public open class ListPolynomialSpace>( // TODO: When context receivers will be ready move all of this substitutions and invocations to utilities with // [ListPolynomialSpace] as a context receiver /** - * Evaluates value of [this] polynomial on provided argument. + * Evaluates value of [this] polynomial on provided [argument]. */ @Suppress("NOTHING_TO_INLINE") - public inline fun ListPolynomial.substitute(argument: C): C = this.substitute(ring, argument) + public inline fun ListPolynomial.substitute(argument: C): C = substitute(ring, argument) /** * Substitutes provided polynomial [argument] into [this] polynomial. */ @Suppress("NOTHING_TO_INLINE") - public inline fun ListPolynomial.substitute(argument: ListPolynomial): ListPolynomial = this.substitute(ring, argument) + public inline fun ListPolynomial.substitute(argument: ListPolynomial): ListPolynomial = substitute(ring, argument) /** * Represent [this] polynomial as a regular context-less function. */ @Suppress("NOTHING_TO_INLINE") - public inline fun ListPolynomial.asFunction(): (C) -> C = { this.substitute(ring, it) } + public inline fun ListPolynomial.asFunction(): (C) -> C = asFunctionOver(ring) /** * Represent [this] polynomial as a regular context-less function. */ @Suppress("NOTHING_TO_INLINE") - public inline fun ListPolynomial.asFunctionOfConstant(): (C) -> C = { this.substitute(ring, it) } + public inline fun ListPolynomial.asFunctionOfConstant(): (C) -> C = asFunctionOfConstantOver(ring) /** * Represent [this] polynomial as a regular context-less function. */ @Suppress("NOTHING_TO_INLINE") - public inline fun ListPolynomial.asFunctionOfPolynomial(): (ListPolynomial) -> ListPolynomial = { this.substitute(ring, it) } + public inline fun ListPolynomial.asFunctionOfPolynomial(): (ListPolynomial) -> ListPolynomial = asFunctionOfPolynomialOver(ring) /** * Evaluates value of [this] polynomial on provided [argument]. */ @Suppress("NOTHING_TO_INLINE") - public inline operator fun ListPolynomial.invoke(argument: C): C = this.substitute(ring, argument) + public inline operator fun ListPolynomial.invoke(argument: C): C = substitute(ring, argument) /** * Evaluates value of [this] polynomial on provided [argument]. */ @Suppress("NOTHING_TO_INLINE") - public inline operator fun ListPolynomial.invoke(argument: ListPolynomial): ListPolynomial = this.substitute(ring, argument) + public inline operator fun ListPolynomial.invoke(argument: ListPolynomial): ListPolynomial = substitute(ring, argument) } /** diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt index f3e352bcd..e23baa548 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt @@ -9,7 +9,7 @@ import space.kscience.kmath.operations.Ring /** - * Represents rational function that stores its numerator and denominator as [ListPolynomial]s. + * Represents univariate rational function that stores its numerator and denominator as [ListPolynomial]s. */ public data class ListRationalFunction( public override val numerator: ListPolynomial, @@ -56,82 +56,82 @@ public class ListRationalFunctionSpace> ( * Evaluates value of [this] polynomial on provided argument. */ @Suppress("NOTHING_TO_INLINE") - public inline fun ListPolynomial.substitute(argument: C): C = this.substitute(ring, argument) + public inline fun ListPolynomial.substitute(argument: C): C = substitute(ring, argument) /** * Substitutes provided polynomial [argument] into [this] polynomial. */ @Suppress("NOTHING_TO_INLINE") - public inline fun ListPolynomial.substitute(argument: ListPolynomial): ListPolynomial = this.substitute(ring, argument) + public inline fun ListPolynomial.substitute(argument: ListPolynomial): ListPolynomial = substitute(ring, argument) /** * Substitutes provided rational function [argument] into [this] polynomial. */ @Suppress("NOTHING_TO_INLINE") - public inline fun ListPolynomial.substitute(argument: ListRationalFunction): ListRationalFunction = this.substitute(ring, argument) + public inline fun ListPolynomial.substitute(argument: ListRationalFunction): ListRationalFunction = substitute(ring, argument) /** * Substitutes provided polynomial [argument] into [this] rational function. */ @Suppress("NOTHING_TO_INLINE") - public inline fun ListRationalFunction.substitute(argument: ListPolynomial): ListRationalFunction = this.substitute(ring, argument) + public inline fun ListRationalFunction.substitute(argument: ListPolynomial): ListRationalFunction = substitute(ring, argument) /** * Substitutes provided rational function [argument] into [this] rational function. */ @Suppress("NOTHING_TO_INLINE") - public inline fun ListRationalFunction.substitute(argument: ListRationalFunction): ListRationalFunction = this.substitute(ring, argument) + public inline fun ListRationalFunction.substitute(argument: ListRationalFunction): ListRationalFunction = substitute(ring, argument) /** * Represent [this] polynomial as a regular context-less function. */ @Suppress("NOTHING_TO_INLINE") - public inline fun ListPolynomial.asFunction(): (C) -> C = { this.substitute(ring, it) } + public inline fun ListPolynomial.asFunction(): (C) -> C = { substitute(ring, it) } /** * Represent [this] polynomial as a regular context-less function. */ @Suppress("NOTHING_TO_INLINE") - public inline fun ListPolynomial.asFunctionOfConstant(): (C) -> C = { this.substitute(ring, it) } + public inline fun ListPolynomial.asFunctionOfConstant(): (C) -> C = { substitute(ring, it) } /** * Represent [this] polynomial as a regular context-less function. */ @Suppress("NOTHING_TO_INLINE") - public inline fun ListPolynomial.asFunctionOfPolynomial(): (ListPolynomial) -> ListPolynomial = { this.substitute(ring, it) } + public inline fun ListPolynomial.asFunctionOfPolynomial(): (ListPolynomial) -> ListPolynomial = { substitute(ring, it) } /** * Represent [this] polynomial as a regular context-less function. */ @Suppress("NOTHING_TO_INLINE") - public inline fun ListPolynomial.asFunctionOfRationalFunction(): (ListRationalFunction) -> ListRationalFunction = { this.substitute(ring, it) } + public inline fun ListPolynomial.asFunctionOfRationalFunction(): (ListRationalFunction) -> ListRationalFunction = { substitute(ring, it) } /** * Represent [this] rational function as a regular context-less function. */ @Suppress("NOTHING_TO_INLINE") - public inline fun ListRationalFunction.asFunctionOfPolynomial(): (ListPolynomial) -> ListRationalFunction = { this.substitute(ring, it) } + public inline fun ListRationalFunction.asFunctionOfPolynomial(): (ListPolynomial) -> ListRationalFunction = { substitute(ring, it) } /** * Represent [this] rational function as a regular context-less function. */ @Suppress("NOTHING_TO_INLINE") - public inline fun ListRationalFunction.asFunctionOfRationalFunction(): (ListRationalFunction) -> ListRationalFunction = { this.substitute(ring, it) } + public inline fun ListRationalFunction.asFunctionOfRationalFunction(): (ListRationalFunction) -> ListRationalFunction = { substitute(ring, it) } /** * Evaluates value of [this] polynomial on provided argument. */ @Suppress("NOTHING_TO_INLINE") - public inline operator fun ListPolynomial.invoke(argument: C): C = this.substitute(ring, argument) + public inline operator fun ListPolynomial.invoke(argument: C): C = substitute(ring, argument) /** * Evaluates value of [this] polynomial on provided argument. */ @Suppress("NOTHING_TO_INLINE") - public inline operator fun ListPolynomial.invoke(argument: ListPolynomial): ListPolynomial = this.substitute(ring, argument) + public inline operator fun ListPolynomial.invoke(argument: ListPolynomial): ListPolynomial = substitute(ring, argument) /** * Evaluates value of [this] polynomial on provided argument. */ @Suppress("NOTHING_TO_INLINE") - public inline operator fun ListPolynomial.invoke(argument: ListRationalFunction): ListRationalFunction = this.substitute(ring, argument) + public inline operator fun ListPolynomial.invoke(argument: ListRationalFunction): ListRationalFunction = substitute(ring, argument) /** * Evaluates value of [this] rational function on provided argument. */ @Suppress("NOTHING_TO_INLINE") - public inline operator fun ListRationalFunction.invoke(argument: ListPolynomial): ListRationalFunction = this.substitute(ring, argument) + public inline operator fun ListRationalFunction.invoke(argument: ListPolynomial): ListRationalFunction = substitute(ring, argument) /** * Evaluates value of [this] rational function on provided argument. */ @Suppress("NOTHING_TO_INLINE") - public inline operator fun ListRationalFunction.invoke(argument: ListRationalFunction): ListRationalFunction = this.substitute(ring, argument) + public inline operator fun ListRationalFunction.invoke(argument: ListRationalFunction): ListRationalFunction = substitute(ring, argument) } \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt new file mode 100644 index 000000000..9304e66da --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -0,0 +1,429 @@ +/* + * 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.functions + +import space.kscience.kmath.operations.Ring +import space.kscience.kmath.structures.Buffer +import kotlin.jvm.JvmName +import kotlin.math.max + + +/** + * Represents univariate polynomial that stores its coefficients in a [Map] and terms' signatures in a [List]. + * + * @param C the type of constants. + */ +public data class NumberedPolynomial +@PublishedApi +internal constructor( + /** + * Map that contains coefficients of the polynomial. Every monomial `a x_1^{d_1} ... x_n^{d_n}` is stored as pair + * "key-value" in the map, where the value is the coefficients `a` and the key is a list that associates index of + * every variable in the monomial with multiplicity of the variable occurring in the monomial. For example + * coefficients of a polynomial `5 x_1^2 x_3^3 - 6 x_2` can be represented as + * ``` + * mapOf( + * listOf(2, 0, 3) to 5, // 5 x_1^2 x_3^3 + + * listOf(0, 1) to (-6), // (-6) x_2^1 + * ) + * ``` + * and also as + * ``` + * mapOf( + * listOf(2, 0, 3) to 5, // 5 x_1^2 x_3^3 + + * listOf(0, 1) to (-6), // (-6) x_2^1 + * listOf(0, 1, 1) to 0, // 0 x_2^1 x_3^1 + * ) + * ``` + * It is not prohibited to put extra zero monomials into the map (as for `0 x_2 x_3` in the example). But the + * bigger the coefficients map the worse performance of arithmetical operations performed on it. Thus, it is + * recommended not to put (or even to remove) extra (or useless) monomials in the coefficients map. + */ + public val coefficients: Map, C> +) : Polynomial { + override fun toString(): String = "NumberedPolynomial$coefficients" +} + +/** + * Arithmetic context for multivariate polynomials with coefficients stored as a [Map] and terms' signatures stored as a + * [List] constructed with the provided [ring] of constants. + * + * @param C the type of constants. Polynomials have them a coefficients in their terms. + * @param A type of provided underlying ring of constants. It's [Ring] of [C]. + * @param ring underlying ring of constants of type [A]. + */ +public class NumberedPolynomialSpace>( + public override val ring: A, +) : PolynomialSpaceOverRing, A> { + /** + * Returns sum of the polynomial and the integer represented as a polynomial. + * + * The operation is equivalent to adding [other] copies of unit polynomial to [this]. + */ + public override operator fun NumberedPolynomial.plus(other: Int): NumberedPolynomial = + if (other == 0) this + else + NumberedPolynomialAsIs( + coefficients + .toMutableMap() + .apply { + val degs = emptyList() + + this[degs] = getOrElse(degs) { constantZero } + other + } + ) + /** + * Returns difference between the polynomial and the integer represented as a polynomial. + * + * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. + */ + public override operator fun NumberedPolynomial.minus(other: Int): NumberedPolynomial = + if (other == 0) this + else + NumberedPolynomialAsIs( + coefficients + .toMutableMap() + .apply { + val degs = emptyList() + + this[degs] = getOrElse(degs) { constantZero } - other + } + ) + /** + * Returns product of the polynomial and the integer represented as a polynomial. + * + * The operation is equivalent to sum of [other] copies of [this]. + */ + public override operator fun NumberedPolynomial.times(other: Int): NumberedPolynomial = + if (other == 0) zero + else NumberedPolynomialAsIs( + coefficients + .toMutableMap() + .apply { + for (degs in keys) this[degs] = this[degs]!! * other + } + ) + + /** + * Returns sum of the integer represented as a polynomial and the polynomial. + * + * The operation is equivalent to adding [this] copies of unit polynomial to [other]. + */ + public override operator fun Int.plus(other: NumberedPolynomial): NumberedPolynomial = + if (this == 0) other + else + NumberedPolynomialAsIs( + other.coefficients + .toMutableMap() + .apply { + val degs = emptyList() + + this[degs] = this@plus + getOrElse(degs) { constantZero } + } + ) + /** + * Returns difference between the integer represented as a polynomial and the polynomial. + * + * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. + */ + public override operator fun Int.minus(other: NumberedPolynomial): NumberedPolynomial = + if (this == 0) other + else + NumberedPolynomialAsIs( + other.coefficients + .toMutableMap() + .apply { + val degs = emptyList() + + this[degs] = this@minus - getOrElse(degs) { constantZero } + } + ) + /** + * Returns product of the integer represented as a polynomial and the polynomial. + * + * The operation is equivalent to sum of [this] copies of [other]. + */ + public override operator fun Int.times(other: NumberedPolynomial): NumberedPolynomial = + if (this == 0) zero + else NumberedPolynomialAsIs( + other.coefficients + .toMutableMap() + .apply { + for (degs in keys) this[degs] = this@times * this[degs]!! + } + ) + + /** + * Converts the integer [value] to polynomial. + */ + public override fun number(value: Int): NumberedPolynomial = number(constantNumber(value)) + + /** + * Returns sum of the constant represented as a polynomial and the polynomial. + */ + override operator fun C.plus(other: NumberedPolynomial): NumberedPolynomial = + with(other.coefficients) { + if (isEmpty()) NumberedPolynomialAsIs(mapOf(emptyList() to this@plus)) + else NumberedPolynomialAsIs( + toMutableMap() + .apply { + val degs = emptyList() + + this[degs] = this@plus + getOrElse(degs) { constantZero } + } + ) + } + /** + * Returns difference between the constant represented as a polynomial and the polynomial. + */ + override operator fun C.minus(other: NumberedPolynomial): NumberedPolynomial = + with(other.coefficients) { + if (isEmpty()) NumberedPolynomialAsIs(mapOf(emptyList() to this@minus)) + else NumberedPolynomialAsIs( + toMutableMap() + .apply { + forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } + + val degs = emptyList() + + this[degs] = this@minus - getOrElse(degs) { constantZero } + } + ) + } + /** + * Returns product of the constant represented as a polynomial and the polynomial. + */ + override operator fun C.times(other: NumberedPolynomial): NumberedPolynomial = + NumberedPolynomialAsIs( + other.coefficients + .toMutableMap() + .apply { + for (degs in keys) this[degs] = this@times * this[degs]!! + } + ) + + /** + * Returns sum of the constant represented as a polynomial and the polynomial. + */ + override operator fun NumberedPolynomial.plus(other: C): NumberedPolynomial = + with(coefficients) { + if (isEmpty()) NumberedPolynomialAsIs(mapOf(emptyList() to other)) + else NumberedPolynomialAsIs( + toMutableMap() + .apply { + val degs = emptyList() + + this[degs] = getOrElse(degs) { constantZero } + other + } + ) + } + /** + * Returns difference between the constant represented as a polynomial and the polynomial. + */ + override operator fun NumberedPolynomial.minus(other: C): NumberedPolynomial = + with(coefficients) { + if (isEmpty()) NumberedPolynomialAsIs(mapOf(emptyList() to other)) + else NumberedPolynomialAsIs( + toMutableMap() + .apply { + val degs = emptyList() + + this[degs] = getOrElse(degs) { constantZero } - other + } + ) + } + /** + * Returns product of the constant represented as a polynomial and the polynomial. + */ + override operator fun NumberedPolynomial.times(other: C): NumberedPolynomial = + NumberedPolynomialAsIs( + coefficients + .toMutableMap() + .apply { + for (degs in keys) this[degs] = this[degs]!! * other + } + ) + + /** + * Converts the constant [value] to polynomial. + */ + public override fun number(value: C): NumberedPolynomial = + NumberedPolynomialAsIs(mapOf(emptyList() to value)) + + /** + * Returns negation of the polynomial. + */ + override fun NumberedPolynomial.unaryMinus(): NumberedPolynomial = + NumberedPolynomialAsIs( + coefficients.mapValues { -it.value } + ) + /** + * Returns sum of the polynomials. + */ + override operator fun NumberedPolynomial.plus(other: NumberedPolynomial): NumberedPolynomial = + NumberedPolynomialAsIs( + buildMap(coefficients.size + other.coefficients.size) { + other.coefficients.mapValuesTo(this) { it.value } + other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! + value else value } + } + ) + /** + * Returns difference of the polynomials. + */ + override operator fun NumberedPolynomial.minus(other: NumberedPolynomial): NumberedPolynomial = + NumberedPolynomialAsIs( + buildMap(coefficients.size + other.coefficients.size) { + other.coefficients.mapValuesTo(this) { it.value } + other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! - value else -value } + } + ) + /** + * Returns product of the polynomials. + */ + override operator fun NumberedPolynomial.times(other: NumberedPolynomial): NumberedPolynomial = + NumberedPolynomialAsIs( + buildMap(coefficients.size * other.coefficients.size) { + for ((degs1, c1) in coefficients) for ((degs2, c2) in other.coefficients) { + val degs = + (0..max(degs1.lastIndex, degs2.lastIndex)) + .map { degs1.getOrElse(it) { 0U } + degs2.getOrElse(it) { 0U } } + val c = c1 * c2 + this[degs] = if (degs in this) this[degs]!! + c else c + } + } + ) + /** + * Raises [arg] to the integer power [exponent]. + */ // TODO: To optimize boxing + override fun power(arg: NumberedPolynomial, exponent: UInt): NumberedPolynomial = super.power(arg, exponent) + + /** + * Instance of zero polynomial (zero of the polynomial ring). + */ + override val zero: NumberedPolynomial = NumberedPolynomialAsIs(emptyMap()) + /** + * Instance of unit polynomial (unit of the polynomial ring). + */ + override val one: NumberedPolynomial by lazy { + NumberedPolynomialAsIs( + mapOf( + emptyList() to constantOne // 1 * x_1^0 * x_2^0 * ... + ) + ) + } + + /** + * Maximal index (ID) of variable occurring in the polynomial with positive power. If there is no such variable, + * the result is `-1`. + */ + public val NumberedPolynomial.lastVariable: Int + get() = coefficients.entries.maxOfOrNull { (degs, _) -> degs.lastIndex } ?: -1 + /** + * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is + * zero, degree is -1. + */ + override val NumberedPolynomial.degree: Int + get() = coefficients.entries.maxOfOrNull { (degs, _) -> degs.sum().toInt() } ?: -1 + /** + * List that associates indices of variables (that appear in the polynomial in positive exponents) with their most + * exponents in which the variables are appeared in the polynomial. + * + * As consequence all values in the list are non-negative integers. Also, if the polynomial is constant, the list is empty. + * And last index of the list is [lastVariable]. + */ + public val NumberedPolynomial.degrees: List + get() = + MutableList(lastVariable + 1) { 0u }.apply { + coefficients.entries.forEach { (degs, _) -> + degs.forEachIndexed { index, deg -> + this[index] = max(this[index], deg) + } + } + } + /** + * Counts degree of the polynomial by the specified [variable]. + */ + public fun NumberedPolynomial.degreeBy(variable: Int): UInt = + coefficients.entries.maxOfOrNull { (degs, _) -> degs.getOrElse(variable) { 0u } } ?: 0u + /** + * Counts degree of the polynomial by the specified [variables]. + */ + public fun NumberedPolynomial.degreeBy(variables: Collection): UInt = + coefficients.entries.maxOfOrNull { (degs, _) -> + degs.withIndex().filter { (index, _) -> index in variables }.sumOf { it.value } + } ?: 0u + /** + * Count of variables occurring in the polynomial with positive power. If there is no such variable, + * the result is `0`. + */ + public val NumberedPolynomial.countOfVariables: Int + get() = + MutableList(lastVariable + 1) { false }.apply { + coefficients.entries.forEach { (degs, _) -> + degs.forEachIndexed { index, deg -> + if (deg != 0u) this[index] = true + } + } + }.count { it } + + // TODO: When context receivers will be ready move all of this substitutions and invocations to utilities with + // [ListPolynomialSpace] as a context receiver + /** + * Substitutes provided arguments [arguments] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.substitute(arguments: Map): NumberedPolynomial = substitute(ring, arguments) + /** + * Substitutes provided arguments [arguments] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + @JvmName("substitutePolynomial") + public inline fun NumberedPolynomial.substitute(arguments: Map>) : NumberedPolynomial = substitute(ring, arguments) + /** + * Substitutes provided arguments [arguments] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.substitute(arguments: Buffer): NumberedPolynomial = substitute(ring, arguments) + /** + * Substitutes provided arguments [arguments] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + @JvmName("substitutePolynomial") + public inline fun NumberedPolynomial.substitute(arguments: Buffer>) : NumberedPolynomial = substitute(ring, arguments) + /** + * Substitutes provided arguments [arguments] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.substituteFully(arguments: Buffer): C = this.substituteFully(ring, arguments) + + /** + * Represent [this] polynomial as a regular context-less function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.asFunction(): (Buffer) -> C = asFunctionOver(ring) + /** + * Represent [this] polynomial as a regular context-less function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.asFunctionOfConstant(): (Buffer) -> C = asFunctionOfConstantOver(ring) + /** + * Represent [this] polynomial as a regular context-less function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.asFunctionOfPolynomial(): (Buffer>) -> NumberedPolynomial = asFunctionOfPolynomialOver(ring) + + /** + * Evaluates value of [this] polynomial on provided [arguments]. + */ + @Suppress("NOTHING_TO_INLINE") + public inline operator fun NumberedPolynomial.invoke(arguments: Buffer): C = substituteFully(ring, arguments) + /** + * Substitutes provided [arguments] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + @JvmName("invokePolynomial") + public inline operator fun NumberedPolynomial.invoke(arguments: Buffer>): NumberedPolynomial = substitute(ring, arguments) +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt new file mode 100644 index 000000000..a2986879d --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt @@ -0,0 +1,239 @@ +/* + * 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.functions + +import space.kscience.kmath.operations.Ring +import space.kscience.kmath.operations.invoke +import space.kscience.kmath.structures.Buffer +import kotlin.jvm.JvmName +import kotlin.math.max + + +/** + * Represents multivariate rational function that stores its numerator and denominator as [NumberedPolynomial]s. + */ +public class NumberedRationalFunction internal constructor( + public override val numerator: NumberedPolynomial, + public override val denominator: NumberedPolynomial +) : RationalFunction> { + override fun toString(): String = "NumberedRationalFunction${numerator.coefficients}/${denominator.coefficients}" +} + +/** + * Arithmetic context for univariate rational functions with numerator and denominator represented as [NumberedPolynomial]s. + * + * @param C the type of constants. Polynomials have them a coefficients in their terms. + * @param A type of provided underlying ring of constants. It's [Ring] of [C]. + * @param ring underlying ring of constants of type [A]. + */ +public class NumberedRationalFunctionSpace> ( + public val ring: A, +) : + RationalFunctionalSpaceOverPolynomialSpace< + C, + NumberedPolynomial, + NumberedRationalFunction, + NumberedPolynomialSpace, + >, + PolynomialSpaceOfFractions< + C, + NumberedPolynomial, + NumberedRationalFunction, + >() { + + /** + * Underlying polynomial ring. Its polynomial operations are inherited by local polynomial operations. + */ + public override val polynomialRing : NumberedPolynomialSpace = NumberedPolynomialSpace(ring) + /** + * Constructor of rational functions (of type [NumberedRationalFunction]) from numerator and denominator (of type [NumberedPolynomial]). + */ + protected override fun constructRationalFunction( + numerator: NumberedPolynomial, + denominator: NumberedPolynomial + ): NumberedRationalFunction = + NumberedRationalFunction(numerator, denominator) + + /** + * Maximal index (ID) of variable occurring in the polynomial with positive power. If there is no such variable, + * the result is `-1`. + */ + public val NumberedPolynomial.lastVariable: Int get() = polynomialRing { lastVariable } + /** + * List that associates indices of variables (that appear in the polynomial in positive exponents) with their most + * exponents in which the variables are appeared in the polynomial. + * + * As consequence all values in the list are non-negative integers. Also, if the polynomial is constant, the list is empty. + * And last index of the list is [lastVariable]. + */ + public val NumberedPolynomial.degrees: List get() = polynomialRing { degrees } + /** + * Counts degree of the polynomial by the specified [variable]. + */ + public fun NumberedPolynomial.degreeBy(variable: Int): UInt = polynomialRing { degreeBy(variable) } + /** + * Counts degree of the polynomial by the specified [variables]. + */ + public fun NumberedPolynomial.degreeBy(variables: Collection): UInt = polynomialRing { degreeBy(variables) } + /** + * Count of variables occurring in the polynomial with positive power. If there is no such variable, + * the result is `0`. + */ + public val NumberedPolynomial.countOfVariables: Int get() = polynomialRing { countOfVariables } + + /** + * Count of all variables that appear in the polynomial in positive exponents. + */ + public val NumberedRationalFunction.lastVariable: Int + get() = polynomialRing { max(numerator.lastVariable, denominator.lastVariable) } + /** + * Count of variables occurring in the rational function with positive power. If there is no such variable, + * the result is `0`. + */ + public val NumberedRationalFunction.countOfVariables: Int + get() = + MutableList(lastVariable + 1) { false }.apply { + numerator.coefficients.entries.forEach { (degs, _) -> + degs.forEachIndexed { index, deg -> + if (deg != 0u) this[index] = true + } + } + denominator.coefficients.entries.forEach { (degs, _) -> + degs.forEachIndexed { index, deg -> + if (deg != 0u) this[index] = true + } + } + }.count { it } + + // TODO: When context receivers will be ready move all of this substitutions and invocations to utilities with + // [ListPolynomialSpace] as a context receiver + /** + * Substitutes provided constant [argument] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.substitute(argument: Map): NumberedPolynomial = substitute(ring, argument) + /** + * Substitutes provided polynomial [argument] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.substitute(argument: Map>): NumberedPolynomial = substitute(ring, argument) + /** + * Substitutes provided rational function [argument] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.substitute(argument: Map>): NumberedRationalFunction = substitute(ring, argument) + /** + * Substitutes provided constant [argument] into [this] rational function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedRationalFunction.substitute(argument: Map): NumberedRationalFunction = substitute(ring, argument) + /** + * Substitutes provided polynomial [argument] into [this] rational function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedRationalFunction.substitute(argument: Map>): NumberedRationalFunction = substitute(ring, argument) + /** + * Substitutes provided rational function [argument] into [this] rational function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedRationalFunction.substitute(argument: Map>): NumberedRationalFunction = substitute(ring, argument) + /** + * Substitutes provided constant [argument] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.substitute(argument: Buffer): NumberedPolynomial = substitute(ring, argument) + /** + * Substitutes provided polynomial [argument] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.substitute(argument: Buffer>): NumberedPolynomial = substitute(ring, argument) + /** + * Substitutes provided rational function [argument] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.substitute(argument: Buffer>): NumberedRationalFunction = substitute(ring, argument) + /** + * Substitutes provided constant [argument] into [this] rational function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedRationalFunction.substitute(argument: Buffer): NumberedRationalFunction = substitute(ring, argument) + /** + * Substitutes provided polynomial [arguments] into [this] rational function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedRationalFunction.substitute(arguments: Buffer>): NumberedRationalFunction = substitute(ring, arguments) + /** + * Substitutes provided rational function [arguments] into [this] rational function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedRationalFunction.substitute(arguments: Buffer>): NumberedRationalFunction = substitute(ring, arguments) + /** + * Substitutes provided constant [arguments] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.substituteFully(arguments: Buffer): C = substituteFully(ring, arguments) + + /** + * Represent [this] polynomial as a regular context-less function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.asFunction(): (Buffer) -> C = asFunctionOver(ring) + /** + * Represent [this] polynomial as a regular context-less function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.asFunctionOfConstant(): (Buffer) -> C = asFunctionOfConstantOver(ring) + /** + * Represent [this] polynomial as a regular context-less function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.asFunctionOfPolynomial(): (Buffer>) -> NumberedPolynomial = asFunctionOfPolynomialOver(ring) + /** + * Represent [this] polynomial as a regular context-less function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.asFunctionOfRationalFunction(): (Buffer>) -> NumberedRationalFunction = asFunctionOfRationalFunctionOver(ring) + /** + * Represent [this] polynomial as a regular context-less function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedRationalFunction.asFunctionOfPolynomial(): (Buffer>) -> NumberedRationalFunction = asFunctionOfPolynomialOver(ring) + /** + * Represent [this] polynomial as a regular context-less function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedRationalFunction.asFunctionOfRationalFunction(): (Buffer>) -> NumberedRationalFunction = asFunctionOfRationalFunctionOver(ring) + + /** + * Evaluates value of [this] polynomial on provided [arguments]. + */ + @Suppress("NOTHING_TO_INLINE") + public inline operator fun NumberedPolynomial.invoke(arguments: Buffer): C = substituteFully(ring, arguments) + /** + * Substitutes provided [arguments] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + @JvmName("invokePolynomial") + public inline operator fun NumberedPolynomial.invoke(arguments: Buffer>): NumberedPolynomial = substitute(ring, arguments) + /** + * Substitutes provided [arguments] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + @JvmName("invokePolynomial") + public inline operator fun NumberedPolynomial.invoke(arguments: Buffer>): NumberedRationalFunction = substitute(ring, arguments) + /** + * Substitutes provided [arguments] into [this] rational function. + */ + @Suppress("NOTHING_TO_INLINE") + @JvmName("invokePolynomial") + public inline operator fun NumberedRationalFunction.invoke(arguments: Buffer>): NumberedRationalFunction = substitute(ring, arguments) + /** + * Substitutes provided [arguments] into [this] rational function. + */ + @Suppress("NOTHING_TO_INLINE") + @JvmName("invokePolynomial") + public inline operator fun NumberedRationalFunction.invoke(arguments: Buffer>): NumberedRationalFunction = substitute(ring, arguments) +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt index 01911f980..338ae9935 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt @@ -1076,6 +1076,14 @@ public abstract class PolynomialSpaceOfFractions< numerator * other.denominator, denominator * other.numerator ) + /** + * Raises [arg] to the integer power [exponent]. + */ + public override fun power(arg: R, exponent: UInt): R = + constructRationalFunction( + power(arg.numerator, exponent), + power(arg.denominator, exponent), + ) /** * Instance of zero rational function (zero of the rational functions ring). diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt index 127dd8c7a..649fc48bd 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt @@ -147,12 +147,17 @@ public fun > ListPolynomial.asFunctionOver(ring: A): (C) -> C /** * Represent [this] polynomial as a regular context-less function. */ -public fun > ListPolynomial.asPolynomialFunctionOver(ring: A): (ListPolynomial) -> ListPolynomial = { substitute(ring, it) } +public fun > ListPolynomial.asFunctionOfConstantOver(ring: A): (C) -> C = { substitute(ring, it) } /** * Represent [this] polynomial as a regular context-less function. */ -public fun > ListPolynomial.asFunctionOfRationalFunctionOver(ring: A): (ListPolynomial) -> ListPolynomial = { substitute(ring, it) } +public fun > ListPolynomial.asFunctionOfPolynomialOver(ring: A): (ListPolynomial) -> ListPolynomial = { substitute(ring, it) } + +/** + * Represent [this] polynomial as a regular context-less function. + */ +public fun > ListPolynomial.asFunctionOfRationalFunctionOver(ring: A): (ListRationalFunction) -> ListRationalFunction = { substitute(ring, it) } /** * Represent [this] rational function as a regular context-less function. @@ -162,12 +167,17 @@ public fun > ListRationalFunction.asFunctionOver(ring: A): (C /** * Represent [this] rational function as a regular context-less function. */ -public fun > ListRationalFunction.asPolynomialFunctionOver(ring: A): (ListPolynomial) -> ListRationalFunction = { substitute(ring, it) } +public fun > ListRationalFunction.asFunctionOfConstantOver(ring: A): (C) -> C = { substitute(ring, it) } /** * Represent [this] rational function as a regular context-less function. */ -public fun > ListRationalFunction.asFunctionOfRationalFunctionOver(ring: A): (ListPolynomial) -> ListRationalFunction = { substitute(ring, it) } +public fun > ListRationalFunction.asFunctionOfPolynomialOver(ring: A): (ListPolynomial) -> ListRationalFunction = { substitute(ring, it) } + +/** + * Represent [this] rational function as a regular context-less function. + */ +public fun > ListRationalFunction.asFunctionOfRationalFunctionOver(ring: A): (ListRationalFunction) -> ListRationalFunction = { substitute(ring, it) } /** * Returns algebraic derivative of received polynomial. @@ -242,27 +252,4 @@ public fun > ListPolynomial.integrate( ): C = ring { val antiderivative = antiderivative(ring) antiderivative.substitute(ring, range.endInclusive) - antiderivative.substitute(ring, range.start) -} - -/** - * Returns algebraic derivative of received rational function. - */ -@UnstableKMathAPI -public fun ListRationalFunction.derivative( - ring: A, -): ListRationalFunction where A : Ring, A : NumericAlgebra = ring.listRationalFunctionSpace { - ListRationalFunction( - numerator.derivative(ring) * denominator - numerator * denominator.derivative(ring), - denominator * denominator - ) -} - -/** - * Returns algebraic derivative of received rational function of specified [order]. The [order] should be non-negative integer. - */ -@UnstableKMathAPI -public tailrec fun ListRationalFunction.nthDerivative( - ring: A, - order: Int, -): ListRationalFunction where A : Ring, A : NumericAlgebra = - if (order == 0) this else derivative(ring).nthDerivative(ring, order - 1) \ No newline at end of file +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt new file mode 100644 index 000000000..05fff3472 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt @@ -0,0 +1,478 @@ +/* + * 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.functions + +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.Ring + + +/** + * Returns the same degrees' description of the monomial, but without extra zero degrees on the end. + */ +internal fun List.cleanUp() = subList(0, indexOfLast { it != 0U } + 1) + +/** + * Constructs [NumberedPolynomial] with provided coefficients map [coefs]. The map is used as is. + */ +@Suppress("FunctionName", "NOTHING_TO_INLINE") +@PublishedApi +internal inline fun NumberedPolynomialAsIs(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs) + +/** + * Constructs [NumberedPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient". + * The collections will be transformed to map with [toMap] and then will be used as is. + */ +@Suppress("FunctionName", "NOTHING_TO_INLINE") +@PublishedApi +internal inline fun NumberedPolynomialAsIs(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs.toMap()) + +/** + * Constructs [NumberedPolynomial] with provided array of [pairs] of pairs "term's signature — term's coefficient". + * The array will be transformed to map with [toMap] and then will be used as is. + */ +@Suppress("FunctionName", "NOTHING_TO_INLINE") +@PublishedApi +internal inline fun NumberedPolynomialAsIs(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(pairs.toMap()) + +/** + * Constructs [NumberedPolynomial] with provided coefficients map [coefs]. + * + * [coefs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [coefs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +@Suppress("FunctionName") +public fun NumberedPolynomial(coefs: Map, C>, add: (C, C) -> C) : NumberedPolynomial { + val fixedCoefs = mutableMapOf, C>() + + for (entry in coefs) { + val key = entry.key.cleanUp() + val value = entry.value + fixedCoefs[key] = if (key in fixedCoefs) add(fixedCoefs[key]!!, value) else value + } + + return NumberedPolynomial(fixedCoefs) +} + +/** + * Constructs [NumberedPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient". + * + * [pairs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +@Suppress("FunctionName") +public fun NumberedPolynomial(pairs: Collection, C>>, add: (C, C) -> C) : NumberedPolynomial { + val fixedCoefs = mutableMapOf, C>() + + for (entry in pairs) { + val key = entry.first.cleanUp() + val value = entry.second + fixedCoefs[key] = if (key in fixedCoefs) add(fixedCoefs[key]!!, value) else value + } + + return NumberedPolynomial(fixedCoefs) +} + +/** + * Constructs [NumberedPolynomial] with provided array [pairs] of pairs "term's signature — term's coefficient". + * + * [pairs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +@Suppress("FunctionName") +public fun NumberedPolynomial(vararg pairs: Pair, C>, add: (C, C) -> C) : NumberedPolynomial { + val fixedCoefs = mutableMapOf, C>() + + for (entry in pairs) { + val key = entry.first.cleanUp() + val value = entry.second + fixedCoefs[key] = if (key in fixedCoefs) add(fixedCoefs[key]!!, value) else value + } + + return NumberedPolynomial(fixedCoefs) +} + +// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available + +/** + * Constructs [NumberedPolynomial] with provided coefficients map [coefs]. + * + * [coefs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [coefs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +@Suppress("FunctionName", "NOTHING_TO_INLINE") +public inline fun > A.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, ::add) +/** + * Constructs [NumberedPolynomial] with provided coefficients map [coefs]. + * + * [coefs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [coefs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +@Suppress("FunctionName", "NOTHING_TO_INLINE") +public inline fun > NumberedPolynomialSpace.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs) { left: C, right: C -> left + right } + +/** + * Constructs [NumberedPolynomial] with provided coefficients map [coefs]. + * + * [coefs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [coefs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +@Suppress("FunctionName", "NOTHING_TO_INLINE") +public inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs) { left: C, right: C -> left + right } + +/** + * Constructs [NumberedPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient". + * + * [pairs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +@Suppress("FunctionName", "NOTHING_TO_INLINE") +public inline fun > A.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, ::add) + +/** + * Constructs [NumberedPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient". + * + * [pairs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +@Suppress("FunctionName", "NOTHING_TO_INLINE") +public inline fun > NumberedPolynomialSpace.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs) { left: C, right: C -> left + right } +/** + * Constructs [NumberedPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient". + * + * [pairs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +@Suppress("FunctionName", "NOTHING_TO_INLINE") +public inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs) { left: C, right: C -> left + right } + +/** + * Constructs [NumberedPolynomial] with provided array [pairs] of pairs "term's signature — term's coefficient". + * + * [pairs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +@Suppress("FunctionName", "NOTHING_TO_INLINE") +public inline fun > A.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs) { left: C, right: C -> left + right } +/** + * Constructs [NumberedPolynomial] with provided array [pairs] of pairs "term's signature — term's coefficient". + * + * [pairs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +@Suppress("FunctionName", "NOTHING_TO_INLINE") +public inline fun > NumberedPolynomialSpace.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs) { left: C, right: C -> left + right } +/** + * Constructs [NumberedPolynomial] with provided array [pairs] of pairs "term's signature — term's coefficient". + * + * [pairs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +@Suppress("FunctionName", "NOTHING_TO_INLINE") +public inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs) { left: C, right: C -> left + right } + +/** + * Converts [this] constant to [NumberedPolynomial]. + */ +@Suppress("NOTHING_TO_INLINE") +public inline fun C.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomialAsIs(mapOf(emptyList() to this)) + +/** + * Marks DSL that allows to more simply create [NumberedPolynomial]s with good performance. + * + * For example, polynomial `5 x_1^2 x_3^3 - 6 x_2` can be described as + * ``` + * Int.algebra { + * val numberedPolynomial : NumberedPolynomial = NumberedPolynomial { + * 5 { 1 inPowerOf 2u; 3 inPowerOf 3u } // 5 x_1^2 x_3^3 + + * (-6) { 2 inPowerOf 1u } // (-6) x_2^1 + * } + * } + * ``` + */ +@DslMarker +@UnstableKMathAPI +internal annotation class NumberedPolynomialConstructorDSL + +/** + * Builder of [NumberedPolynomial] signature. It should be used as an implicit context for lambdas that describe term signature. + */ +@UnstableKMathAPI +@NumberedPolynomialConstructorDSL +public class NumberedPolynomialTermSignatureBuilder { + /** + * Signature storage. Any declaration of any variable's power updates the storage by increasing corresponding value. + * Afterward the storage will be used as a resulting signature. + */ + private val signature: MutableList = ArrayList() + + /** + * Builds the resulting signature. + * + * In fact, it just returns [signature] as regular signature of type `List`. + */ + internal fun build(): List = signature + + /** + * Declares power of variable #[this] of degree [deg]. + * + * Declaring another power of the same variable will increase its degree by received degree. + */ + public infix fun Int.inPowerOf(deg: UInt) { + if (this > signature.lastIndex) { + signature.addAll(List(this - signature.lastIndex - 1) { 0u }) + signature.add(deg) + } else { + signature[this] += deg + } + } + /** + * Declares power of variable #[this] of degree [deg]. + * + * Declaring another power of the same variable will increase its degree by received degree. + */ + @Suppress("NOTHING_TO_INLINE") + public inline infix fun Int.pow(deg: UInt): Unit = this inPowerOf deg + /** + * Declares power of variable #[this] of degree [deg]. + * + * Declaring another power of the same variable will increase its degree by received degree. + */ + @Suppress("NOTHING_TO_INLINE") + public inline infix fun Int.`in`(deg: UInt): Unit = this inPowerOf deg + /** + * Declares power of variable #[this] of degree [deg]. + * + * Declaring another power of the same variable will increase its degree by received degree. + */ + @Suppress("NOTHING_TO_INLINE") + public inline infix fun Int.of(deg: UInt): Unit = this inPowerOf deg +} + +/** + * Builder of [NumberedPolynomial]. It should be used as an implicit context for lambdas that describe [NumberedPolynomial]. + */ +@UnstableKMathAPI +@NumberedPolynomialConstructorDSL +public class NumberedPolynomialBuilder( + /** + * Summation operation that will be used to sum coefficients of monomials of same signatures. + */ + private val add: (C, C) -> C, + /** + * Initial capacity of coefficients map. + */ + initialCapacity: Int = 0 +) { + /** + * Coefficients storage. Any declaration of any monomial updates the storage. + * Afterward the storage will be used as a resulting coefficients map. + */ + private val coefficients: MutableMap, C> = LinkedHashMap(initialCapacity) + + /** + * Builds the resulting coefficients map. + * + * In fact, it just returns [coefficients] as regular coefficients map of type `Map, C>`. + */ + @PublishedApi + internal fun build(): NumberedPolynomial = NumberedPolynomial(coefficients) + + /** + * Declares monomial with [this] coefficient and provided [signature]. + * + * Declaring another monomial with the same signature will add [this] coefficient to existing one. If the sum of such + * coefficients is zero at any moment the monomial won't be removed but will be left as it is. + */ + public infix fun C.with(signature: List) { + if (signature in coefficients) coefficients[signature] = add(coefficients[signature]!!, this@with) + else coefficients[signature] = this@with + } + /** + * Declares monomial with [this] coefficient and signature constructed by [block]. + * + * Declaring another monomial with the same signature will add [this] coefficient to existing one. If the sum of such + * coefficients is zero at any moment the monomial won't be removed but will be left as it is. + */ + @Suppress("NOTHING_TO_INLINE") + public inline infix fun C.with(noinline block: NumberedPolynomialTermSignatureBuilder.() -> Unit): Unit = this.invoke(block) + /** + * Declares monomial with [this] coefficient and signature constructed by [block]. + * + * Declaring another monomial with the same signature will add [this] coefficient to existing one. If the sum of such + * coefficients is zero at any moment the monomial won't be removed but will be left as it is. + */ + public operator fun C.invoke(block: NumberedPolynomialTermSignatureBuilder.() -> Unit): Unit = + this with NumberedPolynomialTermSignatureBuilder().apply(block).build() +} + +// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available + +/** + * Creates [NumberedPolynomial] with lambda [block] in context of [this] ring of constants. + * + * For example, polynomial `5 x_1^2 x_3^3 - 6 x_2` can be described as + * ``` + * Int.algebra { + * val numberedPolynomial : NumberedPolynomial = NumberedPolynomial { + * 5 { 1 inPowerOf 2u; 3 inPowerOf 3u } // 5 x_1^2 x_3^3 + + * (-6) { 2 inPowerOf 1u } // (-6) x_2^1 + * } + * } + * ``` + */ +@UnstableKMathAPI +@Suppress("FunctionName") +public inline fun > A.NumberedPolynomial(initialCapacity: Int = 0, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder(::add, initialCapacity).apply(block).build() +/** + * Creates [NumberedPolynomial] with lambda [block] in context of [this] ring of [NumberedPolynomial]s. + * + * For example, polynomial `5 x_1^2 x_3^3 - 6 x_2` can be described as + * ``` + * Int.algebra { + * val numberedPolynomial : NumberedPolynomial = NumberedPolynomial { + * 5 { 1 inPowerOf 2u; 3 inPowerOf 3u } // 5 x_1^2 x_3^3 + + * (-6) { 2 inPowerOf 1u } // (-6) x_2^1 + * } + * } + * ``` + */ +@UnstableKMathAPI +@Suppress("FunctionName") +public inline fun > NumberedPolynomialSpace.NumberedPolynomial(initialCapacity: Int, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() +/** + * Creates [NumberedPolynomial] with lambda [block] in context of [this] field of [NumberedRationalFunction]s. + * + * For example, polynomial `5 x_1^2 x_3^3 - 6 x_2` can be described as + * ``` + * Int.algebra { + * val numberedPolynomial : NumberedPolynomial = NumberedPolynomial { + * 5 { 1 inPowerOf 2u; 3 inPowerOf 3u } // 5 x_1^2 x_3^3 + + * (-6) { 2 inPowerOf 1u } // (-6) x_2^1 + * } + * } + * ``` + */ +@UnstableKMathAPI +@Suppress("FunctionName") +public inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(initialCapacity: Int, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() + +// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available + +/** + * Constructs [NumberedRationalFunction] with provided coefficients maps [numeratorCoefficients] and [denominatorCoefficients]. + * + * The maps will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. the maps' keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +@Suppress("FunctionName") +public fun > A.NumberedRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): NumberedRationalFunction = + NumberedRationalFunction( + NumberedPolynomial(numeratorCoefficients), + NumberedPolynomial(denominatorCoefficients) + ) +/** + * Constructs [NumberedRationalFunction] with provided coefficients maps [numeratorCoefficients] and [denominatorCoefficients]. + * + * The maps will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. the maps' keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +@Suppress("FunctionName") +public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): NumberedRationalFunction = + NumberedRationalFunction( + NumberedPolynomial(numeratorCoefficients), + NumberedPolynomial(denominatorCoefficients) + ) + +/** + * Constructs [NumberedRationalFunction] with provided [numerator] and unit denominator. + */ +@Suppress("FunctionName") +public fun > A.NumberedRationalFunction(numerator: NumberedPolynomial): NumberedRationalFunction = + NumberedRationalFunction(numerator, NumberedPolynomial(mapOf(emptyList() to one))) +/** + * Constructs [NumberedRationalFunction] with provided [numerator] and unit denominator. + */ +@Suppress("FunctionName") +public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numerator: NumberedPolynomial): NumberedRationalFunction = + NumberedRationalFunction(numerator, polynomialOne) + +/** + * Constructs [NumberedRationalFunction] with provided coefficients map [numeratorCoefficients] for numerator and unit + * denominator. + * + * [numeratorCoefficients] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [numeratorCoefficients]'s keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +@Suppress("FunctionName") +public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numeratorCoefficients: Map, C>): NumberedRationalFunction = + NumberedRationalFunction( + NumberedPolynomial(numeratorCoefficients), + polynomialOne + ) +/** + * Constructs [NumberedRationalFunction] with provided coefficients map [numeratorCoefficients] for numerator and unit + * denominator. + * + * [numeratorCoefficients] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [numeratorCoefficients]'s keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +@Suppress("FunctionName") +public fun > A.NumberedRationalFunction(numeratorCoefficients: Map, C>): NumberedRationalFunction = + NumberedRationalFunction( + NumberedPolynomial(numeratorCoefficients), + NumberedPolynomialAsIs(mapOf(emptyList() to one)) + ) + +///** +// * Converts [this] coefficient to [NumberedRationalFunction]. +// */ +//context(A) +//public fun > C.asNumberedRationalFunction() : NumberedRationalFunction = +// NumberedRationalFunction( +// NumberedPolynomialAsIs(mapOf(emptyList() to this)), +// NumberedPolynomialAsIs(mapOf(emptyList() to one)) +// ) +///** +// * Converts [this] coefficient to [NumberedRationalFunction]. +// */ +//context(NumberedRationalFunctionSpace) +//public fun > C.asNumberedRationalFunction() : NumberedRationalFunction = +// NumberedRationalFunction( +// NumberedPolynomialAsIs(mapOf(emptyList() to this)), +// NumberedPolynomialAsIs(mapOf(emptyList() to constantOne)) +// ) \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt new file mode 100644 index 000000000..484cd11e3 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt @@ -0,0 +1,515 @@ +/* + * 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.functions + +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.Field +import space.kscience.kmath.operations.Ring +import space.kscience.kmath.operations.algebra +import space.kscience.kmath.operations.invoke +import space.kscience.kmath.structures.Buffer +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract +import kotlin.jvm.JvmName +import kotlin.math.max +import kotlin.math.min + + +/** + * Creates a [NumberedPolynomialSpace] over a received ring. + */ +public fun > A.numberedPolynomialSpace(): NumberedPolynomialSpace = + NumberedPolynomialSpace(this) + +/** + * Creates a [NumberedPolynomialSpace]'s scope over a received ring. + */ +public inline fun , R> A.numberedPolynomialSpace(block: NumberedPolynomialSpace.() -> R): R { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return NumberedPolynomialSpace(this).block() +} + +/** + * Creates a [NumberedRationalFunctionSpace] over a received ring. + */ +public fun > A.numberedRationalFunctionSpace(): NumberedRationalFunctionSpace = + NumberedRationalFunctionSpace(this) + +/** + * Creates a [NumberedRationalFunctionSpace]'s scope over a received ring. + */ +public inline fun , R> A.numberedRationalFunctionSpace(block: NumberedRationalFunctionSpace.() -> R): R { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return NumberedRationalFunctionSpace(this).block() +} + +/** + * Substitutes provided Double arguments [args] into [this] Double polynomial. + */ +public fun NumberedPolynomial.substitute(args: Map): NumberedPolynomial = Double.algebra { + NumberedPolynomial( + buildMap, Double>(coefficients.size) { + for ((degs, c) in coefficients) { + val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp() + val newC = args.entries.fold(c) { product, (variable, substitution) -> + val deg = degs.getOrElse(variable) { 0u } + if (deg == 0u) product else product * substitution.pow(deg.toInt()) + } + if (newDegs !in this) this[newDegs] = newC + else this[newDegs] = this[newDegs]!! + newC + } + } + ) +} + +/** + * Substitutes provided arguments [args] into [this] polynomial. + */ +public fun NumberedPolynomial.substitute(ring: Ring, args: Map): NumberedPolynomial = ring { + NumberedPolynomial( + buildMap, C>(coefficients.size) { + for ((degs, c) in coefficients) { + val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp() + val newC = args.entries.fold(c) { product, (variable, substitution) -> + val deg = degs.getOrElse(variable) { 0u } + if (deg == 0u) product else product * power(substitution, deg) + } + if (newDegs !in this) this[newDegs] = newC + else this[newDegs] = this[newDegs]!! + newC + } + } + ) +} + +/** + * Substitutes provided arguments [args] into [this] polynomial. + */ // TODO: To optimize boxing +@JvmName("substitutePolynomial") +public fun NumberedPolynomial.substitute(ring: Ring, args: Map>) : NumberedPolynomial = + ring.numberedPolynomialSpace { + coefficients.entries.fold(zero) { acc, (degs, c) -> + val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp() + acc + args.entries.fold(NumberedPolynomial(mapOf(newDegs to c))) { product, (variable, substitution) -> + val deg = degs.getOrElse(variable) { 0u } + if (deg == 0u) product else product * power(substitution, deg) + } + } + } + +/** + * Substitutes provided arguments [args] into [this] polynomial. + */ // TODO: To optimize boxing +@JvmName("substituteRationalFunction") +public fun NumberedPolynomial.substitute(ring: Ring, args: Map>) : NumberedRationalFunction = + ring.numberedRationalFunctionSpace { + coefficients.entries.fold(zero) { acc, (degs, c) -> + val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp() + acc + args.entries.fold(NumberedRationalFunction(NumberedPolynomial(mapOf(newDegs to c)))) { product, (variable, substitution) -> + val deg = degs.getOrElse(variable) { 0u } + if (deg == 0u) product else product * power(substitution, deg) + } + } + } + +/** + * Substitutes provided Double arguments [args] into [this] Double rational function. + */ +public fun NumberedRationalFunction.substitute(args: Map): NumberedRationalFunction = + NumberedRationalFunction(numerator.substitute(args), denominator.substitute(args)) + +/** + * Substitutes provided arguments [args] into [this] rational function. + */ +public fun NumberedRationalFunction.substitute(ring: Ring, args: Map): NumberedRationalFunction = + NumberedRationalFunction(numerator.substitute(ring, args), denominator.substitute(ring, args)) + +/** + * Substitutes provided arguments [args] into [this] rational function. + */ // TODO: To optimize boxing +@JvmName("substitutePolynomial") +public fun NumberedRationalFunction.substitute(ring: Ring, args: Map>) : NumberedRationalFunction = + NumberedRationalFunction(numerator.substitute(ring, args), denominator.substitute(ring, args)) + +/** + * Substitutes provided arguments [args] into [this] rational function. + */ // TODO: To optimize boxing +@JvmName("substituteRationalFunction") +public fun NumberedRationalFunction.substitute(ring: Ring, args: Map>) : NumberedRationalFunction = + ring.numberedRationalFunctionSpace { + numerator.substitute(ring, args) / denominator.substitute(ring, args) + } + +/** + * Substitutes provided Double arguments [args] into [this] Double polynomial. + */ +public fun NumberedPolynomial.substitute(args: Buffer): NumberedPolynomial = Double.algebra { + val lastSubstitutionVariable = args.size - 1 + NumberedPolynomial( + buildMap(coefficients.size) { + for ((degs, c) in coefficients) { + val lastDegsIndex = degs.lastIndex + val newDegs = + if (lastDegsIndex <= lastSubstitutionVariable) emptyList() + else degs.toMutableList().apply { + for (i in 0..lastSubstitutionVariable) this[i] = 0u + } + val newC = (0..min(lastDegsIndex, lastSubstitutionVariable)).fold(c) { product, variable -> + val deg = degs[variable] + if (deg == 0u) product else product * args[variable].pow(deg.toInt()) + } + if (newDegs !in this) this[newDegs] = newC + else this[newDegs] = this[newDegs]!! + newC + } + } + ) +} + +/** + * Substitutes provided arguments [args] into [this] polynomial. + */ +public fun NumberedPolynomial.substitute(ring: Ring, args: Buffer): NumberedPolynomial = ring { + val lastSubstitutionVariable = args.size - 1 + NumberedPolynomial( + buildMap, C>(coefficients.size) { + for ((degs, c) in coefficients) { + val lastDegsIndex = degs.lastIndex + val newDegs = + if (lastDegsIndex <= lastSubstitutionVariable) emptyList() + else degs.toMutableList().apply { + for (i in 0..lastSubstitutionVariable) this[i] = 0u + } + val newC = (0..min(lastDegsIndex, lastSubstitutionVariable)).fold(c) { product, variable -> + val deg = degs[variable] + if (deg == 0u) product else product * power(args[variable], deg) + } + if (newDegs !in this) this[newDegs] = newC + else this[newDegs] = this[newDegs]!! + newC + } + } + ) +} + +/** + * Substitutes provided arguments [args] into [this] polynomial. + */ // TODO: To optimize boxing +@JvmName("substitutePolynomial") +public fun NumberedPolynomial.substitute(ring: Ring, args: Buffer>) : NumberedPolynomial = + ring.numberedPolynomialSpace { + val lastSubstitutionVariable = args.size - 1 + coefficients.entries.fold(zero) { acc, (degs, c) -> + val lastDegsIndex = degs.lastIndex + val newDegs = + if (lastDegsIndex <= lastSubstitutionVariable) emptyList() + else degs.toMutableList().apply { + for (i in 0..lastSubstitutionVariable) this[i] = 0u + } + acc + (0..min(lastDegsIndex, lastSubstitutionVariable)) + .fold(NumberedPolynomial(mapOf(newDegs to c))) { product, variable -> + val deg = degs[variable] + if (deg == 0u) product else product * power(args[variable], deg) + } + } + } + +/** + * Substitutes provided arguments [args] into [this] polynomial. + */ // TODO: To optimize boxing +@JvmName("substituteRationalFunction") +public fun NumberedPolynomial.substitute(ring: Ring, args: Buffer>) : NumberedRationalFunction = + ring.numberedRationalFunctionSpace { + val lastSubstitutionVariable = args.size - 1 + coefficients.entries.fold(zero) { acc, (degs, c) -> + val lastDegsIndex = degs.lastIndex + val newDegs = + if (lastDegsIndex <= lastSubstitutionVariable) emptyList() + else degs.toMutableList().apply { + for (i in 0..lastSubstitutionVariable) this[i] = 0u + } + acc + (0..min(lastDegsIndex, lastSubstitutionVariable)) + .fold(NumberedRationalFunction(NumberedPolynomial(mapOf(newDegs to c)))) { product, variable -> + val deg = degs[variable] + if (deg == 0u) product else product * power(args[variable], deg) + } + } + } + +/** + * Substitutes provided Double arguments [args] into [this] Double rational function. + */ +public fun NumberedRationalFunction.substitute(args: Buffer): NumberedRationalFunction = + NumberedRationalFunction(numerator.substitute(args), denominator.substitute(args)) + +/** + * Substitutes provided arguments [args] into [this] rational function. + */ +public fun NumberedRationalFunction.substitute(ring: Ring, args: Buffer): NumberedRationalFunction = + NumberedRationalFunction(numerator.substitute(ring, args), denominator.substitute(ring, args)) + +/** + * Substitutes provided arguments [args] into [this] rational function. + */ // TODO: To optimize boxing +@JvmName("substitutePolynomial") +public fun NumberedRationalFunction.substitute(ring: Ring, args: Buffer>) : NumberedRationalFunction = + NumberedRationalFunction(numerator.substitute(ring, args), denominator.substitute(ring, args)) + +/** + * Substitutes provided arguments [args] into [this] rational function. + */ // TODO: To optimize boxing +@JvmName("substituteRationalFunction") +public fun NumberedRationalFunction.substitute(ring: Ring, args: Buffer>) : NumberedRationalFunction = + ring.numberedRationalFunctionSpace { + numerator.substitute(ring, args) / denominator.substitute(ring, args) + } + +/** + * Substitutes provided Double arguments [args] into [this] Double polynomial. + */ +public fun NumberedPolynomial.substituteFully(args: Buffer): Double = Double.algebra { + val lastSubstitutionVariable = args.size - 1 + require(coefficients.keys.all { it.lastIndex <= lastSubstitutionVariable }) { "Fully substituting buffer should cover all variables of the polynomial." } + coefficients.entries.fold(.0) { acc, (degs, c) -> + acc + degs.foldIndexed(c) { variable, product, deg -> + if (deg == 0u) product else product * args[variable].pow(deg.toInt()) + } + } +} + +/** + * Substitutes provided arguments [args] into [this] polynomial. + */ +public fun NumberedPolynomial.substituteFully(ring: Ring, args: Buffer): C = ring { + val lastSubstitutionVariable = args.size - 1 + require(coefficients.keys.all { it.lastIndex <= lastSubstitutionVariable }) { "Fully substituting buffer should cover all variables of the polynomial." } + coefficients.entries.fold(zero) { acc, (degs, c) -> + acc + degs.foldIndexed(c) { variable, product, deg -> + if (deg == 0u) product else product * power(args[variable], deg) + } + } +} + +/** + * Substitutes provided Double arguments [args] into [this] Double rational function. + */ +public fun NumberedRationalFunction.substituteFully(args: Buffer): Double = + numerator.substituteFully(args) / denominator.substituteFully(args) + +/** + * Substitutes provided arguments [args] into [this] rational function. + */ +public fun NumberedRationalFunction.substituteFully(ring: Field, args: Buffer): C = ring { + numerator.substituteFully(ring, args) / denominator.substituteFully(ring, args) +} + +/** + * Represent [this] polynomial as a regular context-less function. + */ +public fun > NumberedPolynomial.asFunctionOver(ring: A): (Buffer) -> C = { substituteFully(ring, it) } + +/** + * Represent [this] polynomial as a regular context-less function. + */ +public fun > NumberedPolynomial.asFunctionOfConstantOver(ring: A): (Buffer) -> C = { substituteFully(ring, it) } + +/** + * Represent [this] polynomial as a regular context-less function. + */ +public fun > NumberedPolynomial.asFunctionOfPolynomialOver(ring: A): (Buffer>) -> NumberedPolynomial = { substitute(ring, it) } + +/** + * Represent [this] polynomial as a regular context-less function. + */ +public fun > NumberedPolynomial.asFunctionOfRationalFunctionOver(ring: A): (Buffer>) -> NumberedRationalFunction = { substitute(ring, it) } + +/** + * Represent [this] rational function as a regular context-less function. + */ +public fun > NumberedRationalFunction.asFunctionOver(ring: A): (Buffer) -> C = { substituteFully(ring, it) } + +/** + * Represent [this] rational function as a regular context-less function. + */ +public fun > NumberedRationalFunction.asFunctionOfConstantOver(ring: A): (Buffer) -> C = { substituteFully(ring, it) } + +/** + * Represent [this] rational function as a regular context-less function. + */ +public fun > NumberedRationalFunction.asFunctionOfPolynomialOver(ring: A): (Buffer>) -> NumberedRationalFunction = { substitute(ring, it) } + +/** + * Represent [this] rational function as a regular context-less function. + */ +public fun > NumberedRationalFunction.asFunctionOfRationalFunctionOver(ring: A): (Buffer>) -> NumberedRationalFunction = { substitute(ring, it) } + +/** + * Returns algebraic derivative of received polynomial with respect to provided variable. + */ +@UnstableKMathAPI +public fun > NumberedPolynomial.derivativeWithRespectTo( + ring: A, + variable: Int, +): NumberedPolynomial = ring { + NumberedPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + if (degs.size > variable) return@forEach + put( + degs.mapIndexed { index, deg -> + when { + index != variable -> deg + deg > 0u -> deg - 1u + else -> return@forEach + } + }.cleanUp(), + multiplyByDoubling(c, degs[variable]) + ) + } + } + ) +} + +/** + * Returns algebraic derivative of received polynomial with respect to provided variable of specified order. + */ +@UnstableKMathAPI +public fun > NumberedPolynomial.nthDerivativeWithRespectTo( + ring: A, + variable: Int, + order: UInt +): NumberedPolynomial = ring { + if (order == 0u) return this@nthDerivativeWithRespectTo + NumberedPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + if (degs.size > variable) return@forEach + put( + degs.mapIndexed { index, deg -> + when { + index != variable -> deg + deg >= order -> deg - order + else -> return@forEach + } + }.cleanUp(), + degs[variable].let { deg -> + (deg downTo deg - order + 1u) + .fold(c) { acc, ord -> multiplyByDoubling(acc, ord) } + } + ) + } + } + ) +} + +/** + * Returns algebraic derivative of received polynomial with respect to provided variables of specified orders. + */ +@UnstableKMathAPI +public fun > NumberedPolynomial.nthDerivativeWithRespectTo( + ring: A, + variablesAndOrders: Map, +): NumberedPolynomial = ring { + val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u } + if (filteredVariablesAndOrders.isEmpty()) return this@nthDerivativeWithRespectTo + val maxRespectedVariable = filteredVariablesAndOrders.keys.maxOrNull()!! + NumberedPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + if (degs.size > maxRespectedVariable) return@forEach + put( + degs.mapIndexed { index, deg -> + if (index !in filteredVariablesAndOrders) return@mapIndexed deg + val order = filteredVariablesAndOrders[index]!! + if (deg >= order) deg - order else return@forEach + }.cleanUp(), + filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> + degs[index].let { deg -> + (deg downTo deg - order + 1u) + .fold(acc1) { acc2, ord -> multiplyByDoubling(acc2, ord) } + } + } + ) + } + } + ) +} + +/** + * Returns algebraic antiderivative of received polynomial with respect to provided variable. + */ +@UnstableKMathAPI +public fun > NumberedPolynomial.antiderivativeWithRespectTo( + ring: A, + variable: Int, +): NumberedPolynomial = ring { + NumberedPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + put( + List(max(variable + 1, degs.size)) { if (it != variable) degs[it] else degs[it] + 1u }, + c / multiplyByDoubling(one, degs[variable]) + ) + } + } + ) +} + +/** + * Returns algebraic antiderivative of received polynomial with respect to provided variable of specified order. + */ +@UnstableKMathAPI +public fun > NumberedPolynomial.nthAntiderivativeWithRespectTo( + ring: A, + variable: Int, + order: UInt +): NumberedPolynomial = ring { + if (order == 0u) return this@nthAntiderivativeWithRespectTo + NumberedPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + put( + List(max(variable + 1, degs.size)) { if (it != variable) degs[it] else degs[it] + order }, + degs[variable].let { deg -> + (deg downTo deg - order + 1u) + .fold(c) { acc, ord -> acc / multiplyByDoubling(one, ord) } + } + ) + } + } + ) +} + +/** + * Returns algebraic derivative of received polynomial with respect to provided variables of specified orders. + */ +@UnstableKMathAPI +public fun > NumberedPolynomial.nthAntiderivativeWithRespectTo( + ring: A, + variablesAndOrders: Map, +): NumberedPolynomial = ring { + val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u } + if (filteredVariablesAndOrders.isEmpty()) return this@nthAntiderivativeWithRespectTo + val maxRespectedVariable = filteredVariablesAndOrders.keys.maxOrNull()!! + NumberedPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + put( + List(max(maxRespectedVariable + 1, degs.size)) { degs[it] + filteredVariablesAndOrders.getOrElse(it) { 0u } }, + filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> + degs[index].let { deg -> + (deg downTo deg - order + 1u) + .fold(acc1) { acc2, ord -> acc2 / multiplyByDoubling(one, ord) } + } + } + ) + } + } + ) +} \ No newline at end of file -- 2.34.1 From b5a94923b574bb840214fde3e1af1875c64777ef Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Fri, 17 Jun 2022 01:53:40 +0300 Subject: [PATCH 076/123] Fixed problems with JVM names. Exposed internal NumberedPolynomial constructor with opt-in condition. Added and upgraded tests. Fixed small bugs (mistakes). Upgraded arithmetic operations a bit. --- .../kmath/functions/ListPolynomial.kt | 60 +- .../kmath/functions/NumberedPolynomial.kt | 60 +- .../functions/NumberedRationalFunction.kt | 12 +- .../space/kscience/kmath/functions/misc.kt | 21 +- .../kmath/functions/numberedConstructors.kt | 79 +- .../kscience/kmath/functions/numberedUtil.kt | 2 +- .../kmath/functions/ListPolynomialTest.kt | 94 +- .../functions/NumberedConstructorsTest.kt | 111 ++ .../kmath/functions/NumberedPolynomialTest.kt | 1368 +++++++++++++++++ .../kscience/kmath/test/misc/IntModulo.kt | 6 +- 10 files changed, 1714 insertions(+), 99 deletions(-) create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt index 42e3f7301..b3f1eb8f7 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt @@ -100,14 +100,17 @@ public open class ListPolynomialSpace>( * The operation is equivalent to sum of [other] copies of [this]. */ public override operator fun ListPolynomial.times(other: Int): ListPolynomial = - if (other == 0) zero - else ListPolynomial( - coefficients - .toMutableList() - .apply { - for (deg in indices) this[deg] = this[deg] * other - } - ) + when (other) { + 0 -> zero + 1 -> this + else -> ListPolynomial( + coefficients + .toMutableList() + .apply { + for (deg in indices) this[deg] = this[deg] * other + } + ) + } /** * Returns sum of the integer represented as a polynomial and the polynomial. @@ -133,34 +136,39 @@ public open class ListPolynomialSpace>( * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. */ public override operator fun Int.minus(other: ListPolynomial): ListPolynomial = - if (this == 0) other - else - ListPolynomial( - other.coefficients - .toMutableList() - .apply { - forEachIndexed { index, c -> if (index != 0) this[index] = -c } + ListPolynomial( + other.coefficients + .toMutableList() + .apply { + if (this@minus == 0) { + indices.forEach { this[it] = -this[it] } + } else { + (1..lastIndex).forEach { this[it] = -this[it] } val result = this@minus - getOrElse(0) { constantZero } - if(size == 0) add(result) + if (size == 0) add(result) else this[0] = result } - ) + } + ) /** * Returns product of the integer represented as a polynomial and the polynomial. * * The operation is equivalent to sum of [this] copies of [other]. */ public override operator fun Int.times(other: ListPolynomial): ListPolynomial = - if (this == 0) zero - else ListPolynomial( - other.coefficients - .toMutableList() - .apply { - for (deg in indices) this[deg] = this@times * this[deg] - } - ) + when (this) { + 0 -> zero + 1 -> other + else -> ListPolynomial( + other.coefficients + .toMutableList() + .apply { + for (deg in indices) this[deg] = this@times * this[deg] + } + ) + } /** * Converts the integer [value] to polynomial. @@ -192,7 +200,7 @@ public open class ListPolynomialSpace>( else ListPolynomial( toMutableList() .apply { - forEachIndexed { index, c -> if (index != 0) this[index] = -c } + (1 .. lastIndex).forEach { this[it] = -this[it] } val result = if (size == 0) this@minus else this@minus - get(0) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt index 9304e66da..02a3af683 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -98,14 +98,17 @@ public class NumberedPolynomialSpace>( * The operation is equivalent to sum of [other] copies of [this]. */ public override operator fun NumberedPolynomial.times(other: Int): NumberedPolynomial = - if (other == 0) zero - else NumberedPolynomialAsIs( - coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this[degs]!! * other - } - ) + when (other) { + 0 -> zero + 1 -> this + else -> NumberedPolynomialAsIs( + coefficients + .toMutableMap() + .apply { + for (degs in keys) this[degs] = this[degs]!! * other + } + ) + } /** * Returns sum of the integer represented as a polynomial and the polynomial. @@ -130,16 +133,20 @@ public class NumberedPolynomialSpace>( * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. */ public override operator fun Int.minus(other: NumberedPolynomial): NumberedPolynomial = - if (this == 0) other - else - NumberedPolynomialAsIs( - other.coefficients - .toMutableMap() - .apply { + NumberedPolynomialAsIs( + other.coefficients + .toMutableMap() + .apply { + if (this@minus == 0) { + forEach { (key, value) -> this[key] = -value } + } else { + forEach { (key, value) -> if (key.isNotEmpty()) this[key] = -value } + val degs = emptyList() this[degs] = this@minus - getOrElse(degs) { constantZero } } + } ) /** * Returns product of the integer represented as a polynomial and the polynomial. @@ -147,14 +154,17 @@ public class NumberedPolynomialSpace>( * The operation is equivalent to sum of [this] copies of [other]. */ public override operator fun Int.times(other: NumberedPolynomial): NumberedPolynomial = - if (this == 0) zero - else NumberedPolynomialAsIs( - other.coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this@times * this[degs]!! - } - ) + when (this) { + 0 -> zero + 1 -> other + else -> NumberedPolynomialAsIs( + other.coefficients + .toMutableMap() + .apply { + for (degs in keys) this[degs] = this@times * this[degs]!! + } + ) + } /** * Converts the integer [value] to polynomial. @@ -185,7 +195,7 @@ public class NumberedPolynomialSpace>( else NumberedPolynomialAsIs( toMutableMap() .apply { - forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } + forEach { (degs, c) -> if (degs.isNotEmpty()) this[degs] = -c } val degs = emptyList() @@ -266,7 +276,7 @@ public class NumberedPolynomialSpace>( override operator fun NumberedPolynomial.plus(other: NumberedPolynomial): NumberedPolynomial = NumberedPolynomialAsIs( buildMap(coefficients.size + other.coefficients.size) { - other.coefficients.mapValuesTo(this) { it.value } + coefficients.mapValuesTo(this) { it.value } other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! + value else value } } ) @@ -276,7 +286,7 @@ public class NumberedPolynomialSpace>( override operator fun NumberedPolynomial.minus(other: NumberedPolynomial): NumberedPolynomial = NumberedPolynomialAsIs( buildMap(coefficients.size + other.coefficients.size) { - other.coefficients.mapValuesTo(this) { it.value } + coefficients.mapValuesTo(this) { it.value } other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! - value else -value } } ) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt index a2986879d..92f507735 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt @@ -119,11 +119,13 @@ public class NumberedRationalFunctionSpace> ( * Substitutes provided polynomial [argument] into [this] polynomial. */ @Suppress("NOTHING_TO_INLINE") + @JvmName("substitutePolynomial") public inline fun NumberedPolynomial.substitute(argument: Map>): NumberedPolynomial = substitute(ring, argument) /** * Substitutes provided rational function [argument] into [this] polynomial. */ @Suppress("NOTHING_TO_INLINE") + @JvmName("substituteRationalFunction") public inline fun NumberedPolynomial.substitute(argument: Map>): NumberedRationalFunction = substitute(ring, argument) /** * Substitutes provided constant [argument] into [this] rational function. @@ -134,11 +136,13 @@ public class NumberedRationalFunctionSpace> ( * Substitutes provided polynomial [argument] into [this] rational function. */ @Suppress("NOTHING_TO_INLINE") + @JvmName("substitutePolynomial") public inline fun NumberedRationalFunction.substitute(argument: Map>): NumberedRationalFunction = substitute(ring, argument) /** * Substitutes provided rational function [argument] into [this] rational function. */ @Suppress("NOTHING_TO_INLINE") + @JvmName("substituteRationalFunction") public inline fun NumberedRationalFunction.substitute(argument: Map>): NumberedRationalFunction = substitute(ring, argument) /** * Substitutes provided constant [argument] into [this] polynomial. @@ -149,11 +153,13 @@ public class NumberedRationalFunctionSpace> ( * Substitutes provided polynomial [argument] into [this] polynomial. */ @Suppress("NOTHING_TO_INLINE") + @JvmName("substitutePolynomial") public inline fun NumberedPolynomial.substitute(argument: Buffer>): NumberedPolynomial = substitute(ring, argument) /** * Substitutes provided rational function [argument] into [this] polynomial. */ @Suppress("NOTHING_TO_INLINE") + @JvmName("substituteRationalFunction") public inline fun NumberedPolynomial.substitute(argument: Buffer>): NumberedRationalFunction = substitute(ring, argument) /** * Substitutes provided constant [argument] into [this] rational function. @@ -164,11 +170,13 @@ public class NumberedRationalFunctionSpace> ( * Substitutes provided polynomial [arguments] into [this] rational function. */ @Suppress("NOTHING_TO_INLINE") + @JvmName("substitutePolynomial") public inline fun NumberedRationalFunction.substitute(arguments: Buffer>): NumberedRationalFunction = substitute(ring, arguments) /** * Substitutes provided rational function [arguments] into [this] rational function. */ @Suppress("NOTHING_TO_INLINE") + @JvmName("substituteRationalFunction") public inline fun NumberedRationalFunction.substitute(arguments: Buffer>): NumberedRationalFunction = substitute(ring, arguments) /** * Substitutes provided constant [arguments] into [this] polynomial. @@ -222,7 +230,7 @@ public class NumberedRationalFunctionSpace> ( * Substitutes provided [arguments] into [this] polynomial. */ @Suppress("NOTHING_TO_INLINE") - @JvmName("invokePolynomial") + @JvmName("invokeRationalFunction") public inline operator fun NumberedPolynomial.invoke(arguments: Buffer>): NumberedRationalFunction = substitute(ring, arguments) /** * Substitutes provided [arguments] into [this] rational function. @@ -234,6 +242,6 @@ public class NumberedRationalFunctionSpace> ( * Substitutes provided [arguments] into [this] rational function. */ @Suppress("NOTHING_TO_INLINE") - @JvmName("invokePolynomial") + @JvmName("invokeRationalFunction") public inline operator fun NumberedRationalFunction.invoke(arguments: Buffer>): NumberedRationalFunction = substitute(ring, arguments) } \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt index 8b6fac39e..7d6fc84fa 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt @@ -6,8 +6,27 @@ package space.kscience.kmath.functions +/** + * Marks operations that are going to be optimized reimplementations by reducing number of boxings but currently is + * under development and is not stable (or even ready to use). + */ @RequiresOptIn( message = "It's copy of operation with optimized boxing. It's currently unstable.", level = RequiresOptIn.Level.ERROR ) -internal annotation class UnstablePolynomialBoxingOptimization \ No newline at end of file +internal annotation class UnstablePolynomialBoxingOptimization + +/** + * Marks declarations that give access to internal entities of polynomials delicate structure. Thus, it allows to + * optimize performance a bit by skipping standard steps, but such skips may cause critical errors if something is + * implemented badly. Make sure you fully read and understand documentation and don't break internal contracts. + */ +@RequiresOptIn( + message = "This declaration gives access to delicate internal structure of polynomials. " + + "It allows to optimize performance by skipping unnecessary arguments check. " + + "But at the same time makes it easy to make a mistake " + + "that will cause wrong computation result or even runtime error. " + + "Make sure you fully read and understand documentation.", + level = RequiresOptIn.Level.WARNING +) +internal annotation class DelicatePolynomialAPI \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt index 05fff3472..37d5d7fb6 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt @@ -37,6 +37,38 @@ internal inline fun NumberedPolynomialAsIs(pairs: Collection @PublishedApi internal inline fun NumberedPolynomialAsIs(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(pairs.toMap()) +/** + * Constructs [NumberedPolynomial] with provided coefficients map [coefs]. The map is used as is. + * + * **Be sure you read description of [NumberedPolynomial.coefficients]. Otherwise, you may make a mistake that will + * cause wrong computation result or even runtime error.** + */ +@Suppress("FunctionName", "NOTHING_TO_INLINE") +@DelicatePolynomialAPI +public inline fun NumberedPolynomialWithoutCheck(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs) + +/** + * Constructs [NumberedPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient". + * The collections will be transformed to map with [toMap] and then will be used as is. + * + * **Be sure you read description of [NumberedPolynomial.coefficients]. Otherwise, you may make a mistake that will + * cause wrong computation result or even runtime error.** + */ +@Suppress("FunctionName", "NOTHING_TO_INLINE") +@DelicatePolynomialAPI +public inline fun NumberedPolynomialWithoutCheck(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs.toMap()) + +/** + * Constructs [NumberedPolynomial] with provided array of [pairs] of pairs "term's signature — term's coefficient". + * The array will be transformed to map with [toMap] and then will be used as is. + * + * **Be sure you read description of [NumberedPolynomial.coefficients]. Otherwise, you may make a mistake that will + * cause wrong computation result or even runtime error.** + */ +@Suppress("FunctionName", "NOTHING_TO_INLINE") +@DelicatePolynomialAPI +public inline fun NumberedPolynomialWithoutCheck(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(pairs.toMap()) + /** * Constructs [NumberedPolynomial] with provided coefficients map [coefs]. * @@ -245,11 +277,12 @@ public class NumberedPolynomialTermSignatureBuilder { * Declaring another power of the same variable will increase its degree by received degree. */ public infix fun Int.inPowerOf(deg: UInt) { - if (this > signature.lastIndex) { - signature.addAll(List(this - signature.lastIndex - 1) { 0u }) + val index = this - 1 + if (index > signature.lastIndex) { + signature.addAll(List(index - signature.lastIndex - 1) { 0u }) signature.add(deg) } else { - signature[this] += deg + signature[index] += deg } } /** @@ -334,22 +367,26 @@ public class NumberedPolynomialBuilder( // Waiting for context receivers :( FIXME: Replace with context receivers when they will be available -/** - * Creates [NumberedPolynomial] with lambda [block] in context of [this] ring of constants. - * - * For example, polynomial `5 x_1^2 x_3^3 - 6 x_2` can be described as - * ``` - * Int.algebra { - * val numberedPolynomial : NumberedPolynomial = NumberedPolynomial { - * 5 { 1 inPowerOf 2u; 3 inPowerOf 3u } // 5 x_1^2 x_3^3 + - * (-6) { 2 inPowerOf 1u } // (-6) x_2^1 - * } - * } - * ``` - */ -@UnstableKMathAPI -@Suppress("FunctionName") -public inline fun > A.NumberedPolynomial(initialCapacity: Int = 0, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder(::add, initialCapacity).apply(block).build() +///** +// * Creates [NumberedPolynomial] with lambda [block] in context of [this] ring of constants. +// * +// * For example, polynomial `5 x_1^2 x_3^3 - 6 x_2` can be described as +// * ``` +// * Int.algebra { +// * val numberedPolynomial : NumberedPolynomial = NumberedPolynomial { +// * 5 { 1 inPowerOf 2u; 3 inPowerOf 3u } // 5 x_1^2 x_3^3 + +// * (-6) { 2 inPowerOf 1u } // (-6) x_2^1 +// * } +// * } +// * ``` +// */ +// FIXME: For now this fabric does not let next two fabrics work. (See KT-52803.) Possible feature solutions: +// 1. `LowPriorityInOverloadResolution` becomes public. Then it should be applied to this function. +// 2. Union types are implemented. Then all three functions should be rewritten +// as one with single union type as a (context) receiver. +//@UnstableKMathAPI +//@Suppress("FunctionName") +//public inline fun > A.NumberedPolynomial(initialCapacity: Int = 0, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder(::add, initialCapacity).apply(block).build() /** * Creates [NumberedPolynomial] with lambda [block] in context of [this] ring of [NumberedPolynomial]s. * @@ -365,7 +402,7 @@ public inline fun > A.NumberedPolynomial(initialCapacity: Int = 0, */ @UnstableKMathAPI @Suppress("FunctionName") -public inline fun > NumberedPolynomialSpace.NumberedPolynomial(initialCapacity: Int, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() +public inline fun > NumberedPolynomialSpace.NumberedPolynomial(initialCapacity: Int = 0, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() /** * Creates [NumberedPolynomial] with lambda [block] in context of [this] field of [NumberedRationalFunction]s. * @@ -381,7 +418,7 @@ public inline fun > NumberedPolynomialSpace.NumberedPolynomi */ @UnstableKMathAPI @Suppress("FunctionName") -public inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(initialCapacity: Int, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() +public inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(initialCapacity: Int = 0, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() // Waiting for context receivers :( FIXME: Replace with context receivers when they will be available diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt index 484cd11e3..fca9a8ab8 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt @@ -86,7 +86,7 @@ public fun NumberedPolynomial.substitute(ring: Ring, args: Map /** * Substitutes provided arguments [args] into [this] polynomial. - */ // TODO: To optimize boxing + */ // TODO: To optimize boxing @JvmName("substitutePolynomial") public fun NumberedPolynomial.substitute(ring: Ring, args: Map>) : NumberedPolynomial = ring.numberedPolynomialSpace { diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt index c9950fac5..c4a7cc564 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt @@ -3,6 +3,8 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ +@file:Suppress("LocalVariableName") + package space.kscience.kmath.functions import space.kscience.kmath.test.misc.* @@ -28,25 +30,32 @@ class ListPolynomialTest { ListPolynomial(Rational(-2)) + 2, "test 3" ) - assertEquals( - ListPolynomial(), - ListPolynomial() + 0, + val polynomial_4 = ListPolynomial() + assertSame( + polynomial_4, + polynomial_4 + 0, "test 4" ) + val polynomial_5 = ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)) + assertSame( + polynomial_5, + polynomial_5 + 0, + "test 5" + ) assertEquals( ListPolynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + 1, - "test 5" + "test 6" ) assertEquals( ListPolynomial(Rational(-1)), ListPolynomial(Rational(-2)) + 1, - "test 6" + "test 7" ) assertEquals( ListPolynomial(Rational(2)), ListPolynomial() + 2, - "test 7" + "test 8" ) } } @@ -68,25 +77,32 @@ class ListPolynomialTest { ListPolynomial(Rational(2)) - 2, "test 3" ) - assertEquals( - ListPolynomial(), - ListPolynomial() - 0, + val polynomial_4 = ListPolynomial() + assertSame( + polynomial_4, + polynomial_4 - 0, "test 4" ) + val polynomial_5 = ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)) + assertEquals( + polynomial_5, + polynomial_5 - 0, + "test 5" + ) assertEquals( ListPolynomial(Rational(1), Rational(0), Rational(0), Rational(0)), ListPolynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - 1, - "test 5" + "test 6" ) assertEquals( ListPolynomial(Rational(1)), ListPolynomial(Rational(2)) - 1, - "test 6" + "test 7" ) assertEquals( ListPolynomial(Rational(-2)), ListPolynomial() - 2, - "test 7" + "test 8" ) } } @@ -103,6 +119,17 @@ class ListPolynomialTest { ListPolynomial(7, 0, 49, 21, 14) * 15, "test 2" ) + val polynomial = ListPolynomial(22, 26, 13, 15, 26) + assertSame( + zero, + polynomial * 0, + "test 3" + ) + assertSame( + polynomial, + polynomial * 1, + "test 4" + ) } } @Test @@ -123,25 +150,32 @@ class ListPolynomialTest { 2 + ListPolynomial(Rational(-2)), "test 3" ) - assertEquals( - ListPolynomial(), - 0 + ListPolynomial(), + val polynomial_4 = ListPolynomial() + assertSame( + polynomial_4, + 0 + polynomial_4, "test 4" ) + val polynomial_5 = ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)) + assertSame( + polynomial_5, + 0 + polynomial_5, + "test 5" + ) assertEquals( ListPolynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), 1 + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 5" + "test 6" ) assertEquals( ListPolynomial(Rational(-1)), 1 + ListPolynomial(Rational(-2)), - "test 6" + "test 7" ) assertEquals( ListPolynomial(Rational(2)), 2 + ListPolynomial(), - "test 7" + "test 8" ) } } @@ -163,25 +197,30 @@ class ListPolynomialTest { -2 - ListPolynomial(Rational(-2)), "test 3" ) + assertEquals( + ListPolynomial(Rational(-32, 9), Rational(-8, -9), Rational(8, 7)), + 0 - ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), + "test 4" + ) assertEquals( ListPolynomial(), 0 - ListPolynomial(), - "test 4" + "test 5" ) assertEquals( ListPolynomial(Rational(1), Rational(0), Rational(0), Rational(0)), -1 - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 5" + "test 6" ) assertEquals( ListPolynomial(Rational(1)), -1 - ListPolynomial(Rational(-2)), - "test 6" + "test 7" ) assertEquals( ListPolynomial(Rational(-2)), -2 - ListPolynomial(), - "test 7" + "test 8" ) } } @@ -198,6 +237,17 @@ class ListPolynomialTest { 15 * ListPolynomial(7, 0, 49, 21, 14), "test 2" ) + val polynomial = ListPolynomial(22, 26, 13, 15, 26) + assertSame( + zero, + 0 * polynomial, + "test 3" + ) + assertSame( + polynomial, + 1 * polynomial, + "test 4" + ) } } @Test diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt new file mode 100644 index 000000000..14493aaae --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt @@ -0,0 +1,111 @@ +/* + * 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.functions + +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.algebra +import space.kscience.kmath.operations.invoke +import kotlin.test.Test +import kotlin.test.assertEquals + + +class NumberedConstructorsTest { + @Test + @UnstableKMathAPI + fun testBuilder() { + assertEquals( + NumberedPolynomialAsIs( + listOf(2u, 0u, 3u) to 5, + listOf(0u, 1u) to -6, + ), + Int.algebra.numberedPolynomialSpace { + NumberedPolynomial { + 5 { 1 inPowerOf 2u; 3 inPowerOf 3u } + (-6) { 2 inPowerOf 1u } + } + }, + "test 1" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to -1, + ), + Int.algebra.numberedPolynomialSpace { + NumberedPolynomial { + 5 { } + (-6) { } + } + }, + "test 2" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(2u) to -1, + ), + Int.algebra.numberedPolynomialSpace { + NumberedPolynomial { + 5 { 1 inPowerOf 1u; 1 inPowerOf 1u } + (-6) { 1 inPowerOf 2u } + } + }, + "test 3" + ) + } + @Test + @UnstableKMathAPI + fun testFabric() { + assertEquals( + NumberedPolynomialAsIs( + listOf(2u, 0u, 3u) to 5, + listOf(0u, 1u) to -6, + ), + Int.algebra { + NumberedPolynomial( + listOf(2u, 0u, 3u) to 5, + listOf(0u, 1u) to -6, + ) + }, + "test 1" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(2u, 0u, 3u) to 5, + listOf(0u, 1u) to -6, + ), + Int.algebra { + NumberedPolynomial( + listOf(2u, 0u, 3u, 0u) to 5, + listOf(0u, 1u, 0u, 0u) to -6, + ) + }, + "test 2" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to -1, + ), + Int.algebra { + NumberedPolynomial( + listOf(0u) to 5, + listOf(0u, 0u) to -6, + ) + }, + "test 3" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to 0, + ), + Int.algebra { + NumberedPolynomial( + listOf(0u) to 5, + listOf(0u, 0u) to -5, + ) + }, + "test 4" + ) + } +} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt new file mode 100644 index 000000000..537e3b85d --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt @@ -0,0 +1,1368 @@ +/* + * 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. + */ + +@file:Suppress("LocalVariableName") + +package space.kscience.kmath.functions + +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.test.misc.* +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertSame + + +@UnstableKMathAPI +class NumberedPolynomialTest { + @Test + fun test_Polynomial_Int_plus() { + RationalField.numberedPolynomialSpace { + assertEquals( + NumberedPolynomial { + Rational(-22, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(5, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + -3, + "test 1" + ) + assertEquals( + NumberedPolynomial { + Rational(-3, 1) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + -3, + "test 2" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 1) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(27, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + -3, + "test 3" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 1) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(27, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + -3, + "test 4" + ) + val polynomial_5 = NumberedPolynomial { + Rational(-22, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + assertSame( + polynomial_5, + polynomial_5 + 0, + "test 5" + ) + val polynomial_6 = NumberedPolynomial { + Rational(0, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + assertSame( + polynomial_6, + polynomial_6 + 0, + "test 6" + ) + val polynomial_7 = NumberedPolynomial { + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + assertSame( + polynomial_7, + polynomial_7 + 0, + "test 7" + ) + } + } + @Test + fun test_Polynomial_Int_minus() { + RationalField.numberedPolynomialSpace { + assertEquals( + NumberedPolynomial { + Rational(-22, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(5, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } - 3, + "test 1" + ) + assertEquals( + NumberedPolynomial { + Rational(-3, 1) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } - 3, + "test 2" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 1) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(27, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } - 3, + "test 3" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 1) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(27, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } - 3, + "test 4" + ) + val polynomial_5 = NumberedPolynomial { + Rational(-22, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + assertSame( + polynomial_5, + polynomial_5 - 0, + "test 5" + ) + val polynomial_6 = NumberedPolynomial { + Rational(0, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + assertSame( + polynomial_6, + polynomial_6 - 0, + "test 6" + ) + val polynomial_7 = NumberedPolynomial { + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + assertSame( + polynomial_7, + polynomial_7 - 0, + "test 7" + ) + } + } + @Test + fun test_Polynomial_Int_times() { + IntModuloRing(35).numberedPolynomialSpace { + assertEquals( + NumberedPolynomial { + m(34) with {} + m(2) with { 1 pow 3u } + m(1) with { 2 pow 1u } + m(20) with { 1 pow 1u } + m(2) with { 3 pow 2u } + }, + NumberedPolynomial { + m(22) with {} + m(26) with { 1 pow 3u } + m(13) with { 2 pow 1u } + m(15) with { 1 pow 1u } + m(26) with { 3 pow 2u } + } * 27, + "test 1" + ) + assertEquals( + NumberedPolynomial { + m(0) with {} + m(0) with { 1 pow 3u } + m(0) with { 2 pow 1u } + m(0) with { 1 pow 1u } + m(0) with { 3 pow 2u } + }, + NumberedPolynomial { + m(7) with {} + m(0) with { 1 pow 3u } + m(49) with { 2 pow 1u } + m(21) with { 1 pow 1u } + m(14) with { 3 pow 2u } + } * 15, + "test 2" + ) + val polynomial = NumberedPolynomial { + m(22) with {} + m(26) with { 1 pow 3u } + m(13) with { 2 pow 1u } + m(15) with { 1 pow 1u } + m(26) with { 3 pow 2u } + } + assertSame( + zero, + polynomial * 0, + "test 3" + ) + assertSame( + polynomial, + polynomial * 1, + "test 4" + ) + } + } + @Test + fun test_Int_Polynomial_plus() { + RationalField.numberedPolynomialSpace { + assertEquals( + NumberedPolynomial { + Rational(-22, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + -3 + NumberedPolynomial { + Rational(5, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 1" + ) + assertEquals( + NumberedPolynomial { + Rational(-3, 1) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + -3 + NumberedPolynomial { + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 2" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 1) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + -3 + NumberedPolynomial { + Rational(27, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 3" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 1) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + -3 + NumberedPolynomial { + Rational(27, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 4" + ) + val polynomial_5 = NumberedPolynomial { + Rational(-22, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + assertSame( + polynomial_5, + 0 + polynomial_5, + "test 5" + ) + val polynomial_6 = NumberedPolynomial { + Rational(0, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + assertSame( + polynomial_6, + 0 + polynomial_6, + "test 6" + ) + val polynomial_7 = NumberedPolynomial { + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + assertSame( + polynomial_7, + 0 + polynomial_7, + "test 7" + ) + } + } + @Test + fun test_Int_Polynomial_minus() { + RationalField.numberedPolynomialSpace { + assertEquals( + NumberedPolynomial { + Rational(22, 9) with {} + Rational(8, 9) with { 1 pow 3u } + Rational(8, 7) with { 2 pow 4u } + }, + 3 - NumberedPolynomial { + Rational(5, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 1" + ) + assertEquals( + NumberedPolynomial { + Rational(3, 1) with {} + Rational(8, 9) with { 1 pow 3u } + Rational(8, 7) with { 2 pow 4u } + }, + 3 - NumberedPolynomial { + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 2" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 1) with {} + Rational(8, 9) with { 1 pow 3u } + Rational(8, 7) with { 2 pow 4u } + }, + 3 - NumberedPolynomial { + Rational(27, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 3" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 1) with {} + Rational(8, 9) with { 1 pow 3u } + Rational(8, 7) with { 2 pow 4u } + }, + 3 - NumberedPolynomial { + Rational(27, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 4" + ) + assertEquals( + NumberedPolynomial { + Rational(22, 9) with {} + Rational(8, 9) with { 1 pow 3u } + Rational(8, 7) with { 2 pow 4u } + }, + 0 - NumberedPolynomial { + Rational(-22, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 5" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 9) with {} + Rational(8, 9) with { 1 pow 3u } + Rational(8, 7) with { 2 pow 4u } + }, + 0 - NumberedPolynomial { + Rational(0, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 6" + ) + assertEquals( + NumberedPolynomial { + Rational(8, 9) with { 1 pow 3u } + Rational(8, 7) with { 2 pow 4u } + }, + 0 - NumberedPolynomial { + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 7" + ) + } + } + @Test + fun test_Int_Polynomial_times() { + IntModuloRing(35).numberedPolynomialSpace { + assertEquals( + NumberedPolynomial { + m(34) with {} + m(2) with { 1 pow 3u } + m(1) with { 2 pow 1u } + m(20) with { 1 pow 1u } + m(2) with { 3 pow 2u } + }, + 27 * NumberedPolynomial { + m(22) with {} + m(26) with { 1 pow 3u } + m(13) with { 2 pow 1u } + m(15) with { 1 pow 1u } + m(26) with { 3 pow 2u } + }, + "test 1" + ) + assertEquals( + NumberedPolynomial { + m(0) with {} + m(0) with { 1 pow 3u } + m(0) with { 2 pow 1u } + m(0) with { 1 pow 1u } + m(0) with { 3 pow 2u } + }, + 15 * NumberedPolynomial { + m(7) with {} + m(0) with { 1 pow 3u } + m(49) with { 2 pow 1u } + m(21) with { 1 pow 1u } + m(14) with { 3 pow 2u } + }, + "test 2" + ) + val polynomial = NumberedPolynomial { + m(22) with {} + m(26) with { 1 pow 3u } + m(13) with { 2 pow 1u } + m(15) with { 1 pow 1u } + m(26) with { 3 pow 2u } + } + assertSame( + zero, + 0 * polynomial, + "test 3" + ) + assertSame( + polynomial, + 1 * polynomial, + "test 4" + ) + } + } + @Test + fun test_Polynomial_Constant_plus() { + RationalField.numberedPolynomialSpace { + assertEquals( + NumberedPolynomial { + Rational(-22, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(5, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + Rational(-3), + "test 1" + ) + assertEquals( + NumberedPolynomial { + Rational(-3, 1) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + Rational(-3), + "test 2" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 1) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(27, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + Rational(-3), + "test 3" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 1) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(27, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + Rational(-3), + "test 4" + ) + assertEquals( + NumberedPolynomial { + Rational(-22, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(-22, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + Rational(0), + "test 5" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(0, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + Rational(0), + "test 6" + ) + assertEquals( + NumberedPolynomial { + Rational(0) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + Rational(0), + "test 7" + ) + } + } + @Test + fun test_Polynomial_Constant_minus() { + RationalField.numberedPolynomialSpace { + assertEquals( + NumberedPolynomial { + Rational(-22, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(5, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } - Rational(3), + "test 1" + ) + assertEquals( + NumberedPolynomial { + Rational(-3, 1) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } - Rational(3), + "test 2" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 1) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(27, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } - Rational(3), + "test 3" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 1) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(27, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } - Rational(3), + "test 4" + ) + assertEquals( + NumberedPolynomial { + Rational(-22, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(-22, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } - Rational(0), + "test 5" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(0, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } - Rational(0), + "test 6" + ) + assertEquals( + NumberedPolynomial { + Rational(0) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } - Rational(0), + "test 7" + ) + } + } + @Test + fun test_Polynomial_Constant_times() { + IntModuloRing(35).numberedPolynomialSpace { + assertEquals( + NumberedPolynomial { + m(34) with {} + m(2) with { 1 pow 3u } + m(1) with { 2 pow 1u } + m(20) with { 1 pow 1u } + m(2) with { 3 pow 2u } + }, + NumberedPolynomial { + m(22) with {} + m(26) with { 1 pow 3u } + m(13) with { 2 pow 1u } + m(15) with { 1 pow 1u } + m(26) with { 3 pow 2u } + } * m(27), + "test 1" + ) + assertEquals( + NumberedPolynomial { + m(0) with {} + m(0) with { 1 pow 3u } + m(0) with { 2 pow 1u } + m(0) with { 1 pow 1u } + m(0) with { 3 pow 2u } + }, + NumberedPolynomial { + m(7) with {} + m(0) with { 1 pow 3u } + m(49) with { 2 pow 1u } + m(21) with { 1 pow 1u } + m(14) with { 3 pow 2u } + } * m(15), + "test 2" + ) + assertEquals( + NumberedPolynomial { + m(0) with {} + m(0) with { 1 pow 3u } + m(0) with { 2 pow 1u } + m(0) with { 1 pow 1u } + m(0) with { 3 pow 2u } + }, + NumberedPolynomial { + m(22) with {} + m(26) with { 1 pow 3u } + m(13) with { 2 pow 1u } + m(15) with { 1 pow 1u } + m(26) with { 3 pow 2u } + } * m(0), + "test 3" + ) + assertEquals( + NumberedPolynomial { + m(22) with {} + m(26) with { 1 pow 3u } + m(13) with { 2 pow 1u } + m(15) with { 1 pow 1u } + m(26) with { 3 pow 2u } + }, + NumberedPolynomial { + m(22) with {} + m(26) with { 1 pow 3u } + m(13) with { 2 pow 1u } + m(15) with { 1 pow 1u } + m(26) with { 3 pow 2u } + } * m(1), + "test 4" + ) + } + } + @Test + fun test_Constant_Polynomial_plus() { + RationalField.numberedPolynomialSpace { + assertEquals( + NumberedPolynomial { + Rational(-22, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + Rational(-3) + NumberedPolynomial { + Rational(5, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 1" + ) + assertEquals( + NumberedPolynomial { + Rational(-3, 1) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + Rational(-3) + NumberedPolynomial { + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 2" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 1) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + Rational(-3) + NumberedPolynomial { + Rational(27, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 3" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 1) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + Rational(-3) + NumberedPolynomial { + Rational(27, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 4" + ) + assertEquals( + NumberedPolynomial { + Rational(-22, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + Rational(0) + NumberedPolynomial { + Rational(-22, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 5" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + Rational(0) + NumberedPolynomial { + Rational(0, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 6" + ) + assertEquals( + NumberedPolynomial { + Rational(0) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + Rational(0) + NumberedPolynomial { + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 7" + ) + } + } + @Test + fun test_Constant_Polynomial_minus() { + RationalField.numberedPolynomialSpace { + assertEquals( + NumberedPolynomial { + Rational(22, 9) with {} + Rational(8, 9) with { 1 pow 3u } + Rational(8, 7) with { 2 pow 4u } + }, + Rational(3) - NumberedPolynomial { + Rational(5, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 1" + ) + assertEquals( + NumberedPolynomial { + Rational(3, 1) with {} + Rational(8, 9) with { 1 pow 3u } + Rational(8, 7) with { 2 pow 4u } + }, + Rational(3) - NumberedPolynomial { + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 2" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 1) with {} + Rational(8, 9) with { 1 pow 3u } + Rational(8, 7) with { 2 pow 4u } + }, + Rational(3) - NumberedPolynomial { + Rational(27, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 3" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 1) with {} + Rational(8, 9) with { 1 pow 3u } + Rational(8, 7) with { 2 pow 4u } + }, + Rational(3) - NumberedPolynomial { + Rational(27, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 4" + ) + assertEquals( + NumberedPolynomial { + Rational(22, 9) with {} + Rational(8, 9) with { 1 pow 3u } + Rational(8, 7) with { 2 pow 4u } + }, + Rational(0) - NumberedPolynomial { + Rational(-22, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 5" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 9) with {} + Rational(8, 9) with { 1 pow 3u } + Rational(8, 7) with { 2 pow 4u } + }, + Rational(0) - NumberedPolynomial { + Rational(0, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 6" + ) + assertEquals( + NumberedPolynomial { + Rational(0) with {} + Rational(8, 9) with { 1 pow 3u } + Rational(8, 7) with { 2 pow 4u } + }, + Rational(0) - NumberedPolynomial { + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 7" + ) + } + } + @Test + fun test_Constant_Polynomial_times() { + IntModuloRing(35).numberedPolynomialSpace { + assertEquals( + NumberedPolynomial { + m(34) with {} + m(2) with { 1 pow 3u } + m(1) with { 2 pow 1u } + m(20) with { 1 pow 1u } + m(2) with { 3 pow 2u } + }, + m(27) * NumberedPolynomial { + m(22) with {} + m(26) with { 1 pow 3u } + m(13) with { 2 pow 1u } + m(15) with { 1 pow 1u } + m(26) with { 3 pow 2u } + }, + "test 1" + ) + assertEquals( + NumberedPolynomial { + m(0) with {} + m(0) with { 1 pow 3u } + m(0) with { 2 pow 1u } + m(0) with { 1 pow 1u } + m(0) with { 3 pow 2u } + }, + m(15) * NumberedPolynomial { + m(7) with {} + m(0) with { 1 pow 3u } + m(49) with { 2 pow 1u } + m(21) with { 1 pow 1u } + m(14) with { 3 pow 2u } + }, + "test 2" + ) + assertEquals( + NumberedPolynomial { + m(0) with {} + m(0) with { 1 pow 3u } + m(0) with { 2 pow 1u } + m(0) with { 1 pow 1u } + m(0) with { 3 pow 2u } + }, + m(0) * NumberedPolynomial { + m(22) with {} + m(26) with { 1 pow 3u } + m(13) with { 2 pow 1u } + m(15) with { 1 pow 1u } + m(26) with { 3 pow 2u } + }, + "test 3" + ) + assertEquals( + NumberedPolynomial { + m(22) with {} + m(26) with { 1 pow 3u } + m(13) with { 2 pow 1u } + m(15) with { 1 pow 1u } + m(26) with { 3 pow 2u } + }, + m(1) * NumberedPolynomial { + m(22) with {} + m(26) with { 1 pow 3u } + m(13) with { 2 pow 1u } + m(15) with { 1 pow 1u } + m(26) with { 3 pow 2u } + }, + "test 4" + ) + } + } + @Test + fun test_Polynomial_unaryMinus() { + RationalField.numberedPolynomialSpace { + assertEquals( + NumberedPolynomial { + Rational(-5, 9) with { 1 pow 5u } + Rational(8, 9) with {} + Rational(8, 7) with { 7 pow 13u } + }, + -NumberedPolynomial { + Rational(5, 9) with { 1 pow 5u } + Rational(-8, 9) with {} + Rational(-8, 7) with { 7 pow 13u } + }, + "test 1" + ) + assertEquals( + NumberedPolynomial { + Rational(-5, 9) with { 3 pow 7u } + Rational(8, 9) with {} + Rational(8, 7) with { 1 pow 3u } + Rational(0) with { 2 pow 4u } + Rational(0) with { 1 pow 5u } + }, + -NumberedPolynomial { + Rational(5, 9) with { 3 pow 7u } + Rational(-8, 9) with {} + Rational(-8, 7) with { 1 pow 3u } + Rational(0) with { 2 pow 4u } + Rational(0) with { 1 pow 5u } + }, + "test 2" + ) + } + } + @Test + fun test_Polynomial_Polynomial_plus() { + RationalField.numberedPolynomialSpace { + assertEquals( + NumberedPolynomial { + Rational(-17, 2) with {} + Rational(-1, 3) with { 1 pow 1u } + Rational(-25, 21) with { 1 pow 2u } + Rational(146, 63) with { 2 pow 1u } + Rational(-3, 5) with { 1 pow 1u; 2 pow 1u } + Rational(61, 15) with { 1 pow 2u; 2 pow 1u } + Rational(157, 63) with { 2 pow 2u } + Rational(-55, 21) with { 1 pow 1u; 2 pow 2u } + Rational(11, 24) with { 1 pow 2u; 2 pow 2u } + }, + NumberedPolynomial { + Rational(6, 4) with {} + Rational(-2, 6) with { 1 pow 1u } + Rational(10, 6) with { 1 pow 2u } + Rational(17, 7) with { 2 pow 1u } + Rational(-7, 7) with { 1 pow 1u; 2 pow 1u } + Rational(12, 5) with { 1 pow 2u; 2 pow 1u } + Rational(12, 7) with { 2 pow 2u } + Rational(-10, 3) with { 1 pow 1u; 2 pow 2u } + Rational(9, 8) with { 1 pow 2u; 2 pow 2u } + } + NumberedPolynomial { + Rational(-20, 2) with {} + Rational(0, 9) with { 1 pow 1u } + Rational(-20, 7) with { 1 pow 2u } + Rational(-1, 9) with { 2 pow 1u } + Rational(2, 5) with { 1 pow 1u; 2 pow 1u } + Rational(10, 6) with { 1 pow 2u; 2 pow 1u } + Rational(7, 9) with { 2 pow 2u } + Rational(5, 7) with { 1 pow 1u; 2 pow 2u } + Rational(-2, 3) with { 1 pow 2u; 2 pow 2u } + }, + "test 1" + ) + assertEquals( + NumberedPolynomial { + Rational(-17, 2) with {} + Rational(-1, 3) with { 1 pow 1u } + Rational(-25, 21) with { 1 pow 2u } + Rational(-1, 9) with { 2 pow 1u } + Rational(2, 5) with { 1 pow 1u; 2 pow 1u } + Rational(10, 6) with { 1 pow 2u; 2 pow 1u } + Rational(157, 63) with { 2 pow 2u } + Rational(-55, 21) with { 1 pow 1u; 2 pow 2u } + Rational(11, 24) with { 1 pow 2u; 2 pow 2u } + }, + NumberedPolynomial { + Rational(6, 4) with {} + Rational(-2, 6) with { 1 pow 1u } + Rational(10, 6) with { 1 pow 2u } + Rational(12, 7) with { 2 pow 2u } + Rational(-10, 3) with { 1 pow 1u; 2 pow 2u } + Rational(9, 8) with { 1 pow 2u; 2 pow 2u } + } + NumberedPolynomial { + Rational(-20, 2) with {} + Rational(0, 9) with { 1 pow 1u } + Rational(-20, 7) with { 1 pow 2u } + Rational(-1, 9) with { 2 pow 1u } + Rational(2, 5) with { 1 pow 1u; 2 pow 1u } + Rational(10, 6) with { 1 pow 2u; 2 pow 1u } + Rational(7, 9) with { 2 pow 2u } + Rational(5, 7) with { 1 pow 1u; 2 pow 2u } + Rational(-2, 3) with { 1 pow 2u; 2 pow 2u } + }, + "test 2" + ) + assertEquals( + NumberedPolynomial { + Rational(-17, 2) with {} + Rational(-1, 3) with { 1 pow 1u } + Rational(-25, 21) with { 1 pow 2u } + Rational(-1, 9) with { 2 pow 1u } + Rational(2, 5) with { 1 pow 1u; 2 pow 1u } + Rational(10, 6) with { 1 pow 2u; 2 pow 1u } + Rational(12, 7) with { 2 pow 2u } + Rational(-10, 3) with { 1 pow 1u; 2 pow 2u } + Rational(9, 8) with { 1 pow 2u; 2 pow 2u } + }, + NumberedPolynomial { + Rational(6, 4) with {} + Rational(-2, 6) with { 1 pow 1u } + Rational(10, 6) with { 1 pow 2u } + Rational(12, 7) with { 2 pow 2u } + Rational(-10, 3) with { 1 pow 1u; 2 pow 2u } + Rational(9, 8) with { 1 pow 2u; 2 pow 2u } + } + NumberedPolynomial { + Rational(-20, 2) with {} + Rational(0, 9) with { 1 pow 1u } + Rational(-20, 7) with { 1 pow 2u } + Rational(-1, 9) with { 2 pow 1u } + Rational(2, 5) with { 1 pow 1u; 2 pow 1u } + Rational(10, 6) with { 1 pow 2u; 2 pow 1u } + Rational(0) with { 2 pow 2u } + Rational(0) with { 1 pow 1u; 2 pow 2u } + Rational(0) with { 1 pow 2u; 2 pow 2u } + }, + "test 3" + ) + assertEquals( + NumberedPolynomial { + Rational(0) with {} + Rational(0) with { 1 pow 1u } + Rational(0) with { 1 pow 2u } + Rational(0) with { 2 pow 1u } + Rational(0) with { 1 pow 1u; 2 pow 1u } + Rational(0) with { 1 pow 2u; 2 pow 1u } + Rational(0) with { 2 pow 2u } + Rational(0) with { 1 pow 1u; 2 pow 2u } + Rational(0) with { 1 pow 2u; 2 pow 2u } + }, + NumberedPolynomial { + Rational(6, 4) with {} + Rational(-2, 6) with { 1 pow 1u } + Rational(10, 6) with { 1 pow 2u } + Rational(17, 7) with { 2 pow 1u } + Rational(-7, 7) with { 1 pow 1u; 2 pow 1u } + Rational(12, 5) with { 1 pow 2u; 2 pow 1u } + Rational(12, 7) with { 2 pow 2u } + Rational(-10, 3) with { 1 pow 1u; 2 pow 2u } + Rational(9, 8) with { 1 pow 2u; 2 pow 2u } + } + NumberedPolynomial { + Rational(-6, 4) with {} + Rational(2, 6) with { 1 pow 1u } + Rational(-10, 6) with { 1 pow 2u } + Rational(-17, 7) with { 2 pow 1u } + Rational(7, 7) with { 1 pow 1u; 2 pow 1u } + Rational(-12, 5) with { 1 pow 2u; 2 pow 1u } + Rational(-12, 7) with { 2 pow 2u } + Rational(10, 3) with { 1 pow 1u; 2 pow 2u } + Rational(-9, 8) with { 1 pow 2u; 2 pow 2u } + }, + "test 4" + ) + } + } + @Test + fun test_Polynomial_Polynomial_minus() { + RationalField.numberedPolynomialSpace { + assertEquals( + NumberedPolynomial { + Rational(-17, 2) with {} + Rational(-1, 3) with { 1 pow 1u } + Rational(-25, 21) with { 1 pow 2u } + Rational(146, 63) with { 2 pow 1u } + Rational(-3, 5) with { 1 pow 1u; 2 pow 1u } + Rational(61, 15) with { 1 pow 2u; 2 pow 1u } + Rational(157, 63) with { 2 pow 2u } + Rational(-55, 21) with { 1 pow 1u; 2 pow 2u } + Rational(11, 24) with { 1 pow 2u; 2 pow 2u } + }, + NumberedPolynomial { + Rational(6, 4) with {} + Rational(-2, 6) with { 1 pow 1u } + Rational(10, 6) with { 1 pow 2u } + Rational(17, 7) with { 2 pow 1u } + Rational(-7, 7) with { 1 pow 1u; 2 pow 1u } + Rational(12, 5) with { 1 pow 2u; 2 pow 1u } + Rational(12, 7) with { 2 pow 2u } + Rational(-10, 3) with { 1 pow 1u; 2 pow 2u } + Rational(9, 8) with { 1 pow 2u; 2 pow 2u } + } - NumberedPolynomial { + Rational(20, 2) with {} + Rational(0, 9) with { 1 pow 1u } + Rational(20, 7) with { 1 pow 2u } + Rational(1, 9) with { 2 pow 1u } + Rational(-2, 5) with { 1 pow 1u; 2 pow 1u } + Rational(-10, 6) with { 1 pow 2u; 2 pow 1u } + Rational(-7, 9) with { 2 pow 2u } + Rational(-5, 7) with { 1 pow 1u; 2 pow 2u } + Rational(2, 3) with { 1 pow 2u; 2 pow 2u } + }, + "test 1" + ) + assertEquals( + NumberedPolynomial { + Rational(-17, 2) with {} + Rational(-1, 3) with { 1 pow 1u } + Rational(-25, 21) with { 1 pow 2u } + Rational(-1, 9) with { 2 pow 1u } + Rational(2, 5) with { 1 pow 1u; 2 pow 1u } + Rational(10, 6) with { 1 pow 2u; 2 pow 1u } + Rational(157, 63) with { 2 pow 2u } + Rational(-55, 21) with { 1 pow 1u; 2 pow 2u } + Rational(11, 24) with { 1 pow 2u; 2 pow 2u } + }, + NumberedPolynomial { + Rational(6, 4) with {} + Rational(-2, 6) with { 1 pow 1u } + Rational(10, 6) with { 1 pow 2u } + Rational(12, 7) with { 2 pow 2u } + Rational(-10, 3) with { 1 pow 1u; 2 pow 2u } + Rational(9, 8) with { 1 pow 2u; 2 pow 2u } + } - NumberedPolynomial { + Rational(20, 2) with {} + Rational(0, 9) with { 1 pow 1u } + Rational(20, 7) with { 1 pow 2u } + Rational(1, 9) with { 2 pow 1u } + Rational(-2, 5) with { 1 pow 1u; 2 pow 1u } + Rational(-10, 6) with { 1 pow 2u; 2 pow 1u } + Rational(-7, 9) with { 2 pow 2u } + Rational(-5, 7) with { 1 pow 1u; 2 pow 2u } + Rational(2, 3) with { 1 pow 2u; 2 pow 2u } + }, + "test 2" + ) + assertEquals( + NumberedPolynomial { + Rational(-17, 2) with {} + Rational(-1, 3) with { 1 pow 1u } + Rational(-25, 21) with { 1 pow 2u } + Rational(-1, 9) with { 2 pow 1u } + Rational(2, 5) with { 1 pow 1u; 2 pow 1u } + Rational(10, 6) with { 1 pow 2u; 2 pow 1u } + Rational(12, 7) with { 2 pow 2u } + Rational(-10, 3) with { 1 pow 1u; 2 pow 2u } + Rational(9, 8) with { 1 pow 2u; 2 pow 2u } + }, + NumberedPolynomial { + Rational(6, 4) with {} + Rational(-2, 6) with { 1 pow 1u } + Rational(10, 6) with { 1 pow 2u } + Rational(12, 7) with { 2 pow 2u } + Rational(-10, 3) with { 1 pow 1u; 2 pow 2u } + Rational(9, 8) with { 1 pow 2u; 2 pow 2u } + } - NumberedPolynomial { + Rational(20, 2) with {} + Rational(0, 9) with { 1 pow 1u } + Rational(20, 7) with { 1 pow 2u } + Rational(1, 9) with { 2 pow 1u } + Rational(-2, 5) with { 1 pow 1u; 2 pow 1u } + Rational(-10, 6) with { 1 pow 2u; 2 pow 1u } + Rational(0) with { 2 pow 2u } + Rational(0) with { 1 pow 1u; 2 pow 2u } + Rational(0) with { 1 pow 2u; 2 pow 2u } + }, + "test 3" + ) + assertEquals( + NumberedPolynomial { + Rational(0) with {} + Rational(0) with { 1 pow 1u } + Rational(0) with { 1 pow 2u } + Rational(0) with { 2 pow 1u } + Rational(0) with { 1 pow 1u; 2 pow 1u } + Rational(0) with { 1 pow 2u; 2 pow 1u } + Rational(0) with { 2 pow 2u } + Rational(0) with { 1 pow 1u; 2 pow 2u } + Rational(0) with { 1 pow 2u; 2 pow 2u } + }, + NumberedPolynomial { + Rational(6, 4) with {} + Rational(-2, 6) with { 1 pow 1u } + Rational(10, 6) with { 1 pow 2u } + Rational(17, 7) with { 2 pow 1u } + Rational(-7, 7) with { 1 pow 1u; 2 pow 1u } + Rational(12, 5) with { 1 pow 2u; 2 pow 1u } + Rational(12, 7) with { 2 pow 2u } + Rational(-10, 3) with { 1 pow 1u; 2 pow 2u } + Rational(9, 8) with { 1 pow 2u; 2 pow 2u } + } - NumberedPolynomial { + Rational(6, 4) with {} + Rational(-2, 6) with { 1 pow 1u } + Rational(10, 6) with { 1 pow 2u } + Rational(17, 7) with { 2 pow 1u } + Rational(-7, 7) with { 1 pow 1u; 2 pow 1u } + Rational(12, 5) with { 1 pow 2u; 2 pow 1u } + Rational(12, 7) with { 2 pow 2u } + Rational(-10, 3) with { 1 pow 1u; 2 pow 2u } + Rational(9, 8) with { 1 pow 2u; 2 pow 2u } + }, + "test 4" + ) + } + } + @Test + fun test_Polynomial_Polynomial_times() { + IntModuloRing(35).numberedPolynomialSpace { + // (p + q + r) * (p^2 + q^2 + r^2 - pq - pr - qr) = p^3 + q^3 + r^3 - 3pqr + assertEquals( + NumberedPolynomial { + m(1) with { 1 pow 3u } + m(1) with { 2 pow 3u } + m(1) with { 3 pow 3u } + m(0) with { 1 pow 1u; 2 pow 2u } + m(0) with { 2 pow 1u; 3 pow 2u } + m(0) with { 3 pow 1u; 1 pow 2u } + m(0) with { 1 pow 1u; 3 pow 2u } + m(0) with { 2 pow 1u; 1 pow 2u } + m(0) with { 3 pow 1u; 2 pow 2u } + m(-3) with { 1 pow 1u; 2 pow 1u; 3 pow 1u } + }, + NumberedPolynomial { + m(1) with { 1 pow 1u } + m(1) with { 2 pow 1u } + m(1) with { 3 pow 1u } + } * NumberedPolynomial { + m(1) with { 1 pow 2u } + m(1) with { 2 pow 2u } + m(1) with { 3 pow 2u } + m(-1) with { 1 pow 1u; 2 pow 1u } + m(-1) with { 2 pow 1u; 3 pow 1u } + m(-1) with { 3 pow 1u; 1 pow 1u } + }, + "test 1" + ) + // Spoiler: 5 * 7 = 0 + assertEquals( + NumberedPolynomial { + m(0) with { 1 pow 2u } + m(0) with { 2 pow 2u } + m(0) with { 3 pow 2u } + m(0) with { 1 pow 1u; 2 pow 1u } + m(0) with { 2 pow 1u; 3 pow 1u } + m(0) with { 3 pow 1u; 1 pow 1u } + }, + NumberedPolynomial { + m(5) with { 1 pow 1u } + m(-25) with { 2 pow 1u } + m(10) with { 3 pow 1u } + } * NumberedPolynomial { + m(21) with { 1 pow 1u } + m(14) with { 2 pow 1u } + m(-7) with { 3 pow 1u } + }, + "test 2" + ) + } + } +} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt index 89764db46..afd2b5add 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt @@ -7,6 +7,7 @@ package space.kscience.kmath.test.misc import space.kscience.kmath.functions.ListPolynomial import space.kscience.kmath.functions.ListPolynomialSpace +import space.kscience.kmath.functions.PolynomialSpaceOverRing import space.kscience.kmath.operations.Ring @@ -135,4 +136,7 @@ class IntModuloRing : Ring { fun ListPolynomialSpace.ListPolynomial(vararg coefs: Int): ListPolynomial = ListPolynomial(coefs.map { IntModulo(it, ring.modulus) }) fun IntModuloRing.ListPolynomial(vararg coefs: Int): ListPolynomial = - ListPolynomial(coefs.map { IntModulo(it, modulus) }) \ No newline at end of file + ListPolynomial(coefs.map { IntModulo(it, modulus) }) + +fun IntModuloRing.m(arg: Int) = IntModulo(arg, modulus) +fun PolynomialSpaceOverRing.m(arg: Int) = IntModulo(arg, ring.modulus) \ No newline at end of file -- 2.34.1 From 1ea336b70ea5a0f44722071b29193215c1460b14 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Fri, 17 Jun 2022 22:07:54 +0300 Subject: [PATCH 077/123] Added some test of NumberedPolynomial utilities. --- .../functions/NumberedPolynomialUtilTest.kt | 293 ++++++++++++++++++ .../kscience/kmath/test/misc/assertion.kt | 14 + 2 files changed, 307 insertions(+) create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/assertion.kt diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt new file mode 100644 index 000000000..ecad6198e --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt @@ -0,0 +1,293 @@ +/* + * 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.functions + +import space.kscience.kmath.test.misc.Rational +import space.kscience.kmath.test.misc.RationalField +import space.kscience.kmath.test.misc.assertContentEquals +import kotlin.test.Test +import kotlin.test.assertEquals + + +class NumberedPolynomialUtilTest { + @Test + fun test_substitute_Double_Map() { + assertContentEquals( + mapOf(emptyList() to 0.0), + NumberedPolynomialAsIs( + listOf() to 1.0, + listOf(1u) to -2.0, + listOf(2u) to 1.0, + ).substitute(mapOf( + 0 to 1.0 + )).coefficients, + 0.001, + "test 1" + ) + assertContentEquals( + mapOf( + listOf() to 0.8597048543814783, + listOf(1u) to 0.22997637465889875, + listOf(2u) to 0.32675302591924016, + listOf(0u, 1u) to 0.4561746111587508, + listOf(1u, 1u) to 0.5304946210170756, + listOf(2u, 1u) to 0.6244313712888998, + listOf(0u, 2u) to 0.2700930201481795, + listOf(1u, 2u) to -0.06962351375204712, + listOf(2u, 2u) to -0.015206988092131501, + ), + NumberedPolynomialAsIs( + listOf() to 0.8597048543814783, + listOf(1u) to 0.22997637465889875, + listOf(2u) to 0.32675302591924016, + listOf(0u, 1u) to 0.4561746111587508, + listOf(1u, 1u) to 0.5304946210170756, + listOf(2u, 1u) to 0.6244313712888998, + listOf(0u, 2u) to 0.2700930201481795, + listOf(1u, 2u) to -0.06962351375204712, + listOf(2u, 2u) to -0.015206988092131501, + ).substitute(mapOf()).coefficients, + 0.001, + "test 2" + ) + assertContentEquals( + mapOf( + listOf() to 0.8597048543814783, + listOf(0u, 1u) to 0.4561746111587508, + listOf(0u, 2u) to 0.2700930201481795, + ), + NumberedPolynomialAsIs( + listOf() to 0.8597048543814783, + listOf(1u) to 0.22997637465889875, + listOf(2u) to 0.32675302591924016, + listOf(0u, 1u) to 0.4561746111587508, + listOf(1u, 1u) to 0.5304946210170756, + listOf(2u, 1u) to 0.6244313712888998, + listOf(0u, 2u) to 0.2700930201481795, + listOf(1u, 2u) to -0.06962351375204712, + listOf(2u, 2u) to -0.015206988092131501, + ).substitute(mapOf( + 0 to 0.0 + )).coefficients, + 0.001, + "test 3" + ) + assertContentEquals( + mapOf( + listOf() to 1.433510890645169, + listOf(1u) to 0.6264844682514724, + listOf(2u) to 0.8405727903771333, + ), + NumberedPolynomialAsIs( + listOf() to 0.8597048543814783, + listOf(1u) to 0.22997637465889875, + listOf(2u) to 0.32675302591924016, + listOf(0u, 1u) to 0.4561746111587508, + listOf(1u, 1u) to 0.5304946210170756, + listOf(2u, 1u) to 0.6244313712888998, + listOf(0u, 2u) to 0.2700930201481795, + listOf(1u, 2u) to -0.06962351375204712, + listOf(2u, 2u) to -0.015206988092131501, + ).substitute(mapOf( + 1 to 0.8400458576651112 + )).coefficients, + 0.001, + "test 4" + ) + assertContentEquals( + mapOf( + listOf() to 1.934530767358133, + ), + NumberedPolynomialAsIs( + listOf() to 0.8597048543814783, + listOf(1u) to 0.22997637465889875, + listOf(2u) to 0.32675302591924016, + listOf(0u, 1u) to 0.4561746111587508, + listOf(1u, 1u) to 0.5304946210170756, + listOf(2u, 1u) to 0.6244313712888998, + listOf(0u, 2u) to 0.2700930201481795, + listOf(1u, 2u) to -0.06962351375204712, + listOf(2u, 2u) to -0.015206988092131501, + ).substitute(mapOf( + 0 to 0.4846192734143442, + 1 to 0.8400458576651112, + )).coefficients, + 0.001, + "test 5" + ) + assertContentEquals( + mapOf( + listOf() to 0.8597048543814783, + listOf(1u) to 0.22997637465889875, + listOf(2u) to 0.32675302591924016, + listOf(0u, 1u) to 0.4561746111587508, + listOf(1u, 1u) to 0.5304946210170756, + listOf(2u, 1u) to 0.6244313712888998, + listOf(0u, 2u) to 0.2700930201481795, + listOf(1u, 2u) to -0.06962351375204712, + listOf(2u, 2u) to -0.015206988092131501, + ), + NumberedPolynomialAsIs( + listOf() to 0.8597048543814783, + listOf(1u) to 0.22997637465889875, + listOf(2u) to 0.32675302591924016, + listOf(0u, 1u) to 0.4561746111587508, + listOf(1u, 1u) to 0.5304946210170756, + listOf(2u, 1u) to 0.6244313712888998, + listOf(0u, 2u) to 0.2700930201481795, + listOf(1u, 2u) to -0.06962351375204712, + listOf(2u, 2u) to -0.015206988092131501, + ).substitute(mapOf( + 5 to 0.9211194782050933 + )).coefficients, + 0.001, + "test 6" + ) + } + @Test + fun test_substitute_Constant() { + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(0) + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1) + ).substitute(RationalField, mapOf( + 0 to Rational(1) + )), + "test 1" + ) + // https://www.wolframalpha.com/input?i=%28-3%2F2+%2B+8%2F6+x+%2B+14%2F6+x%5E2%29+%2B+%28-3%2F1+%2B+-19%2F2+x+%2B+9%2F4+x%5E2%29+y+%2B+%285%2F5+%2B+18%2F9+x+%2B+5%2F2+x%5E2%29+y%5E2+where+x+%3D+-2%2F5%2C+y+%3D+12%2F9 + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(143, 150) + ), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + 0 to Rational(-2, 5), + 1 to Rational(12, 9), + )), + "test 2" + ) + // https://www.wolframalpha.com/input?i=%28%28-3%2F2+%2B+8%2F6+x+%2B+14%2F6+x%5E2%29+%2B+%28-3%2F1+%2B+-19%2F2+x+%2B+9%2F4+x%5E2%29+y+%2B+%285%2F5+%2B+18%2F9+x+%2B+5%2F2+x%5E2%29+y%5E2%29+p%5E8+where+x+%3D+q%2Fp%2C+y+%3D+x%5E3%2C+p+%3D+-2%2F5%2C+q+%3D+12%2F9 + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(47639065216, 2562890625) + ), + NumberedPolynomialAsIs( + listOf(8u) to Rational(-3, 2), + listOf(7u, 1u) to Rational(8, 6), + listOf(6u, 2u) to Rational(14, 6), + listOf(5u, 3u) to Rational(-3, 1), + listOf(4u, 4u) to Rational(-19, 2), + listOf(3u, 5u) to Rational(9, 4), + listOf(2u, 6u) to Rational(5, 5), + listOf(1u, 7u) to Rational(18, 9), + listOf(0u, 8u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + 0 to Rational(-2, 5), + 1 to Rational(12, 9), + )), + "test 3" + ) + // https://www.wolframalpha.com/input?i=%28%28-3%2F2+%2B+8%2F6+x+%2B+14%2F6+x%5E2%29+%2B+%28-3%2F1+%2B+-19%2F2+x+%2B+9%2F4+x%5E2%29+y+%2B+%285%2F5+%2B+18%2F9+x+%2B+5%2F2+x%5E2%29+y%5E2%29+p%5E8+where+x+%3D+q%2Fp%2C+y+%3D+x%5E3%2C+p+%3D+-2%2F5%2C+q+%3D+12%2F9 + assertEquals( + NumberedPolynomialAsIs( + listOf(8u) to Rational(-3, 2), + listOf(7u, 1u) to Rational(8, 6), + listOf(6u, 2u) to Rational(14, 6), + listOf(5u, 3u) to Rational(-3, 1), + listOf(4u, 4u) to Rational(-19, 2), + listOf(3u, 5u) to Rational(9, 4), + listOf(2u, 6u) to Rational(5, 5), + listOf(1u, 7u) to Rational(18, 9), + listOf(0u, 8u) to Rational(5, 2), + ), + NumberedPolynomialAsIs( + listOf(8u) to Rational(-3, 2), + listOf(7u, 1u) to Rational(8, 6), + listOf(6u, 2u) to Rational(14, 6), + listOf(5u, 3u) to Rational(-3, 1), + listOf(4u, 4u) to Rational(-19, 2), + listOf(3u, 5u) to Rational(9, 4), + listOf(2u, 6u) to Rational(5, 5), + listOf(1u, 7u) to Rational(18, 9), + listOf(0u, 8u) to Rational(5, 2), + ).substitute(RationalField, mapOf()), + "test 4" + ) + } + @Test + fun test_substitute_Polynomial() { + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(0) + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1) + ).substitute(RationalField, mapOf( + 0 to NumberedPolynomialAsIs( + listOf() to Rational(1) + ) + )), + "test 1" + ) + // https://www.wolframalpha.com/input?i=%28-3%2F2+%2B+8%2F6+x+%2B+14%2F6+x%5E2%29+%2B+%28-3%2F1+%2B+-19%2F2+x+%2B+9%2F4+x%5E2%29+y+%2B+%285%2F5+%2B+18%2F9+x+%2B+5%2F2+x%5E2%29+y%5E2+where+x+%3D+-2%2F5%2C+y+%3D+12%2F9 + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(0u, 1u) to Rational(-92, 21), + listOf(0u, 2u) to Rational(-2627, 2352), + listOf(0u, 3u) to Rational(4565, 3136), + listOf(0u, 4u) to Rational(605, 1568), + listOf(1u) to Rational(-20, 3), + listOf(1u, 1u) to Rational(1445, 21), + listOf(1u, 2u) to Rational(-13145, 392), + listOf(1u, 3u) to Rational(-3025, 196), + listOf(2u) to Rational(175, 3), + listOf(2u, 1u) to Rational(2475, 28), + listOf(2u, 2u) to Rational(15125, 98), + listOf(3u) to Rational(0), + listOf(3u, 1u) to Rational(0), + listOf(4u) to Rational(0), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + 0 to NumberedPolynomialAsIs( + listOf(1u) to Rational(-5, 1), + listOf(0u, 1u) to Rational(2, 8), + ), + 1 to NumberedPolynomialAsIs( + listOf(1u) to Rational(0, 5), + listOf(0u, 1u) to Rational(11, 7), + ), + )), + "test 2" + ) + } +} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/assertion.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/assertion.kt new file mode 100644 index 000000000..52ecf416a --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/assertion.kt @@ -0,0 +1,14 @@ +/* + * 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 kotlin.test.assertEquals + + +fun assertContentEquals(expected: Map, actual: Map, absoluteTolerance: Double, message: String? = null) { + assertEquals(expected.keys, actual.keys, message) + for ((key, expectedValue) in expected) assertEquals(expectedValue, actual[key]!!, absoluteTolerance, message) +} \ No newline at end of file -- 2.34.1 From 680d23ddcb0c3e11ea779146f3d2ced2d8c741be Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sat, 18 Jun 2022 01:25:14 +0300 Subject: [PATCH 078/123] Last sift. Cleaned up labeled structures. --- .../kmath/functions/LabeledPolynomial.kt | 621 ++++++++++++++++++ .../functions/LabeledRationalFunction.kt | 96 +++ .../kmath/functions/ListPolynomial.kt | 2 +- .../kmath/functions/NumberedPolynomial.kt | 11 +- .../kmath/functions/labeledConstructors.kt | 518 +++++++++++++++ .../kscience/kmath/functions/labeledUtil.kt | 327 +++++++++ .../kmath/functions/numberedConstructors.kt | 40 +- .../kscience/kmath/functions/numberedUtil.kt | 18 +- 8 files changed, 1584 insertions(+), 49 deletions(-) create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledUtil.kt diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt new file mode 100644 index 000000000..b0c54502d --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt @@ -0,0 +1,621 @@ +/* + * 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.functions + +import space.kscience.kmath.expressions.Symbol +import space.kscience.kmath.operations.Ring +import kotlin.jvm.JvmName +import kotlin.math.max + + +/** + * Represents multivariate polynomial that stores its coefficients in a [Map] and terms' signatures in a [Map] that + * associates variables (of type [Symbol]) with their degree. + * + * @param C the type of constants. + */ +public data class LabeledPolynomial +@PublishedApi +internal constructor( + /** + * Map that contains coefficients of the polynomial. + * + * Every monomial `a x_1^{d_1} ... x_n^{d_n}` is stored as a pair "key-value" in the map, where the value is the + * coefficient `a` and the key is a map that associates variables in the monomial with their degree in the monomial. + * For example, coefficients of a polynomial `5 a^2 c^3 - 6 b` can be represented as + * ``` + * mapOf( + * mapOf( + * a to 2, + * c to 3 + * ) to 5, + * mapOf( + * b to 1 + * ) to (-6) + * ) + * ``` + * and also as + * ``` + * mapOf( + * mapOf( + * a to 2, + * c to 3 + * ) to 5, + * mapOf( + * b to 1 + * ) to (-6), + * mapOf( + * b to 1, + * c to 1 + * ) to 0 + * ) + * ``` + * where `a`, `b` and `c` are corresponding [Symbol] objects. + */ + public val coefficients: Map, C> +) : Polynomial { + override fun toString(): String = "LabeledPolynomial$coefficients" +} + +/** + * Arithmetic context for multivariate polynomials with coefficients stored as a [Map] and terms' signatures stored as a + * [Map] constructed with the provided [ring] of constants. + * + * @param C the type of constants. Polynomials have them a coefficients in their terms. + * @param A type of provided underlying ring of constants. It's [Ring] of [C]. + * @param ring underlying ring of constants of type [A]. + */ +public class LabeledPolynomialSpace>( + public override val ring: A, +) : MultivariatePolynomialSpace>, PolynomialSpaceOverRing, A> { + /** + * Returns sum of the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ + public override operator fun Symbol.plus(other: Int): LabeledPolynomial = + if (other == 0) LabeledPolynomialAsIs(mapOf( + mapOf(this@plus to 1U) to constantOne, + )) + else LabeledPolynomialAsIs(mapOf( + mapOf(this@plus to 1U) to constantOne, + emptyMap() to constantOne * other, + )) + /** + * Returns difference between the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ + public override operator fun Symbol.minus(other: Int): LabeledPolynomial = + if (other == 0) LabeledPolynomialAsIs(mapOf( + mapOf(this@minus to 1U) to -constantOne, + )) + else LabeledPolynomialAsIs(mapOf( + mapOf(this@minus to 1U) to -constantOne, + emptyMap() to constantOne * other, + )) + /** + * Returns product of the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ + public override operator fun Symbol.times(other: Int): LabeledPolynomial = + if (other == 0) zero + else LabeledPolynomialAsIs(mapOf( + mapOf(this to 1U) to constantOne * other, + )) + + /** + * Returns sum of the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ + public override operator fun Int.plus(other: Symbol): LabeledPolynomial = + if (this == 0) LabeledPolynomialAsIs(mapOf( + mapOf(other to 1U) to constantOne, + )) + else LabeledPolynomialAsIs(mapOf( + mapOf(other to 1U) to constantOne, + emptyMap() to constantOne * this@plus, + )) + /** + * Returns difference between the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ + public override operator fun Int.minus(other: Symbol): LabeledPolynomial = + if (this == 0) LabeledPolynomialAsIs(mapOf( + mapOf(other to 1U) to -constantOne, + )) + else LabeledPolynomialAsIs(mapOf( + mapOf(other to 1U) to -constantOne, + emptyMap() to constantOne * this@minus, + )) + /** + * Returns product of the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ + public override operator fun Int.times(other: Symbol): LabeledPolynomial = + if (this == 0) zero + else LabeledPolynomialAsIs(mapOf( + mapOf(other to 1U) to constantOne * this@times, + )) + + /** + * Returns sum of the polynomial and the integer represented as a polynomial. + * + * The operation is equivalent to adding [other] copies of unit polynomial to [this]. + */ + public override operator fun LabeledPolynomial.plus(other: Int): LabeledPolynomial = + if (other == 0) this + else with(coefficients) { + if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap() to other.asConstant())) + else LabeledPolynomialAsIs( + toMutableMap() + .apply { + val degs = emptyMap() + + this[degs] = getOrElse(degs) { constantZero } + other + } + ) + } + /** + * Returns difference between the polynomial and the integer represented as a polynomial. + * + * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. + */ + public override operator fun LabeledPolynomial.minus(other: Int): LabeledPolynomial = + if (other == 0) this + else with(coefficients) { + if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap() to (-other).asConstant())) + else LabeledPolynomialAsIs( + toMutableMap() + .apply { + val degs = emptyMap() + + this[degs] = getOrElse(degs) { constantZero } - other + } + ) + } + /** + * Returns product of the polynomial and the integer represented as a polynomial. + * + * The operation is equivalent to sum of [other] copies of [this]. + */ + public override operator fun LabeledPolynomial.times(other: Int): LabeledPolynomial = + if (other == 0) zero + else LabeledPolynomial( + coefficients + .toMutableMap() + .apply { + for (degs in keys) this[degs] = this[degs]!! * other + } + ) + + /** + * Returns sum of the integer represented as a polynomial and the polynomial. + * + * The operation is equivalent to adding [this] copies of unit polynomial to [other]. + */ + public override operator fun Int.plus(other: LabeledPolynomial): LabeledPolynomial = + if (this == 0) other + else with(other.coefficients) { + if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap() to this@plus.asConstant())) + else LabeledPolynomialAsIs( + toMutableMap() + .apply { + val degs = emptyMap() + + this[degs] = this@plus + getOrElse(degs) { constantZero } + } + ) + } + /** + * Returns difference between the integer represented as a polynomial and the polynomial. + * + * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. + */ + public override operator fun Int.minus(other: LabeledPolynomial): LabeledPolynomial = + if (this == 0) other + else with(other.coefficients) { + if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap() to this@minus.asConstant())) + else LabeledPolynomialAsIs( + toMutableMap() + .apply { + forEach { (key, value) -> if (key.isNotEmpty()) this[key] = -value } + + val degs = emptyMap() + + this[degs] = this@minus - getOrElse(degs) { constantZero } + } + ) + } + /** + * Returns product of the integer represented as a polynomial and the polynomial. + * + * The operation is equivalent to sum of [this] copies of [other]. + */ + public override operator fun Int.times(other: LabeledPolynomial): LabeledPolynomial = + if (this == 0) zero + else LabeledPolynomial( + other.coefficients + .toMutableMap() + .apply { + for (degs in keys) this[degs] = this@times * this[degs]!! + } + ) + + /** + * Converts the integer [value] to polynomial. + */ + public override fun number(value: Int): LabeledPolynomial = number(constantNumber(value)) + + /** + * Returns sum of the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ + public override operator fun Symbol.plus(other: C): LabeledPolynomial = + LabeledPolynomialAsIs(mapOf( + mapOf(this@plus to 1U) to constantOne, + emptyMap() to other, + )) + /** + * Returns difference between the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ + public override operator fun Symbol.minus(other: C): LabeledPolynomial = + LabeledPolynomialAsIs(mapOf( + mapOf(this@minus to 1U) to -constantOne, + emptyMap() to other, + )) + /** + * Returns product of the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ + public override operator fun Symbol.times(other: C): LabeledPolynomial = + LabeledPolynomialAsIs(mapOf( + mapOf(this@times to 1U) to other, + )) + + /** + * Returns sum of the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + public override operator fun C.plus(other: Symbol): LabeledPolynomial = + LabeledPolynomialAsIs(mapOf( + mapOf(other to 1U) to constantOne, + emptyMap() to this@plus, + )) + /** + * Returns difference between the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + public override operator fun C.minus(other: Symbol): LabeledPolynomial = + LabeledPolynomialAsIs(mapOf( + mapOf(other to 1U) to -constantOne, + emptyMap() to this@minus, + )) + /** + * Returns product of the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + public override operator fun C.times(other: Symbol): LabeledPolynomial = + LabeledPolynomialAsIs(mapOf( + mapOf(other to 1U) to this@times, + )) + + /** + * Returns sum of the constant represented as a polynomial and the polynomial. + */ + override operator fun C.plus(other: LabeledPolynomial): LabeledPolynomial = + with(other.coefficients) { + if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap() to this@plus)) + else LabeledPolynomialAsIs( + toMutableMap() + .apply { + val degs = emptyMap() + + this[degs] = this@plus + getOrElse(degs) { constantZero } + } + ) + } + /** + * Returns difference between the constant represented as a polynomial and the polynomial. + */ + override operator fun C.minus(other: LabeledPolynomial): LabeledPolynomial = + with(other.coefficients) { + if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap() to this@minus)) + else LabeledPolynomialAsIs( + toMutableMap() + .apply { + forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } + + val degs = emptyMap() + + this[degs] = this@minus - getOrElse(degs) { constantZero } + } + ) + } + /** + * Returns product of the constant represented as a polynomial and the polynomial. + */ + override operator fun C.times(other: LabeledPolynomial): LabeledPolynomial = + LabeledPolynomialAsIs( + other.coefficients + .toMutableMap() + .apply { + for (degs in keys) this[degs] = this@times * this[degs]!! + } + ) + + /** + * Returns sum of the constant represented as a polynomial and the polynomial. + */ + override operator fun LabeledPolynomial.plus(other: C): LabeledPolynomial = + with(coefficients) { + if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap() to other)) + else LabeledPolynomialAsIs( + toMutableMap() + .apply { + val degs = emptyMap() + + this[degs] = getOrElse(degs) { constantZero } + other + } + ) + } + /** + * Returns difference between the constant represented as a polynomial and the polynomial. + */ + override operator fun LabeledPolynomial.minus(other: C): LabeledPolynomial = + with(coefficients) { + if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap() to other)) + else LabeledPolynomialAsIs( + toMutableMap() + .apply { + forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } + + val degs = emptyMap() + + this[degs] = getOrElse(degs) { constantZero } - other + } + ) + } + /** + * Returns product of the constant represented as a polynomial and the polynomial. + */ + override operator fun LabeledPolynomial.times(other: C): LabeledPolynomial = + LabeledPolynomialAsIs( + coefficients + .toMutableMap() + .apply { + for (degs in keys) this[degs] = this[degs]!! * other + } + ) + + /** + * Converts the constant [value] to polynomial. + */ + public override fun number(value: C): LabeledPolynomial = + LabeledPolynomial(mapOf(emptyMap() to value)) + + /** + * Represents the variable as a monic monomial. + */ + public override operator fun Symbol.unaryPlus(): LabeledPolynomial = + LabeledPolynomialAsIs(mapOf( + mapOf(this to 1U) to constantOne, + )) + /** + * Returns negation of representation of the variable as a monic monomial. + */ + public override operator fun Symbol.unaryMinus(): LabeledPolynomial = + LabeledPolynomialAsIs(mapOf( + mapOf(this to 1U) to -constantOne, + )) + /** + * Returns sum of the variables represented as monic monomials. + */ + public override operator fun Symbol.plus(other: Symbol): LabeledPolynomial = + if (this == other) LabeledPolynomialAsIs(mapOf( + mapOf(this to 1U) to constantOne * 2 + )) + else LabeledPolynomialAsIs(mapOf( + mapOf(this to 1U) to constantOne, + mapOf(other to 1U) to constantOne, + )) + /** + * Returns difference between the variables represented as monic monomials. + */ + public override operator fun Symbol.minus(other: Symbol): LabeledPolynomial = + if (this == other) zero + else LabeledPolynomialAsIs(mapOf( + mapOf(this to 1U) to constantOne, + mapOf(other to 1U) to -constantOne, + )) + /** + * Returns product of the variables represented as monic monomials. + */ + public override operator fun Symbol.times(other: Symbol): LabeledPolynomial = + if (this == other) LabeledPolynomialAsIs(mapOf( + mapOf(this to 2U) to constantOne + )) + else LabeledPolynomialAsIs(mapOf( + mapOf(this to 1U, other to 1U) to constantOne, + )) + + /** + * Returns sum of the variable represented as a monic monomial and the polynomial. + */ + public override operator fun Symbol.plus(other: LabeledPolynomial): LabeledPolynomial = + with(other.coefficients) { + if (isEmpty()) LabeledPolynomialAsIs(mapOf(mapOf(this@plus to 1u) to constantOne)) + else LabeledPolynomialAsIs( + toMutableMap() + .apply { + val degs = mapOf(this@plus to 1U) + + this[degs] = constantOne + getOrElse(degs) { constantZero } + } + ) + } + /** + * Returns difference between the variable represented as a monic monomial and the polynomial. + */ + public override operator fun Symbol.minus(other: LabeledPolynomial): LabeledPolynomial = + with(other.coefficients) { + if (isEmpty()) LabeledPolynomialAsIs(mapOf(mapOf(this@minus to 1u) to constantOne)) + else LabeledPolynomialAsIs( + toMutableMap() + .apply { + val degs = mapOf(this@minus to 1U) + + forEach { (degs, c) -> if(degs != degs) this[degs] = -c } + + this[degs] = constantOne - getOrElse(degs) { constantZero } + } + ) + } + /** + * Returns product of the variable represented as a monic monomial and the polynomial. + */ + public override operator fun Symbol.times(other: LabeledPolynomial): LabeledPolynomial = + LabeledPolynomialAsIs( + other.coefficients + .mapKeys { (degs, _) -> degs.toMutableMap().also{ it[this] = if (this in it) it[this]!! + 1U else 1U } } + ) + + /** + * Returns sum of the polynomial and the variable represented as a monic monomial. + */ + public override operator fun LabeledPolynomial.plus(other: Symbol): LabeledPolynomial = + with(coefficients) { + if (isEmpty()) LabeledPolynomialAsIs(mapOf(mapOf(other to 1u) to constantOne)) + else LabeledPolynomialAsIs( + toMutableMap() + .apply { + val degs = mapOf(other to 1U) + + this[degs] = constantOne + getOrElse(degs) { constantZero } + } + ) + } + /** + * Returns difference between the polynomial and the variable represented as a monic monomial. + */ + public override operator fun LabeledPolynomial.minus(other: Symbol): LabeledPolynomial = + with(coefficients) { + if (isEmpty()) LabeledPolynomialAsIs(mapOf(mapOf(other to 1u) to constantOne)) + else LabeledPolynomialAsIs( + toMutableMap() + .apply { + val degs = mapOf(other to 1U) + + this[degs] = constantOne - getOrElse(degs) { constantZero } + } + ) + } + /** + * Returns product of the polynomial and the variable represented as a monic monomial. + */ + public override operator fun LabeledPolynomial.times(other: Symbol): LabeledPolynomial = + LabeledPolynomialAsIs( + coefficients + .mapKeys { (degs, _) -> degs.toMutableMap().also{ it[other] = if (other in it) it[other]!! + 1U else 1U } } + ) + + /** + * Returns negation of the polynomial. + */ + override fun LabeledPolynomial.unaryMinus(): LabeledPolynomial = + LabeledPolynomialAsIs( + coefficients.mapValues { -it.value } + ) + /** + * Returns sum of the polynomials. + */ + override operator fun LabeledPolynomial.plus(other: LabeledPolynomial): LabeledPolynomial = + LabeledPolynomialAsIs( + buildMap(coefficients.size + other.coefficients.size) { + other.coefficients.mapValuesTo(this) { it.value } + other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! + value else value } + } + ) + /** + * Returns difference of the polynomials. + */ + override operator fun LabeledPolynomial.minus(other: LabeledPolynomial): LabeledPolynomial = + LabeledPolynomialAsIs( + buildMap(coefficients.size + other.coefficients.size) { + other.coefficients.mapValuesTo(this) { it.value } + other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! - value else -value } + } + ) + /** + * Returns product of the polynomials. + */ + override operator fun LabeledPolynomial.times(other: LabeledPolynomial): LabeledPolynomial = + LabeledPolynomialAsIs( + buildMap(coefficients.size * other.coefficients.size) { + for ((degs1, c1) in coefficients) for ((degs2, c2) in other.coefficients) { + val degs = degs1.toMutableMap() + degs2.mapValuesTo(degs) { (variable, deg) -> degs.getOrElse(variable) { 0u } + deg } + val c = c1 * c2 + this[degs] = if (degs in this) this[degs]!! + c else c + } + } + ) + + /** + * Instance of zero polynomial (zero of the polynomial ring). + */ + override val zero: LabeledPolynomial = LabeledPolynomialAsIs(mapOf(emptyMap() to constantZero)) + /** + * Instance of unit polynomial (unit of the polynomial ring). + */ + override val one: LabeledPolynomial = LabeledPolynomialAsIs(mapOf(emptyMap() to constantOne)) + + /** + * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is + * zero, degree is -1. + */ + override val LabeledPolynomial.degree: Int + get() = coefficients.entries.maxOfOrNull { (degs, _) -> degs.values.sum().toInt() } ?: -1 + /** + * Map that associates variables (that appear in the polynomial in positive exponents) with their most exponents + * in which they are appeared in the polynomial. + * + * As consequence all values in the map are positive integers. Also, if the polynomial is constant, the map is empty. + * And keys of the map is the same as in [variables]. + */ + public override val LabeledPolynomial.degrees: Map + get() = + buildMap { + coefficients.entries.forEach { (degs, _) -> + degs.mapValuesTo(this) { (variable, deg) -> + max(getOrElse(variable) { 0u }, deg) + } + } + } + /** + * Counts degree of the polynomial by the specified [variable]. + */ + public override fun LabeledPolynomial.degreeBy(variable: Symbol): UInt = + coefficients.entries.maxOfOrNull { (degs, _) -> degs.getOrElse(variable) { 0u } } ?: 0u + /** + * Counts degree of the polynomial by the specified [variables]. + */ + public override fun LabeledPolynomial.degreeBy(variables: Collection): UInt = + coefficients.entries.maxOfOrNull { (degs, _) -> degs.filterKeys { it in variables }.values.sum() } ?: 0u + /** + * Set of all variables that appear in the polynomial in positive exponents. + */ + public override val LabeledPolynomial.variables: Set + get() = + buildSet { + coefficients.entries.forEach { (degs, _) -> addAll(degs.keys) } + } + /** + * Count of all variables that appear in the polynomial in positive exponents. + */ + public override val LabeledPolynomial.countOfVariables: Int get() = variables.size + + // TODO: When context receivers will be ready move all of this substitutions and invocations to utilities with + // [ListPolynomialSpace] as a context receiver + /** + * Substitutes provided arguments [arguments] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun LabeledPolynomial.substitute(arguments: Map): LabeledPolynomial = substitute(ring, arguments) + /** + * Substitutes provided arguments [arguments] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + @JvmName("substitutePolynomial") + public inline fun LabeledPolynomial.substitute(arguments: Map>) : LabeledPolynomial = substitute(ring, arguments) +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt new file mode 100644 index 000000000..03f323813 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt @@ -0,0 +1,96 @@ +/* + * 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.functions + +import space.kscience.kmath.expressions.Symbol +import space.kscience.kmath.operations.Ring +import kotlin.jvm.JvmName + + +/** + * Represents multivariate rational function that stores its numerator and denominator as [LabeledPolynomial]s. + */ +public class LabeledRationalFunction( + public override val numerator: LabeledPolynomial, + public override val denominator: LabeledPolynomial +) : RationalFunction> { + override fun toString(): String = "LabeledRationalFunction${numerator.coefficients}/${denominator.coefficients}" +} + +/** + * Arithmetic context for univariate rational functions with numerator and denominator represented as [LabeledPolynomial]s. + * + * @param C the type of constants. Polynomials have them a coefficients in their terms. + * @param A type of provided underlying ring of constants. It's [Ring] of [C]. + * @param ring underlying ring of constants of type [A]. + */ +public class LabeledRationalFunctionSpace>( + public val ring: A, +) : + MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSpace< + C, + Symbol, + LabeledPolynomial, + LabeledRationalFunction, + LabeledPolynomialSpace, + >, + MultivariatePolynomialSpaceOfFractions< + C, + Symbol, + LabeledPolynomial, + LabeledRationalFunction, + >() { + + /** + * Underlying polynomial ring. Its polynomial operations are inherited by local polynomial operations. + */ + override val polynomialRing : LabeledPolynomialSpace = LabeledPolynomialSpace(ring) + /** + * Constructor of rational functions (of type [LabeledRationalFunction]) from numerator and denominator (of type [LabeledPolynomial]). + */ + override fun constructRationalFunction( + numerator: LabeledPolynomial, + denominator: LabeledPolynomial + ): LabeledRationalFunction = + LabeledRationalFunction(numerator, denominator) + + // TODO: When context receivers will be ready move all of this substitutions and invocations to utilities with + // [ListPolynomialSpace] as a context receiver + /** + * Substitutes provided constant [argument] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun LabeledPolynomial.substitute(argument: Map): LabeledPolynomial = substitute(ring, argument) + /** + * Substitutes provided polynomial [argument] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + @JvmName("substitutePolynomial") + public inline fun LabeledPolynomial.substitute(argument: Map>): LabeledPolynomial = substitute(ring, argument) + /** + * Substitutes provided rational function [argument] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + @JvmName("substituteRationalFunction") + public inline fun LabeledPolynomial.substitute(argument: Map>): LabeledRationalFunction = substitute(ring, argument) + /** + * Substitutes provided constant [argument] into [this] rational function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun LabeledRationalFunction.substitute(argument: Map): LabeledRationalFunction = substitute(ring, argument) + /** + * Substitutes provided polynomial [argument] into [this] rational function. + */ + @Suppress("NOTHING_TO_INLINE") + @JvmName("substitutePolynomial") + public inline fun LabeledRationalFunction.substitute(argument: Map>): LabeledRationalFunction = substitute(ring, argument) + /** + * Substitutes provided rational function [argument] into [this] rational function. + */ + @Suppress("NOTHING_TO_INLINE") + @JvmName("substituteRationalFunction") + public inline fun LabeledRationalFunction.substitute(argument: Map>): LabeledRationalFunction = substitute(ring, argument) +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt index b3f1eb8f7..8db93cbb1 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt @@ -15,7 +15,7 @@ import kotlin.math.min /** * Represents univariate polynomial that stores its coefficients in a [List]. * - * @param coefficients constant is the leftmost coefficient. + * @param C the type of constants. */ public data class ListPolynomial( /** diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt index 02a3af683..eadeb68ab 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -12,7 +12,7 @@ import kotlin.math.max /** - * Represents univariate polynomial that stores its coefficients in a [Map] and terms' signatures in a [List]. + * Represents multivariate polynomial that stores its coefficients in a [Map] and terms' signatures in a [List]. * * @param C the type of constants. */ @@ -20,10 +20,11 @@ public data class NumberedPolynomial @PublishedApi internal constructor( /** - * Map that contains coefficients of the polynomial. Every monomial `a x_1^{d_1} ... x_n^{d_n}` is stored as pair - * "key-value" in the map, where the value is the coefficients `a` and the key is a list that associates index of - * every variable in the monomial with multiplicity of the variable occurring in the monomial. For example - * coefficients of a polynomial `5 x_1^2 x_3^3 - 6 x_2` can be represented as + * Map that contains coefficients of the polynomial. + * + * Every monomial `a x_1^{d_1} ... x_n^{d_n}` is stored as a pair "key-value" in the map, where the value is the + * coefficient `a` and the key is a list that associates index of every variable in the monomial with their degree + * in the monomial. For example, coefficients of a polynomial `5 x_1^2 x_3^3 - 6 x_2` can be represented as * ``` * mapOf( * listOf(2, 0, 3) to 5, // 5 x_1^2 x_3^3 + diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt new file mode 100644 index 000000000..47325c4bb --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt @@ -0,0 +1,518 @@ +/* + * 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. + */ + +@file:Suppress("FunctionName", "NOTHING_TO_INLINE") + +package space.kscience.kmath.functions + +import space.kscience.kmath.expressions.Symbol +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.Ring + + +/** + * Returns the same degrees' description of the monomial, but without zero degrees. + */ +internal fun Map.cleanUp() = filterValues { it > 0U } + +/** + * Constructs [LabeledPolynomial] with provided coefficients map [coefs]. The map is used as is. + */ +@PublishedApi +internal inline fun LabeledPolynomialAsIs(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs) + +/** + * Constructs [LabeledPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient". + * The collections will be transformed to map with [toMap] and then will be used as is. + */ +@PublishedApi +internal inline fun LabeledPolynomialAsIs(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs.toMap()) + +/** + * Constructs [LabeledPolynomial] with provided array of [pairs] of pairs "term's signature — term's coefficient". + * The array will be transformed to map with [toMap] and then will be used as is. + */ +@PublishedApi +internal inline fun LabeledPolynomialAsIs(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(pairs.toMap()) + +/** + * Constructs [LabeledPolynomial] with provided coefficients map [coefs]. The map is used as is. + * + * **Be sure you read description of [LabeledPolynomial.coefficients]. Otherwise, you may make a mistake that will + * cause wrong computation result or even runtime error.** + */ +@DelicatePolynomialAPI +public inline fun LabeledPolynomialWithoutCheck(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs) + +/** + * Constructs [LabeledPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient". + * The collections will be transformed to map with [toMap] and then will be used as is. + * + * **Be sure you read description of [LabeledPolynomial.coefficients]. Otherwise, you may make a mistake that will + * cause wrong computation result or even runtime error.** + */ +@DelicatePolynomialAPI +public inline fun LabeledPolynomialWithoutCheck(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs.toMap()) + +/** + * Constructs [LabeledPolynomial] with provided array of [pairs] of pairs "term's signature — term's coefficient". + * The array will be transformed to map with [toMap] and then will be used as is. + * + * **Be sure you read description of [LabeledPolynomial.coefficients]. Otherwise, you may make a mistake that will + * cause wrong computation result or even runtime error.** + */ +@DelicatePolynomialAPI +public inline fun LabeledPolynomialWithoutCheck(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(pairs.toMap()) + +/** + * Constructs [LabeledPolynomial] with provided coefficients map [coefs]. + * + * [coefs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [coefs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +public fun LabeledPolynomial(coefs: Map, C>, add: (C, C) -> C) : LabeledPolynomial { + val fixedCoefs = mutableMapOf, C>() + + for (entry in coefs) { + val key = entry.key.cleanUp() + val value = entry.value + fixedCoefs[key] = if (key in fixedCoefs) add(fixedCoefs[key]!!, value) else value + } + + return LabeledPolynomial(fixedCoefs) +} + +/** + * Constructs [LabeledPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient". + * + * [pairs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +public fun LabeledPolynomial(pairs: Collection, C>>, add: (C, C) -> C) : LabeledPolynomial { + val fixedCoefs = mutableMapOf, C>() + + for (entry in pairs) { + val key = entry.first.cleanUp() + val value = entry.second + fixedCoefs[key] = if (key in fixedCoefs) add(fixedCoefs[key]!!, value) else value + } + + return LabeledPolynomial(fixedCoefs) +} + +/** + * Constructs [LabeledPolynomial] with provided array [pairs] of pairs "term's signature — term's coefficient". + * + * [pairs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +public fun LabeledPolynomial(vararg pairs: Pair, C>, add: (C, C) -> C) : LabeledPolynomial { + val fixedCoefs = mutableMapOf, C>() + + for (entry in pairs) { + val key = entry.first.cleanUp() + val value = entry.second + fixedCoefs[key] = if (key in fixedCoefs) add(fixedCoefs[key]!!, value) else value + } + + return LabeledPolynomial(fixedCoefs) +} + +// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available + +/** + * Constructs [LabeledPolynomial] with provided coefficients map [coefs]. + * + * [coefs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [coefs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +public inline fun > A.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs, ::add) +/** + * Constructs [LabeledPolynomial] with provided coefficients map [coefs]. + * + * [coefs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [coefs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +public inline fun > LabeledPolynomialSpace.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs) { left: C, right: C -> left + right } + +/** + * Constructs [LabeledPolynomial] with provided coefficients map [coefs]. + * + * [coefs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [coefs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +public inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs) { left: C, right: C -> left + right } + +/** + * Constructs [LabeledPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient". + * + * [pairs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +public inline fun > A.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs, ::add) + +/** + * Constructs [LabeledPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient". + * + * [pairs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +public inline fun > LabeledPolynomialSpace.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs) { left: C, right: C -> left + right } +/** + * Constructs [LabeledPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient". + * + * [pairs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +public inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs) { left: C, right: C -> left + right } + +/** + * Constructs [LabeledPolynomial] with provided array [pairs] of pairs "term's signature — term's coefficient". + * + * [pairs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +public inline fun > A.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs) { left: C, right: C -> left + right } +/** + * Constructs [LabeledPolynomial] with provided array [pairs] of pairs "term's signature — term's coefficient". + * + * [pairs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +public inline fun > LabeledPolynomialSpace.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs) { left: C, right: C -> left + right } +/** + * Constructs [LabeledPolynomial] with provided array [pairs] of pairs "term's signature — term's coefficient". + * + * [pairs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +public inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs) { left: C, right: C -> left + right } + +/** + * Converts [this] constant to [LabeledPolynomial]. + */ +public inline fun C.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomialAsIs(mapOf(emptyMap() to this)) + +///** +//// * Converts [this] variable to [LabeledPolynomial]. +//// */ +//context(A) +//public inline fun > Symbol.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1u) to one)) +///** +// * Converts [this] variable to [LabeledPolynomial]. +// */ +//context(LabeledPolynomialSpace) +//public inline fun > Symbol.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1u) to constantOne)) +///** +// * Converts [this] variable to [LabeledPolynomial]. +// */ +//context(LabeledRationalFunctionSpace) +//public inline fun > Symbol.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1u) to constantOne)) + +/** + * Marks DSL that allows to more simply create [LabeledPolynomial]s with good performance. + * + * For example, polynomial `5 a^2 c^3 - 6 b` can be described as + * ``` + * Int.algebra { + * val numberedPolynomial : NumberedPolynomial = NumberedPolynomial { + * 5 { a inPowerOf 2u; c inPowerOf 3u } // 5 a^2 c^3 + + * (-6) { b inPowerOf 1u } // (-6) b^1 + * } + * } + * ``` + */ +@DslMarker +@UnstableKMathAPI +internal annotation class LabeledPolynomialConstructorDSL + +/** + * Builder of [LabeledPolynomial] signature. It should be used as an implicit context for lambdas that describe term signature. + */ +@UnstableKMathAPI +@LabeledPolynomialConstructorDSL +public class LabeledPolynomialTermSignatureBuilder { + /** + * Signature storage. Any declaration of any variable's power updates the storage by increasing corresponding value. + * Afterward the storage will be used as a resulting signature. + */ + private val signature: MutableMap = LinkedHashMap() + + /** + * Builds the resulting signature. + * + * In fact, it just returns [signature] as regular signature of type `List`. + */ + @PublishedApi + internal fun build(): Map = signature + + /** + * Declares power of [this] variable of degree [deg]. + * + * Declaring another power of the same variable will increase its degree by received degree. + */ + public infix fun Symbol.inPowerOf(deg: UInt) { + signature[this] = deg + } + /** + * Declares power of [this] variable of degree [deg]. + * + * Declaring another power of the same variable will increase its degree by received degree. + */ + @Suppress("NOTHING_TO_INLINE") + public inline infix fun Symbol.pow(deg: UInt): Unit = this inPowerOf deg + /** + * Declares power of [this] variable of degree [deg]. + * + * Declaring another power of the same variable will increase its degree by received degree. + */ + @Suppress("NOTHING_TO_INLINE") + public inline infix fun Symbol.`in`(deg: UInt): Unit = this inPowerOf deg + /** + * Declares power of [this] variable of degree [deg]. + * + * Declaring another power of the same variable will increase its degree by received degree. + */ + @Suppress("NOTHING_TO_INLINE") + public inline infix fun Symbol.of(deg: UInt): Unit = this inPowerOf deg +} + +/** + * Builder of [LabeledPolynomial]. It should be used as an implicit context for lambdas that describe [LabeledPolynomial]. + */ +@UnstableKMathAPI +public class LabeledPolynomialBuilder( + /** + * Summation operation that will be used to sum coefficients of monomials of same signatures. + */ + private val add: (C, C) -> C, + /** + * Initial capacity of coefficients map. + */ + initialCapacity: Int = 0 +) { + /** + * Coefficients storage. Any declaration of any monomial updates the storage. + * Afterward the storage will be used as a resulting coefficients map. + */ + private val coefficients: MutableMap, C> = LinkedHashMap(initialCapacity) + + /** + * Builds the resulting coefficients map. + * + * In fact, it just returns [coefficients] as regular coefficients map of type `Map, C>`. + */ + @PublishedApi + internal fun build(): LabeledPolynomial = LabeledPolynomial(coefficients) + + /** + * Declares monomial with [this] coefficient and provided [signature]. + * + * Declaring another monomial with the same signature will add [this] coefficient to existing one. If the sum of such + * coefficients is zero at any moment the monomial won't be removed but will be left as it is. + */ + public infix fun C.with(signature: Map) { + coefficients[signature] = if (signature in coefficients) add(coefficients[signature]!!, this@with) else this@with + } + /** + * Declares monomial with [this] coefficient and signature constructed by [block]. + * + * Declaring another monomial with the same signature will add [this] coefficient to existing one. If the sum of such + * coefficients is zero at any moment the monomial won't be removed but will be left as it is. + */ + @Suppress("NOTHING_TO_INLINE") + public inline infix fun C.with(noinline block: LabeledPolynomialTermSignatureBuilder.() -> Unit): Unit = this.invoke(block) + /** + * Declares monomial with [this] coefficient and signature constructed by [block]. + * + * Declaring another monomial with the same signature will add [this] coefficient to existing one. If the sum of such + * coefficients is zero at any moment the monomial won't be removed but will be left as it is. + */ + public inline operator fun C.invoke(block: LabeledPolynomialTermSignatureBuilder.() -> Unit): Unit = + this with LabeledPolynomialTermSignatureBuilder().apply(block).build() +} + +// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available + +///** +// * Creates [LabeledPolynomial] with lambda [block] in context of [this] ring of constants. +// * +// * For example, polynomial `5 x_1^2 x_3^3 - 6 x_2` can be described as +// * ``` +// * Int.algebra { +// * val LabeledPolynomial : LabeledPolynomial = LabeledPolynomial { +// * 5 { 1 inPowerOf 2u; 3 inPowerOf 3u } // 5 x_1^2 x_3^3 + +// * (-6) { 2 inPowerOf 1u } // (-6) x_2^1 +// * } +// * } +// * ``` +// */ +// FIXME: For now this fabric does not let next two fabrics work. (See KT-52803.) Possible feature solutions: +// 1. `LowPriorityInOverloadResolution` becomes public. Then it should be applied to this function. +// 2. Union types are implemented. Then all three functions should be rewritten +// as one with single union type as a (context) receiver. +//@UnstableKMathAPI +//public inline fun > A.LabeledPolynomial(initialCapacity: Int = 0, block: LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = LabeledPolynomialBuilder(::add, initialCapacity).apply(block).build() +/** + * Creates [LabeledPolynomial] with lambda [block] in context of [this] ring of [LabeledPolynomial]s. + * + * For example, polynomial `5 x_1^2 x_3^3 - 6 x_2` can be described as + * ``` + * Int.algebra { + * val LabeledPolynomial : LabeledPolynomial = LabeledPolynomial { + * 5 { 1 inPowerOf 2u; 3 inPowerOf 3u } // 5 x_1^2 x_3^3 + + * (-6) { 2 inPowerOf 1u } // (-6) x_2^1 + * } + * } + * ``` + */ +@UnstableKMathAPI +public inline fun > LabeledPolynomialSpace.LabeledPolynomial(initialCapacity: Int = 0, block: LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = LabeledPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() +/** + * Creates [LabeledPolynomial] with lambda [block] in context of [this] field of [LabeledRationalFunction]s. + * + * For example, polynomial `5 x_1^2 x_3^3 - 6 x_2` can be described as + * ``` + * Int.algebra { + * val LabeledPolynomial : LabeledPolynomial = LabeledPolynomial { + * 5 { 1 inPowerOf 2u; 3 inPowerOf 3u } // 5 x_1^2 x_3^3 + + * (-6) { 2 inPowerOf 1u } // (-6) x_2^1 + * } + * } + * ``` + */ +@UnstableKMathAPI +public inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(initialCapacity: Int = 0, block: LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = LabeledPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() + +// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available + +/** + * Constructs [LabeledRationalFunction] with provided coefficients maps [numeratorCoefficients] and [denominatorCoefficients]. + * + * The maps will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. the maps' keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +public fun > A.LabeledRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): LabeledRationalFunction = + LabeledRationalFunction( + LabeledPolynomial(numeratorCoefficients), + LabeledPolynomial(denominatorCoefficients) + ) +/** + * Constructs [LabeledRationalFunction] with provided coefficients maps [numeratorCoefficients] and [denominatorCoefficients]. + * + * The maps will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. the maps' keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +public fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): LabeledRationalFunction = + LabeledRationalFunction( + LabeledPolynomial(numeratorCoefficients), + LabeledPolynomial(denominatorCoefficients) + ) + +/** + * Constructs [LabeledRationalFunction] with provided [numerator] and unit denominator. + */ +public fun > A.LabeledRationalFunction(numerator: LabeledPolynomial): LabeledRationalFunction = + LabeledRationalFunction(numerator, LabeledPolynomial(mapOf(emptyMap() to one))) +/** + * Constructs [LabeledRationalFunction] with provided [numerator] and unit denominator. + */ +public fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numerator: LabeledPolynomial): LabeledRationalFunction = + LabeledRationalFunction(numerator, polynomialOne) + +/** + * Constructs [LabeledRationalFunction] with provided coefficients map [numeratorCoefficients] for numerator and unit + * denominator. + * + * [numeratorCoefficients] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [numeratorCoefficients]'s keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +public fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numeratorCoefficients: Map, C>): LabeledRationalFunction = + LabeledRationalFunction( + LabeledPolynomial(numeratorCoefficients), + polynomialOne + ) +/** + * Constructs [LabeledRationalFunction] with provided coefficients map [numeratorCoefficients] for numerator and unit + * denominator. + * + * [numeratorCoefficients] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [numeratorCoefficients]'s keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +public fun > A.LabeledRationalFunction(numeratorCoefficients: Map, C>): LabeledRationalFunction = + LabeledRationalFunction( + LabeledPolynomial(numeratorCoefficients), + LabeledPolynomialAsIs(mapOf(emptyMap() to one)) + ) + +///** +// * Converts [this] constant to [LabeledRationalFunction]. +// */ +//context(A) +//public fun > C.asLabeledRationalFunction() : LabeledRationalFunction = +// LabeledRationalFunction( +// LabeledPolynomialAsIs(mapOf(emptyMap() to this)), +// LabeledPolynomialAsIs(mapOf(emptyMap() to one)) +// ) +///** +// * Converts [this] constant to [LabeledRationalFunction]. +// */ +//context(LabeledRationalFunctionSpace) +//public fun > C.asLabeledRationalFunction() : LabeledRationalFunction = +// LabeledRationalFunction( +// LabeledPolynomialAsIs(mapOf(emptyMap() to this)), +// LabeledPolynomialAsIs(mapOf(emptyMap() to constantOne)) +// ) + +///** +// * Converts [this] variable to [LabeledRationalFunction]. +// */ +//context(A) +//public fun > Symbol.asLabeledRationalFunction() : LabeledRationalFunction = +// LabeledRationalFunction( +// LabeledPolynomialAsIs(mapOf(mapOf(this to 1u) to one)), +// LabeledPolynomialAsIs(mapOf(emptyMap() to one)) +// ) +///** +// * Converts [this] variable to [LabeledRationalFunction]. +// */ +//context(LabeledRationalFunctionSpace) +//public fun > Symbol.asLabeledRationalFunction() : LabeledRationalFunction = +// LabeledRationalFunction( +// LabeledPolynomialAsIs(mapOf(mapOf(this to 1u) to constantOne)), +// LabeledPolynomialAsIs(mapOf(emptyMap() to constantOne)) +// ) \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledUtil.kt new file mode 100644 index 000000000..39c781a14 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledUtil.kt @@ -0,0 +1,327 @@ +/* + * 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.functions + +import space.kscience.kmath.expressions.Symbol +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.Field +import space.kscience.kmath.operations.invoke +import space.kscience.kmath.operations.Ring +import space.kscience.kmath.operations.algebra +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract +import kotlin.jvm.JvmName + + +/** + * Creates a [LabeledPolynomialSpace] over a received ring. + */ +public fun > A.labeledPolynomialSpace(): LabeledPolynomialSpace = + LabeledPolynomialSpace(this) + +/** + * Creates a [LabeledPolynomialSpace]'s scope over a received ring. + */ +public inline fun , R> A.labeledPolynomialSpace(block: LabeledPolynomialSpace.() -> R): R { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return LabeledPolynomialSpace(this).block() +} +/** + * Creates a [LabeledRationalFunctionSpace] over a received ring. + */ +public fun > A.labeledRationalFunctionSpace(): LabeledRationalFunctionSpace = + LabeledRationalFunctionSpace(this) + +/** + * Creates a [LabeledRationalFunctionSpace]'s scope over a received ring. + */ +public inline fun , R> A.labeledRationalFunctionSpace(block: LabeledRationalFunctionSpace.() -> R): R { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return LabeledRationalFunctionSpace(this).block() +} + +/** + * Substitutes provided Double arguments [args] into [this] Double polynomial. + */ +public fun LabeledPolynomial.substitute(args: Map): LabeledPolynomial = Double.algebra { + if (coefficients.isEmpty()) return this@substitute + LabeledPolynomial( + buildMap { + coefficients.forEach { (degs, c) -> + val newDegs = degs.filterKeys { it !in args } + val newC = args.entries.fold(c) { product, (variable, substitution) -> + val deg = degs.getOrElse(variable) { 0u } + if (deg == 0u) product else product * power(substitution, deg) + } + this[newDegs] = if (newDegs in this) this[newDegs]!! + newC else newC + } + } + ) +} + +/** + * Substitutes provided arguments [args] into [this] polynomial. + */ +public fun LabeledPolynomial.substitute(ring: Ring, args: Map): LabeledPolynomial = ring { + if (coefficients.isEmpty()) return this@substitute + LabeledPolynomial( + buildMap { + coefficients.forEach { (degs, c) -> + val newDegs = degs.filterKeys { it !in args } + val newC = args.entries.fold(c) { product, (variable, substitution) -> + val deg = degs.getOrElse(variable) { 0u } + if (deg == 0u) product else product * power(substitution, deg) + } + this[newDegs] = if (newDegs in this) this[newDegs]!! + newC else newC + } + } + ) +} + +/** + * Substitutes provided arguments [args] into [this] polynomial. + */ // TODO: To optimize boxing +@JvmName("substitutePolynomial") +public fun LabeledPolynomial.substitute(ring: Ring, args: Map>) : LabeledPolynomial = + ring.labeledPolynomialSpace { + coefficients.entries.fold(zero) { acc, (degs, c) -> + val newDegs = degs.filterKeys { it !in args } + acc + args.entries.fold(LabeledPolynomial(mapOf(newDegs to c))) { product, (variable, substitution) -> + val deg = degs.getOrElse(variable) { 0u } + if (deg == 0u) product else product * power(substitution, deg) + } + } + } + +/** + * Substitutes provided arguments [args] into [this] polynomial. + */ // TODO: To optimize boxing +@JvmName("substituteRationalFunction") +public fun LabeledPolynomial.substitute(ring: Ring, args: Map>) : LabeledRationalFunction = + ring.labeledRationalFunctionSpace { + coefficients.entries.fold(zero) { acc, (degs, c) -> + val newDegs = degs.filterKeys { it !in args } + acc + args.entries.fold(LabeledRationalFunction(LabeledPolynomial(mapOf(newDegs to c)))) { product, (variable, substitution) -> + val deg = degs.getOrElse(variable) { 0u } + if (deg == 0u) product else product * power(substitution, deg) + } + } + } + +/** + * Substitutes provided Double arguments [args] into [this] Double rational function. + */ +public fun LabeledRationalFunction.substitute(args: Map): LabeledRationalFunction = + LabeledRationalFunction(numerator.substitute(args), denominator.substitute(args)) + +/** + * Substitutes provided arguments [args] into [this] rational function. + */ +public fun LabeledRationalFunction.substitute(ring: Ring, args: Map): LabeledRationalFunction = + LabeledRationalFunction(numerator.substitute(ring, args), denominator.substitute(ring, args)) + +/** + * Substitutes provided arguments [args] into [this] rational function. + */ // TODO: To optimize calculation +@JvmName("substitutePolynomial") +public fun LabeledRationalFunction.substitute(ring: Ring, args: Map>) : LabeledRationalFunction = + LabeledRationalFunction(numerator.substitute(ring, args), denominator.substitute(ring, args)) + +/** + * Substitutes provided arguments [args] into [this] rational function. + */ // TODO: To optimize calculation +@JvmName("substituteRationalFunction") +public fun LabeledRationalFunction.substitute(ring: Ring, args: Map>) : LabeledRationalFunction = + ring.labeledRationalFunctionSpace { + numerator.substitute(ring, args) / denominator.substitute(ring, args) + } + +/** + * Returns algebraic derivative of received polynomial with respect to provided variable. + */ +@UnstableKMathAPI +public fun > LabeledPolynomial.derivativeWithRespectTo( + algebra: A, + variable: Symbol, +): LabeledPolynomial = algebra { + LabeledPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + if (variable !in degs) return@forEach + put( + buildMap { + degs.forEach { (vari, deg) -> + when { + vari != variable -> put(vari, deg) + deg > 1u -> put(vari, deg - 1u) + } + } + }, + multiplyByDoubling(c, degs[variable]!!) + ) + } + } + ) +} + +/** + * Returns algebraic derivative of received polynomial with respect to provided variable of specified order. + */ +@UnstableKMathAPI +public fun > LabeledPolynomial.nthDerivativeWithRespectTo( + algebra: A, + variable: Symbol, + order: UInt +): LabeledPolynomial = algebra { + if (order == 0u) return this@nthDerivativeWithRespectTo + LabeledPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + if (degs.getOrElse(variable) { 0u } < order) return@forEach + put( + buildMap { + degs.forEach { (vari, deg) -> + when { + vari != variable -> put(vari, deg) + deg > order -> put(vari, deg - order) + } + } + }, + degs[variable]!!.let { deg -> + (deg downTo deg - order + 1u) + .fold(c) { acc, ord -> multiplyByDoubling(acc, ord) } + } + ) + } + } + ) +} + +/** + * Returns algebraic derivative of received polynomial with respect to provided variables of specified orders. + */ +@UnstableKMathAPI +public fun > LabeledPolynomial.nthDerivativeWithRespectTo( + algebra: A, + variablesAndOrders: Map, +): LabeledPolynomial = algebra { + val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u } + if (filteredVariablesAndOrders.isEmpty()) return this@nthDerivativeWithRespectTo + LabeledPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + if (filteredVariablesAndOrders.any { (variable, order) -> degs.getOrElse(variable) { 0u } < order }) return@forEach + put( + buildMap { + degs.forEach { (vari, deg) -> + if (vari !in filteredVariablesAndOrders) put(vari, deg) + else { + val order = filteredVariablesAndOrders[vari]!! + if (deg > order) put(vari, deg - order) + } + } + }, + filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> + degs[index]!!.let { deg -> + (deg downTo deg - order + 1u) + .fold(acc1) { acc2, ord -> multiplyByDoubling(acc2, ord) } + } + } + ) + } + } + ) +} + +/** + * Returns algebraic antiderivative of received polynomial with respect to provided variable. + */ +@UnstableKMathAPI +public fun > LabeledPolynomial.antiderivativeWithRespectTo( + algebra: A, + variable: Symbol, +): LabeledPolynomial = algebra { + LabeledPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + val newDegs = buildMap(degs.size + 1) { + put(variable, 1u) + for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) + } + put( + newDegs, + c / multiplyByDoubling(one, newDegs[variable]!!) + ) + } + } + ) +} + +/** + * Returns algebraic antiderivative of received polynomial with respect to provided variable of specified order. + */ +@UnstableKMathAPI +public fun > LabeledPolynomial.nthAntiderivativeWithRespectTo( + algebra: A, + variable: Symbol, + order: UInt +): LabeledPolynomial = algebra { + if (order == 0u) return this@nthAntiderivativeWithRespectTo + LabeledPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + val newDegs = buildMap(degs.size + 1) { + put(variable, order) + for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) + } + put( + newDegs, + newDegs[variable]!!.let { deg -> + (deg downTo deg - order + 1u) + .fold(c) { acc, ord -> acc / multiplyByDoubling(one, ord) } + } + ) + } + } + ) +} + +/** + * Returns algebraic derivative of received polynomial with respect to provided variables of specified orders. + */ +@UnstableKMathAPI +public fun > LabeledPolynomial.nthAntiderivativeWithRespectTo( + algebra: A, + variablesAndOrders: Map, +): LabeledPolynomial = algebra { + val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u } + if (filteredVariablesAndOrders.isEmpty()) return this@nthAntiderivativeWithRespectTo + LabeledPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + val newDegs = buildMap(degs.size + 1) { + for ((variable, order) in filteredVariablesAndOrders) put(variable, order) + for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) + } + put( + newDegs, + filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> + newDegs[index]!!.let { deg -> + (deg downTo deg - order + 1u) + .fold(acc1) { acc2, ord -> acc2 / multiplyByDoubling(one, ord) } + } + } + ) + } + } + ) +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt index 37d5d7fb6..4850e6cec 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt @@ -3,6 +3,8 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ +@file:Suppress("FunctionName", "NOTHING_TO_INLINE") + package space.kscience.kmath.functions import space.kscience.kmath.misc.UnstableKMathAPI @@ -17,7 +19,6 @@ internal fun List.cleanUp() = subList(0, indexOfLast { it != 0U } + 1) /** * Constructs [NumberedPolynomial] with provided coefficients map [coefs]. The map is used as is. */ -@Suppress("FunctionName", "NOTHING_TO_INLINE") @PublishedApi internal inline fun NumberedPolynomialAsIs(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs) @@ -25,7 +26,6 @@ internal inline fun NumberedPolynomialAsIs(coefs: Map, C>) : Numb * Constructs [NumberedPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient". * The collections will be transformed to map with [toMap] and then will be used as is. */ -@Suppress("FunctionName", "NOTHING_TO_INLINE") @PublishedApi internal inline fun NumberedPolynomialAsIs(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs.toMap()) @@ -33,7 +33,6 @@ internal inline fun NumberedPolynomialAsIs(pairs: Collection * Constructs [NumberedPolynomial] with provided array of [pairs] of pairs "term's signature — term's coefficient". * The array will be transformed to map with [toMap] and then will be used as is. */ -@Suppress("FunctionName", "NOTHING_TO_INLINE") @PublishedApi internal inline fun NumberedPolynomialAsIs(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(pairs.toMap()) @@ -43,7 +42,6 @@ internal inline fun NumberedPolynomialAsIs(vararg pairs: Pair, C> * **Be sure you read description of [NumberedPolynomial.coefficients]. Otherwise, you may make a mistake that will * cause wrong computation result or even runtime error.** */ -@Suppress("FunctionName", "NOTHING_TO_INLINE") @DelicatePolynomialAPI public inline fun NumberedPolynomialWithoutCheck(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs) @@ -54,7 +52,6 @@ public inline fun NumberedPolynomialWithoutCheck(coefs: Map, C>) * **Be sure you read description of [NumberedPolynomial.coefficients]. Otherwise, you may make a mistake that will * cause wrong computation result or even runtime error.** */ -@Suppress("FunctionName", "NOTHING_TO_INLINE") @DelicatePolynomialAPI public inline fun NumberedPolynomialWithoutCheck(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs.toMap()) @@ -65,7 +62,6 @@ public inline fun NumberedPolynomialWithoutCheck(pairs: Collection NumberedPolynomialWithoutCheck(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(pairs.toMap()) @@ -77,7 +73,6 @@ public inline fun NumberedPolynomialWithoutCheck(vararg pairs: Pair NumberedPolynomial(coefs: Map, C>, add: (C, C) -> C) : NumberedPolynomial { val fixedCoefs = mutableMapOf, C>() @@ -98,7 +93,6 @@ public fun NumberedPolynomial(coefs: Map, C>, add: (C, C) -> C) : * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. */ -@Suppress("FunctionName") public fun NumberedPolynomial(pairs: Collection, C>>, add: (C, C) -> C) : NumberedPolynomial { val fixedCoefs = mutableMapOf, C>() @@ -119,7 +113,6 @@ public fun NumberedPolynomial(pairs: Collection, C>>, add: ( * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. */ -@Suppress("FunctionName") public fun NumberedPolynomial(vararg pairs: Pair, C>, add: (C, C) -> C) : NumberedPolynomial { val fixedCoefs = mutableMapOf, C>() @@ -142,7 +135,6 @@ public fun NumberedPolynomial(vararg pairs: Pair, C>, add: (C, C) * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. */ -@Suppress("FunctionName", "NOTHING_TO_INLINE") public inline fun > A.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, ::add) /** * Constructs [NumberedPolynomial] with provided coefficients map [coefs]. @@ -152,7 +144,6 @@ public inline fun > A.NumberedPolynomial(coefs: Map, C> * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. */ -@Suppress("FunctionName", "NOTHING_TO_INLINE") public inline fun > NumberedPolynomialSpace.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs) { left: C, right: C -> left + right } /** @@ -163,7 +154,6 @@ public inline fun > NumberedPolynomialSpace.NumberedPolynomi * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. */ -@Suppress("FunctionName", "NOTHING_TO_INLINE") public inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs) { left: C, right: C -> left + right } /** @@ -174,7 +164,6 @@ public inline fun > NumberedRationalFunctionSpace.NumberedPo * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. */ -@Suppress("FunctionName", "NOTHING_TO_INLINE") public inline fun > A.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, ::add) /** @@ -185,7 +174,6 @@ public inline fun > A.NumberedPolynomial(pairs: Collection> NumberedPolynomialSpace.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs) { left: C, right: C -> left + right } /** * Constructs [NumberedPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient". @@ -195,7 +183,6 @@ public inline fun > NumberedPolynomialSpace.NumberedPolynomi * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. */ -@Suppress("FunctionName", "NOTHING_TO_INLINE") public inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs) { left: C, right: C -> left + right } /** @@ -206,7 +193,6 @@ public inline fun > NumberedRationalFunctionSpace.NumberedPo * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. */ -@Suppress("FunctionName", "NOTHING_TO_INLINE") public inline fun > A.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs) { left: C, right: C -> left + right } /** * Constructs [NumberedPolynomial] with provided array [pairs] of pairs "term's signature — term's coefficient". @@ -216,7 +202,6 @@ public inline fun > A.NumberedPolynomial(vararg pairs: Pair> NumberedPolynomialSpace.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs) { left: C, right: C -> left + right } /** * Constructs [NumberedPolynomial] with provided array [pairs] of pairs "term's signature — term's coefficient". @@ -226,13 +211,11 @@ public inline fun > NumberedPolynomialSpace.NumberedPolynomi * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. */ -@Suppress("FunctionName", "NOTHING_TO_INLINE") public inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs) { left: C, right: C -> left + right } /** * Converts [this] constant to [NumberedPolynomial]. */ -@Suppress("NOTHING_TO_INLINE") public inline fun C.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomialAsIs(mapOf(emptyList() to this)) /** @@ -269,6 +252,7 @@ public class NumberedPolynomialTermSignatureBuilder { * * In fact, it just returns [signature] as regular signature of type `List`. */ + @PublishedApi internal fun build(): List = signature /** @@ -344,8 +328,7 @@ public class NumberedPolynomialBuilder( * coefficients is zero at any moment the monomial won't be removed but will be left as it is. */ public infix fun C.with(signature: List) { - if (signature in coefficients) coefficients[signature] = add(coefficients[signature]!!, this@with) - else coefficients[signature] = this@with + coefficients[signature] = if (signature in coefficients) add(coefficients[signature]!!, this@with) else this@with } /** * Declares monomial with [this] coefficient and signature constructed by [block]. @@ -361,7 +344,7 @@ public class NumberedPolynomialBuilder( * Declaring another monomial with the same signature will add [this] coefficient to existing one. If the sum of such * coefficients is zero at any moment the monomial won't be removed but will be left as it is. */ - public operator fun C.invoke(block: NumberedPolynomialTermSignatureBuilder.() -> Unit): Unit = + public inline operator fun C.invoke(block: NumberedPolynomialTermSignatureBuilder.() -> Unit): Unit = this with NumberedPolynomialTermSignatureBuilder().apply(block).build() } @@ -385,7 +368,6 @@ public class NumberedPolynomialBuilder( // 2. Union types are implemented. Then all three functions should be rewritten // as one with single union type as a (context) receiver. //@UnstableKMathAPI -//@Suppress("FunctionName") //public inline fun > A.NumberedPolynomial(initialCapacity: Int = 0, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder(::add, initialCapacity).apply(block).build() /** * Creates [NumberedPolynomial] with lambda [block] in context of [this] ring of [NumberedPolynomial]s. @@ -401,7 +383,6 @@ public class NumberedPolynomialBuilder( * ``` */ @UnstableKMathAPI -@Suppress("FunctionName") public inline fun > NumberedPolynomialSpace.NumberedPolynomial(initialCapacity: Int = 0, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() /** * Creates [NumberedPolynomial] with lambda [block] in context of [this] field of [NumberedRationalFunction]s. @@ -417,7 +398,6 @@ public inline fun > NumberedPolynomialSpace.NumberedPolynomi * ``` */ @UnstableKMathAPI -@Suppress("FunctionName") public inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(initialCapacity: Int = 0, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() // Waiting for context receivers :( FIXME: Replace with context receivers when they will be available @@ -430,7 +410,6 @@ public inline fun > NumberedRationalFunctionSpace.NumberedPo * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. */ -@Suppress("FunctionName") public fun > A.NumberedRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): NumberedRationalFunction = NumberedRationalFunction( NumberedPolynomial(numeratorCoefficients), @@ -444,7 +423,6 @@ public fun > A.NumberedRationalFunction(numeratorCoefficients: Map * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. */ -@Suppress("FunctionName") public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): NumberedRationalFunction = NumberedRationalFunction( NumberedPolynomial(numeratorCoefficients), @@ -454,13 +432,11 @@ public fun > NumberedRationalFunctionSpace.NumberedRationalF /** * Constructs [NumberedRationalFunction] with provided [numerator] and unit denominator. */ -@Suppress("FunctionName") public fun > A.NumberedRationalFunction(numerator: NumberedPolynomial): NumberedRationalFunction = NumberedRationalFunction(numerator, NumberedPolynomial(mapOf(emptyList() to one))) /** * Constructs [NumberedRationalFunction] with provided [numerator] and unit denominator. */ -@Suppress("FunctionName") public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numerator: NumberedPolynomial): NumberedRationalFunction = NumberedRationalFunction(numerator, polynomialOne) @@ -473,7 +449,6 @@ public fun > NumberedRationalFunctionSpace.NumberedRationalF * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. */ -@Suppress("FunctionName") public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numeratorCoefficients: Map, C>): NumberedRationalFunction = NumberedRationalFunction( NumberedPolynomial(numeratorCoefficients), @@ -488,7 +463,6 @@ public fun > NumberedRationalFunctionSpace.NumberedRationalF * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. */ -@Suppress("FunctionName") public fun > A.NumberedRationalFunction(numeratorCoefficients: Map, C>): NumberedRationalFunction = NumberedRationalFunction( NumberedPolynomial(numeratorCoefficients), @@ -496,7 +470,7 @@ public fun > A.NumberedRationalFunction(numeratorCoefficients: Map ) ///** -// * Converts [this] coefficient to [NumberedRationalFunction]. +// * Converts [this] constant to [NumberedRationalFunction]. // */ //context(A) //public fun > C.asNumberedRationalFunction() : NumberedRationalFunction = @@ -505,7 +479,7 @@ public fun > A.NumberedRationalFunction(numeratorCoefficients: Map // NumberedPolynomialAsIs(mapOf(emptyList() to one)) // ) ///** -// * Converts [this] coefficient to [NumberedRationalFunction]. +// * Converts [this] constant to [NumberedRationalFunction]. // */ //context(NumberedRationalFunctionSpace) //public fun > C.asNumberedRationalFunction() : NumberedRationalFunction = diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt index fca9a8ab8..06911feca 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt @@ -51,15 +51,14 @@ public inline fun , R> A.numberedRationalFunctionSpace(block: Num */ public fun NumberedPolynomial.substitute(args: Map): NumberedPolynomial = Double.algebra { NumberedPolynomial( - buildMap, Double>(coefficients.size) { + buildMap(coefficients.size) { for ((degs, c) in coefficients) { val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp() val newC = args.entries.fold(c) { product, (variable, substitution) -> val deg = degs.getOrElse(variable) { 0u } if (deg == 0u) product else product * substitution.pow(deg.toInt()) } - if (newDegs !in this) this[newDegs] = newC - else this[newDegs] = this[newDegs]!! + newC + this[newDegs] = if (newDegs !in this) newC else this[newDegs]!! + newC } } ) @@ -70,15 +69,14 @@ public fun NumberedPolynomial.substitute(args: Map): Number */ public fun NumberedPolynomial.substitute(ring: Ring, args: Map): NumberedPolynomial = ring { NumberedPolynomial( - buildMap, C>(coefficients.size) { + buildMap(coefficients.size) { for ((degs, c) in coefficients) { val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp() val newC = args.entries.fold(c) { product, (variable, substitution) -> val deg = degs.getOrElse(variable) { 0u } if (deg == 0u) product else product * power(substitution, deg) } - if (newDegs !in this) this[newDegs] = newC - else this[newDegs] = this[newDegs]!! + newC + this[newDegs] = if (newDegs !in this) newC else this[newDegs]!! + newC } } ) @@ -128,14 +126,14 @@ public fun NumberedRationalFunction.substitute(ring: Ring, args: Map NumberedRationalFunction.substitute(ring: Ring, args: Map>) : NumberedRationalFunction = NumberedRationalFunction(numerator.substitute(ring, args), denominator.substitute(ring, args)) /** * Substitutes provided arguments [args] into [this] rational function. - */ // TODO: To optimize boxing + */ // TODO: To optimize calculation @JvmName("substituteRationalFunction") public fun NumberedRationalFunction.substitute(ring: Ring, args: Map>) : NumberedRationalFunction = ring.numberedRationalFunctionSpace { @@ -250,14 +248,14 @@ public fun NumberedRationalFunction.substitute(ring: Ring, args: Buffe /** * Substitutes provided arguments [args] into [this] rational function. - */ // TODO: To optimize boxing + */ // TODO: To optimize calculation @JvmName("substitutePolynomial") public fun NumberedRationalFunction.substitute(ring: Ring, args: Buffer>) : NumberedRationalFunction = NumberedRationalFunction(numerator.substitute(ring, args), denominator.substitute(ring, args)) /** * Substitutes provided arguments [args] into [this] rational function. - */ // TODO: To optimize boxing + */ // TODO: To optimize calculation @JvmName("substituteRationalFunction") public fun NumberedRationalFunction.substitute(ring: Ring, args: Buffer>) : NumberedRationalFunction = ring.numberedRationalFunctionSpace { -- 2.34.1 From 9fc99a4c727eb6ca5870a36a38832bddd8415aea Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sat, 25 Jun 2022 15:45:10 +0300 Subject: [PATCH 079/123] Removed extra copyright comment. --- .../space/kscience/kmath/functions/listConstructors.kt | 5 ----- 1 file changed, 5 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt index 35c736914..e95361724 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt @@ -3,11 +3,6 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -/* - * 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.functions import space.kscience.kmath.operations.Ring -- 2.34.1 From 403ff93f4af2960facb25696ae5fc1f50e428711 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sat, 25 Jun 2022 16:01:18 +0300 Subject: [PATCH 080/123] Moved optimizations to branch refactor/polynomials --- .../kmath/functions/listUtilOptimized.kt | 250 ------------------ .../space/kscience/kmath/functions/misc.kt | 10 - 2 files changed, 260 deletions(-) delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtilOptimized.kt diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtilOptimized.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtilOptimized.kt deleted file mode 100644 index 6eb3a1dc7..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtilOptimized.kt +++ /dev/null @@ -1,250 +0,0 @@ -/* - * 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.functions - -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.invoke -import kotlin.math.max -import kotlin.math.min - - -// TODO: Optimized copies of substitution and invocation -@UnstablePolynomialBoxingOptimization -@Suppress("NOTHING_TO_INLINE") -internal inline fun copyTo( - origin: List, - originDegree: Int, - target: MutableList, -) { - for (deg in 0 .. originDegree) target[deg] = origin[deg] -} - -@UnstablePolynomialBoxingOptimization -@Suppress("NOTHING_TO_INLINE") -internal inline fun multiplyAddingToUpdater( - ring: Ring, - multiplicand: MutableList, - multiplicandDegree: Int, - multiplier: List, - multiplierDegree: Int, - updater: MutableList, - zero: C, -) { - multiplyAddingTo( - ring = ring, - multiplicand = multiplicand, - multiplicandDegree = multiplicandDegree, - multiplier = multiplier, - multiplierDegree = multiplierDegree, - target = updater - ) - for (updateDeg in 0 .. multiplicandDegree + multiplierDegree) { - multiplicand[updateDeg] = updater[updateDeg] - updater[updateDeg] = zero - } -} - -@UnstablePolynomialBoxingOptimization -@Suppress("NOTHING_TO_INLINE") -internal inline fun multiplyAddingTo( - ring: Ring, - multiplicand: List, - multiplicandDegree: Int, - multiplier: List, - multiplierDegree: Int, - target: MutableList -) = ring { - for (d in 0 .. multiplicandDegree + multiplierDegree) - for (k in max(0, d - multiplierDegree)..min(multiplicandDegree, d)) - target[d] += multiplicand[k] * multiplier[d - k] -} - -@UnstablePolynomialBoxingOptimization -public fun ListPolynomial.substitute2(ring: Ring, arg: ListPolynomial) : ListPolynomial = ring { - if (coefficients.isEmpty()) return ListPolynomial(emptyList()) - - val thisDegree = coefficients.lastIndex - if (thisDegree == -1) return ListPolynomial(emptyList()) - val argDegree = arg.coefficients.lastIndex - if (argDegree == -1) return coefficients[0].asListPolynomial() - val constantZero = zero - val resultCoefs: MutableList = MutableList(thisDegree * argDegree + 1) { constantZero } - resultCoefs[0] = coefficients[thisDegree] - val resultCoefsUpdate: MutableList = MutableList(thisDegree * argDegree + 1) { constantZero } - var resultDegree = 0 - for (deg in thisDegree - 1 downTo 0) { - resultCoefsUpdate[0] = coefficients[deg] - multiplyAddingToUpdater( - ring = ring, - multiplicand = resultCoefs, - multiplicandDegree = resultDegree, - multiplier = arg.coefficients, - multiplierDegree = argDegree, - updater = resultCoefsUpdate, - zero = constantZero - ) - resultDegree += argDegree - } - - return ListPolynomial(resultCoefs) -} - -/** - * Returns numerator (polynomial) of rational function gotten by substitution rational function [arg] to the polynomial instance. - * More concrete, if [arg] is a fraction `f(x)/g(x)` and the receiving instance is `p(x)`, then - * ``` - * p(f/g) * g^deg(p) - * ``` - * is returned. - * - * Used in [ListPolynomial.substitute] and [ListRationalFunction.substitute] for performance optimisation. - */ // TODO: Дописать -@UnstablePolynomialBoxingOptimization -internal fun ListPolynomial.substituteRationalFunctionTakeNumerator(ring: Ring, arg: ListRationalFunction): ListPolynomial = ring { - if (coefficients.isEmpty()) return ListPolynomial(emptyList()) - - val thisDegree = coefficients.lastIndex - if (thisDegree == -1) return ListPolynomial(emptyList()) - val thisDegreeLog2 = 31 - thisDegree.countLeadingZeroBits() - val numeratorDegree = arg.numerator.coefficients.lastIndex - val denominatorDegree = arg.denominator.coefficients.lastIndex - val argDegree = max(numeratorDegree, denominatorDegree) - val constantZero = zero - val powersOf2 = buildList(thisDegreeLog2 + 1) { - var result = 1 - for (exp in 0 .. thisDegreeLog2) { - add(result) - result = result shl 1 - } - } - val hashes = powersOf2.runningReduce { acc, i -> acc + i } - val numeratorPowers = buildList>(thisDegreeLog2 + 1) { - add(arg.numerator.coefficients) - repeat(thisDegreeLog2) { - val next = MutableList(powersOf2[it + 1] * numeratorDegree + 1) { constantZero } - add(next) - val last = last() - multiplyAddingTo( - ring = ring, - multiplicand = last, - multiplicandDegree = powersOf2[it] * numeratorDegree + 1, - multiplier = last, - multiplierDegree = powersOf2[it] * numeratorDegree + 1, - target = next, - ) - } - } - val denominatorPowers = buildList>(thisDegreeLog2 + 1) { - add(arg.denominator.coefficients) - repeat(thisDegreeLog2) { - val next = MutableList(powersOf2[it + 1] * denominatorDegree + 1) { constantZero } - add(next) - val last = last() - multiplyAddingTo( - ring = ring, - multiplicand = last, - multiplicandDegree = powersOf2[it] * denominatorDegree + 1, - multiplier = last, - multiplierDegree = powersOf2[it] * denominatorDegree + 1, - target = next, - ) - } - } - val levelResultCoefsPool = buildList>(thisDegreeLog2 + 1) { - repeat(thisDegreeLog2 + 1) { - add(MutableList(hashes[it] * argDegree) { constantZero }) - } - } - val edgedMultiplier = MutableList(0) { TODO() } - val edgedMultiplierUpdater = MutableList(0) { TODO() } - - fun MutableList.reset() { - for (i in indices) set(i, constantZero) - } - - fun processLevel(level: Int, start: Int, end: Int) : List { - val levelResultCoefs = levelResultCoefsPool[level + 1] - - if (level == -1) { - levelResultCoefs[0] = coefficients[start] - } else { - levelResultCoefs.reset() - multiplyAddingTo( - ring = ring, - multiplicand = processLevel(level = level - 1, start = start, end = (start + end) / 2), - multiplicandDegree = hashes[level] * argDegree, - multiplier = denominatorPowers[level], - multiplierDegree = powersOf2[level] * denominatorDegree, - target = levelResultCoefs - ) - multiplyAddingTo( - ring = ring, - multiplicand = processLevel(level = level - 1, start = (start + end) / 2, end = end), - multiplicandDegree = hashes[level] * argDegree, - multiplier = numeratorPowers[level], - multiplierDegree = powersOf2[level] * numeratorDegree, - target = levelResultCoefs - ) - } - - return levelResultCoefs - } - - fun processLevelEdged(level: Int, start: Int, end: Int) : List { - val levelResultCoefs = levelResultCoefsPool[level + 1] - - if (level == -1) { - levelResultCoefs[0] = coefficients[start] - } else { - val levelsPowerOf2 = powersOf2[level] - if (end - start >= levelsPowerOf2) { - multiplyAddingTo( - ring = ring, - multiplicand = processLevelEdged(level = level - 1, start = start + levelsPowerOf2, end = end), - multiplicandDegree = hashes[level] * argDegree, // TODO: Ввести переменную - multiplier = numeratorPowers[level], - multiplierDegree = powersOf2[level] * numeratorDegree, - target = levelResultCoefs - ) - multiplyAddingTo( - ring = ring, - multiplicand = processLevel(level = level - 1, start = start, end = start + levelsPowerOf2), - multiplicandDegree = hashes[level] * argDegree, - multiplier = edgedMultiplier, - multiplierDegree = max((hashes[level] and thisDegree) - powersOf2[level] + 1, 0) * denominatorDegree, // TODO: Ввести переменную - target = levelResultCoefs - ) - if (level != thisDegreeLog2) { - multiplyAddingToUpdater( - ring = ring, - multiplicand = edgedMultiplier, - multiplicandDegree = max((hashes[level] and thisDegree) - powersOf2[level] + 1, 0) * denominatorDegree, // TODO: Ввести переменную - multiplier = denominatorPowers[level], - multiplierDegree = powersOf2[level] * denominatorDegree, - updater = edgedMultiplierUpdater, - zero = constantZero - ) - } - } else { - copyTo( - origin = processLevelEdged(level = level - 1, start = start + levelsPowerOf2, end = end), - originDegree = hashes[level] * argDegree, // TODO: Ввести переменную - target = levelResultCoefs - ) - } - } - - return levelResultCoefs - } - - return ListPolynomial( - processLevelEdged( - level = thisDegreeLog2, - start = 0, - end = thisDegree + 1 - ) - ) -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt index 7d6fc84fa..aba246519 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt @@ -6,16 +6,6 @@ package space.kscience.kmath.functions -/** - * Marks operations that are going to be optimized reimplementations by reducing number of boxings but currently is - * under development and is not stable (or even ready to use). - */ -@RequiresOptIn( - message = "It's copy of operation with optimized boxing. It's currently unstable.", - level = RequiresOptIn.Level.ERROR -) -internal annotation class UnstablePolynomialBoxingOptimization - /** * Marks declarations that give access to internal entities of polynomials delicate structure. Thus, it allows to * optimize performance a bit by skipping standard steps, but such skips may cause critical errors if something is -- 2.34.1 From 3e917baaaf86ae8a7c73eda36c20dafbe418bda0 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sat, 25 Jun 2022 21:23:32 +0300 Subject: [PATCH 081/123] Added examples for polynomials. Also: - Fixed bug in differentiation of NumberedPolynomials. - Fixed bug in addition and subtraction of LabeledPolynomials. - Added references to NumberedPolynomialWithoutCheck and LabeledPolynomialWithoutCheck. - Made NumberedRationalFunction and LabeledRationalFunction classes data. Made their constructor public. --- .../kscience/kmath/functions/polynomials.kt | 396 ++++++++++++++++++ .../kmath/functions/LabeledPolynomial.kt | 4 +- .../functions/LabeledRationalFunction.kt | 2 +- .../functions/NumberedRationalFunction.kt | 2 +- .../kmath/functions/labeledConstructors.kt | 24 ++ .../kmath/functions/numberedConstructors.kt | 22 + .../kscience/kmath/functions/numberedUtil.kt | 6 +- 7 files changed, 449 insertions(+), 7 deletions(-) create mode 100644 examples/src/main/kotlin/space/kscience/kmath/functions/polynomials.kt diff --git a/examples/src/main/kotlin/space/kscience/kmath/functions/polynomials.kt b/examples/src/main/kotlin/space/kscience/kmath/functions/polynomials.kt new file mode 100644 index 000000000..273fe5cb9 --- /dev/null +++ b/examples/src/main/kotlin/space/kscience/kmath/functions/polynomials.kt @@ -0,0 +1,396 @@ +/* + * 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.functions + +import space.kscience.kmath.expressions.Symbol +import space.kscience.kmath.expressions.symbol +import space.kscience.kmath.operations.algebra + + +/** + * Shows [ListPolynomial]s' and [ListRationalFunction]s' capabilities. + */ +fun listPolynomialsExample() { + // [ListPolynomial] is a representation of a univariate polynomial as a list of coefficients from the least term to + // the greatest term. For example, + val polynomial1: ListPolynomial = ListPolynomial(listOf(2, -3, 1)) + // represents polynomial 2 + (-3) x + x^2 + + // There are also shortcut fabrics: + val polynomial2: ListPolynomial = ListPolynomial(2, -3, 1) + println(polynomial1 == polynomial2) // true + // and even + val polynomial3: ListPolynomial = 57.asListPolynomial() + val polynomial4: ListPolynomial = ListPolynomial(listOf(57)) + println(polynomial3 == polynomial4) // true + + val polynomial5: ListPolynomial = ListPolynomial(3, -1) + // For every ring there can be provided a polynomial ring: + Int.algebra.listPolynomialSpace { + println(-polynomial5 == ListPolynomial(-3, 1)) // true + println(polynomial1 + polynomial5 == ListPolynomial(5, -4, 1)) // true + println(polynomial1 - polynomial5 == ListPolynomial(-1, -2, 1)) // true + println(polynomial1 * polynomial5 == ListPolynomial(6, -11, 6, -1)) // true + } + // You can even write + val x: ListPolynomial = ListPolynomial(0.0, 1.0) + val polynomial6: ListPolynomial = ListPolynomial(2.0, -3.0, 1.0) + Double.algebra.listPolynomialSpace { + println(2 - 3 * x + x * x == polynomial6) + println(2.0 - 3.0 * x + x * x == polynomial6) + } + + // Also there are some utilities for polynomials: + println(polynomial1.substitute(Int.algebra, 1) == 0) // true, because 2 + (-3) * 1 + 1^2 = 0 + println(polynomial1.substitute(Int.algebra, polynomial5) == polynomial1) // true, because 2 + (-3) * (3-x) + (3-x)^2 = 2 - 3x + x^2 + println(polynomial1.derivative(Int.algebra) == ListPolynomial(-3, 2)) // true, (2 - 3x + x^2)' = -3 + 2x + println(polynomial1.nthDerivative(Int.algebra, 2) == 2.asListPolynomial()) // true, (2 - 3x + x^2)'' = 2 + + // Lastly, there are rational functions and some other utilities: + Double.algebra.listRationalFunctionSpace { + val rationalFunction1: ListRationalFunction = ListRationalFunction(listOf(2.0, -3.0, 1.0), listOf(3.0, -1.0)) + // It's just (2 - 3x + x^2)/(3 - x) + + val rationalFunction2 : ListRationalFunction = ListRationalFunction(listOf(5.0, -4.0, 1.0), listOf(3.0, -1.0)) + // It's just (5 - 4x + x^2)/(3 - x) + + println(rationalFunction1 + 1 == rationalFunction2) + } +} + +/** + * Shows [NumberedPolynomial]s' and [NumberedRationalFunction]s' capabilities. + */ +fun numberedPolynomialsExample() { + // Consider polynomial + // 3 + 5 x_2 - 7 x_1^2 x_3 + // Consider, for example, its term -7 x_1^2 x_3. -7 is a coefficient of the term, whereas (2, 0, 1, 0, 0, ...) is + // description of degrees of variables x_1, x_2, ... in the term. Such description with removed leading zeros + // [2, 0, 1] is called "signature" of the term -7 x_1^2 x_3. + + val polynomial1: NumberedPolynomial + with(Int.algebra) { + // [NumberedPolynomial] is a representation of a multivariate polynomial, that stores terms in a map with terms' + // signatures as the map's keys and terms' coefficients as corresponding values. For example, + polynomial1 = NumberedPolynomial( + mapOf( + listOf() to 3, + listOf(0u, 1u) to 5, + listOf(2u, 0u, 1u) to -7, + ) + ) + // represents polynomial 3 + 5 x_2 - 7 x_1^2 x_3 + + // This `NumberedPolynomial` function needs context of either ring of constant (as `Int.algebra` in this example) + // or space of NumberedPolynomials over it. To understand why it is like this see documentations of functions + // NumberedPolynomial and NumberedPolynomialWithoutCheck + + // There are also shortcut fabrics: + val polynomial2: NumberedPolynomial = NumberedPolynomial( + listOf() to 3, + listOf(0u, 1u) to 5, + listOf(2u, 0u, 1u) to -7, + ) + println(polynomial1 == polynomial2) // true + // and even + val polynomial3: NumberedPolynomial = 57.asNumberedPolynomial() // This one actually does not algebraic context! + val polynomial4: NumberedPolynomial = NumberedPolynomial(listOf() to 57) + println(polynomial3 == polynomial4) // true + + numberedPolynomialSpace { + // Also there is DSL for constructing NumberedPolynomials: + val polynomial5: NumberedPolynomial = NumberedPolynomial { + 3 {} + 5 { 2 inPowerOf 1u } + -7 with { 1 pow 2u; 3 pow 1u } + // `pow` and `inPowerOf` are the same + // `with` is omittable + } + println(polynomial1 == polynomial5) // true + + // Unfortunately the DSL does not work good in bare context of constants' ring, so for now it's disabled and + // works only in NumberedPolynomialSpace and NumberedRationalFunctionSpace + } + } + + val polynomial6: NumberedPolynomial = with(Int.algebra) { + NumberedPolynomial( + listOf() to 7, + listOf(0u, 1u) to -5, + listOf(2u, 0u, 1u) to 0, + listOf(0u, 0u, 0u, 4u) to 4, + ) + } + // For every ring there can be provided a polynomial ring: + Int.algebra.numberedPolynomialSpace { + println( + -polynomial6 == NumberedPolynomial { + (-7) {} + 5 { 2 pow 1u } + 0 { 1 pow 2u; 3 pow 1u } + (-4) { 4 pow 4u } + } + ) // true + println( + polynomial1 + polynomial6 == NumberedPolynomial { + 10 {} + 0 { 2 pow 1u } + (-7) { 1 pow 2u; 3 pow 1u } + 4 { 4 pow 4u } + } + ) // true + println( + polynomial1 - polynomial6 == NumberedPolynomial { + (-4) {} + 10 { 2 pow 1u } + (-7) { 1 pow 2u; 3 pow 1u } + (-4) { 4 pow 4u } + } + ) // true + + polynomial1 * polynomial6 // Multiplication works too + } + + Double.algebra.numberedPolynomialSpace { + // You can even write + val x_1: NumberedPolynomial = NumberedPolynomial { 1.0 { 1 pow 1u } } + val x_2: NumberedPolynomial = NumberedPolynomial { 1.0 { 2 pow 1u } } + val x_3: NumberedPolynomial = NumberedPolynomial { 1.0 { 3 pow 1u } } + val polynomial7: NumberedPolynomial = NumberedPolynomial { + 3.0 {} + 5.0 { 2 pow 1u } + (-7.0) { 1 pow 2u; 3 pow 1u } + } + Double.algebra.listPolynomialSpace { + println(3 + 5 * x_2 - 7 * x_1 * x_1 * x_3 == polynomial7) + println(3.0 + 5.0 * x_2 - 7.0 * x_1 * x_1 * x_3 == polynomial7) + } + } + + Int.algebra.numberedPolynomialSpace { + val x_4: NumberedPolynomial = NumberedPolynomial { 1 { 4 pow 1u } } + // Also there are some utilities for polynomials: + println(polynomial1.substitute(mapOf(0 to 1, 1 to -2, 2 to -1)) == 0.asNumberedPolynomial()) // true, + // because it's substitution x_1 -> 1, x_2 -> -2, x_3 -> -1, + // so 3 + 5 x_2 - 7 x_1^2 x_3 = 3 + 5 * (-2) - 7 * 1^2 * (-1) = 3 - 10 + 7 = 0 + println( + polynomial1.substitute(mapOf(1 to x_4)) == NumberedPolynomial { + 3 {} + 5 { 4 pow 1u } + (-7) { 1 pow 2u; 3 pow 1u } + } + ) // true, because it's substitution x_2 -> x_4, so result is 3 + 5 x_4 - 7 x_1^2 x_3 + println( + polynomial1.derivativeWithRespectTo(Int.algebra, 1) == + NumberedPolynomial { 5 {} } + ) // true, d/dx_2 (3 + 5 x_2 - 7 x_1^2 x_3) = 5 + } + + // Lastly, there are rational functions and some other utilities: + Double.algebra.numberedRationalFunctionSpace { + val rationalFunction1: NumberedRationalFunction = NumberedRationalFunction( + NumberedPolynomial { + 2.0 {} + (-3.0) { 1 pow 1u } + 1.0 { 1 pow 2u } + }, + NumberedPolynomial { + 3.0 {} + (-1.0) { 1 pow 1u } + } + ) + // It's just (2 - 3x + x^2)/(3 - x) where x = x_1 + + val rationalFunction2: NumberedRationalFunction = NumberedRationalFunction( + NumberedPolynomial { + 5.0 {} + (-4.0) { 1 pow 1u } + 1.0 { 1 pow 2u } + }, + NumberedPolynomial { + 3.0 {} + (-1.0) { 1 pow 1u } + } + ) + // It's just (5 - 4x + x^2)/(3 - x) where x = x_1 + + println(rationalFunction1 + 1 == rationalFunction2) + } +} + +/** + * Shows [LabeledPolynomial]s' and [LabeledRationalFunction]s' capabilities. + */ +fun labeledPolynomialsExample() { + val x by symbol + val y by symbol + val z by symbol + val t by symbol + + // Consider polynomial + // 3 + 5 y - 7 x^2 z + // Consider, for example, its term -7 x^2 z. -7 is a coefficient of the term, whereas matching (x -> 2, z -> 3) is + // description of degrees of variables x_1, x_2, ... in the term. Such description is called "signature" of the + // term -7 x_1^2 x_3. + + val polynomial1: LabeledPolynomial + with(Int.algebra) { + // [LabeledPolynomial] is a representation of a multivariate polynomial, that stores terms in a map with terms' + // signatures as the map's keys and terms' coefficients as corresponding values. For example, + polynomial1 = LabeledPolynomial( + mapOf( + mapOf() to 3, + mapOf(y to 1u) to 5, + mapOf(x to 2u, z to 1u) to -7, + ) + ) + // represents polynomial 3 + 5 y - 7 x^2 z + + // This `LabeledPolynomial` function needs context of either ring of constant (as `Int.algebra` in this example) + // or space of LabeledPolynomials over it. To understand why it is like this see documentations of functions + // LabeledPolynomial and LabeledPolynomialWithoutCheck + + // There are also shortcut fabrics: + val polynomial2: LabeledPolynomial = LabeledPolynomial( + mapOf() to 3, + mapOf(y to 1u) to 5, + mapOf(x to 2u, z to 1u) to -7, + ) + println(polynomial1 == polynomial2) // true + // and even + val polynomial3: LabeledPolynomial = 57.asLabeledPolynomial() // This one actually does not algebraic context! + val polynomial4: LabeledPolynomial = LabeledPolynomial(mapOf() to 57) + println(polynomial3 == polynomial4) // true + + labeledPolynomialSpace { + // Also there is DSL for constructing NumberedPolynomials: + val polynomial5: LabeledPolynomial = LabeledPolynomial { + 3 {} + 5 { y inPowerOf 1u } + -7 with { x pow 2u; z pow 1u } + // `pow` and `inPowerOf` are the same + // `with` is omittable + } + println(polynomial1 == polynomial5) // true + + // Unfortunately the DSL does not work good in bare context of constants' ring, so for now it's disabled and + // works only in NumberedPolynomialSpace and NumberedRationalFunctionSpace + } + } + + val polynomial6: LabeledPolynomial = with(Int.algebra) { + LabeledPolynomial( + mapOf() to 7, + mapOf(y to 1u) to -5, + mapOf(x to 2u, z to 1u) to 0, + mapOf(t to 4u) to 4, + ) + } + // For every ring there can be provided a polynomial ring: + Int.algebra.labeledPolynomialSpace { + println( + -polynomial6 == LabeledPolynomial { + (-7) {} + 5 { y pow 1u } + 0 { x pow 2u; z pow 1u } + (-4) { t pow 4u } + } + ) // true + println( + polynomial1 + polynomial6 == LabeledPolynomial { + 10 {} + 0 { y pow 1u } + (-7) { x pow 2u; z pow 1u } + 4 { t pow 4u } + } + ) // true + println( + polynomial1 - polynomial6 == LabeledPolynomial { + (-4) {} + 10 { y pow 1u } + (-7) { x pow 2u; z pow 1u } + (-4) { t pow 4u } + } + ) // true + + polynomial1 * polynomial6 // Multiplication works too + } + + Double.algebra.labeledPolynomialSpace { + // You can even write + val polynomial7: LabeledPolynomial = LabeledPolynomial { + 3.0 {} + 5.0 { y pow 1u } + (-7.0) { x pow 2u; z pow 1u } + } + Double.algebra.listPolynomialSpace { + println(3 + 5 * y - 7 * x * x * z == polynomial7) + println(3.0 + 5.0 * y - 7.0 * x * x * z == polynomial7) + } + } + + Int.algebra.labeledPolynomialSpace { + // Also there are some utilities for polynomials: + println(polynomial1.substitute(mapOf(x to 1, y to -2, z to -1)) == 0.asLabeledPolynomial()) // true, + // because it's substitution x -> 1, y -> -2, z -> -1, + // so 3 + 5 y - 7 x^2 z = 3 + 5 * (-2) - 7 * 1^2 * (-1) = 3 - 10 + 7 = 0 + println( + polynomial1.substitute(mapOf(y to t.asPolynomial())) == LabeledPolynomial { + 3 {} + 5 { t pow 1u } + (-7) { x pow 2u; z pow 1u } + } + ) // true, because it's substitution y -> t, so result is 3 + 5 t - 7 x^2 z + println( + polynomial1.derivativeWithRespectTo(Int.algebra, y) == LabeledPolynomial { 5 {} } + ) // true, d/dy (3 + 5 y - 7 x^2 z) = 5 + } + + // Lastly, there are rational functions and some other utilities: + Double.algebra.labeledRationalFunctionSpace { + val rationalFunction1: LabeledRationalFunction = LabeledRationalFunction( + LabeledPolynomial { + 2.0 {} + (-3.0) { x pow 1u } + 1.0 { x pow 2u } + }, + LabeledPolynomial { + 3.0 {} + (-1.0) { x pow 1u } + } + ) + // It's just (2 - 3x + x^2)/(3 - x) + + val rationalFunction2: LabeledRationalFunction = LabeledRationalFunction( + LabeledPolynomial { + 5.0 {} + (-4.0) { x pow 1u } + 1.0 { x pow 2u } + }, + LabeledPolynomial { + 3.0 {} + (-1.0) { x pow 1u } + } + ) + // It's just (5 - 4x + x^2)/(3 - x) + + println(rationalFunction1 + 1 == rationalFunction2) + } +} + +fun main() { + println("ListPolynomials:") + listPolynomialsExample() + println() + + println("NumberedPolynomials:") + numberedPolynomialsExample() + println() + + println("ListPolynomials:") + labeledPolynomialsExample() + println() +} diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt index b0c54502d..061325b60 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt @@ -522,7 +522,7 @@ public class LabeledPolynomialSpace>( override operator fun LabeledPolynomial.plus(other: LabeledPolynomial): LabeledPolynomial = LabeledPolynomialAsIs( buildMap(coefficients.size + other.coefficients.size) { - other.coefficients.mapValuesTo(this) { it.value } + coefficients.mapValuesTo(this) { it.value } other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! + value else value } } ) @@ -532,7 +532,7 @@ public class LabeledPolynomialSpace>( override operator fun LabeledPolynomial.minus(other: LabeledPolynomial): LabeledPolynomial = LabeledPolynomialAsIs( buildMap(coefficients.size + other.coefficients.size) { - other.coefficients.mapValuesTo(this) { it.value } + coefficients.mapValuesTo(this) { it.value } other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! - value else -value } } ) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt index 03f323813..1b0bbbec8 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt @@ -13,7 +13,7 @@ import kotlin.jvm.JvmName /** * Represents multivariate rational function that stores its numerator and denominator as [LabeledPolynomial]s. */ -public class LabeledRationalFunction( +public data class LabeledRationalFunction( public override val numerator: LabeledPolynomial, public override val denominator: LabeledPolynomial ) : RationalFunction> { diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt index 92f507735..497755126 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt @@ -15,7 +15,7 @@ import kotlin.math.max /** * Represents multivariate rational function that stores its numerator and denominator as [NumberedPolynomial]s. */ -public class NumberedRationalFunction internal constructor( +public data class NumberedRationalFunction( public override val numerator: NumberedPolynomial, public override val denominator: NumberedPolynomial ) : RationalFunction> { diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt index 47325c4bb..7586b7012 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt @@ -73,6 +73,8 @@ public inline fun LabeledPolynomialWithoutCheck(vararg pairs: Pair LabeledPolynomial(coefs: Map, C>, add: (C, C) -> C) : LabeledPolynomial { val fixedCoefs = mutableMapOf, C>() @@ -93,6 +95,8 @@ public fun LabeledPolynomial(coefs: Map, C>, add: (C, C) - * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. + * + * @see LabeledPolynomialWithoutCheck */ public fun LabeledPolynomial(pairs: Collection, C>>, add: (C, C) -> C) : LabeledPolynomial { val fixedCoefs = mutableMapOf, C>() @@ -113,6 +117,8 @@ public fun LabeledPolynomial(pairs: Collection, C>>, * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. + * + * @see LabeledPolynomialWithoutCheck */ public fun LabeledPolynomial(vararg pairs: Pair, C>, add: (C, C) -> C) : LabeledPolynomial { val fixedCoefs = mutableMapOf, C>() @@ -135,6 +141,8 @@ public fun LabeledPolynomial(vararg pairs: Pair, C>, add: * 1. Zeros at the ends of terms' signatures (e.g. [coefs] keys) will be removed. (See [cleanUp].) * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. + * + * @see LabeledPolynomialWithoutCheck */ public inline fun > A.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs, ::add) /** @@ -144,6 +152,8 @@ public inline fun > A.LabeledPolynomial(coefs: Map> LabeledPolynomialSpace.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs) { left: C, right: C -> left + right } @@ -154,6 +164,8 @@ public inline fun > LabeledPolynomialSpace.LabeledPolynomial * 1. Zeros at the ends of terms' signatures (e.g. [coefs] keys) will be removed. (See [cleanUp].) * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. + * + * @see LabeledPolynomialWithoutCheck */ public inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs) { left: C, right: C -> left + right } @@ -164,6 +176,8 @@ public inline fun > LabeledRationalFunctionSpace.LabeledPoly * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. + * + * @see LabeledPolynomialWithoutCheck */ public inline fun > A.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs, ::add) @@ -174,6 +188,8 @@ public inline fun > A.LabeledPolynomial(pairs: Collection> LabeledPolynomialSpace.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs) { left: C, right: C -> left + right } /** @@ -183,6 +199,8 @@ public inline fun > LabeledPolynomialSpace.LabeledPolynomial * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. + * + * @see LabeledPolynomialWithoutCheck */ public inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs) { left: C, right: C -> left + right } @@ -193,6 +211,8 @@ public inline fun > LabeledRationalFunctionSpace.LabeledPoly * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. + * + * @see LabeledPolynomialWithoutCheck */ public inline fun > A.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs) { left: C, right: C -> left + right } /** @@ -202,6 +222,8 @@ public inline fun > A.LabeledPolynomial(vararg pairs: Pair> LabeledPolynomialSpace.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs) { left: C, right: C -> left + right } /** @@ -211,6 +233,8 @@ public inline fun > LabeledPolynomialSpace.LabeledPolynomial * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. + * + * @see LabeledPolynomialWithoutCheck */ public inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs) { left: C, right: C -> left + right } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt index 4850e6cec..3cd398623 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt @@ -72,6 +72,8 @@ public inline fun NumberedPolynomialWithoutCheck(vararg pairs: Pair NumberedPolynomial(coefs: Map, C>, add: (C, C) -> C) : NumberedPolynomial { val fixedCoefs = mutableMapOf, C>() @@ -92,6 +94,8 @@ public fun NumberedPolynomial(coefs: Map, C>, add: (C, C) -> C) : * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. + * + * @see NumberedPolynomialWithoutCheck */ public fun NumberedPolynomial(pairs: Collection, C>>, add: (C, C) -> C) : NumberedPolynomial { val fixedCoefs = mutableMapOf, C>() @@ -112,6 +116,8 @@ public fun NumberedPolynomial(pairs: Collection, C>>, add: ( * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. + * + * @see NumberedPolynomialWithoutCheck */ public fun NumberedPolynomial(vararg pairs: Pair, C>, add: (C, C) -> C) : NumberedPolynomial { val fixedCoefs = mutableMapOf, C>() @@ -134,6 +140,8 @@ public fun NumberedPolynomial(vararg pairs: Pair, C>, add: (C, C) * 1. Zeros at the ends of terms' signatures (e.g. [coefs] keys) will be removed. (See [cleanUp].) * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. + * + * @see NumberedPolynomialWithoutCheck */ public inline fun > A.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, ::add) /** @@ -143,6 +151,8 @@ public inline fun > A.NumberedPolynomial(coefs: Map, C> * 1. Zeros at the ends of terms' signatures (e.g. [coefs] keys) will be removed. (See [cleanUp].) * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. + * + * @see NumberedPolynomialWithoutCheck */ public inline fun > NumberedPolynomialSpace.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs) { left: C, right: C -> left + right } @@ -153,6 +163,8 @@ public inline fun > NumberedPolynomialSpace.NumberedPolynomi * 1. Zeros at the ends of terms' signatures (e.g. [coefs] keys) will be removed. (See [cleanUp].) * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. + * + * @see NumberedPolynomialWithoutCheck */ public inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs) { left: C, right: C -> left + right } @@ -163,6 +175,8 @@ public inline fun > NumberedRationalFunctionSpace.NumberedPo * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. + * + * @see NumberedPolynomialWithoutCheck */ public inline fun > A.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, ::add) @@ -173,6 +187,8 @@ public inline fun > A.NumberedPolynomial(pairs: Collection> NumberedPolynomialSpace.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs) { left: C, right: C -> left + right } /** @@ -192,6 +208,8 @@ public inline fun > NumberedRationalFunctionSpace.NumberedPo * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. + * + * @see NumberedPolynomialWithoutCheck */ public inline fun > A.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs) { left: C, right: C -> left + right } /** @@ -201,6 +219,8 @@ public inline fun > A.NumberedPolynomial(vararg pairs: Pair> NumberedPolynomialSpace.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs) { left: C, right: C -> left + right } /** @@ -210,6 +230,8 @@ public inline fun > NumberedPolynomialSpace.NumberedPolynomi * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. + * + * @see NumberedPolynomialWithoutCheck */ public inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs) { left: C, right: C -> left + right } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt index 06911feca..96f5f480b 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt @@ -353,7 +353,7 @@ public fun > NumberedPolynomial.derivativeWithRespectTo( buildMap(coefficients.size) { coefficients .forEach { (degs, c) -> - if (degs.size > variable) return@forEach + if (degs.lastIndex < variable) return@forEach put( degs.mapIndexed { index, deg -> when { @@ -383,7 +383,7 @@ public fun > NumberedPolynomial.nthDerivativeWithRespectTo( buildMap(coefficients.size) { coefficients .forEach { (degs, c) -> - if (degs.size > variable) return@forEach + if (degs.lastIndex < variable) return@forEach put( degs.mapIndexed { index, deg -> when { @@ -417,7 +417,7 @@ public fun > NumberedPolynomial.nthDerivativeWithRespectTo( buildMap(coefficients.size) { coefficients .forEach { (degs, c) -> - if (degs.size > maxRespectedVariable) return@forEach + if (degs.lastIndex < maxRespectedVariable) return@forEach put( degs.mapIndexed { index, deg -> if (index !in filteredVariablesAndOrders) return@mapIndexed deg -- 2.34.1 From 630d16bbeefbd8d402732dd8410ea950c26a6ca6 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sun, 26 Jun 2022 12:16:51 +0300 Subject: [PATCH 082/123] Added design notes. Also: - Changed `xxxPolynomialSpace()` and `xxxPolynomialSpace()` functions to `xxxPolynomialSpace` value properties. - Changed inconsistency of names `XxxRationalFunctionalSpaceYyy` and `XxxRationalFunctionSpaceYyy` in favor of second one. --- docs/polynomials.md | 172 ++++++++++++++++++ .../functions/LabeledRationalFunction.kt | 2 +- .../kmath/functions/ListRationalFunction.kt | 2 +- .../functions/NumberedRationalFunction.kt | 2 +- .../kmath/functions/RationalFunction.kt | 22 +-- .../kscience/kmath/functions/labeledUtil.kt | 8 +- .../kscience/kmath/functions/listUtil.kt | 12 +- .../kscience/kmath/functions/numberedUtil.kt | 8 +- 8 files changed, 200 insertions(+), 28 deletions(-) create mode 100644 docs/polynomials.md diff --git a/docs/polynomials.md b/docs/polynomials.md new file mode 100644 index 000000000..fe69948e5 --- /dev/null +++ b/docs/polynomials.md @@ -0,0 +1,172 @@ +# Polynomials and Rational Functions + +KMath provides a way to work with uni- and multivariate polynomials and rational functions. It includes full support of arithmetic operations of integers, **constants** (elements of ring polynomials are build over), variables (for certain multivariate implementations), polynomials and rational functions encapsulated in so-called **polynomial space** and **rational function space** and some other utilities such as algebraic differentiation and substitution. + +## Concrete realizations + +There are 3 approaches to represent polynomials: +1. For univariate polynomials one can represent and store polynomial as a list of coefficients for each power of the variable. I.e. polynomial $a_0 + \dots + a_n x^n $ can be represented as a finite sequence $(a_0; \dots; a_n)$. (Compare to sequential definition of polynomials.) +2. For multivariate polynomials one can represent and store polynomial as a matching (in programming it is called "map" or "dictionary", in math it is called [functional relation](https://en.wikipedia.org/wiki/Binary_relation#Special_types_of_binary_relations)) of each "**term signature**" (that describes what variables and in what powers appear in the term) with corresponding coefficient of the term. But there are 2 possible approaches of term signature representation: + 1. One can number all the variables, so term signature can be represented as a sequence describing powers of the variables. I.e. signature of term $c \\; x_0^{d_0} \dots x_n^{d_n} $ (for natural or zero $d_i $) can be represented as a finite sequence $(d_0; \dots; d_n)$. + 2. One can represent variables as objects ("**labels**"), so term signature can be also represented as a matching of each appeared variable with its power in the term. + +All that three approaches are implemented by "list", "numbered", and "labeled" versions of polynomials and polynomial spaces respectively. Whereas all rational functions are represented as fractions with corresponding polynomial numerator and denominator, and rational functions' spaces are implemented in the same way as usual field of rational numbers (or more precisely, as any field of fractions over integral domain) should be implemented. + +So here are a bit of details. Let `C` by type of constants. Then: +1. `ListPolynomial`, `ListPolynomialSpace`, `ListRationalFunction` and `ListRationalFunctionSpace` implement the first scenario. `ListPolynomial` stores polynomial $a_0 + \dots + a_n x^n $ as a coefficients list `listOf(a_0, ..., a_n)` (of type `List`). + + They also have variation `ScalableListPolynomialSpace` that replaces former polynomials and implements `ScaleOperations`. +2. `NumberedPolynomial`, `NumberedPolynomialSpace`, `NumberedRationalFunction` and `NumberedRationalFunctionSpace` implement second scenario. `NumberedPolynomial` stores polynomials as structures of type `Map, C>`. Signatures are stored as `List`. To prevent ambiguity signatures should not end with zeros. +3. `LabeledPolynomial`, `LabeledPolynomialSpace`, `LabeledRationalFunction` and `LabeledRationalFunctionSpace` implement third scenario using common `Symbol` as variable type. `LabeledPolynomial` stores polynomials as structures of type `Map, C>`. Signatures are stored as `Map`. To prevent ambiguity each signature should not map any variable to zero. + +### Example: `ListPolynomial` + +For example, polynomial $2 - 3x + x^2 $ (with `Int` coefficients) is represented +```kotlin +val polynomial: ListPolynomial = ListPolynomial(listOf(2, -3, 1)) +// or +val polynomial: ListPolynomial = ListPolynomial(2, -3, 1) +``` + +All algebraic operations can be used in corresponding space: +```kotlin +val computationResult = Int.algebra.listPolynomialSpace { + ListPolynomial(2, -3, 1) + ListPolynomial(0, 6) == ListPolynomial(2, 3, 1) +} + +println(computationResult) // true +``` + +For more see [examples](../examples/src/main/kotlin/space/kscience/kmath/functions/polynomials.kt). + +### Example: `NumberedPolynomial` + +For example, polynomial $3 + 5 x_1 - 7 x_0^2 x_2 $ (with `Int` coefficients) is represented +```kotlin +val polynomial: NumberedPolynomial = NumberedPolynomial( + mapOf( + listOf() to 3, + listOf(0u, 1u) to 5, + listOf(2u, 0u, 1u) to -7, + ) +) +// or +val polynomial: NumberedPolynomial = NumberedPolynomial( + listOf() to 3, + listOf(0u, 1u) to 5, + listOf(2u, 0u, 1u) to -7, +) +``` + +All algebraic operations can be used in corresponding space: +```kotlin +val computationResult = Int.algebra.numberedPolynomialSpace { + NumberedPolynomial( + listOf() to 3, + listOf(0u, 1u) to 5, + listOf(2u, 0u, 1u) to -7, + ) + NumberedPolynomial( + listOf(0u, 1u) to -5, + listOf(0u, 0u, 0u, 4u) to 4, + ) == NumberedPolynomial( + listOf() to 3, + listOf(0u, 1u) to 0, + listOf(2u, 0u, 1u) to -7, + listOf(0u, 0u, 0u, 4u) to 4, + ) +} + +println(computationResult) // true +``` + +For more see [examples](../examples/src/main/kotlin/space/kscience/kmath/functions/polynomials.kt). + +### Example: `LabeledPolynomial` + +For example, polynomial $3 + 5 y - 7 x^2 z $ (with `Int` coefficients) is represented +```kotlin +val polynomial: LabeledPolynomial = LabeledPolynomial( + mapOf( + mapOf() to 3, + mapOf(y to 1u) to 5, + mapOf(x to 2u, z to 1u) to -7, + ) +) +// or +val polynomial: LabeledPolynomial = LabeledPolynomial( + mapOf() to 3, + mapOf(y to 1u) to 5, + mapOf(x to 2u, z to 1u) to -7, +) +``` + +All algebraic operations can be used in corresponding space: +```kotlin +val computationResult = Int.algebra.labeledPolynomialSpace { + LabeledPolynomial( + listOf() to 3, + listOf(0u, 1u) to 5, + listOf(2u, 0u, 1u) to -7, + ) + LabeledPolynomial( + listOf(0u, 1u) to -5, + listOf(0u, 0u, 0u, 4u) to 4, + ) == LabeledPolynomial( + listOf() to 3, + listOf(0u, 1u) to 0, + listOf(2u, 0u, 1u) to -7, + listOf(0u, 0u, 0u, 4u) to 4, + ) +} + +println(computationResult) // true +``` + +For more see [examples](../examples/src/main/kotlin/space/kscience/kmath/functions/polynomials.kt). + +## Abstract entities (interfaces and abstract classes) + +```mermaid +classDiagram + Polynomial <|-- ListPolynomial + Polynomial <|-- NumberedPolynomial + Polynomial <|-- LabeledPolynomial + + RationalFunction <|-- ListRationalFunction + RationalFunction <|-- NumberedRationalFunction + RationalFunction <|-- LabeledRationalFunction + + Ring <|-- PolynomialSpace + PolynomialSpace <|-- MultivariatePolynomialSpace + PolynomialSpace <|-- PolynomialSpaceOverRing + + Ring <|-- RationalFunctionSpace + RationalFunctionSpace <|-- MultivariateRationalFunctionSpace + RationalFunctionSpace <|-- RationalFunctionSpaceOverRing + RationalFunctionSpace <|-- RationalFunctionSpaceOverPolynomialSpace + RationalFunctionSpace <|-- PolynomialSpaceOfFractions + RationalFunctionSpaceOverPolynomialSpace <|-- MultivariateRationalFunctionSpaceOverMultivariatePolynomialSpace + MultivariateRationalFunctionSpace <|-- MultivariateRationalFunctionSpaceOverMultivariatePolynomialSpace + MultivariateRationalFunctionSpace <|-- MultivariatePolynomialSpaceOfFractions + PolynomialSpaceOfFractions <|-- MultivariatePolynomialSpaceOfFractions +``` + +There are implemented `Polynomial` and `RationalFunction` interfaces as abstractions of polynomials and rational functions respectively (although, there is not a lot of logic in them) and `PolynomialSpace` and `RationalFunctionSpace` (that implement `Ring` interface) as abstractions of polynomials' and rational functions' spaces respectively. More precisely, that means they allow to declare common logic of interaction with such objects and spaces: +- `Polynomial` does not provide any logic. It is marker interface. +- `RationalFunction` provides numerator and denominator of rational function and destructuring declaration for them. +- `PolynomialSpace` provides all possible arithmetic interactions of integers, constants (of type `C`), and polynomials (of type `P`) like addition, subtraction, multiplication, and some others and common properties like degree of polynomial. +- `RationalFunctionSpace` provides the same as `PolynomialSpace` but also for rational functions: all possible arithmetic interactions of integers, constants (of type `C`), polynomials (of type `P`), and rational functions (of type `R`) like addition, subtraction, multiplication, division (in some cases), and some others and common properties like degree of polynomial. + +Then to add abstraction of similar behaviour with variables (in multivariate case) there are implemented `MultivariatePolynomialSpace` and `MultivariateRationalFunctionSpace`. They just include variables (of type `V`) in the interactions of the entities. + +Also, to remove boilerplates there were provided helping subinterfaces and abstract subclasses: +- `PolynomialSpaceOverRing` allows to replace implementation of interactions of integers and constants with implementations from provided ring over constants (of type `A: Ring`). +- `RationalFunctionSpaceOverRing` — the same but for `RationalFunctionSpace`. +- `RationalFunctionSpaceOverPolynomialSpace` — the same but "the inheritance" includes interactions with polynomials from provided `PolynomialSpace`. +- `PolynomialSpaceOfFractions` is actually abstract subclass of `RationalFunctionSpace` that implements all fractions boilerplates with provided (`protected`) constructor of rational functions by polynomial numerator and denominator. +- `MultivariateRationalFunctionSpaceOverMultivariatePolynomialSpace` and `MultivariatePolynomialSpaceOfFractions` — the same stories of operators inheritance and fractions boilerplates respectively but in multivariate case. + +## Utilities + +For all kinds of polynomials there are provided (implementation details depend on kind of polynomials) such common utilities as: +1. differentiation and anti-differentiation, +2. substitution, invocation and functional representation. \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt index 1b0bbbec8..b1d0dd4d9 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt @@ -30,7 +30,7 @@ public data class LabeledRationalFunction( public class LabeledRationalFunctionSpace>( public val ring: A, ) : - MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSpace< + MultivariateRationalFunctionSpaceOverMultivariatePolynomialSpace< C, Symbol, LabeledPolynomial, diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt index e23baa548..7434063f2 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt @@ -28,7 +28,7 @@ public data class ListRationalFunction( public class ListRationalFunctionSpace> ( public val ring: A, ) : - RationalFunctionalSpaceOverPolynomialSpace< + RationalFunctionSpaceOverPolynomialSpace< C, ListPolynomial, ListRationalFunction, diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt index 497755126..e61d6c55e 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt @@ -32,7 +32,7 @@ public data class NumberedRationalFunction( public class NumberedRationalFunctionSpace> ( public val ring: A, ) : - RationalFunctionalSpaceOverPolynomialSpace< + RationalFunctionSpaceOverPolynomialSpace< C, NumberedPolynomial, NumberedRationalFunction, diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt index 338ae9935..1782dba74 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt @@ -29,7 +29,7 @@ public interface RationalFunction> { * @param R the type of rational functions. */ @Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") // FIXME: Waiting for KT-31420 -public interface RationalFunctionalSpace, R: RationalFunction> : Ring { +public interface RationalFunctionSpace, R: RationalFunction> : Ring { /** * Returns sum of the constant and the integer represented as a constant (member of underlying ring). * @@ -459,12 +459,12 @@ public interface RationalFunctionalSpace, R: RationalFunctio * @param A the type of algebraic structure (precisely, of ring) provided for constants. */ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 -public interface RationalFunctionalSpaceOverRing< +public interface RationalFunctionSpaceOverRing< C, P: Polynomial, R: RationalFunction, A: Ring - > : RationalFunctionalSpace { + > : RationalFunctionSpace { /** * Underlying ring of constants. Its operations on constants are inherited by local operations on constants. @@ -561,12 +561,12 @@ public interface RationalFunctionalSpaceOverRing< * @param AP the type of algebraic structure (precisely, of ring) provided for polynomials. */ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 -public interface RationalFunctionalSpaceOverPolynomialSpace< +public interface RationalFunctionSpaceOverPolynomialSpace< C, P: Polynomial, R: RationalFunction, AP: PolynomialSpace, - > : RationalFunctionalSpace { + > : RationalFunctionSpace { /** * Underlying polynomial ring. Its polynomial operations are inherited by local polynomial operations. @@ -797,7 +797,7 @@ public abstract class PolynomialSpaceOfFractions< C, P: Polynomial, R: RationalFunction, - > : RationalFunctionalSpace { + > : RationalFunctionSpace { /** * Constructor of rational functions (of type [R]) from numerator and denominator (of type [P]). @@ -1106,12 +1106,12 @@ public abstract class PolynomialSpaceOfFractions< * @param R the type of rational functions. */ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 -public interface MultivariateRationalFunctionalSpace< +public interface MultivariateRationalFunctionSpace< C, V, P: Polynomial, R: RationalFunction - >: RationalFunctionalSpace { + >: RationalFunctionSpace { /** * Returns sum of the variable represented as a monic monomial and the integer represented as a constant polynomial. */ @@ -1335,13 +1335,13 @@ public interface MultivariateRationalFunctionalSpace< * @param AP the type of algebraic structure (precisely, of ring) provided for polynomials. */ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 -public interface MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSpace< +public interface MultivariateRationalFunctionSpaceOverMultivariatePolynomialSpace< C, V, P: Polynomial, R: RationalFunction, AP: MultivariatePolynomialSpace, - > : RationalFunctionalSpaceOverPolynomialSpace, MultivariateRationalFunctionalSpace { + > : RationalFunctionSpaceOverPolynomialSpace, MultivariateRationalFunctionSpace { /** * Returns sum of the variable represented as a monic monomial and the integer represented as a constant polynomial. */ @@ -1517,7 +1517,7 @@ public abstract class MultivariatePolynomialSpaceOfFractions< V, P: Polynomial, R: RationalFunction, - > : MultivariateRationalFunctionalSpace, PolynomialSpaceOfFractions() { + > : MultivariateRationalFunctionSpace, PolynomialSpaceOfFractions() { /** * Returns sum of the variable represented as a rational function and the rational function. */ diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledUtil.kt index 39c781a14..4002eb25a 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledUtil.kt @@ -19,8 +19,8 @@ import kotlin.jvm.JvmName /** * Creates a [LabeledPolynomialSpace] over a received ring. */ -public fun > A.labeledPolynomialSpace(): LabeledPolynomialSpace = - LabeledPolynomialSpace(this) +public inline val > A.labeledPolynomialSpace: LabeledPolynomialSpace + get() = LabeledPolynomialSpace(this) /** * Creates a [LabeledPolynomialSpace]'s scope over a received ring. @@ -32,8 +32,8 @@ public inline fun , R> A.labeledPolynomialSpace(block: LabeledPol /** * Creates a [LabeledRationalFunctionSpace] over a received ring. */ -public fun > A.labeledRationalFunctionSpace(): LabeledRationalFunctionSpace = - LabeledRationalFunctionSpace(this) +public inline val > A.labeledRationalFunctionSpace: LabeledRationalFunctionSpace + get() = LabeledRationalFunctionSpace(this) /** * Creates a [LabeledRationalFunctionSpace]'s scope over a received ring. diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt index 649fc48bd..4f3f6d88e 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt @@ -16,8 +16,8 @@ import kotlin.math.pow /** * Creates a [ListPolynomialSpace] over a received ring. */ -public fun > A.listPolynomialSpace(): ListPolynomialSpace = - ListPolynomialSpace(this) +public inline val > A.listPolynomialSpace: ListPolynomialSpace + get() = ListPolynomialSpace(this) /** * Creates a [ListPolynomialSpace]'s scope over a received ring. @@ -30,8 +30,8 @@ public inline fun , R> A.listPolynomialSpace(block: ListPolynomia /** * Creates a [ScalableListPolynomialSpace] over a received scalable ring. */ -public fun A.scalableListPolynomialSpace(): ScalableListPolynomialSpace where A : Ring, A : ScaleOperations = - ScalableListPolynomialSpace(this) +public inline val A.scalableListPolynomialSpace: ScalableListPolynomialSpace where A : Ring, A : ScaleOperations + get() = ScalableListPolynomialSpace(this) /** * Creates a [ScalableListPolynomialSpace]'s scope over a received scalable ring. @@ -44,8 +44,8 @@ public inline fun A.scalableListPolynomialSpace(block: ScalableListPol /** * Creates a [ListRationalFunctionSpace] over a received ring. */ -public fun > A.listRationalFunctionSpace(): ListRationalFunctionSpace = - ListRationalFunctionSpace(this) +public inline val > A.listRationalFunctionSpace: ListRationalFunctionSpace + get() = ListRationalFunctionSpace(this) /** * Creates a [ListRationalFunctionSpace]'s scope over a received ring. diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt index 96f5f480b..e485652f4 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt @@ -21,8 +21,8 @@ import kotlin.math.min /** * Creates a [NumberedPolynomialSpace] over a received ring. */ -public fun > A.numberedPolynomialSpace(): NumberedPolynomialSpace = - NumberedPolynomialSpace(this) +public inline val > A.numberedPolynomialSpace: NumberedPolynomialSpace + get() = NumberedPolynomialSpace(this) /** * Creates a [NumberedPolynomialSpace]'s scope over a received ring. @@ -35,8 +35,8 @@ public inline fun , R> A.numberedPolynomialSpace(block: NumberedP /** * Creates a [NumberedRationalFunctionSpace] over a received ring. */ -public fun > A.numberedRationalFunctionSpace(): NumberedRationalFunctionSpace = - NumberedRationalFunctionSpace(this) +public inline val > A.numberedRationalFunctionSpace: NumberedRationalFunctionSpace + get() = NumberedRationalFunctionSpace(this) /** * Creates a [NumberedRationalFunctionSpace]'s scope over a received ring. -- 2.34.1 From cb7291ccb00e5b167b69928360ae4fadafcaf0cd Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sun, 26 Jun 2022 12:58:30 +0300 Subject: [PATCH 083/123] Little addition to polynomials design note. --- docs/polynomials.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/polynomials.md b/docs/polynomials.md index fe69948e5..b255acda1 100644 --- a/docs/polynomials.md +++ b/docs/polynomials.md @@ -8,7 +8,7 @@ There are 3 approaches to represent polynomials: 1. For univariate polynomials one can represent and store polynomial as a list of coefficients for each power of the variable. I.e. polynomial $a_0 + \dots + a_n x^n $ can be represented as a finite sequence $(a_0; \dots; a_n)$. (Compare to sequential definition of polynomials.) 2. For multivariate polynomials one can represent and store polynomial as a matching (in programming it is called "map" or "dictionary", in math it is called [functional relation](https://en.wikipedia.org/wiki/Binary_relation#Special_types_of_binary_relations)) of each "**term signature**" (that describes what variables and in what powers appear in the term) with corresponding coefficient of the term. But there are 2 possible approaches of term signature representation: 1. One can number all the variables, so term signature can be represented as a sequence describing powers of the variables. I.e. signature of term $c \\; x_0^{d_0} \dots x_n^{d_n} $ (for natural or zero $d_i $) can be represented as a finite sequence $(d_0; \dots; d_n)$. - 2. One can represent variables as objects ("**labels**"), so term signature can be also represented as a matching of each appeared variable with its power in the term. + 2. One can represent variables as objects ("**labels**"), so term signature can be also represented as a matching of each appeared variable with its power in the term. I.e. signature of term $c \\; x_0^{d_0} \dots x_n^{d_n} $ (for natural non-zero $d_i $) can be represented as a finite matching $(x_0 \to d_1; \dots; x_n \to d_n)$. All that three approaches are implemented by "list", "numbered", and "labeled" versions of polynomials and polynomial spaces respectively. Whereas all rational functions are represented as fractions with corresponding polynomial numerator and denominator, and rational functions' spaces are implemented in the same way as usual field of rational numbers (or more precisely, as any field of fractions over integral domain) should be implemented. -- 2.34.1 From ed634013f67b71002919ef43a75555f1623d1945 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Mon, 27 Jun 2022 17:07:33 +0300 Subject: [PATCH 084/123] Removed extra suppresses. --- .../kmath/functions/LabeledPolynomial.kt | 2 -- .../functions/LabeledRationalFunction.kt | 6 ----- .../kmath/functions/ListPolynomial.kt | 7 ------ .../kmath/functions/ListRationalFunction.kt | 16 ------------- .../functions/NumberedRationalFunction.kt | 24 ------------------- .../kmath/functions/labeledConstructors.kt | 6 +---- .../kmath/functions/numberedConstructors.kt | 6 +---- 7 files changed, 2 insertions(+), 65 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt index 061325b60..f1859ac4b 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt @@ -610,12 +610,10 @@ public class LabeledPolynomialSpace>( /** * Substitutes provided arguments [arguments] into [this] polynomial. */ - @Suppress("NOTHING_TO_INLINE") public inline fun LabeledPolynomial.substitute(arguments: Map): LabeledPolynomial = substitute(ring, arguments) /** * Substitutes provided arguments [arguments] into [this] polynomial. */ - @Suppress("NOTHING_TO_INLINE") @JvmName("substitutePolynomial") public inline fun LabeledPolynomial.substitute(arguments: Map>) : LabeledPolynomial = substitute(ring, arguments) } \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt index b1d0dd4d9..c34d1e46f 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt @@ -62,35 +62,29 @@ public class LabeledRationalFunctionSpace>( /** * Substitutes provided constant [argument] into [this] polynomial. */ - @Suppress("NOTHING_TO_INLINE") public inline fun LabeledPolynomial.substitute(argument: Map): LabeledPolynomial = substitute(ring, argument) /** * Substitutes provided polynomial [argument] into [this] polynomial. */ - @Suppress("NOTHING_TO_INLINE") @JvmName("substitutePolynomial") public inline fun LabeledPolynomial.substitute(argument: Map>): LabeledPolynomial = substitute(ring, argument) /** * Substitutes provided rational function [argument] into [this] polynomial. */ - @Suppress("NOTHING_TO_INLINE") @JvmName("substituteRationalFunction") public inline fun LabeledPolynomial.substitute(argument: Map>): LabeledRationalFunction = substitute(ring, argument) /** * Substitutes provided constant [argument] into [this] rational function. */ - @Suppress("NOTHING_TO_INLINE") public inline fun LabeledRationalFunction.substitute(argument: Map): LabeledRationalFunction = substitute(ring, argument) /** * Substitutes provided polynomial [argument] into [this] rational function. */ - @Suppress("NOTHING_TO_INLINE") @JvmName("substitutePolynomial") public inline fun LabeledRationalFunction.substitute(argument: Map>): LabeledRationalFunction = substitute(ring, argument) /** * Substitutes provided rational function [argument] into [this] rational function. */ - @Suppress("NOTHING_TO_INLINE") @JvmName("substituteRationalFunction") public inline fun LabeledRationalFunction.substitute(argument: Map>): LabeledRationalFunction = substitute(ring, argument) } \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt index 8db93cbb1..3f470d5e7 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt @@ -346,39 +346,32 @@ public open class ListPolynomialSpace>( /** * Evaluates value of [this] polynomial on provided [argument]. */ - @Suppress("NOTHING_TO_INLINE") public inline fun ListPolynomial.substitute(argument: C): C = substitute(ring, argument) /** * Substitutes provided polynomial [argument] into [this] polynomial. */ - @Suppress("NOTHING_TO_INLINE") public inline fun ListPolynomial.substitute(argument: ListPolynomial): ListPolynomial = substitute(ring, argument) /** * Represent [this] polynomial as a regular context-less function. */ - @Suppress("NOTHING_TO_INLINE") public inline fun ListPolynomial.asFunction(): (C) -> C = asFunctionOver(ring) /** * Represent [this] polynomial as a regular context-less function. */ - @Suppress("NOTHING_TO_INLINE") public inline fun ListPolynomial.asFunctionOfConstant(): (C) -> C = asFunctionOfConstantOver(ring) /** * Represent [this] polynomial as a regular context-less function. */ - @Suppress("NOTHING_TO_INLINE") public inline fun ListPolynomial.asFunctionOfPolynomial(): (ListPolynomial) -> ListPolynomial = asFunctionOfPolynomialOver(ring) /** * Evaluates value of [this] polynomial on provided [argument]. */ - @Suppress("NOTHING_TO_INLINE") public inline operator fun ListPolynomial.invoke(argument: C): C = substitute(ring, argument) /** * Evaluates value of [this] polynomial on provided [argument]. */ - @Suppress("NOTHING_TO_INLINE") public inline operator fun ListPolynomial.invoke(argument: ListPolynomial): ListPolynomial = substitute(ring, argument) } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt index 7434063f2..40c6745d9 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt @@ -55,83 +55,67 @@ public class ListRationalFunctionSpace> ( /** * Evaluates value of [this] polynomial on provided argument. */ - @Suppress("NOTHING_TO_INLINE") public inline fun ListPolynomial.substitute(argument: C): C = substitute(ring, argument) /** * Substitutes provided polynomial [argument] into [this] polynomial. */ - @Suppress("NOTHING_TO_INLINE") public inline fun ListPolynomial.substitute(argument: ListPolynomial): ListPolynomial = substitute(ring, argument) /** * Substitutes provided rational function [argument] into [this] polynomial. */ - @Suppress("NOTHING_TO_INLINE") public inline fun ListPolynomial.substitute(argument: ListRationalFunction): ListRationalFunction = substitute(ring, argument) /** * Substitutes provided polynomial [argument] into [this] rational function. */ - @Suppress("NOTHING_TO_INLINE") public inline fun ListRationalFunction.substitute(argument: ListPolynomial): ListRationalFunction = substitute(ring, argument) /** * Substitutes provided rational function [argument] into [this] rational function. */ - @Suppress("NOTHING_TO_INLINE") public inline fun ListRationalFunction.substitute(argument: ListRationalFunction): ListRationalFunction = substitute(ring, argument) /** * Represent [this] polynomial as a regular context-less function. */ - @Suppress("NOTHING_TO_INLINE") public inline fun ListPolynomial.asFunction(): (C) -> C = { substitute(ring, it) } /** * Represent [this] polynomial as a regular context-less function. */ - @Suppress("NOTHING_TO_INLINE") public inline fun ListPolynomial.asFunctionOfConstant(): (C) -> C = { substitute(ring, it) } /** * Represent [this] polynomial as a regular context-less function. */ - @Suppress("NOTHING_TO_INLINE") public inline fun ListPolynomial.asFunctionOfPolynomial(): (ListPolynomial) -> ListPolynomial = { substitute(ring, it) } /** * Represent [this] polynomial as a regular context-less function. */ - @Suppress("NOTHING_TO_INLINE") public inline fun ListPolynomial.asFunctionOfRationalFunction(): (ListRationalFunction) -> ListRationalFunction = { substitute(ring, it) } /** * Represent [this] rational function as a regular context-less function. */ - @Suppress("NOTHING_TO_INLINE") public inline fun ListRationalFunction.asFunctionOfPolynomial(): (ListPolynomial) -> ListRationalFunction = { substitute(ring, it) } /** * Represent [this] rational function as a regular context-less function. */ - @Suppress("NOTHING_TO_INLINE") public inline fun ListRationalFunction.asFunctionOfRationalFunction(): (ListRationalFunction) -> ListRationalFunction = { substitute(ring, it) } /** * Evaluates value of [this] polynomial on provided argument. */ - @Suppress("NOTHING_TO_INLINE") public inline operator fun ListPolynomial.invoke(argument: C): C = substitute(ring, argument) /** * Evaluates value of [this] polynomial on provided argument. */ - @Suppress("NOTHING_TO_INLINE") public inline operator fun ListPolynomial.invoke(argument: ListPolynomial): ListPolynomial = substitute(ring, argument) /** * Evaluates value of [this] polynomial on provided argument. */ - @Suppress("NOTHING_TO_INLINE") public inline operator fun ListPolynomial.invoke(argument: ListRationalFunction): ListRationalFunction = substitute(ring, argument) /** * Evaluates value of [this] rational function on provided argument. */ - @Suppress("NOTHING_TO_INLINE") public inline operator fun ListRationalFunction.invoke(argument: ListPolynomial): ListRationalFunction = substitute(ring, argument) /** * Evaluates value of [this] rational function on provided argument. */ - @Suppress("NOTHING_TO_INLINE") public inline operator fun ListRationalFunction.invoke(argument: ListRationalFunction): ListRationalFunction = substitute(ring, argument) } \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt index e61d6c55e..97dffebe1 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt @@ -113,135 +113,111 @@ public class NumberedRationalFunctionSpace> ( /** * Substitutes provided constant [argument] into [this] polynomial. */ - @Suppress("NOTHING_TO_INLINE") public inline fun NumberedPolynomial.substitute(argument: Map): NumberedPolynomial = substitute(ring, argument) /** * Substitutes provided polynomial [argument] into [this] polynomial. */ - @Suppress("NOTHING_TO_INLINE") @JvmName("substitutePolynomial") public inline fun NumberedPolynomial.substitute(argument: Map>): NumberedPolynomial = substitute(ring, argument) /** * Substitutes provided rational function [argument] into [this] polynomial. */ - @Suppress("NOTHING_TO_INLINE") @JvmName("substituteRationalFunction") public inline fun NumberedPolynomial.substitute(argument: Map>): NumberedRationalFunction = substitute(ring, argument) /** * Substitutes provided constant [argument] into [this] rational function. */ - @Suppress("NOTHING_TO_INLINE") public inline fun NumberedRationalFunction.substitute(argument: Map): NumberedRationalFunction = substitute(ring, argument) /** * Substitutes provided polynomial [argument] into [this] rational function. */ - @Suppress("NOTHING_TO_INLINE") @JvmName("substitutePolynomial") public inline fun NumberedRationalFunction.substitute(argument: Map>): NumberedRationalFunction = substitute(ring, argument) /** * Substitutes provided rational function [argument] into [this] rational function. */ - @Suppress("NOTHING_TO_INLINE") @JvmName("substituteRationalFunction") public inline fun NumberedRationalFunction.substitute(argument: Map>): NumberedRationalFunction = substitute(ring, argument) /** * Substitutes provided constant [argument] into [this] polynomial. */ - @Suppress("NOTHING_TO_INLINE") public inline fun NumberedPolynomial.substitute(argument: Buffer): NumberedPolynomial = substitute(ring, argument) /** * Substitutes provided polynomial [argument] into [this] polynomial. */ - @Suppress("NOTHING_TO_INLINE") @JvmName("substitutePolynomial") public inline fun NumberedPolynomial.substitute(argument: Buffer>): NumberedPolynomial = substitute(ring, argument) /** * Substitutes provided rational function [argument] into [this] polynomial. */ - @Suppress("NOTHING_TO_INLINE") @JvmName("substituteRationalFunction") public inline fun NumberedPolynomial.substitute(argument: Buffer>): NumberedRationalFunction = substitute(ring, argument) /** * Substitutes provided constant [argument] into [this] rational function. */ - @Suppress("NOTHING_TO_INLINE") public inline fun NumberedRationalFunction.substitute(argument: Buffer): NumberedRationalFunction = substitute(ring, argument) /** * Substitutes provided polynomial [arguments] into [this] rational function. */ - @Suppress("NOTHING_TO_INLINE") @JvmName("substitutePolynomial") public inline fun NumberedRationalFunction.substitute(arguments: Buffer>): NumberedRationalFunction = substitute(ring, arguments) /** * Substitutes provided rational function [arguments] into [this] rational function. */ - @Suppress("NOTHING_TO_INLINE") @JvmName("substituteRationalFunction") public inline fun NumberedRationalFunction.substitute(arguments: Buffer>): NumberedRationalFunction = substitute(ring, arguments) /** * Substitutes provided constant [arguments] into [this] polynomial. */ - @Suppress("NOTHING_TO_INLINE") public inline fun NumberedPolynomial.substituteFully(arguments: Buffer): C = substituteFully(ring, arguments) /** * Represent [this] polynomial as a regular context-less function. */ - @Suppress("NOTHING_TO_INLINE") public inline fun NumberedPolynomial.asFunction(): (Buffer) -> C = asFunctionOver(ring) /** * Represent [this] polynomial as a regular context-less function. */ - @Suppress("NOTHING_TO_INLINE") public inline fun NumberedPolynomial.asFunctionOfConstant(): (Buffer) -> C = asFunctionOfConstantOver(ring) /** * Represent [this] polynomial as a regular context-less function. */ - @Suppress("NOTHING_TO_INLINE") public inline fun NumberedPolynomial.asFunctionOfPolynomial(): (Buffer>) -> NumberedPolynomial = asFunctionOfPolynomialOver(ring) /** * Represent [this] polynomial as a regular context-less function. */ - @Suppress("NOTHING_TO_INLINE") public inline fun NumberedPolynomial.asFunctionOfRationalFunction(): (Buffer>) -> NumberedRationalFunction = asFunctionOfRationalFunctionOver(ring) /** * Represent [this] polynomial as a regular context-less function. */ - @Suppress("NOTHING_TO_INLINE") public inline fun NumberedRationalFunction.asFunctionOfPolynomial(): (Buffer>) -> NumberedRationalFunction = asFunctionOfPolynomialOver(ring) /** * Represent [this] polynomial as a regular context-less function. */ - @Suppress("NOTHING_TO_INLINE") public inline fun NumberedRationalFunction.asFunctionOfRationalFunction(): (Buffer>) -> NumberedRationalFunction = asFunctionOfRationalFunctionOver(ring) /** * Evaluates value of [this] polynomial on provided [arguments]. */ - @Suppress("NOTHING_TO_INLINE") public inline operator fun NumberedPolynomial.invoke(arguments: Buffer): C = substituteFully(ring, arguments) /** * Substitutes provided [arguments] into [this] polynomial. */ - @Suppress("NOTHING_TO_INLINE") @JvmName("invokePolynomial") public inline operator fun NumberedPolynomial.invoke(arguments: Buffer>): NumberedPolynomial = substitute(ring, arguments) /** * Substitutes provided [arguments] into [this] polynomial. */ - @Suppress("NOTHING_TO_INLINE") @JvmName("invokeRationalFunction") public inline operator fun NumberedPolynomial.invoke(arguments: Buffer>): NumberedRationalFunction = substitute(ring, arguments) /** * Substitutes provided [arguments] into [this] rational function. */ - @Suppress("NOTHING_TO_INLINE") @JvmName("invokePolynomial") public inline operator fun NumberedRationalFunction.invoke(arguments: Buffer>): NumberedRationalFunction = substitute(ring, arguments) /** * Substitutes provided [arguments] into [this] rational function. */ - @Suppress("NOTHING_TO_INLINE") @JvmName("invokeRationalFunction") public inline operator fun NumberedRationalFunction.invoke(arguments: Buffer>): NumberedRationalFunction = substitute(ring, arguments) } \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt index 7586b7012..f3fa32334 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt @@ -3,7 +3,7 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -@file:Suppress("FunctionName", "NOTHING_TO_INLINE") +@file:Suppress("FunctionName") package space.kscience.kmath.functions @@ -309,21 +309,18 @@ public class LabeledPolynomialTermSignatureBuilder { * * Declaring another power of the same variable will increase its degree by received degree. */ - @Suppress("NOTHING_TO_INLINE") public inline infix fun Symbol.pow(deg: UInt): Unit = this inPowerOf deg /** * Declares power of [this] variable of degree [deg]. * * Declaring another power of the same variable will increase its degree by received degree. */ - @Suppress("NOTHING_TO_INLINE") public inline infix fun Symbol.`in`(deg: UInt): Unit = this inPowerOf deg /** * Declares power of [this] variable of degree [deg]. * * Declaring another power of the same variable will increase its degree by received degree. */ - @Suppress("NOTHING_TO_INLINE") public inline infix fun Symbol.of(deg: UInt): Unit = this inPowerOf deg } @@ -370,7 +367,6 @@ public class LabeledPolynomialBuilder( * Declaring another monomial with the same signature will add [this] coefficient to existing one. If the sum of such * coefficients is zero at any moment the monomial won't be removed but will be left as it is. */ - @Suppress("NOTHING_TO_INLINE") public inline infix fun C.with(noinline block: LabeledPolynomialTermSignatureBuilder.() -> Unit): Unit = this.invoke(block) /** * Declares monomial with [this] coefficient and signature constructed by [block]. diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt index 3cd398623..0a0e6d902 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt @@ -3,7 +3,7 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -@file:Suppress("FunctionName", "NOTHING_TO_INLINE") +@file:Suppress("FunctionName") package space.kscience.kmath.functions @@ -296,21 +296,18 @@ public class NumberedPolynomialTermSignatureBuilder { * * Declaring another power of the same variable will increase its degree by received degree. */ - @Suppress("NOTHING_TO_INLINE") public inline infix fun Int.pow(deg: UInt): Unit = this inPowerOf deg /** * Declares power of variable #[this] of degree [deg]. * * Declaring another power of the same variable will increase its degree by received degree. */ - @Suppress("NOTHING_TO_INLINE") public inline infix fun Int.`in`(deg: UInt): Unit = this inPowerOf deg /** * Declares power of variable #[this] of degree [deg]. * * Declaring another power of the same variable will increase its degree by received degree. */ - @Suppress("NOTHING_TO_INLINE") public inline infix fun Int.of(deg: UInt): Unit = this inPowerOf deg } @@ -358,7 +355,6 @@ public class NumberedPolynomialBuilder( * Declaring another monomial with the same signature will add [this] coefficient to existing one. If the sum of such * coefficients is zero at any moment the monomial won't be removed but will be left as it is. */ - @Suppress("NOTHING_TO_INLINE") public inline infix fun C.with(noinline block: NumberedPolynomialTermSignatureBuilder.() -> Unit): Unit = this.invoke(block) /** * Declares monomial with [this] coefficient and signature constructed by [block]. -- 2.34.1 From 0ef2258665d3571b67a48933b43f0896b0ca80df Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Mon, 27 Jun 2022 17:11:39 +0300 Subject: [PATCH 085/123] Removed extra suppresses. --- .../kscience/kmath/functions/NumberedPolynomial.kt | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt index eadeb68ab..8bcfbae5b 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -385,56 +385,46 @@ public class NumberedPolynomialSpace>( /** * Substitutes provided arguments [arguments] into [this] polynomial. */ - @Suppress("NOTHING_TO_INLINE") public inline fun NumberedPolynomial.substitute(arguments: Map): NumberedPolynomial = substitute(ring, arguments) /** * Substitutes provided arguments [arguments] into [this] polynomial. */ - @Suppress("NOTHING_TO_INLINE") @JvmName("substitutePolynomial") public inline fun NumberedPolynomial.substitute(arguments: Map>) : NumberedPolynomial = substitute(ring, arguments) /** * Substitutes provided arguments [arguments] into [this] polynomial. */ - @Suppress("NOTHING_TO_INLINE") public inline fun NumberedPolynomial.substitute(arguments: Buffer): NumberedPolynomial = substitute(ring, arguments) /** * Substitutes provided arguments [arguments] into [this] polynomial. */ - @Suppress("NOTHING_TO_INLINE") @JvmName("substitutePolynomial") public inline fun NumberedPolynomial.substitute(arguments: Buffer>) : NumberedPolynomial = substitute(ring, arguments) /** * Substitutes provided arguments [arguments] into [this] polynomial. */ - @Suppress("NOTHING_TO_INLINE") public inline fun NumberedPolynomial.substituteFully(arguments: Buffer): C = this.substituteFully(ring, arguments) /** * Represent [this] polynomial as a regular context-less function. */ - @Suppress("NOTHING_TO_INLINE") public inline fun NumberedPolynomial.asFunction(): (Buffer) -> C = asFunctionOver(ring) /** * Represent [this] polynomial as a regular context-less function. */ - @Suppress("NOTHING_TO_INLINE") public inline fun NumberedPolynomial.asFunctionOfConstant(): (Buffer) -> C = asFunctionOfConstantOver(ring) /** * Represent [this] polynomial as a regular context-less function. */ - @Suppress("NOTHING_TO_INLINE") public inline fun NumberedPolynomial.asFunctionOfPolynomial(): (Buffer>) -> NumberedPolynomial = asFunctionOfPolynomialOver(ring) /** * Evaluates value of [this] polynomial on provided [arguments]. */ - @Suppress("NOTHING_TO_INLINE") public inline operator fun NumberedPolynomial.invoke(arguments: Buffer): C = substituteFully(ring, arguments) /** * Substitutes provided [arguments] into [this] polynomial. */ - @Suppress("NOTHING_TO_INLINE") @JvmName("invokePolynomial") public inline operator fun NumberedPolynomial.invoke(arguments: Buffer>): NumberedPolynomial = substitute(ring, arguments) } \ No newline at end of file -- 2.34.1 From 043d292eca11f5ffea1ceb0f507a0bd101dbb399 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Mon, 27 Jun 2022 17:14:03 +0300 Subject: [PATCH 086/123] Added test. Fixed bug in NumberedPolynomial's DSL. --- .../kmath/functions/NumberedPolynomial.kt | 12 +- .../kmath/functions/numberedConstructors.kt | 1 + .../functions/NumberedConstructorsTest.kt | 20 +- .../kmath/functions/NumberedPolynomialTest.kt | 304 +++++++++++++++++- 4 files changed, 324 insertions(+), 13 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt index 8bcfbae5b..35d0c7448 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -331,13 +331,13 @@ public class NumberedPolynomialSpace>( * the result is `-1`. */ public val NumberedPolynomial.lastVariable: Int - get() = coefficients.entries.maxOfOrNull { (degs, _) -> degs.lastIndex } ?: -1 + get() = coefficients.keys.maxOfOrNull { degs -> degs.lastIndex } ?: -1 /** * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is * zero, degree is -1. */ override val NumberedPolynomial.degree: Int - get() = coefficients.entries.maxOfOrNull { (degs, _) -> degs.sum().toInt() } ?: -1 + get() = coefficients.keys.maxOfOrNull { degs -> degs.sum().toInt() } ?: -1 /** * List that associates indices of variables (that appear in the polynomial in positive exponents) with their most * exponents in which the variables are appeared in the polynomial. @@ -348,7 +348,7 @@ public class NumberedPolynomialSpace>( public val NumberedPolynomial.degrees: List get() = MutableList(lastVariable + 1) { 0u }.apply { - coefficients.entries.forEach { (degs, _) -> + coefficients.keys.forEach { degs -> degs.forEachIndexed { index, deg -> this[index] = max(this[index], deg) } @@ -358,13 +358,13 @@ public class NumberedPolynomialSpace>( * Counts degree of the polynomial by the specified [variable]. */ public fun NumberedPolynomial.degreeBy(variable: Int): UInt = - coefficients.entries.maxOfOrNull { (degs, _) -> degs.getOrElse(variable) { 0u } } ?: 0u + coefficients.keys.maxOfOrNull { degs -> degs.getOrElse(variable) { 0u } } ?: 0u /** * Counts degree of the polynomial by the specified [variables]. */ public fun NumberedPolynomial.degreeBy(variables: Collection): UInt = - coefficients.entries.maxOfOrNull { (degs, _) -> - degs.withIndex().filter { (index, _) -> index in variables }.sumOf { it.value } + coefficients.keys.maxOfOrNull { degs -> + degs.withIndex().fold(0u) { acc, (index, value) -> if (index in variables) acc + value else acc } } ?: 0u /** * Count of variables occurring in the polynomial with positive power. If there is no such variable, diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt index 0a0e6d902..d561e06ba 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt @@ -283,6 +283,7 @@ public class NumberedPolynomialTermSignatureBuilder { * Declaring another power of the same variable will increase its degree by received degree. */ public infix fun Int.inPowerOf(deg: UInt) { + if (deg == 0u) return val index = this - 1 if (index > signature.lastIndex) { signature.addAll(List(index - signature.lastIndex - 1) { 0u }) diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt index 14493aaae..8d1b128cf 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt @@ -23,8 +23,8 @@ class NumberedConstructorsTest { ), Int.algebra.numberedPolynomialSpace { NumberedPolynomial { - 5 { 1 inPowerOf 2u; 3 inPowerOf 3u } - (-6) { 2 inPowerOf 1u } + 5 { 1 pow 2u; 3 pow 3u } + (-6) { 2 pow 1u } } }, "test 1" @@ -47,8 +47,20 @@ class NumberedConstructorsTest { ), Int.algebra.numberedPolynomialSpace { NumberedPolynomial { - 5 { 1 inPowerOf 1u; 1 inPowerOf 1u } - (-6) { 1 inPowerOf 2u } + 5 { 1 pow 1u; 1 pow 1u } + (-6) { 1 pow 2u } + } + }, + "test 3" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(2u) to -1, + ), + Int.algebra.numberedPolynomialSpace { + NumberedPolynomial { + 5 { 1 pow 1u; 1 pow 1u } + (-6) { 1 pow 2u; 3 pow 0u } } }, "test 3" diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt index 537e3b85d..223ff5d92 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt @@ -9,9 +9,7 @@ package space.kscience.kmath.functions import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.test.misc.* -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertSame +import kotlin.test.* @UnstableKMathAPI @@ -1365,4 +1363,304 @@ class NumberedPolynomialTest { ) } } + @Test + fun test_lastVariable() { + val o = Rational(0) + RationalField.numberedPolynomialSpace { + assertEquals( + -1, + NumberedPolynomial {}.lastVariable, + "test 1" + ) + assertEquals( + -1, + NumberedPolynomial { + o {} + }.lastVariable, + "test 2" + ) + assertEquals( + 2, + NumberedPolynomial { + o { 1 pow 1u; 2 pow 2u; 3 pow 3u } + }.lastVariable, + "test 3" + ) + assertEquals( + 3, + NumberedPolynomial { + o { 1 pow 0u; 2 pow 1u; 3 pow 2u; 4 pow 1u; 5 pow 0u } + }.also { println(it) }.lastVariable, + "test 4" + ) + assertEquals( + 2, + NumberedPolynomial { + o {} + o { 2 pow 1u } + o { 1 pow 2u; 3 pow 1u } + }.lastVariable, + "test 5" + ) + } + } + @Test + fun test_degree() { + val o = Rational(0) + RationalField.numberedPolynomialSpace { + assertEquals( + -1, + NumberedPolynomial {}.degree, + "test 1" + ) + assertEquals( + 0, + NumberedPolynomial { + o {} + }.degree, + "test 2" + ) + assertEquals( + 6, + NumberedPolynomial { + o { 1 pow 1u; 2 pow 2u; 3 pow 3u } + }.degree, + "test 3" + ) + assertEquals( + 4, + NumberedPolynomial { + o { 1 pow 0u; 2 pow 1u; 3 pow 2u; 4 pow 1u; 5 pow 0u } + }.degree, + "test 4" + ) + assertEquals( + 3, + NumberedPolynomial { + o {} + o { 2 pow 1u } + o { 1 pow 2u; 3 pow 1u } + }.degree, + "test 5" + ) + assertEquals( + 4, + NumberedPolynomial { + o {} + o { 2 pow 1u } + o { 1 pow 2u; 3 pow 1u } + o { 4 pow 4u } + }.degree, + "test 6" + ) + } + } + @Test + fun test_countOfVariables() { + val o = Rational(0) + RationalField.numberedPolynomialSpace { + assertEquals( + listOf(), + NumberedPolynomial {}.degrees, + "test 1" + ) + assertEquals( + listOf(), + NumberedPolynomial { + o {} + }.degrees, + "test 2" + ) + assertEquals( + listOf(1u, 2u, 3u), + NumberedPolynomial { + o { 1 pow 1u; 2 pow 2u; 3 pow 3u } + }.degrees, + "test 3" + ) + assertEquals( + listOf(0u, 1u, 2u, 1u), + NumberedPolynomial { + o { 1 pow 0u; 2 pow 1u; 3 pow 2u; 4 pow 1u; 5 pow 0u } + }.degrees, + "test 4" + ) + assertEquals( + listOf(2u, 1u, 1u), + NumberedPolynomial { + o {} + o { 2 pow 1u } + o { 1 pow 2u; 3 pow 1u } + }.degrees, + "test 5" + ) + assertEquals( + listOf(2u, 2u, 2u, 4u), + NumberedPolynomial { + o {} + o { 1 pow 1u; 2 pow 2u } + o { 2 pow 1u; 3 pow 2u } + o { 1 pow 2u; 3 pow 1u } + o { 4 pow 4u } + }.degrees, + "test 6" + ) + } + } + @Test + fun test_degreeBy() { + val o = Rational(0) + RationalField.numberedPolynomialSpace { + fun NumberedPolynomial.collectDegrees(limit: Int = lastVariable + 2): List = List(limit) { degreeBy(it) } + assertEquals( + listOf(0u), + NumberedPolynomial {}.collectDegrees(), + "test 1" + ) + assertEquals( + listOf(0u), + NumberedPolynomial { + o {} + }.collectDegrees(), + "test 2" + ) + assertEquals( + listOf(1u, 2u, 3u, 0u), + NumberedPolynomial { + o { 1 pow 1u; 2 pow 2u; 3 pow 3u } + }.collectDegrees(), + "test 3" + ) + assertEquals( + listOf(0u, 1u, 2u, 1u, 0u), + NumberedPolynomial { + o { 1 pow 0u; 2 pow 1u; 3 pow 2u; 4 pow 1u; 5 pow 0u } + }.collectDegrees(), + "test 4" + ) + assertEquals( + listOf(2u, 1u, 1u, 0u), + NumberedPolynomial { + o {} + o { 2 pow 1u } + o { 1 pow 2u; 3 pow 1u } + }.collectDegrees(), + "test 5" + ) + assertEquals( + listOf(2u, 2u, 2u, 4u, 0u), + NumberedPolynomial { + o {} + o { 1 pow 1u; 2 pow 2u } + o { 2 pow 1u; 3 pow 2u } + o { 1 pow 2u; 3 pow 1u } + o { 4 pow 4u } + }.collectDegrees(), + "test 6" + ) + } + } + @Test + fun test_degreeBy_Collection() { + val o = Rational(0) + RationalField.numberedPolynomialSpace { + fun NumberedPolynomial.checkDegreeBy(message: String? = null) { + val lastVariable = lastVariable + val indexCollectionSequence: Sequence> = sequence { + val appearances = MutableList(lastVariable + 2) { 0 } + while (true) { + yield( + buildList { + for ((variable, count) in appearances.withIndex()) repeat(count) { add(variable) } + } + ) + val indexChange = appearances.indexOfFirst { it < 4 } + if (indexChange == -1) break + appearances[indexChange] += 1 + for (index in 0 until indexChange) appearances[index] = 0 + } + } + for (indexCollection in indexCollectionSequence) { + val expected = coefficients.keys.maxOfOrNull { degs -> degs.slice(indexCollection.distinct().filter { it in degs.indices }).sum() } ?: 0u + val actual = degreeBy(indexCollection) + if (actual != expected) + fail("${message ?: ""} Incorrect answer for variable collection $indexCollection: expected $expected, actual $actual") + } + } + NumberedPolynomial {}.checkDegreeBy("test 1") + NumberedPolynomial { + o {} + }.checkDegreeBy("test 2") + NumberedPolynomial { + o { 1 pow 1u; 2 pow 2u; 3 pow 3u } + }.checkDegreeBy("test 3") + NumberedPolynomial { + o { 1 pow 0u; 2 pow 1u; 3 pow 2u; 4 pow 1u; 5 pow 0u } + }.checkDegreeBy("test 4") + NumberedPolynomial { + o {} + o { 2 pow 1u } + o { 1 pow 2u; 3 pow 1u } + }.checkDegreeBy("test 5") + NumberedPolynomial { + o {} + o { 1 pow 1u; 2 pow 2u } + o { 2 pow 1u; 3 pow 2u } + o { 1 pow 2u; 3 pow 1u } + o { 4 pow 4u } + }.checkDegreeBy("test 6") + } + } + @Test + fun test_degrees() { + val o = Rational(0) + RationalField.numberedPolynomialSpace { + assertEquals( + 0, + NumberedPolynomial {}.countOfVariables, + "test 1" + ) + assertEquals( + 0, + NumberedPolynomial { + o {} + }.countOfVariables, + "test 2" + ) + assertEquals( + 3, + NumberedPolynomial { + o { 1 pow 1u; 2 pow 2u; 3 pow 3u } + }.countOfVariables, + "test 3" + ) + assertEquals( + 3, + NumberedPolynomial { + o { 1 pow 0u; 2 pow 1u; 3 pow 2u; 4 pow 1u; 5 pow 0u } + }.countOfVariables, + "test 4" + ) + assertEquals( + 3, + NumberedPolynomial { + o {} + o { 2 pow 1u } + o { 1 pow 2u; 3 pow 1u } + }.countOfVariables, + "test 5" + ) + assertEquals( + 4, + NumberedPolynomial { + o {} + o { 1 pow 1u; 2 pow 2u } + o { 2 pow 1u; 3 pow 2u } + o { 1 pow 2u; 3 pow 1u } + o { 4 pow 4u } + }.countOfVariables, + "test 6" + ) + } + } } \ No newline at end of file -- 2.34.1 From da46ea923c52c586cb9351d922281df6f1f36bf4 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Tue, 28 Jun 2022 15:07:09 +0300 Subject: [PATCH 087/123] Extended test for NumberedPolynomial --- .../kmath/functions/NumberedPolynomialTest.kt | 80 ++++++++++++++++++- 1 file changed, 78 insertions(+), 2 deletions(-) diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt index 223ff5d92..dac7c1a62 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt @@ -1456,7 +1456,7 @@ class NumberedPolynomialTest { } } @Test - fun test_countOfVariables() { + fun test_degrees() { val o = Rational(0) RationalField.numberedPolynomialSpace { assertEquals( @@ -1612,7 +1612,7 @@ class NumberedPolynomialTest { } } @Test - fun test_degrees() { + fun test_countOfVariables() { val o = Rational(0) RationalField.numberedPolynomialSpace { assertEquals( @@ -1663,4 +1663,80 @@ class NumberedPolynomialTest { ) } } + @Test + fun test_RF_countOfVariables() { + val o = Rational(0) + RationalField.numberedRationalFunctionSpace { + assertEquals( + 0, + NumberedRationalFunction( + NumberedPolynomial {} + ).countOfVariables, + "test 1" + ) + assertEquals( + 0, + NumberedRationalFunction( + NumberedPolynomial {}, + NumberedPolynomial {} + ).countOfVariables, + "test 2" + ) + assertEquals( + 0, + NumberedRationalFunction( + NumberedPolynomial { + o {} + } + ).countOfVariables, + "test 3" + ) + assertEquals( + 3, + NumberedRationalFunction( + NumberedPolynomial { + o { 1 pow 1u; 2 pow 2u; 3 pow 3u } + } + ).countOfVariables, + "test 4" + ) + assertEquals( + 3, + NumberedRationalFunction( + NumberedPolynomial { + o { 2 pow 1u; 4 pow 1u } + }, + NumberedPolynomial { + o { 1 pow 0u; 3 pow 2u; 5 pow 0u } + } + ).countOfVariables, + "test 5" + ) + assertEquals( + 3, + NumberedRationalFunction( + NumberedPolynomial { + o {} + o { 2 pow 1u } + o { 1 pow 2u; 3 pow 1u } + } + ).countOfVariables, + "test 6" + ) + assertEquals( + 4, + NumberedRationalFunction( + NumberedPolynomial { + o {} + o { 1 pow 1u; 2 pow 2u } + o { 1 pow 2u; 3 pow 1u } + }, NumberedPolynomial { + o { 2 pow 1u; 3 pow 2u } + o { 4 pow 4u } + } + ).countOfVariables, + "test 7" + ) + } + } } \ No newline at end of file -- 2.34.1 From 64b33aed184e0f52a4f2938022cf6e0eae0e8591 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Wed, 29 Jun 2022 14:53:12 +0300 Subject: [PATCH 088/123] Remove extra suppresses. --- .../kotlin/space/kscience/kmath/test/misc/IntModulo.kt | 2 +- .../kotlin/space/kscience/kmath/test/misc/Rational.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt index afd2b5add..b3bb4faf7 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt @@ -108,7 +108,7 @@ class IntModulo { override fun toString(): String = "$residue mod $modulus" } -@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") +@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE") class IntModuloRing : Ring { val modulus: Int 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 index 72bb5942c..4bdd60704 100644 --- 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 @@ -114,7 +114,7 @@ class Rational { override fun toString(): String = if (denominator == 1L) "$numerator" else "$numerator/$denominator" } -@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") +@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE") @OptIn(UnstableKMathAPI::class) object RationalField : Field, NumbersAddOps { override inline val zero: Rational get() = Rational.ZERO -- 2.34.1 From c8b9951f46c27f7af85f43188af9eb9d6e3cb48d Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Wed, 29 Jun 2022 14:54:49 +0300 Subject: [PATCH 089/123] Added for list utilities for rational functions. --- .../kmath/functions/ListPolynomialUtilTest.kt | 725 +++++++++++++++++- 1 file changed, 718 insertions(+), 7 deletions(-) diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt index 69c1611f3..314044ba8 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt @@ -8,6 +8,7 @@ package space.kscience.kmath.functions import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.test.misc.Rational import space.kscience.kmath.test.misc.RationalField +import kotlin.test.Ignore import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertFailsWith @@ -16,7 +17,7 @@ import kotlin.test.assertFailsWith @OptIn(UnstableKMathAPI::class) class ListPolynomialUtilTest { @Test - fun test_substitute_Double() { + fun test_Polynomial_substitute_Double() { assertEquals( 0.0, ListPolynomial(1.0, -2.0, 1.0).substitute(1.0), @@ -49,7 +50,7 @@ class ListPolynomialUtilTest { ) } @Test - fun test_substitute_Constant() { + fun test_Polynomial_substitute_Constant() { assertEquals( Rational(0), ListPolynomial(Rational(1), Rational(-2), Rational(1)).substitute(RationalField, Rational(1)), @@ -81,7 +82,7 @@ class ListPolynomialUtilTest { ) } @Test - fun test_substitute_Polynomial() { + fun test_Polynomial_substitute_Polynomial() { assertEquals( ListPolynomial(Rational(0)), ListPolynomial(Rational(1), Rational(-2), Rational(1)).substitute(RationalField, ListPolynomial(Rational(1))), @@ -119,7 +120,717 @@ class ListPolynomialUtilTest { ) } @Test - fun test_derivative() { + @Ignore // FIXME: This tests work only for sane realisations of the substitutions. Currently, it is not. + // Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should make denominator r^deg(p), + // not r^(deg(p)(deg(p)+1)/2) as it is now. + fun test_Polynomial_substitute_RationalFunction() { + assertEquals( + ListRationalFunction(ListPolynomial(Rational(0)), ListPolynomial(Rational(1))), + ListPolynomial(Rational(1), Rational(-2), Rational(1)) + .substitute(RationalField, ListRationalFunction(ListPolynomial(Rational(1)), ListPolynomial(Rational(1)))), + "test 1" + ) + assertEquals( + ListRationalFunction( + ListPolynomial( + Rational(66349, 243), + Rational(-17873, 405), + Rational(173533, 3780), + Rational(-91141, 567), + Rational(5773909, 105840), + Rational(-23243, 630), + Rational(1573, 27) + ), + ListPolynomial( + Rational(169, 81), + Rational(-130, 27), + Rational(115, 18), + Rational(-797, 54), + Rational(1985, 144), + Rational(-55, 6), + Rational(121, 9) + ) + ), + ListPolynomial( + Rational(13, 3), + Rational(-9, 5), + Rational(5, 5) + ).substitute(RationalField, + ListRationalFunction( + ListPolynomial( + Rational(15, 1), + Rational(6, 9), + Rational(-3, 7) + ), + ListPolynomial( + Rational(-13, 9), + Rational(10, 6), + Rational(-10, 8), + Rational(11, 3) + ) + ) + ), + "test 2" + ) + assertEquals( + ListRationalFunction( + ListPolynomial( + Rational(0, 1), + Rational(0, 1), + Rational(-14, 9), + Rational(31, 14), + Rational(-5077, 980), + Rational(99, 35) + ), + ListPolynomial( + Rational(0, 1), + Rational(0, 1), + Rational(25, 9), + Rational(-25, 6), + Rational(1985, 144), + Rational(-55, 6), + Rational(121, 9) + ) + ), + ListPolynomial( + Rational(0), + Rational(-9, 5), + Rational(5, 5) + ).substitute(RationalField, + ListRationalFunction( + ListPolynomial( + Rational(0), + Rational(6, 9), + Rational(-3, 7) + ), + ListPolynomial( + Rational(0), + Rational(10, 6), + Rational(-10, 8), + Rational(11, 3) + ) + ) + ), + "test 3" + ) + assertEquals( + ListRationalFunction( + ListPolynomial( + Rational(-898, 27), + Rational(271, 45), + Rational(-65, 12) , + Rational(0), + Rational(0), + Rational(0), + Rational(0) + ), + ListPolynomial( + Rational(-13, 9), + Rational(5, 3), + Rational(-5, 4) , + Rational(0), + Rational(0), + Rational(0), + Rational(0) + ) + ), + ListPolynomial( + Rational(13, 3), + Rational(-9, 5), + Rational(0) + ).substitute(RationalField, + ListRationalFunction( + ListPolynomial( + Rational(15, 1), + Rational(6, 9), + Rational(0) + ), + ListPolynomial( + Rational(-13, 9), + Rational(10, 6), + Rational(-10, 8), + Rational(0) + ) + ) + ), + "test 4" + ) + assertEquals( + ListRationalFunction( + ListPolynomial( + Rational(56872, 243), + Rational(0, 1), + Rational(-90, 7), + Rational(-3718, 81), + Rational(9, 49), + Rational(0, 1), + Rational(1573, 27) + ), + ListPolynomial( + Rational(169, 81), + Rational(0, 1), + Rational(0, 1), + Rational(-286, 27), + Rational(0, 1), + Rational(0, 1), + Rational(121, 9) + ) + ), + ListPolynomial( + Rational(13, 3), + Rational(0), + Rational(5, 5) + ).substitute(RationalField, + ListRationalFunction( + ListPolynomial( + Rational(15, 1), + Rational(0), + Rational(-3, 7) + ), + ListPolynomial( + Rational(-13, 9), + Rational(0), + Rational(0), + Rational(11, 3) + ) + ) + ), + "test 5" + ) + } + @Test + fun test_RationalFunction_substitute_Double() { + assertEquals( + 0.0, + ListRationalFunction( + ListPolynomial(1.0, -2.0, 1.0), + ListPolynomial(-6.302012278484357, 5.831971885376948, -9.271604788393432, 5.494387848015814, -3.7187384450880785) + ).substitute(1.0), + 0.001, + "test 1" + ) + assertEquals( + 2.693702616649797, + ListRationalFunction( + ListPolynomial(-5.848840571263625, -1.660411278951134, -3.793740946372443, -9.624569269490076), + ListPolynomial(-2.9680680215311073, -1.862973627119981, 4.776550592888336, -2.7320154512368466) + ).substitute(-7.53452770353279), + 0.001, + "test 2" + ) + assertEquals( + 2.692226268901378, + ListRationalFunction( + ListPolynomial(0.0, -1.660411278951134, -3.793740946372443, -9.624569269490076), + ListPolynomial(0.0, -1.862973627119981, 4.776550592888336, -2.7320154512368466) + ).substitute(-7.53452770353279), + 0.001, + "test 3" + ) + assertEquals( + -0.7394904842099175, + ListRationalFunction( + ListPolynomial(-5.848840571263625, -1.660411278951134, -3.793740946372443, 0.0), + ListPolynomial(-2.9680680215311073, -1.862973627119981, 4.776550592888336, 0.0) + ).substitute(-7.53452770353279), + 0.001, + "test 4" + ) + assertEquals( + 3.526835209398159, + ListRationalFunction( + ListPolynomial(-5.848840571263625, 0.0, 0.0, -9.624569269490076), + ListPolynomial(-2.9680680215311073, 0.0, 0.0, -2.7320154512368466) + ).substitute(-7.53452770353279), + 0.001, + "test 5" + ) + } + @Test + fun test_RationalFunction_substitute_Constant() { + assertEquals( + Rational(0), + ListRationalFunction( + ListPolynomial(Rational(1), Rational(-2), Rational(1)), + ListPolynomial(Rational(1)), + ).substitute(RationalField, Rational(1)), + "test 1" + ) + assertEquals( + Rational(1149615, 61306), + ListRationalFunction( + ListPolynomial(Rational(17, 7), Rational(18, 3), Rational(18, 8), Rational(9, 1)), + ListPolynomial(Rational(11, 9), Rational(-6, 5), Rational(-12, 7), Rational(2, 1)), + ).substitute(RationalField, Rational(-7, 8)), + "test 2" + ) + assertEquals( + Rational(3495, 586), + ListRationalFunction( + ListPolynomial(Rational(0), Rational(18, 3), Rational(18, 8), Rational(9, 1)), + ListPolynomial(Rational(0), Rational(-6, 5), Rational(-12, 7), Rational(2, 1)), + ).substitute(RationalField, Rational(-7, 8)), + "test 3" + ) + assertEquals( + Rational(-88605, 77392), + ListRationalFunction( + ListPolynomial(Rational(17, 7), Rational(18, 3), Rational(18, 8), Rational(0)), + ListPolynomial(Rational(11, 9), Rational(-6, 5), Rational(-12, 7), Rational(0)), + ).substitute(RationalField, Rational(-7, 8)), + "test 4" + ) + assertEquals( + Rational(116145, 3794), + ListRationalFunction( + ListPolynomial(Rational(17, 7), Rational(0), Rational(0), Rational(9, 1)), + ListPolynomial(Rational(11, 9), Rational(0), Rational(0), Rational(2, 1)), + ).substitute(RationalField, Rational(-7, 8)), + "test 5" + ) + } + @Test + fun test_RationalFunction_substitute_Polynomial() { + assertEquals( + ListRationalFunction( + ListPolynomial(Rational(0)), + ListPolynomial(Rational(1)) + ), + ListRationalFunction( + ListPolynomial(Rational(1), Rational(-2), Rational(1)), + ListPolynomial(Rational(1)), + ).substitute(RationalField, ListPolynomial(Rational(1))), + "test 1" + ) + assertEquals( + ListRationalFunction( + ListPolynomial( + Rational(-283303, 36), + Rational(-23593, 24), + Rational(368713, 192), + Rational(1455, 8), + Rational(-272171, 1536), + Rational(-2149, 192), + Rational(469, 64), + Rational(11, 48), + Rational(-11, 96) + ), + ListPolynomial( + Rational(5797, 12), + Rational(595, 16), + Rational(-5285, 72), + Rational(-745, 192), + Rational(1105, 288), + Rational(5, 48), + Rational(-5, 72) + ) + ), + ListRationalFunction( + ListPolynomial( + Rational(2, 9), + Rational(11, 3), + Rational(-9, 4), + Rational(-6, 1), + Rational(-11, 6) + ), + ListPolynomial( + Rational(-2, 3), + Rational(-15, 4), + Rational(5, 9), + Rational(-5, 9) + ) + ).substitute(RationalField, + ListPolynomial( + Rational(-9, 1), + Rational(-1, 4), + Rational(2, 4) + ) + ), + "test 2" + ) + assertEquals( + ListRationalFunction( + ListPolynomial( + Rational(0, 1), + Rational(-11, 12), + Rational(325, 192), + Rational(21, 32), + Rational(-1739, 1536), + Rational(227, 192), + Rational(-59, 64), + Rational(11, 48), + Rational(-11, 96) + ), + ListPolynomial( + Rational(0, 1), + Rational(15, 16), + Rational(-265, 144), + Rational(-25, 192), + Rational(25, 288), + Rational(5, 48), + Rational(-5, 72) + ) + ), + ListRationalFunction( + ListPolynomial( + Rational(0, 9), + Rational(11, 3), + Rational(-9, 4), + Rational(-6, 1), + Rational(-11, 6) + ), + ListPolynomial( + Rational(0, 3), + Rational(-15, 4), + Rational(5, 9), + Rational(-5, 9) + ) + ).substitute(RationalField, + ListPolynomial( + Rational(0, 1), + Rational(-1, 4), + Rational(2, 4) + ) + ), + "test 3" + ) + assertEquals( + ListRationalFunction( + ListPolynomial( + Rational(149723, 36), + Rational(8483, 24), + Rational(639, 64), + Rational(3, 32), + Rational(0), + Rational(0), + Rational(0), + Rational(0), + Rational(0) + ), + ListPolynomial( + Rational(937, 12), + Rational(55, 16), + Rational(5, 144), + Rational(0), + Rational(0), + Rational(0), + Rational(0) + ) + ), + ListRationalFunction( + ListPolynomial( + Rational(2, 9), + Rational(11, 3), + Rational(-9, 4), + Rational(-6, 1), + Rational(0) + ), + ListPolynomial( + Rational(-2, 3), + Rational(-15, 4), + Rational(5, 9), + Rational(0) + ) + ).substitute(RationalField, + ListPolynomial( + Rational(-9, 1), + Rational(-1, 4), + Rational(0) + ) + ), + "test 4" + ) + assertEquals( + ListRationalFunction( + ListPolynomial( + Rational(-216509, 18), + Rational(0, 1), + Rational(2673, 1), + Rational(0, 1), + Rational(-891, 4), + Rational(0, 1), + Rational(33, 4), + Rational(0, 1), + Rational(-11, 96) + ), + ListPolynomial( + Rational(1213, 3), + Rational(0, 1), + Rational(-135, 2), + Rational(0, 1), + Rational(15, 4), + Rational(0, 1), + Rational(-5, 72) + ) + ), + ListRationalFunction( + ListPolynomial( + Rational(2, 9), + Rational(0), + Rational(0), + Rational(0), + Rational(-11, 6) + ), + ListPolynomial( + Rational(-2, 3), + Rational(0), + Rational(0), + Rational(-5, 9) + ) + ).substitute(RationalField, + ListPolynomial( + Rational(-9, 1), + Rational(0), + Rational(2, 4) + ) + ), + "test 5" + ) + } + @Test + @Ignore // FIXME: This tests work only for sane realisations of the substitutions. Currently, it is not. + // Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should make denominator r^deg(p), + // not r^(deg(p)(deg(p)+1)/2) as it is now. + fun test_RationalFunction_substitute_RationalFunction() { + assertEquals( + ListRationalFunction( + ListPolynomial(Rational(0)), + ListPolynomial(Rational(1)) + ), + ListRationalFunction( + ListPolynomial(Rational(1), Rational(-2), Rational(1)), + ListPolynomial(Rational(1)) + ).substitute(RationalField, + ListRationalFunction( + ListPolynomial(Rational(1)), + ListPolynomial(Rational(1)) + ) + ), + "test 1" + ) + assertEquals( + ListRationalFunction( + ListPolynomial( + Rational(130087, 3888), + Rational(-2866333, 65610), + Rational(-5076229, 97200), + Rational(222136997, 3280500), + Rational(754719329, 20995200), + Rational(-12010283, 324000), + Rational(-2011967, 172800), + Rational(18607, 2880), + Rational(4705, 4096) + ), + ListPolynomial( + Rational(-143820355, 3779136), + Rational(73886869, 1574640), + Rational(1440175193, 15746400), + Rational(-5308968857, 52488000), + Rational(-186910083731, 2099520000), + Rational(125043463, 1555200), + Rational(5299123, 388800), + Rational(-213757, 15360), + Rational(1380785, 147456) + ) + ), + ListRationalFunction( + ListPolynomial( + Rational(1, 1), + Rational(-10, 5), + Rational(18, 8), + Rational(-8, 8) + ), + ListPolynomial( + Rational(-14, 8), + Rational(-14, 8), + Rational(-19, 6), + Rational(14, 3), + Rational(8, 9) + ) + ).substitute(RationalField, + ListRationalFunction( + ListPolynomial( + Rational(14, 9), + Rational(-2, 5), + Rational(-14, 7) + ), + ListPolynomial( + Rational(-6, 4), + Rational(5, 9), + Rational(1, 8) + ) + ) + ), + "test 2" + ) + assertEquals( + ListRationalFunction( + ListPolynomial( + Rational(0, 1), + Rational(0, 1), + Rational(0, 1), + Rational(0, 1), + Rational(5173, 18225), + Rational(904291, 364500), + Rational(283127, 43200), + Rational(37189, 5760), + Rational(147, 128) + ), + ListPolynomial( + Rational(0, 1), + Rational(0, 1), + Rational(0, 1), + Rational(0, 1), + Rational(-163589, 911250), + Rational(-881831, 291600), + Rational(-10722229, 777600), + Rational(-640921, 46080), + Rational(86303, 9216) + ) + ), + ListRationalFunction( + ListPolynomial( + Rational(0), + Rational(-10, 5), + Rational(18, 8), + Rational(-8, 8) + ), + ListPolynomial( + Rational(0), + Rational(-14, 8), + Rational(-19, 6), + Rational(14, 3), + Rational(8, 9) + ) + ).substitute(RationalField, + ListRationalFunction( + ListPolynomial( + Rational(0), + Rational(-2, 5), + Rational(-14, 7) + ), + ListPolynomial( + Rational(0), + Rational(5, 9), + Rational(1, 8) + ) + ) + ), + "test 3" + ) + assertEquals( + ListRationalFunction( + ListPolynomial( + Rational(445, 16), + Rational(-2011, 54), + Rational(1359199, 72900), + Rational(-135733, 32805), + Rational(2254, 6561), + Rational(0, 1), + Rational(0, 1), + Rational(0, 1), + Rational(0, 1) + ), + ListPolynomial( + Rational(-2018387, 46656), + Rational(82316437, 1574640), + Rational(-9335047, 393660), + Rational(15765889, 3280500), + Rational(-242089, 656100), + Rational(0, 1), + Rational(0, 1), + Rational(0, 1), + Rational(0, 1) + ) + ), + ListRationalFunction( + ListPolynomial( + Rational(1, 1), + Rational(-10, 5), + Rational(18, 8), + Rational(0) + ), + ListPolynomial( + Rational(-14, 8), + Rational(-14, 8), + Rational(-19, 6), + Rational(14, 3), + Rational(0) + ) + ).substitute(RationalField, + ListRationalFunction( + ListPolynomial( + Rational(14, 9), + Rational(-2, 5), + Rational(0) + ), + ListPolynomial( + Rational(-6, 4), + Rational(5, 9), + Rational(0) + ) + ) + ), + "test 4" + ) + assertEquals( + ListRationalFunction( + ListPolynomial( + Rational(41635, 3888), + Rational(0, 1), + Rational(-279187, 11664), + Rational(0, 1), + Rational(103769, 3456), + Rational(0, 1), + Rational(-11017, 768), + Rational(0, 1), + Rational(4097, 4096) + ), + ListPolynomial( + Rational(-13811791, 3779136), + Rational(0, 1), + Rational(-9999395, 419904), + Rational(0, 1), + Rational(6376601, 124416), + Rational(0, 1), + Rational(-3668315, 82944), + Rational(0, 1), + Rational(2097089, 147456) + ) + ), + ListRationalFunction( + ListPolynomial( + Rational(1, 1), + Rational(0), + Rational(0), + Rational(-8, 8) + ), + ListPolynomial( + Rational(-14, 8), + Rational(0), + Rational(0), + Rational(0), + Rational(8, 9) + ) + ).substitute(RationalField, + ListRationalFunction( + ListPolynomial( + Rational(14, 9), + Rational(0), + Rational(-14, 7) + ), + ListPolynomial( + Rational(-6, 4), + Rational(0), + Rational(1, 8) + ) + ) + ), + "test 5" + ) + } + @Test + fun test_Polynomial_derivative() { assertEquals( ListPolynomial(Rational(-2), Rational(2)), ListPolynomial(Rational(1), Rational(-2), Rational(1)).derivative(RationalField), @@ -142,7 +853,7 @@ class ListPolynomialUtilTest { ) } @Test - fun test_nthDerivative() { + fun test_Polynomial_nthDerivative() { assertEquals( ListPolynomial(Rational(-2), Rational(2)), ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 1), @@ -188,7 +899,7 @@ class ListPolynomialUtilTest { ) } @Test - fun test_antiderivative() { + fun test_Polynomial_antiderivative() { assertEquals( ListPolynomial(Rational(0), Rational(1), Rational(-1), Rational(1, 3)), ListPolynomial(Rational(1), Rational(-2), Rational(1)).antiderivative(RationalField), @@ -211,7 +922,7 @@ class ListPolynomialUtilTest { ) } @Test - fun test_nthAntiderivative() { + fun test_Polynomial_nthAntiderivative() { assertEquals( ListPolynomial(Rational(0), Rational(1), Rational(-1), Rational(1, 3)), ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 1), -- 2.34.1 From f147636e9d0402dd4c4d3b4c0e73e8a0c12a4d57 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Fri, 1 Jul 2022 14:46:05 +0300 Subject: [PATCH 090/123] Tests generation for numbered utilities in progress. --- .../space/kscience/kmath/functions/misc.kt | 4 +- .../functions/NumberedPolynomialUtilTest.kt | 2113 ++++++++++++++++- 2 files changed, 2074 insertions(+), 43 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt index aba246519..76f1c294e 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt @@ -17,6 +17,6 @@ package space.kscience.kmath.functions "But at the same time makes it easy to make a mistake " + "that will cause wrong computation result or even runtime error. " + "Make sure you fully read and understand documentation.", - level = RequiresOptIn.Level.WARNING + level = RequiresOptIn.Level.ERROR ) -internal annotation class DelicatePolynomialAPI \ No newline at end of file +public annotation class DelicatePolynomialAPI \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt index ecad6198e..8ece66145 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt @@ -8,13 +8,14 @@ package space.kscience.kmath.functions import space.kscience.kmath.test.misc.Rational import space.kscience.kmath.test.misc.RationalField import space.kscience.kmath.test.misc.assertContentEquals +import kotlin.test.Ignore import kotlin.test.Test import kotlin.test.assertEquals class NumberedPolynomialUtilTest { @Test - fun test_substitute_Double_Map() { + fun test_Polynomial_substitute_Double_Map() { assertContentEquals( mapOf(emptyList() to 0.0), NumberedPolynomialAsIs( @@ -53,6 +54,34 @@ class NumberedPolynomialUtilTest { 0.001, "test 2" ) + assertContentEquals( + mapOf( + listOf() to 0.8597048543814783, + listOf(1u) to 0.22997637465889875, + listOf(2u) to 0.32675302591924016, + listOf(0u, 1u) to 0.4561746111587508, + listOf(1u, 1u) to 0.5304946210170756, + listOf(2u, 1u) to 0.6244313712888998, + listOf(0u, 2u) to 0.2700930201481795, + listOf(1u, 2u) to -0.06962351375204712, + listOf(2u, 2u) to -0.015206988092131501, + ), + NumberedPolynomialAsIs( + listOf() to 0.8597048543814783, + listOf(1u) to 0.22997637465889875, + listOf(2u) to 0.32675302591924016, + listOf(0u, 1u) to 0.4561746111587508, + listOf(1u, 1u) to 0.5304946210170756, + listOf(2u, 1u) to 0.6244313712888998, + listOf(0u, 2u) to 0.2700930201481795, + listOf(1u, 2u) to -0.06962351375204712, + listOf(2u, 2u) to -0.015206988092131501, + ).substitute(mapOf( + 5 to 0.9211194782050933 + )).coefficients, + 0.001, + "test 2'" + ) assertContentEquals( mapOf( listOf() to 0.8597048543814783, @@ -75,6 +104,29 @@ class NumberedPolynomialUtilTest { 0.001, "test 3" ) + assertContentEquals( + mapOf( + listOf() to 0.8597048543814783, + listOf(0u, 1u) to 0.4561746111587508, + listOf(0u, 2u) to 0.2700930201481795, + ), + NumberedPolynomialAsIs( + listOf() to 0.8597048543814783, + listOf(1u) to 0.22997637465889875, + listOf(2u) to 0.32675302591924016, + listOf(0u, 1u) to 0.4561746111587508, + listOf(1u, 1u) to 0.5304946210170756, + listOf(2u, 1u) to 0.6244313712888998, + listOf(0u, 2u) to 0.2700930201481795, + listOf(1u, 2u) to -0.06962351375204712, + listOf(2u, 2u) to -0.015206988092131501, + ).substitute(mapOf( + 0 to 0.0, + 5 to 0.9211194782050933 + )).coefficients, + 0.001, + "test 3'" + ) assertContentEquals( mapOf( listOf() to 1.433510890645169, @@ -97,6 +149,29 @@ class NumberedPolynomialUtilTest { 0.001, "test 4" ) + assertContentEquals( + mapOf( + listOf() to 1.433510890645169, + listOf(1u) to 0.6264844682514724, + listOf(2u) to 0.8405727903771333, + ), + NumberedPolynomialAsIs( + listOf() to 0.8597048543814783, + listOf(1u) to 0.22997637465889875, + listOf(2u) to 0.32675302591924016, + listOf(0u, 1u) to 0.4561746111587508, + listOf(1u, 1u) to 0.5304946210170756, + listOf(2u, 1u) to 0.6244313712888998, + listOf(0u, 2u) to 0.2700930201481795, + listOf(1u, 2u) to -0.06962351375204712, + listOf(2u, 2u) to -0.015206988092131501, + ).substitute(mapOf( + 1 to 0.8400458576651112, + 5 to 0.9211194782050933 + )).coefficients, + 0.001, + "test 4'" + ) assertContentEquals( mapOf( listOf() to 1.934530767358133, @@ -120,15 +195,7 @@ class NumberedPolynomialUtilTest { ) assertContentEquals( mapOf( - listOf() to 0.8597048543814783, - listOf(1u) to 0.22997637465889875, - listOf(2u) to 0.32675302591924016, - listOf(0u, 1u) to 0.4561746111587508, - listOf(1u, 1u) to 0.5304946210170756, - listOf(2u, 1u) to 0.6244313712888998, - listOf(0u, 2u) to 0.2700930201481795, - listOf(1u, 2u) to -0.06962351375204712, - listOf(2u, 2u) to -0.015206988092131501, + listOf() to 1.934530767358133, ), NumberedPolynomialAsIs( listOf() to 0.8597048543814783, @@ -141,14 +208,16 @@ class NumberedPolynomialUtilTest { listOf(1u, 2u) to -0.06962351375204712, listOf(2u, 2u) to -0.015206988092131501, ).substitute(mapOf( + 0 to 0.4846192734143442, + 1 to 0.8400458576651112, 5 to 0.9211194782050933 )).coefficients, 0.001, - "test 6" + "test 5'" ) } @Test - fun test_substitute_Constant() { + fun test_Polynomial_substitute_Constant_Map() { assertEquals( NumberedPolynomialAsIs( listOf() to Rational(0) @@ -183,6 +252,167 @@ class NumberedPolynomialUtilTest { )), "test 2" ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(143, 150) + ), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + 0 to Rational(-2, 5), + 1 to Rational(12, 9), + 5 to Rational(57, 179), + )), + "test 2'" + ) + // https://www.wolframalpha.com/input?i=%28-3%2F2+%2B+8%2F6+x+%2B+14%2F6+x%5E2%29+%2B+%28-3%2F1+%2B+-19%2F2+x+%2B+9%2F4+x%5E2%29+y+%2B+%285%2F5+%2B+18%2F9+x+%2B+5%2F2+x%5E2%29+y%5E2+where+y+%3D+12%2F9 + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(-67, 18), + listOf(1u) to Rational(-70, 9), + listOf(2u) to Rational(88, 9), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + 1 to Rational(12, 9), + )), + "test 3" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(-67, 18), + listOf(1u) to Rational(-70, 9), + listOf(2u) to Rational(88, 9), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + 1 to Rational(12, 9), + 5 to Rational(57, 179), + )), + "test 3'" + ) + // https://www.wolframalpha.com/input?i=%28-3%2F2+%2B+8%2F6+x+%2B+14%2F6+x%5E2%29+%2B+%28-3%2F1+%2B+-19%2F2+x+%2B+9%2F4+x%5E2%29+y+%2B+%285%2F5+%2B+18%2F9+x+%2B+5%2F2+x%5E2%29+y%5E2+where+x+%3D+-2%2F5 + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(-83, 50), + listOf(0u, 1u) to Rational(29, 25), + listOf(0u, 2u) to Rational(3, 5), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + 0 to Rational(-2, 5), + )), + "test 4" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(-83, 50), + listOf(0u, 1u) to Rational(29, 25), + listOf(0u, 2u) to Rational(3, 5), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + 0 to Rational(-2, 5), + 5 to Rational(57, 179), + )), + "test 4'" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf()), + "test 5" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + 5 to Rational(57, 179), + )), + "test 5'" + ) // https://www.wolframalpha.com/input?i=%28%28-3%2F2+%2B+8%2F6+x+%2B+14%2F6+x%5E2%29+%2B+%28-3%2F1+%2B+-19%2F2+x+%2B+9%2F4+x%5E2%29+y+%2B+%285%2F5+%2B+18%2F9+x+%2B+5%2F2+x%5E2%29+y%5E2%29+p%5E8+where+x+%3D+q%2Fp%2C+y+%3D+x%5E3%2C+p+%3D+-2%2F5%2C+q+%3D+12%2F9 assertEquals( NumberedPolynomialAsIs( @@ -202,37 +432,11 @@ class NumberedPolynomialUtilTest { 0 to Rational(-2, 5), 1 to Rational(12, 9), )), - "test 3" - ) - // https://www.wolframalpha.com/input?i=%28%28-3%2F2+%2B+8%2F6+x+%2B+14%2F6+x%5E2%29+%2B+%28-3%2F1+%2B+-19%2F2+x+%2B+9%2F4+x%5E2%29+y+%2B+%285%2F5+%2B+18%2F9+x+%2B+5%2F2+x%5E2%29+y%5E2%29+p%5E8+where+x+%3D+q%2Fp%2C+y+%3D+x%5E3%2C+p+%3D+-2%2F5%2C+q+%3D+12%2F9 - assertEquals( - NumberedPolynomialAsIs( - listOf(8u) to Rational(-3, 2), - listOf(7u, 1u) to Rational(8, 6), - listOf(6u, 2u) to Rational(14, 6), - listOf(5u, 3u) to Rational(-3, 1), - listOf(4u, 4u) to Rational(-19, 2), - listOf(3u, 5u) to Rational(9, 4), - listOf(2u, 6u) to Rational(5, 5), - listOf(1u, 7u) to Rational(18, 9), - listOf(0u, 8u) to Rational(5, 2), - ), - NumberedPolynomialAsIs( - listOf(8u) to Rational(-3, 2), - listOf(7u, 1u) to Rational(8, 6), - listOf(6u, 2u) to Rational(14, 6), - listOf(5u, 3u) to Rational(-3, 1), - listOf(4u, 4u) to Rational(-19, 2), - listOf(3u, 5u) to Rational(9, 4), - listOf(2u, 6u) to Rational(5, 5), - listOf(1u, 7u) to Rational(18, 9), - listOf(0u, 8u) to Rational(5, 2), - ).substitute(RationalField, mapOf()), - "test 4" + "test 6" ) } @Test - fun test_substitute_Polynomial() { + fun test_Polynomial_substitute_Polynomial_Map() { assertEquals( NumberedPolynomialAsIs( listOf() to Rational(0) @@ -248,7 +452,7 @@ class NumberedPolynomialUtilTest { )), "test 1" ) - // https://www.wolframalpha.com/input?i=%28-3%2F2+%2B+8%2F6+x+%2B+14%2F6+x%5E2%29+%2B+%28-3%2F1+%2B+-19%2F2+x+%2B+9%2F4+x%5E2%29+y+%2B+%285%2F5+%2B+18%2F9+x+%2B+5%2F2+x%5E2%29+y%5E2+where+x+%3D+-2%2F5%2C+y+%3D+12%2F9 + // https://www.wolframalpha.com/input?i=%28-3%2F2+%2B+8%2F6+x+%2B+14%2F6+x%5E2%29+%2B+%28-3%2F1+%2B+-19%2F2+x+%2B+9%2F4+x%5E2%29+y+%2B+%285%2F5+%2B+18%2F9+x+%2B+5%2F2+x%5E2%29+y%5E2+where+x+%3D+-5%2F1+s+%2B+2%2F8+t%2C+y+%3D+11%2F7+t assertEquals( NumberedPolynomialAsIs( listOf() to Rational(-3, 2), @@ -289,5 +493,1832 @@ class NumberedPolynomialUtilTest { )), "test 2" ) + // (-3/2 + 8/6 x + 14/6 x^2) + (-3/1 + -19/2 x + 9/4 x^2) y + (5/5 + 18/9 x + 5/2 x^2) y^2 where x = (0/6 + 14/8 s + -14/2 s^2) + (-3/5 + 11/1 s + 3/7 s^2) t + (-3/7 + -18/5 s + -9/1 s^2) t^2, y = (-9/2 + 2/7 s + 9/1 s^2) + (13/1 + -1/8 s + 2/8 s^2) t + (19/4 + 15/7 s + -19/4 s^2) t^2 + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(129, 4), + listOf(1u) to Rational(48583, 336), + listOf(2u) to Rational(-913477, 1568), + listOf(3u) to Rational(-967567, 672), + listOf(4u) to Rational(4722043, 1344), + listOf(5u) to Rational(8855, 2), + listOf(6u) to Rational(-311971, 32), + listOf(7u) to Rational(-17325, 4), + listOf(8u) to Rational(19845, 2), + listOf(0u, 1u) to Rational(-827, 4), + listOf(1u, 1u) to Rational(191927, 840), + listOf(2u, 1u) to Rational(9592627, 2352), + listOf(3u, 1u) to Rational(-105400711, 53760), + listOf(4u, 1u) to Rational(-10054101459, 439040), + listOf(5u, 1u) to Rational(2127351, 128), + listOf(6u, 1u) to Rational(116680973, 3136), + listOf(7u, 1u) to Rational(-220445, 7), + listOf(8u, 1u) to Rational(-2655, 4), + listOf(0u, 2u) to Rational(30567, 100), + listOf(1u, 2u) to Rational(-156284953, 39200), + listOf(2u, 2u) to Rational(-57661541711, 6585600), + listOf(3u, 2u) to Rational(131931579, 3136), + listOf(4u, 2u) to Rational(98818124791, 3512320), + listOf(5u, 2u) to Rational(-94458855053, 878080), + listOf(6u, 2u) to Rational(13937705305, 1229312), + listOf(7u, 2u) to Rational(335706887, 21952), + listOf(8u, 2u) to Rational(23549165, 1568), + listOf(0u, 3u) to Rational(111367, 1400), + listOf(1u, 3u) to Rational(4937369, 700), + listOf(2u, 3u) to Rational(-4449423711, 274400), + listOf(3u, 3u) to Rational(-351873325703, 4390400), + listOf(4u, 3u) to Rational(23495875029, 307328), + listOf(5u, 3u) to Rational(17576300919, 878080), + listOf(6u, 3u) to Rational(230316993, 12544), + listOf(7u, 3u) to Rational(-191130515, 21952), + listOf(8u, 3u) to Rational(332435, 392), + listOf(0u, 4u) to Rational(-275084, 1225), + listOf(1u, 4u) to Rational(-266774603, 137200), + listOf(2u, 4u) to Rational(2176279167121, 30732800), + listOf(3u, 4u) to Rational(10904913303, 2195200), + listOf(4u, 4u) to Rational(-10769286147, 2195200), + listOf(5u, 4u) to Rational(-26277119793, 439040), + listOf(6u, 4u) to Rational(25859735869, 6146560), + listOf(7u, 4u) to Rational(38906289, 2744), + listOf(8u, 4u) to Rational(-3072025, 392), + listOf(0u, 5u) to Rational(9573, 98), + listOf(1u, 5u) to Rational(-4154651399, 548800), + listOf(2u, 5u) to Rational(3446069019, 548800), + listOf(3u, 5u) to Rational(-7851500623, 137200), + listOf(4u, 5u) to Rational(-53205142903, 1920800), + listOf(5u, 5u) to Rational(-31953611, 3430), + listOf(6u, 5u) to Rational(1447380313, 109760), + listOf(7u, 5u) to Rational(764158625, 21952), + listOf(8u, 5u) to Rational(1153515, 784), + listOf(0u, 6u) to Rational(1722351, 7840), + listOf(1u, 6u) to Rational(-164554821, 109760), + listOf(2u, 6u) to Rational(-79096147243, 7683200), + listOf(3u, 6u) to Rational(-624721089, 15680), + listOf(4u, 6u) to Rational(11147305567, 548800), + listOf(5u, 6u) to Rational(8318333679, 109760), + listOf(6u, 6u) to Rational(32981871553, 1536640), + listOf(7u, 6u) to Rational(-225359619, 21952), + listOf(8u, 6u) to Rational(-3973995, 392), + listOf(0u, 7u) to Rational(67203, 784), + listOf(1u, 7u) to Rational(39281469, 54880), + listOf(2u, 7u) to Rational(70162551, 27440), + listOf(3u, 7u) to Rational(413630709, 54880), + listOf(4u, 7u) to Rational(4640410269, 192080), + listOf(5u, 7u) to Rational(802712247, 54880), + listOf(6u, 7u) to Rational(-473517603, 27440), + listOf(7u, 7u) to Rational(-17055459, 1568), + listOf(8u, 7u) to Rational(-12825, 14), + listOf(0u, 8u) to Rational(16245, 1568), + listOf(1u, 8u) to Rational(503253, 2744), + listOf(2u, 8u) to Rational(125292591, 96040), + listOf(3u, 8u) to Rational(12033171, 2744), + listOf(4u, 8u) to Rational(154352673, 27440), + listOf(5u, 8u) to Rational(-1302291, 392), + listOf(6u, 8u) to Rational(-20265741, 1960), + listOf(7u, 8u) to Rational(-26163, 56), + listOf(8u, 8u) to Rational(146205, 32), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + 0 to NumberedPolynomialAsIs( + listOf() to Rational(0, 6), + listOf(1u) to Rational(14, 8), + listOf(2u) to Rational(-14, 2), + listOf(0u, 1u) to Rational(-3, 5), + listOf(1u, 1u) to Rational(11, 1), + listOf(2u, 1u) to Rational(3, 7), + listOf(0u, 2u) to Rational(-3, 7), + listOf(1u, 2u) to Rational(-18, 5), + listOf(2u, 2u) to Rational(-9, 1), + ), + 1 to NumberedPolynomialAsIs( + listOf() to Rational(-9, 2), + listOf(1u) to Rational(2, 7), + listOf(2u) to Rational(9, 1), + listOf(0u, 1u) to Rational(13, 1), + listOf(1u, 1u) to Rational(-1, 8), + listOf(2u, 1u) to Rational(2, 8), + listOf(0u, 2u) to Rational(19, 4), + listOf(1u, 2u) to Rational(15, 7), + listOf(2u, 2u) to Rational(-19, 4), + ), + )), + "test 3" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(129, 4), + listOf(1u) to Rational(48583, 336), + listOf(2u) to Rational(-913477, 1568), + listOf(3u) to Rational(-967567, 672), + listOf(4u) to Rational(4722043, 1344), + listOf(5u) to Rational(8855, 2), + listOf(6u) to Rational(-311971, 32), + listOf(7u) to Rational(-17325, 4), + listOf(8u) to Rational(19845, 2), + listOf(0u, 1u) to Rational(-827, 4), + listOf(1u, 1u) to Rational(191927, 840), + listOf(2u, 1u) to Rational(9592627, 2352), + listOf(3u, 1u) to Rational(-105400711, 53760), + listOf(4u, 1u) to Rational(-10054101459, 439040), + listOf(5u, 1u) to Rational(2127351, 128), + listOf(6u, 1u) to Rational(116680973, 3136), + listOf(7u, 1u) to Rational(-220445, 7), + listOf(8u, 1u) to Rational(-2655, 4), + listOf(0u, 2u) to Rational(30567, 100), + listOf(1u, 2u) to Rational(-156284953, 39200), + listOf(2u, 2u) to Rational(-57661541711, 6585600), + listOf(3u, 2u) to Rational(131931579, 3136), + listOf(4u, 2u) to Rational(98818124791, 3512320), + listOf(5u, 2u) to Rational(-94458855053, 878080), + listOf(6u, 2u) to Rational(13937705305, 1229312), + listOf(7u, 2u) to Rational(335706887, 21952), + listOf(8u, 2u) to Rational(23549165, 1568), + listOf(0u, 3u) to Rational(111367, 1400), + listOf(1u, 3u) to Rational(4937369, 700), + listOf(2u, 3u) to Rational(-4449423711, 274400), + listOf(3u, 3u) to Rational(-351873325703, 4390400), + listOf(4u, 3u) to Rational(23495875029, 307328), + listOf(5u, 3u) to Rational(17576300919, 878080), + listOf(6u, 3u) to Rational(230316993, 12544), + listOf(7u, 3u) to Rational(-191130515, 21952), + listOf(8u, 3u) to Rational(332435, 392), + listOf(0u, 4u) to Rational(-275084, 1225), + listOf(1u, 4u) to Rational(-266774603, 137200), + listOf(2u, 4u) to Rational(2176279167121, 30732800), + listOf(3u, 4u) to Rational(10904913303, 2195200), + listOf(4u, 4u) to Rational(-10769286147, 2195200), + listOf(5u, 4u) to Rational(-26277119793, 439040), + listOf(6u, 4u) to Rational(25859735869, 6146560), + listOf(7u, 4u) to Rational(38906289, 2744), + listOf(8u, 4u) to Rational(-3072025, 392), + listOf(0u, 5u) to Rational(9573, 98), + listOf(1u, 5u) to Rational(-4154651399, 548800), + listOf(2u, 5u) to Rational(3446069019, 548800), + listOf(3u, 5u) to Rational(-7851500623, 137200), + listOf(4u, 5u) to Rational(-53205142903, 1920800), + listOf(5u, 5u) to Rational(-31953611, 3430), + listOf(6u, 5u) to Rational(1447380313, 109760), + listOf(7u, 5u) to Rational(764158625, 21952), + listOf(8u, 5u) to Rational(1153515, 784), + listOf(0u, 6u) to Rational(1722351, 7840), + listOf(1u, 6u) to Rational(-164554821, 109760), + listOf(2u, 6u) to Rational(-79096147243, 7683200), + listOf(3u, 6u) to Rational(-624721089, 15680), + listOf(4u, 6u) to Rational(11147305567, 548800), + listOf(5u, 6u) to Rational(8318333679, 109760), + listOf(6u, 6u) to Rational(32981871553, 1536640), + listOf(7u, 6u) to Rational(-225359619, 21952), + listOf(8u, 6u) to Rational(-3973995, 392), + listOf(0u, 7u) to Rational(67203, 784), + listOf(1u, 7u) to Rational(39281469, 54880), + listOf(2u, 7u) to Rational(70162551, 27440), + listOf(3u, 7u) to Rational(413630709, 54880), + listOf(4u, 7u) to Rational(4640410269, 192080), + listOf(5u, 7u) to Rational(802712247, 54880), + listOf(6u, 7u) to Rational(-473517603, 27440), + listOf(7u, 7u) to Rational(-17055459, 1568), + listOf(8u, 7u) to Rational(-12825, 14), + listOf(0u, 8u) to Rational(16245, 1568), + listOf(1u, 8u) to Rational(503253, 2744), + listOf(2u, 8u) to Rational(125292591, 96040), + listOf(3u, 8u) to Rational(12033171, 2744), + listOf(4u, 8u) to Rational(154352673, 27440), + listOf(5u, 8u) to Rational(-1302291, 392), + listOf(6u, 8u) to Rational(-20265741, 1960), + listOf(7u, 8u) to Rational(-26163, 56), + listOf(8u, 8u) to Rational(146205, 32), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + 0 to NumberedPolynomialAsIs( + listOf() to Rational(0, 6), + listOf(1u) to Rational(14, 8), + listOf(2u) to Rational(-14, 2), + listOf(0u, 1u) to Rational(-3, 5), + listOf(1u, 1u) to Rational(11, 1), + listOf(2u, 1u) to Rational(3, 7), + listOf(0u, 2u) to Rational(-3, 7), + listOf(1u, 2u) to Rational(-18, 5), + listOf(2u, 2u) to Rational(-9, 1), + ), + 1 to NumberedPolynomialAsIs( + listOf() to Rational(-9, 2), + listOf(1u) to Rational(2, 7), + listOf(2u) to Rational(9, 1), + listOf(0u, 1u) to Rational(13, 1), + listOf(1u, 1u) to Rational(-1, 8), + listOf(2u, 1u) to Rational(2, 8), + listOf(0u, 2u) to Rational(19, 4), + listOf(1u, 2u) to Rational(15, 7), + listOf(2u, 2u) to Rational(-19, 4), + ), + 5 to NumberedPolynomialAsIs( + listOf() to Rational(-11, 3), + listOf(1u) to Rational(5, 2), + listOf(2u) to Rational(13, 7), + listOf(0u, 1u) to Rational(16, 9), + listOf(1u, 1u) to Rational(14, 7), + listOf(2u, 1u) to Rational(6, 1), + listOf(0u, 2u) to Rational(-14, 3), + listOf(1u, 2u) to Rational(-2, 7), + listOf(2u, 2u) to Rational(-10, 8), + ) + )), + "test 3'" + ) + // (-3/2 + 8/6 x + 14/6 x^2) + (-3/1 + -19/2 x + 9/4 x^2) y + (5/5 + 18/9 x + 5/2 x^2) y^2 where x = s, y = (-9/2 + 2/7 s + 9/1 s^2) + (13/1 + -1/8 s + 2/8 s^2) t + (19/4 + 15/7 s + -19/4 s^2) t^2 + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(129, 4), + listOf(1u) to Rational(6817, 84), + listOf(2u) to Rational(-21445, 294), + listOf(3u) to Rational(-12151, 49), + listOf(4u) to Rational(-17789, 196), + listOf(5u) to Rational(1224, 7), + listOf(6u) to Rational(405, 2), + listOf(0u, 1u) to Rational(-156), + listOf(1u, 1u) to Rational(-2440, 7), + listOf(2u, 1u) to Rational(-1571, 112), + listOf(3u, 1u) to Rational(107515, 224), + listOf(4u, 1u) to Rational(64965, 112), + listOf(5u, 1u) to Rational(209, 56), + listOf(6u, 1u) to Rational(45, 4), + listOf(0u, 2u) to Rational(112), + listOf(1u, 2u) to Rational(1449, 8), + listOf(2u, 2u) to Rational(1306309, 3136), + listOf(3u, 2u) to Rational(483207, 1568), + listOf(4u, 2u) to Rational(1978437, 6272), + listOf(5u, 2u) to Rational(-18231, 224), + listOf(6u, 2u) to Rational(-6835, 32), + listOf(0u, 3u) to Rational(247, 2), + listOf(1u, 3u) to Rational(33771, 112), + listOf(2u, 3u) to Rational(2073, 7), + listOf(3u, 3u) to Rational(-23463, 224), + listOf(4u, 3u) to Rational(-33825, 112), + listOf(5u, 3u) to Rational(201, 224), + listOf(6u, 3u) to Rational(-95, 16), + listOf(0u, 4u) to Rational(361, 16), + listOf(1u, 4u) to Rational(3667, 56), + listOf(2u, 4u) to Rational(88729, 1568), + listOf(3u, 4u) to Rational(-2476, 49), + listOf(4u, 4u) to Rational(-23419, 196), + listOf(5u, 4u) to Rational(-323, 56), + listOf(6u, 4u) to Rational(1805, 32), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + 1 to NumberedPolynomialAsIs( + listOf() to Rational(-9, 2), + listOf(1u) to Rational(2, 7), + listOf(2u) to Rational(9, 1), + listOf(0u, 1u) to Rational(13, 1), + listOf(1u, 1u) to Rational(-1, 8), + listOf(2u, 1u) to Rational(2, 8), + listOf(0u, 2u) to Rational(19, 4), + listOf(1u, 2u) to Rational(15, 7), + listOf(2u, 2u) to Rational(-19, 4), + ), + )), + "test 4" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(129, 4), + listOf(1u) to Rational(6817, 84), + listOf(2u) to Rational(-21445, 294), + listOf(3u) to Rational(-12151, 49), + listOf(4u) to Rational(-17789, 196), + listOf(5u) to Rational(1224, 7), + listOf(6u) to Rational(405, 2), + listOf(0u, 1u) to Rational(-156), + listOf(1u, 1u) to Rational(-2440, 7), + listOf(2u, 1u) to Rational(-1571, 112), + listOf(3u, 1u) to Rational(107515, 224), + listOf(4u, 1u) to Rational(64965, 112), + listOf(5u, 1u) to Rational(209, 56), + listOf(6u, 1u) to Rational(45, 4), + listOf(0u, 2u) to Rational(112), + listOf(1u, 2u) to Rational(1449, 8), + listOf(2u, 2u) to Rational(1306309, 3136), + listOf(3u, 2u) to Rational(483207, 1568), + listOf(4u, 2u) to Rational(1978437, 6272), + listOf(5u, 2u) to Rational(-18231, 224), + listOf(6u, 2u) to Rational(-6835, 32), + listOf(0u, 3u) to Rational(247, 2), + listOf(1u, 3u) to Rational(33771, 112), + listOf(2u, 3u) to Rational(2073, 7), + listOf(3u, 3u) to Rational(-23463, 224), + listOf(4u, 3u) to Rational(-33825, 112), + listOf(5u, 3u) to Rational(201, 224), + listOf(6u, 3u) to Rational(-95, 16), + listOf(0u, 4u) to Rational(361, 16), + listOf(1u, 4u) to Rational(3667, 56), + listOf(2u, 4u) to Rational(88729, 1568), + listOf(3u, 4u) to Rational(-2476, 49), + listOf(4u, 4u) to Rational(-23419, 196), + listOf(5u, 4u) to Rational(-323, 56), + listOf(6u, 4u) to Rational(1805, 32), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + 1 to NumberedPolynomialAsIs( + listOf() to Rational(-9, 2), + listOf(1u) to Rational(2, 7), + listOf(2u) to Rational(9, 1), + listOf(0u, 1u) to Rational(13, 1), + listOf(1u, 1u) to Rational(-1, 8), + listOf(2u, 1u) to Rational(2, 8), + listOf(0u, 2u) to Rational(19, 4), + listOf(1u, 2u) to Rational(15, 7), + listOf(2u, 2u) to Rational(-19, 4), + ), + 5 to NumberedPolynomialAsIs( + listOf() to Rational(-11, 3), + listOf(1u) to Rational(5, 2), + listOf(2u) to Rational(13, 7), + listOf(0u, 1u) to Rational(16, 9), + listOf(1u, 1u) to Rational(14, 7), + listOf(2u, 1u) to Rational(6, 1), + listOf(0u, 2u) to Rational(-14, 3), + listOf(1u, 2u) to Rational(-2, 7), + listOf(2u, 2u) to Rational(-10, 8), + ) + )), + "test 4'" + ) + // (-3/2 + 8/6 x + 14/6 x^2) + (-3/1 + -19/2 x + 9/4 x^2) y + (5/5 + 18/9 x + 5/2 x^2) y^2 where x = (0/6 + 14/8 s + -14/2 s^2) + (-3/5 + 11/1 s + 3/7 s^2) t + (-3/7 + -18/5 s + -9/1 s^2) t^2, y = t + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(7, 3), + listOf(2u) to Rational(-35, 16), + listOf(3u) to Rational(-343, 6), + listOf(4u) to Rational(343, 3), + listOf(0u, 1u) to Rational(-19, 5), + listOf(1u, 1u) to Rational(-823, 120), + listOf(2u, 1u) to Rational(1232417, 6720), + listOf(3u, 1u) to Rational(-9863, 24), + listOf(4u, 1u) to Rational(385, 4), + listOf(0u, 2u) to Rational(2439, 350), + listOf(1u, 2u) to Rational(-5793, 40), + listOf(2u, 2u) to Rational(1172113, 3360), + listOf(3u, 2u) to Rational(-13531, 40), + listOf(4u, 2u) to Rational(2824, 7), + listOf(0u, 3u) to Rational(3417, 700), + listOf(1u, 3u) to Rational(1191, 200), + listOf(2u, 3u) to Rational(8383, 28), + listOf(3u, 3u) to Rational(-220279, 280), + listOf(4u, 3u) to Rational(49179, 196), + listOf(0u, 4u) to Rational(57, 35), + listOf(1u, 4u) to Rational(-33771, 700), + listOf(2u, 4u) to Rational(196279, 1225), + listOf(3u, 4u) to Rational(-32259, 140), + listOf(4u, 4u) to Rational(23868, 49), + listOf(0u, 5u) to Rational(333, 196), + listOf(1u, 5u) to Rational(-204, 35), + listOf(2u, 5u) to Rational(-307233, 2450), + listOf(3u, 5u) to Rational(-12492, 35), + listOf(4u, 5u) to Rational(4563, 28), + listOf(0u, 6u) to Rational(45, 98), + listOf(1u, 6u) to Rational(54, 7), + listOf(2u, 6u) to Rational(1809, 35), + listOf(3u, 6u) to Rational(162), + listOf(4u, 6u) to Rational(405, 2), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + 0 to NumberedPolynomialAsIs( + listOf() to Rational(0, 6), + listOf(1u) to Rational(14, 8), + listOf(2u) to Rational(-14, 2), + listOf(0u, 1u) to Rational(-3, 5), + listOf(1u, 1u) to Rational(11, 1), + listOf(2u, 1u) to Rational(3, 7), + listOf(0u, 2u) to Rational(-3, 7), + listOf(1u, 2u) to Rational(-18, 5), + listOf(2u, 2u) to Rational(-9, 1), + ), + )), + "test 5" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(7, 3), + listOf(2u) to Rational(-35, 16), + listOf(3u) to Rational(-343, 6), + listOf(4u) to Rational(343, 3), + listOf(0u, 1u) to Rational(-19, 5), + listOf(1u, 1u) to Rational(-823, 120), + listOf(2u, 1u) to Rational(1232417, 6720), + listOf(3u, 1u) to Rational(-9863, 24), + listOf(4u, 1u) to Rational(385, 4), + listOf(0u, 2u) to Rational(2439, 350), + listOf(1u, 2u) to Rational(-5793, 40), + listOf(2u, 2u) to Rational(1172113, 3360), + listOf(3u, 2u) to Rational(-13531, 40), + listOf(4u, 2u) to Rational(2824, 7), + listOf(0u, 3u) to Rational(3417, 700), + listOf(1u, 3u) to Rational(1191, 200), + listOf(2u, 3u) to Rational(8383, 28), + listOf(3u, 3u) to Rational(-220279, 280), + listOf(4u, 3u) to Rational(49179, 196), + listOf(0u, 4u) to Rational(57, 35), + listOf(1u, 4u) to Rational(-33771, 700), + listOf(2u, 4u) to Rational(196279, 1225), + listOf(3u, 4u) to Rational(-32259, 140), + listOf(4u, 4u) to Rational(23868, 49), + listOf(0u, 5u) to Rational(333, 196), + listOf(1u, 5u) to Rational(-204, 35), + listOf(2u, 5u) to Rational(-307233, 2450), + listOf(3u, 5u) to Rational(-12492, 35), + listOf(4u, 5u) to Rational(4563, 28), + listOf(0u, 6u) to Rational(45, 98), + listOf(1u, 6u) to Rational(54, 7), + listOf(2u, 6u) to Rational(1809, 35), + listOf(3u, 6u) to Rational(162), + listOf(4u, 6u) to Rational(405, 2), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + 0 to NumberedPolynomialAsIs( + listOf() to Rational(0, 6), + listOf(1u) to Rational(14, 8), + listOf(2u) to Rational(-14, 2), + listOf(0u, 1u) to Rational(-3, 5), + listOf(1u, 1u) to Rational(11, 1), + listOf(2u, 1u) to Rational(3, 7), + listOf(0u, 2u) to Rational(-3, 7), + listOf(1u, 2u) to Rational(-18, 5), + listOf(2u, 2u) to Rational(-9, 1), + ), + 5 to NumberedPolynomialAsIs( + listOf() to Rational(-11, 3), + listOf(1u) to Rational(5, 2), + listOf(2u) to Rational(13, 7), + listOf(0u, 1u) to Rational(16, 9), + listOf(1u, 1u) to Rational(14, 7), + listOf(2u, 1u) to Rational(6, 1), + listOf(0u, 2u) to Rational(-14, 3), + listOf(1u, 2u) to Rational(-2, 7), + listOf(2u, 2u) to Rational(-10, 8), + ) + )), + "test 5'" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf>()), + "test 6" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + 5 to NumberedPolynomialAsIs( + listOf() to Rational(-11, 3), + listOf(1u) to Rational(5, 2), + listOf(2u) to Rational(13, 7), + listOf(0u, 1u) to Rational(16, 9), + listOf(1u, 1u) to Rational(14, 7), + listOf(2u, 1u) to Rational(6, 1), + listOf(0u, 2u) to Rational(-14, 3), + listOf(1u, 2u) to Rational(-2, 7), + listOf(2u, 2u) to Rational(-10, 8), + ) + )), + "test 6'" + ) + } + @Test + @Ignore // FIXME: This tests work only for sane realisations of the substitutions. Currently, it is not. + // Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should make denominator r^deg(p), + // not r^(deg(p)(deg(p)+1)/2) as it is now. + fun test_Polynomial_substitute_RationalFunction_Map() { + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(0) + ), + NumberedPolynomialAsIs( + listOf() to Rational(1) + ) + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1) + ).substitute(RationalField, mapOf( + 0 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(1) + ), + NumberedPolynomialAsIs( + listOf() to Rational(1) + ) + ) + )), + "test 1" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf(4u) to Rational(-194071, 4900), + listOf(3u, 1u) to Rational(394811, 225), + listOf(2u, 2u) to Rational(-444183161, 66150), + listOf(1u, 3u) to Rational(70537618, 59535), + listOf(0u, 4u) to Rational(9655504, 2835), + ), + NumberedPolynomialAsIs( + listOf(4u) to Rational(9, 1), + listOf(3u, 1u) to Rational(61, 1), + listOf(2u, 2u) to Rational(2137, 36), + listOf(1u, 3u) to Rational(-1342, 9), + listOf(0u, 4u) to Rational(484, 9), + ) + ), + NumberedPolynomialAsIs( + listOf() to Rational(15, 7), + listOf(1u) to Rational(1, 5), + listOf(2u) to Rational(-7, 4), + listOf(0u, 1u) to Rational(-1, 9), + listOf(1u, 1u) to Rational(-2, 7), + listOf(2u, 1u) to Rational(17, 3), + listOf(0u, 2u) to Rational(2, 6), + listOf(1u, 2u) to Rational(-17, 6), + listOf(2u, 2u) to Rational(-6, 2), + ).substitute(RationalField, mapOf( + 0 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf(1u) to Rational(17, 7), + listOf(0u, 1u) to Rational(-13, 1), + ), + NumberedPolynomialAsIs( + listOf(1u) to Rational(-18, 6), + listOf(0u, 1u) to Rational(11, 6), + ) + ), + 1 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf(1u) to Rational(18, 5), + listOf(0u, 1u) to Rational(-16, 3), + ), + NumberedPolynomialAsIs( + listOf(1u) to Rational(-1, 1), + listOf(0u, 1u) to Rational(-4, 1), + ) + ), + )), + "test 2" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-6443599, 10000), + listOf(1u) to Rational(166251223, 210000), + listOf(2u) to Rational(-4606805099, 3528000), + listOf(3u) to Rational(51204379, 19600), + listOf(4u) to Rational(-529045460659, 277830000), + listOf(5u) to Rational(2630836709, 1488375), + listOf(6u) to Rational(-42675691369, 25004700), + listOf(7u) to Rational(495825223, 1250235), + listOf(8u) to Rational(-22531756, 1750329), + listOf(0u, 1u) to Rational(-2526552797, 420000), + listOf(1u, 1u) to Rational(31108840471, 2520000), + listOf(2u, 1u) to Rational(-4789740847, 1102500), + listOf(3u, 1u) to Rational(186594307807, 11340000), + listOf(4u, 1u) to Rational(-11677815943, 1488375), + listOf(5u, 1u) to Rational(-181118486447, 27783000), + listOf(6u, 1u) to Rational(-16123292162, 14586075), + listOf(7u, 1u) to Rational(-140339343808, 26254935), + listOf(8u, 1u) to Rational(4570171616, 5250987), + listOf(0u, 2u) to Rational(-181436530573, 10080000), + listOf(1u, 2u) to Rational(6700437957491, 105840000), + listOf(2u, 2u) to Rational(-3527267461, 1417500), + listOf(3u, 2u) to Rational(-38084563451, 5556600), + listOf(4u, 2u) to Rational(-565662040631, 13891500), + listOf(5u, 2u) to Rational(-35479071126397, 583443000), + listOf(6u, 2u) to Rational(-11717559078469, 525098700), + listOf(7u, 2u) to Rational(-2043385293517, 225042300), + listOf(8u, 2u) to Rational(-3644439630451, 551353635), + listOf(0u, 3u) to Rational(-1760423269, 126000), + listOf(1u, 3u) to Rational(310176758299, 2352000), + listOf(2u, 3u) to Rational(-907229584837, 21168000), + listOf(3u, 3u) to Rational(-16717135885963, 95256000), + listOf(4u, 3u) to Rational(-43762928025353, 333396000), + listOf(5u, 3u) to Rational(-328427480571607, 3000564000), + listOf(6u, 3u) to Rational(-7722675917197, 210039480), + listOf(7u, 3u) to Rational(1713350137019, 1225230300), + listOf(8u, 3u) to Rational(156695935643, 31505922), + listOf(0u, 4u) to Rational(18362364269, 1008000), + listOf(1u, 4u) to Rational(955674858553, 10584000), + listOf(2u, 4u) to Rational(-71937470607371, 444528000), + listOf(3u, 4u) to Rational(-34097985615163, 95256000), + listOf(4u, 4u) to Rational(-340736178775883, 2000376000), + listOf(5u, 4u) to Rational(-511324523441897, 10501974000), + listOf(6u, 4u) to Rational(-125375649409151, 8821658160), + listOf(7u, 4u) to Rational(-2813518533421, 1575296100), + listOf(8u, 4u) to Rational(-17044089109, 5250987), + listOf(0u, 5u) to Rational(600086461, 20160), + listOf(1u, 5u) to Rational(-18959931367, 423360), + listOf(2u, 5u) to Rational(-9178804929607, 44452800), + listOf(3u, 5u) to Rational(-1460114275979, 5334336), + listOf(4u, 5u) to Rational(-342533479090169, 4200789600), + listOf(5u, 5u) to Rational(20335453022963, 4200789600), + listOf(6u, 5u) to Rational(-21649775090197, 6301184400), + listOf(7u, 5u) to Rational(-197301716069, 131274675), + listOf(8u, 5u) to Rational(18711357470, 15752961), + listOf(0u, 6u) to Rational(621417991, 100800), + listOf(1u, 6u) to Rational(-159236792977, 2116800), + listOf(2u, 6u) to Rational(-6602528890883, 66679200), + listOf(3u, 6u) to Rational(-1086091664047, 19051200), + listOf(4u, 6u) to Rational(3769375009003, 1680315840), + listOf(5u, 6u) to Rational(-12920385574769, 1050197400), + listOf(6u, 6u) to Rational(-90219591809287, 6301184400), + listOf(7u, 6u) to Rational(656361553391, 1575296100), + listOf(8u, 6u) to Rational(757900793, 2250423), + listOf(0u, 7u) to Rational(-100770017, 15120), + listOf(1u, 7u) to Rational(-316364851, 17640), + listOf(2u, 7u) to Rational(-85118560057, 6667920), + listOf(3u, 7u) to Rational(6286563719, 416745), + listOf(4u, 7u) to Rational(26803885301, 1714608), + listOf(5u, 7u) to Rational(-13767154393, 4286520), + listOf(6u, 7u) to Rational(-3875138933, 1224720), + listOf(7u, 7u) to Rational(65193755, 333396), + listOf(8u, 7u) to Rational(90974351, 2500470), + listOf(0u, 8u) to Rational(-3182197, 1260), + listOf(1u, 8u) to Rational(24899923, 8820), + listOf(2u, 8u) to Rational(-19999556, 19845), + listOf(3u, 8u) to Rational(3276587, 3969), + listOf(4u, 8u) to Rational(13719549239, 5000940), + listOf(5u, 8u) to Rational(-961839938, 1250235), + listOf(6u, 8u) to Rational(-198184871, 833490), + listOf(7u, 8u) to Rational(230659711, 5000940), + listOf(8u, 8u) to Rational(292447, 35721) + ), + NumberedPolynomialAsIs( + listOf() to Rational(9, 100), + listOf(1u) to Rational(-21, 50), + listOf(2u) to Rational(293, 700), + listOf(3u) to Rational(29, 210), + listOf(4u) to Rational(3233, 8820), + listOf(5u) to Rational(-289, 441), + listOf(6u) to Rational(-1, 9), + listOf(7u) to Rational(-20, 441), + listOf(8u) to Rational(100, 441), + listOf(0u, 1u) to Rational(-57, 80), + listOf(1u, 1u) to Rational(-121, 400), + listOf(2u, 1u) to Rational(37117, 8400), + listOf(3u, 1u) to Rational(-4853, 3150), + listOf(4u, 1u) to Rational(1166203, 132300), + listOf(5u, 1u) to Rational(-2708, 567), + listOf(6u, 1u) to Rational(-287159, 416745), + listOf(7u, 1u) to Rational(-478204, 83349), + listOf(8u, 1u) to Rational(176320, 83349), + listOf(0u, 2u) to Rational(-6239, 6400), + listOf(1u, 2u) to Rational(264211, 11200), + listOf(2u, 2u) to Rational(-1591999, 100800), + listOf(3u, 2u) to Rational(12450091, 529200), + listOf(4u, 2u) to Rational(9230759, 226800), + listOf(5u, 2u) to Rational(18995554, 2083725), + listOf(6u, 2u) to Rational(136706258, 6251175), + listOf(7u, 2u) to Rational(-120907496, 3750705), + listOf(8u, 2u) to Rational(117200176, 15752961), + listOf(0u, 3u) to Rational(5653, 320), + listOf(1u, 3u) to Rational(-130853, 8400), + listOf(2u, 3u) to Rational(-20939327, 151200), + listOf(3u, 3u) to Rational(2566691, 25200), + listOf(4u, 3u) to Rational(-68441519, 476280), + listOf(5u, 3u) to Rational(2462904247, 12502350), + listOf(6u, 3u) to Rational(353667161, 18753525), + listOf(7u, 3u) to Rational(-1689134372, 26254935), + listOf(8u, 3u) to Rational(35084104, 2250423), + listOf(0u, 4u) to Rational(-3587, 300), + listOf(1u, 4u) to Rational(-10513243, 33600), + listOf(2u, 4u) to Rational(30766733, 176400), + listOf(3u, 4u) to Rational(-65680021, 198450), + listOf(4u, 4u) to Rational(-8108910547, 20003760), + listOf(5u, 4u) to Rational(2922125159, 6251175), + listOf(6u, 4u) to Rational(-4245279943, 131274675), + listOf(7u, 4u) to Rational(-371946872, 3750705), + listOf(8u, 4u) to Rational(61286752, 2250423), + listOf(0u, 5u) to Rational(-20477, 160), + listOf(1u, 5u) to Rational(215741, 1120), + listOf(2u, 5u) to Rational(30785843, 31752), + listOf(3u, 5u) to Rational(-357495959, 317520), + listOf(4u, 5u) to Rational(-1611242993, 10001880), + listOf(5u, 5u) to Rational(345925495, 500094), + listOf(6u, 5u) to Rational(-755948411, 3750705), + listOf(7u, 5u) to Rational(-108643496, 1250235), + listOf(8u, 5u) to Rational(1122512, 35721), + listOf(0u, 6u) to Rational(358037, 2880), + listOf(1u, 6u) to Rational(3895837, 3360), + listOf(2u, 6u) to Rational(359419201, 1270080), + listOf(3u, 6u) to Rational(-158522587, 105840), + listOf(4u, 6u) to Rational(10909002599, 20003760), + listOf(5u, 6u) to Rational(76846972, 138915), + listOf(6u, 6u) to Rational(-327696553, 1250235), + listOf(7u, 6u) to Rational(-1687328, 35721), + listOf(8u, 6u) to Rational(1016836, 35721), + listOf(0u, 7u) to Rational(658, 3), + listOf(1u, 7u) to Rational(48035, 168), + listOf(2u, 7u) to Rational(-5777875, 5292), + listOf(3u, 7u) to Rational(-7893899, 10584), + listOf(4u, 7u) to Rational(10191652, 11907), + listOf(5u, 7u) to Rational(2920121, 23814), + listOf(6u, 7u) to Rational(-2699780, 11907), + listOf(7u, 7u) to Rational(4556, 441), + listOf(8u, 7u) to Rational(3440, 189), + listOf(0u, 8u) to Rational(64, 1), + listOf(1u, 8u) to Rational(-808, 7), + listOf(2u, 8u) to Rational(-360895, 1764), + listOf(3u, 8u) to Rational(257657, 882), + listOf(4u, 8u) to Rational(3779917, 15876), + listOf(5u, 8u) to Rational(-610279, 3969), + listOf(6u, 8u) to Rational(-25091, 441), + listOf(7u, 8u) to Rational(9560, 567), + listOf(8u, 8u) to Rational(400, 81) + ) + ), + NumberedPolynomialAsIs( + listOf() to Rational(15, 7), + listOf(1u) to Rational(1, 5), + listOf(2u) to Rational(-7, 4), + listOf(0u, 1u) to Rational(-1, 9), + listOf(1u, 1u) to Rational(-2, 7), + listOf(2u, 1u) to Rational(17, 3), + listOf(0u, 2u) to Rational(2, 6), + listOf(1u, 2u) to Rational(-17, 6), + listOf(2u, 2u) to Rational(-6, 2), + ).substitute(RationalField, mapOf( + 0 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(17, 5), + listOf(1u) to Rational(11, 6), + listOf(2u) to Rational(14, 3), + listOf(0u, 1u) to Rational(17, 1), + listOf(1u, 1u) to Rational(12, 3), + listOf(2u, 1u) to Rational(-6, 2), + listOf(0u, 2u) to Rational(17, 1), + listOf(1u, 2u) to Rational(-4, 3), + listOf(2u, 2u) to Rational(2, 6), + ), + NumberedPolynomialAsIs( + listOf() to Rational(3, 5), + listOf(1u) to Rational(3, 5), + listOf(2u) to Rational(3, 7), + listOf(0u, 1u) to Rational(-3, 8), + listOf(1u, 1u) to Rational(-1, 1), + listOf(2u, 1u) to Rational(17, 9), + listOf(0u, 2u) to Rational(-8, 1), + listOf(1u, 2u) to Rational(6, 4), + listOf(2u, 2u) to Rational(10, 9), + ) + ), + 1 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(18, 5), + listOf(1u) to Rational(-17, 5), + listOf(2u) to Rational(-2, 7), + listOf(0u, 1u) to Rational(6, 5), + listOf(1u, 1u) to Rational(-5, 1), + listOf(2u, 1u) to Rational(-9, 1), + listOf(0u, 2u) to Rational(-8, 8), + listOf(1u, 2u) to Rational(2, 7), + listOf(2u, 2u) to Rational(-13, 7), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-4, 8), + listOf(1u) to Rational(15, 9), + listOf(2u) to Rational(-10, 9), + listOf(0u, 1u) to Rational(5, 3), + listOf(1u, 1u) to Rational(4, 1), + listOf(2u, 1u) to Rational(-2, 7), + listOf(0u, 2u) to Rational(2, 2), + listOf(1u, 2u) to Rational(-5, 7), + listOf(2u, 2u) to Rational(-18, 9), + ) + ), + )), + "test 3" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-6443599, 10000), + listOf(1u) to Rational(166251223, 210000), + listOf(2u) to Rational(-4606805099, 3528000), + listOf(3u) to Rational(51204379, 19600), + listOf(4u) to Rational(-529045460659, 277830000), + listOf(5u) to Rational(2630836709, 1488375), + listOf(6u) to Rational(-42675691369, 25004700), + listOf(7u) to Rational(495825223, 1250235), + listOf(8u) to Rational(-22531756, 1750329), + listOf(0u, 1u) to Rational(-2526552797, 420000), + listOf(1u, 1u) to Rational(31108840471, 2520000), + listOf(2u, 1u) to Rational(-4789740847, 1102500), + listOf(3u, 1u) to Rational(186594307807, 11340000), + listOf(4u, 1u) to Rational(-11677815943, 1488375), + listOf(5u, 1u) to Rational(-181118486447, 27783000), + listOf(6u, 1u) to Rational(-16123292162, 14586075), + listOf(7u, 1u) to Rational(-140339343808, 26254935), + listOf(8u, 1u) to Rational(4570171616, 5250987), + listOf(0u, 2u) to Rational(-181436530573, 10080000), + listOf(1u, 2u) to Rational(6700437957491, 105840000), + listOf(2u, 2u) to Rational(-3527267461, 1417500), + listOf(3u, 2u) to Rational(-38084563451, 5556600), + listOf(4u, 2u) to Rational(-565662040631, 13891500), + listOf(5u, 2u) to Rational(-35479071126397, 583443000), + listOf(6u, 2u) to Rational(-11717559078469, 525098700), + listOf(7u, 2u) to Rational(-2043385293517, 225042300), + listOf(8u, 2u) to Rational(-3644439630451, 551353635), + listOf(0u, 3u) to Rational(-1760423269, 126000), + listOf(1u, 3u) to Rational(310176758299, 2352000), + listOf(2u, 3u) to Rational(-907229584837, 21168000), + listOf(3u, 3u) to Rational(-16717135885963, 95256000), + listOf(4u, 3u) to Rational(-43762928025353, 333396000), + listOf(5u, 3u) to Rational(-328427480571607, 3000564000), + listOf(6u, 3u) to Rational(-7722675917197, 210039480), + listOf(7u, 3u) to Rational(1713350137019, 1225230300), + listOf(8u, 3u) to Rational(156695935643, 31505922), + listOf(0u, 4u) to Rational(18362364269, 1008000), + listOf(1u, 4u) to Rational(955674858553, 10584000), + listOf(2u, 4u) to Rational(-71937470607371, 444528000), + listOf(3u, 4u) to Rational(-34097985615163, 95256000), + listOf(4u, 4u) to Rational(-340736178775883, 2000376000), + listOf(5u, 4u) to Rational(-511324523441897, 10501974000), + listOf(6u, 4u) to Rational(-125375649409151, 8821658160), + listOf(7u, 4u) to Rational(-2813518533421, 1575296100), + listOf(8u, 4u) to Rational(-17044089109, 5250987), + listOf(0u, 5u) to Rational(600086461, 20160), + listOf(1u, 5u) to Rational(-18959931367, 423360), + listOf(2u, 5u) to Rational(-9178804929607, 44452800), + listOf(3u, 5u) to Rational(-1460114275979, 5334336), + listOf(4u, 5u) to Rational(-342533479090169, 4200789600), + listOf(5u, 5u) to Rational(20335453022963, 4200789600), + listOf(6u, 5u) to Rational(-21649775090197, 6301184400), + listOf(7u, 5u) to Rational(-197301716069, 131274675), + listOf(8u, 5u) to Rational(18711357470, 15752961), + listOf(0u, 6u) to Rational(621417991, 100800), + listOf(1u, 6u) to Rational(-159236792977, 2116800), + listOf(2u, 6u) to Rational(-6602528890883, 66679200), + listOf(3u, 6u) to Rational(-1086091664047, 19051200), + listOf(4u, 6u) to Rational(3769375009003, 1680315840), + listOf(5u, 6u) to Rational(-12920385574769, 1050197400), + listOf(6u, 6u) to Rational(-90219591809287, 6301184400), + listOf(7u, 6u) to Rational(656361553391, 1575296100), + listOf(8u, 6u) to Rational(757900793, 2250423), + listOf(0u, 7u) to Rational(-100770017, 15120), + listOf(1u, 7u) to Rational(-316364851, 17640), + listOf(2u, 7u) to Rational(-85118560057, 6667920), + listOf(3u, 7u) to Rational(6286563719, 416745), + listOf(4u, 7u) to Rational(26803885301, 1714608), + listOf(5u, 7u) to Rational(-13767154393, 4286520), + listOf(6u, 7u) to Rational(-3875138933, 1224720), + listOf(7u, 7u) to Rational(65193755, 333396), + listOf(8u, 7u) to Rational(90974351, 2500470), + listOf(0u, 8u) to Rational(-3182197, 1260), + listOf(1u, 8u) to Rational(24899923, 8820), + listOf(2u, 8u) to Rational(-19999556, 19845), + listOf(3u, 8u) to Rational(3276587, 3969), + listOf(4u, 8u) to Rational(13719549239, 5000940), + listOf(5u, 8u) to Rational(-961839938, 1250235), + listOf(6u, 8u) to Rational(-198184871, 833490), + listOf(7u, 8u) to Rational(230659711, 5000940), + listOf(8u, 8u) to Rational(292447, 35721) + ), + NumberedPolynomialAsIs( + listOf() to Rational(9, 100), + listOf(1u) to Rational(-21, 50), + listOf(2u) to Rational(293, 700), + listOf(3u) to Rational(29, 210), + listOf(4u) to Rational(3233, 8820), + listOf(5u) to Rational(-289, 441), + listOf(6u) to Rational(-1, 9), + listOf(7u) to Rational(-20, 441), + listOf(8u) to Rational(100, 441), + listOf(0u, 1u) to Rational(-57, 80), + listOf(1u, 1u) to Rational(-121, 400), + listOf(2u, 1u) to Rational(37117, 8400), + listOf(3u, 1u) to Rational(-4853, 3150), + listOf(4u, 1u) to Rational(1166203, 132300), + listOf(5u, 1u) to Rational(-2708, 567), + listOf(6u, 1u) to Rational(-287159, 416745), + listOf(7u, 1u) to Rational(-478204, 83349), + listOf(8u, 1u) to Rational(176320, 83349), + listOf(0u, 2u) to Rational(-6239, 6400), + listOf(1u, 2u) to Rational(264211, 11200), + listOf(2u, 2u) to Rational(-1591999, 100800), + listOf(3u, 2u) to Rational(12450091, 529200), + listOf(4u, 2u) to Rational(9230759, 226800), + listOf(5u, 2u) to Rational(18995554, 2083725), + listOf(6u, 2u) to Rational(136706258, 6251175), + listOf(7u, 2u) to Rational(-120907496, 3750705), + listOf(8u, 2u) to Rational(117200176, 15752961), + listOf(0u, 3u) to Rational(5653, 320), + listOf(1u, 3u) to Rational(-130853, 8400), + listOf(2u, 3u) to Rational(-20939327, 151200), + listOf(3u, 3u) to Rational(2566691, 25200), + listOf(4u, 3u) to Rational(-68441519, 476280), + listOf(5u, 3u) to Rational(2462904247, 12502350), + listOf(6u, 3u) to Rational(353667161, 18753525), + listOf(7u, 3u) to Rational(-1689134372, 26254935), + listOf(8u, 3u) to Rational(35084104, 2250423), + listOf(0u, 4u) to Rational(-3587, 300), + listOf(1u, 4u) to Rational(-10513243, 33600), + listOf(2u, 4u) to Rational(30766733, 176400), + listOf(3u, 4u) to Rational(-65680021, 198450), + listOf(4u, 4u) to Rational(-8108910547, 20003760), + listOf(5u, 4u) to Rational(2922125159, 6251175), + listOf(6u, 4u) to Rational(-4245279943, 131274675), + listOf(7u, 4u) to Rational(-371946872, 3750705), + listOf(8u, 4u) to Rational(61286752, 2250423), + listOf(0u, 5u) to Rational(-20477, 160), + listOf(1u, 5u) to Rational(215741, 1120), + listOf(2u, 5u) to Rational(30785843, 31752), + listOf(3u, 5u) to Rational(-357495959, 317520), + listOf(4u, 5u) to Rational(-1611242993, 10001880), + listOf(5u, 5u) to Rational(345925495, 500094), + listOf(6u, 5u) to Rational(-755948411, 3750705), + listOf(7u, 5u) to Rational(-108643496, 1250235), + listOf(8u, 5u) to Rational(1122512, 35721), + listOf(0u, 6u) to Rational(358037, 2880), + listOf(1u, 6u) to Rational(3895837, 3360), + listOf(2u, 6u) to Rational(359419201, 1270080), + listOf(3u, 6u) to Rational(-158522587, 105840), + listOf(4u, 6u) to Rational(10909002599, 20003760), + listOf(5u, 6u) to Rational(76846972, 138915), + listOf(6u, 6u) to Rational(-327696553, 1250235), + listOf(7u, 6u) to Rational(-1687328, 35721), + listOf(8u, 6u) to Rational(1016836, 35721), + listOf(0u, 7u) to Rational(658, 3), + listOf(1u, 7u) to Rational(48035, 168), + listOf(2u, 7u) to Rational(-5777875, 5292), + listOf(3u, 7u) to Rational(-7893899, 10584), + listOf(4u, 7u) to Rational(10191652, 11907), + listOf(5u, 7u) to Rational(2920121, 23814), + listOf(6u, 7u) to Rational(-2699780, 11907), + listOf(7u, 7u) to Rational(4556, 441), + listOf(8u, 7u) to Rational(3440, 189), + listOf(0u, 8u) to Rational(64, 1), + listOf(1u, 8u) to Rational(-808, 7), + listOf(2u, 8u) to Rational(-360895, 1764), + listOf(3u, 8u) to Rational(257657, 882), + listOf(4u, 8u) to Rational(3779917, 15876), + listOf(5u, 8u) to Rational(-610279, 3969), + listOf(6u, 8u) to Rational(-25091, 441), + listOf(7u, 8u) to Rational(9560, 567), + listOf(8u, 8u) to Rational(400, 81) + ) + ), + NumberedPolynomialAsIs( + listOf() to Rational(15, 7), + listOf(1u) to Rational(1, 5), + listOf(2u) to Rational(-7, 4), + listOf(0u, 1u) to Rational(-1, 9), + listOf(1u, 1u) to Rational(-2, 7), + listOf(2u, 1u) to Rational(17, 3), + listOf(0u, 2u) to Rational(2, 6), + listOf(1u, 2u) to Rational(-17, 6), + listOf(2u, 2u) to Rational(-6, 2), + ).substitute(RationalField, mapOf( + 0 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(17, 5), + listOf(1u) to Rational(11, 6), + listOf(2u) to Rational(14, 3), + listOf(0u, 1u) to Rational(17, 1), + listOf(1u, 1u) to Rational(12, 3), + listOf(2u, 1u) to Rational(-6, 2), + listOf(0u, 2u) to Rational(17, 1), + listOf(1u, 2u) to Rational(-4, 3), + listOf(2u, 2u) to Rational(2, 6), + ), + NumberedPolynomialAsIs( + listOf() to Rational(3, 5), + listOf(1u) to Rational(3, 5), + listOf(2u) to Rational(3, 7), + listOf(0u, 1u) to Rational(-3, 8), + listOf(1u, 1u) to Rational(-1, 1), + listOf(2u, 1u) to Rational(17, 9), + listOf(0u, 2u) to Rational(-8, 1), + listOf(1u, 2u) to Rational(6, 4), + listOf(2u, 2u) to Rational(10, 9), + ) + ), + 1 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(18, 5), + listOf(1u) to Rational(-17, 5), + listOf(2u) to Rational(-2, 7), + listOf(0u, 1u) to Rational(6, 5), + listOf(1u, 1u) to Rational(-5, 1), + listOf(2u, 1u) to Rational(-9, 1), + listOf(0u, 2u) to Rational(-8, 8), + listOf(1u, 2u) to Rational(2, 7), + listOf(2u, 2u) to Rational(-13, 7), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-4, 8), + listOf(1u) to Rational(15, 9), + listOf(2u) to Rational(-10, 9), + listOf(0u, 1u) to Rational(5, 3), + listOf(1u, 1u) to Rational(4, 1), + listOf(2u, 1u) to Rational(-2, 7), + listOf(0u, 2u) to Rational(2, 2), + listOf(1u, 2u) to Rational(-5, 7), + listOf(2u, 2u) to Rational(-18, 9), + ) + ), + 5 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-2, 9), + listOf(1u) to Rational(-6, 3), + listOf(2u) to Rational(10, 9), + listOf(0u, 1u) to Rational(13, 3), + listOf(1u, 1u) to Rational(-12, 4), + listOf(2u, 1u) to Rational(3, 6), + listOf(0u, 2u) to Rational(2, 9), + listOf(1u, 2u) to Rational(7, 3), + listOf(2u, 2u) to Rational(16, 5), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 2), + listOf(1u) to Rational(6, 2), + listOf(2u) to Rational(2, 7), + listOf(0u, 1u) to Rational(-18, 1), + listOf(1u, 1u) to Rational(-11, 3), + listOf(2u, 1u) to Rational(7, 5), + listOf(0u, 2u) to Rational(8, 1), + listOf(1u, 2u) to Rational(6, 7), + listOf(2u, 2u) to Rational(17, 4), + ) + ) + )), + "test 3'" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-66677, 3500), + listOf(1u) to Rational(-206281, 10500), + listOf(2u) to Rational(-412567, 7056), + listOf(3u) to Rational(-310081, 11025), + listOf(4u) to Rational(-575996, 15435), + listOf(0u, 1u) to Rational(-573701, 4200), + listOf(1u, 1u) to Rational(-2239001, 25200), + listOf(2u, 1u) to Rational(-8817889, 132300), + listOf(3u, 1u) to Rational(2317919, 44100), + listOf(4u, 1u) to Rational(1169471, 6615), + listOf(0u, 2u) to Rational(-4057819, 33600), + listOf(1u, 2u) to Rational(1373311, 12600), + listOf(2u, 2u) to Rational(32433493, 52920), + listOf(3u, 2u) to Rational(4998053, 33075), + listOf(4u, 2u) to Rational(-2147779, 8820), + listOf(0u, 3u) to Rational(2018481, 2240), + listOf(1u, 3u) to Rational(941713, 1440), + listOf(2u, 3u) to Rational(183749, 6615), + listOf(3u, 3u) to Rational(-4631023, 15876), + listOf(4u, 3u) to Rational(25609336, 178605), + listOf(0u, 4u) to Rational(11886431, 6720), + listOf(1u, 4u) to Rational(18433, 504), + listOf(2u, 4u) to Rational(-39613331, 45360), + listOf(3u, 4u) to Rational(681619, 5670), + listOf(4u, 4u) to Rational(-864841, 20412), + listOf(0u, 5u) to Rational(343535, 1008), + listOf(1u, 5u) to Rational(-33583, 72), + listOf(2u, 5u) to Rational(1194625, 9072), + listOf(3u, 5u) to Rational(-62917, 2268), + listOf(4u, 5u) to Rational(157645, 10206), + listOf(0u, 6u) to Rational(-1381, 3), + listOf(1u, 6u) to Rational(919, 36), + listOf(2u, 6u) to Rational(-3053, 36), + listOf(3u, 6u) to Rational(2125, 324), + listOf(4u, 6u) to Rational(-236, 243) + ), + NumberedPolynomialAsIs(listOf() to Rational(0, 1), + listOf() to Rational(1, 4), + listOf(1u) to Rational(-5, 3), + listOf(2u) to Rational(35, 9), + listOf(3u) to Rational(-100, 27), + listOf(4u) to Rational(100, 81), + listOf(0u, 1u) to Rational(-5, 3), + listOf(1u, 1u) to Rational(14, 9), + listOf(2u, 1u) to Rational(1874, 189), + listOf(3u, 1u) to Rational(-620, 63), + listOf(4u, 1u) to Rational(40, 63), + listOf(0u, 2u) to Rational(16, 9), + listOf(1u, 2u) to Rational(365, 21), + listOf(2u, 2u) to Rational(112, 9), + listOf(3u, 2u) to Rational(-464, 63), + listOf(4u, 2u) to Rational(1996, 441), + listOf(0u, 3u) to Rational(10, 3), + listOf(1u, 3u) to Rational(118, 21), + listOf(2u, 3u) to Rational(-272, 21), + listOf(3u, 3u) to Rational(-764, 49), + listOf(4u, 3u) to Rational(8, 7), + listOf(0u, 4u) to Rational(1, 1), + listOf(1u, 4u) to Rational(-10, 7), + listOf(2u, 4u) to Rational(-171, 49), + listOf(3u, 4u) to Rational(20, 7), + listOf(4u, 4u) to Rational(4, 1) + ) + ), + NumberedPolynomialAsIs( + listOf() to Rational(15, 7), + listOf(1u) to Rational(1, 5), + listOf(2u) to Rational(-7, 4), + listOf(0u, 1u) to Rational(-1, 9), + listOf(1u, 1u) to Rational(-2, 7), + listOf(2u, 1u) to Rational(17, 3), + listOf(0u, 2u) to Rational(2, 6), + listOf(1u, 2u) to Rational(-17, 6), + listOf(2u, 2u) to Rational(-6, 2), + ).substitute(RationalField, mapOf( + 0 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(17, 5), + listOf(1u) to Rational(11, 6), + listOf(2u) to Rational(14, 3), + listOf(0u, 1u) to Rational(17, 1), + listOf(1u, 1u) to Rational(12, 3), + listOf(2u, 1u) to Rational(-6, 2), + listOf(0u, 2u) to Rational(17, 1), + listOf(1u, 2u) to Rational(-4, 3), + listOf(2u, 2u) to Rational(2, 6), + ), + NumberedPolynomialAsIs( + listOf() to Rational(3, 5), + listOf(1u) to Rational(3, 5), + listOf(2u) to Rational(3, 7), + listOf(0u, 1u) to Rational(-3, 8), + listOf(1u, 1u) to Rational(-1, 1), + listOf(2u, 1u) to Rational(17, 9), + listOf(0u, 2u) to Rational(-8, 1), + listOf(1u, 2u) to Rational(6, 4), + listOf(2u, 2u) to Rational(10, 9), + ) + ), + )), + "test 4" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-66677, 3500), + listOf(1u) to Rational(-206281, 10500), + listOf(2u) to Rational(-412567, 7056), + listOf(3u) to Rational(-310081, 11025), + listOf(4u) to Rational(-575996, 15435), + listOf(0u, 1u) to Rational(-573701, 4200), + listOf(1u, 1u) to Rational(-2239001, 25200), + listOf(2u, 1u) to Rational(-8817889, 132300), + listOf(3u, 1u) to Rational(2317919, 44100), + listOf(4u, 1u) to Rational(1169471, 6615), + listOf(0u, 2u) to Rational(-4057819, 33600), + listOf(1u, 2u) to Rational(1373311, 12600), + listOf(2u, 2u) to Rational(32433493, 52920), + listOf(3u, 2u) to Rational(4998053, 33075), + listOf(4u, 2u) to Rational(-2147779, 8820), + listOf(0u, 3u) to Rational(2018481, 2240), + listOf(1u, 3u) to Rational(941713, 1440), + listOf(2u, 3u) to Rational(183749, 6615), + listOf(3u, 3u) to Rational(-4631023, 15876), + listOf(4u, 3u) to Rational(25609336, 178605), + listOf(0u, 4u) to Rational(11886431, 6720), + listOf(1u, 4u) to Rational(18433, 504), + listOf(2u, 4u) to Rational(-39613331, 45360), + listOf(3u, 4u) to Rational(681619, 5670), + listOf(4u, 4u) to Rational(-864841, 20412), + listOf(0u, 5u) to Rational(343535, 1008), + listOf(1u, 5u) to Rational(-33583, 72), + listOf(2u, 5u) to Rational(1194625, 9072), + listOf(3u, 5u) to Rational(-62917, 2268), + listOf(4u, 5u) to Rational(157645, 10206), + listOf(0u, 6u) to Rational(-1381, 3), + listOf(1u, 6u) to Rational(919, 36), + listOf(2u, 6u) to Rational(-3053, 36), + listOf(3u, 6u) to Rational(2125, 324), + listOf(4u, 6u) to Rational(-236, 243) + ), + NumberedPolynomialAsIs(listOf() to Rational(0, 1), + listOf() to Rational(1, 4), + listOf(1u) to Rational(-5, 3), + listOf(2u) to Rational(35, 9), + listOf(3u) to Rational(-100, 27), + listOf(4u) to Rational(100, 81), + listOf(0u, 1u) to Rational(-5, 3), + listOf(1u, 1u) to Rational(14, 9), + listOf(2u, 1u) to Rational(1874, 189), + listOf(3u, 1u) to Rational(-620, 63), + listOf(4u, 1u) to Rational(40, 63), + listOf(0u, 2u) to Rational(16, 9), + listOf(1u, 2u) to Rational(365, 21), + listOf(2u, 2u) to Rational(112, 9), + listOf(3u, 2u) to Rational(-464, 63), + listOf(4u, 2u) to Rational(1996, 441), + listOf(0u, 3u) to Rational(10, 3), + listOf(1u, 3u) to Rational(118, 21), + listOf(2u, 3u) to Rational(-272, 21), + listOf(3u, 3u) to Rational(-764, 49), + listOf(4u, 3u) to Rational(8, 7), + listOf(0u, 4u) to Rational(1, 1), + listOf(1u, 4u) to Rational(-10, 7), + listOf(2u, 4u) to Rational(-171, 49), + listOf(3u, 4u) to Rational(20, 7), + listOf(4u, 4u) to Rational(4, 1) + ) + ), + NumberedPolynomialAsIs( + listOf() to Rational(15, 7), + listOf(1u) to Rational(1, 5), + listOf(2u) to Rational(-7, 4), + listOf(0u, 1u) to Rational(-1, 9), + listOf(1u, 1u) to Rational(-2, 7), + listOf(2u, 1u) to Rational(17, 3), + listOf(0u, 2u) to Rational(2, 6), + listOf(1u, 2u) to Rational(-17, 6), + listOf(2u, 2u) to Rational(-6, 2), + ).substitute(RationalField, mapOf( + 0 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(17, 5), + listOf(1u) to Rational(11, 6), + listOf(2u) to Rational(14, 3), + listOf(0u, 1u) to Rational(17, 1), + listOf(1u, 1u) to Rational(12, 3), + listOf(2u, 1u) to Rational(-6, 2), + listOf(0u, 2u) to Rational(17, 1), + listOf(1u, 2u) to Rational(-4, 3), + listOf(2u, 2u) to Rational(2, 6), + ), + NumberedPolynomialAsIs( + listOf() to Rational(3, 5), + listOf(1u) to Rational(3, 5), + listOf(2u) to Rational(3, 7), + listOf(0u, 1u) to Rational(-3, 8), + listOf(1u, 1u) to Rational(-1, 1), + listOf(2u, 1u) to Rational(17, 9), + listOf(0u, 2u) to Rational(-8, 1), + listOf(1u, 2u) to Rational(6, 4), + listOf(2u, 2u) to Rational(10, 9), + ) + ), + 5 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-2, 9), + listOf(1u) to Rational(-6, 3), + listOf(2u) to Rational(10, 9), + listOf(0u, 1u) to Rational(13, 3), + listOf(1u, 1u) to Rational(-12, 4), + listOf(2u, 1u) to Rational(3, 6), + listOf(0u, 2u) to Rational(2, 9), + listOf(1u, 2u) to Rational(7, 3), + listOf(2u, 2u) to Rational(16, 5), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 2), + listOf(1u) to Rational(6, 2), + listOf(2u) to Rational(2, 7), + listOf(0u, 1u) to Rational(-18, 1), + listOf(1u, 1u) to Rational(-11, 3), + listOf(2u, 1u) to Rational(7, 5), + listOf(0u, 2u) to Rational(8, 1), + listOf(1u, 2u) to Rational(6, 7), + listOf(2u, 2u) to Rational(17, 4), + ) + ) + )), + "test 4'" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(3539, 700), + listOf(1u) to Rational(-307079, 6300), + listOf(2u) to Rational(451609, 15120), + listOf(3u) to Rational(35287733, 396900), + listOf(4u) to Rational(-37242617, 396900), + listOf(5u) to Rational(382747, 19845), + listOf(6u) to Rational(-2407, 3969), + listOf(0u, 1u) to Rational(-226, 175), + listOf(1u, 1u) to Rational(-74113, 1890), + listOf(2u, 1u) to Rational(250931, 1764), + listOf(3u, 1u) to Rational(30071473, 99225), + listOf(4u, 1u) to Rational(-286466, 1323), + listOf(5u, 1u) to Rational(-2285282, 9261), + listOf(6u, 1u) to Rational(17900, 441), + listOf(0u, 2u) to Rational(3817, 3150), + listOf(1u, 2u) to Rational(577568, 11025), + listOf(2u, 2u) to Rational(9073553, 99225), + listOf(3u, 2u) to Rational(-1415849, 79380), + listOf(4u, 2u) to Rational(-124715629, 277830), + listOf(5u, 2u) to Rational(-1328953, 1890), + listOf(6u, 2u) to Rational(-297148, 1323), + listOf(0u, 3u) to Rational(6043, 945), + listOf(1u, 3u) to Rational(160381, 6615), + listOf(2u, 3u) to Rational(-673249, 13230), + listOf(3u, 3u) to Rational(-319255, 2058), + listOf(4u, 3u) to Rational(-98144, 1029), + listOf(5u, 3u) to Rational(-320239, 5145), + listOf(6u, 3u) to Rational(400, 147), + listOf(0u, 4u) to Rational(163, 63), + listOf(1u, 4u) to Rational(-25183, 4410), + listOf(2u, 4u) to Rational(-21369, 1372), + listOf(3u, 4u) to Rational(127499, 30870), + listOf(4u, 4u) to Rational(86971, 12348), + listOf(5u, 4u) to Rational(-11129, 1470), + listOf(6u, 4u) to Rational(544, 147) + ), + NumberedPolynomialAsIs(listOf() to Rational(0, 1), + listOf() to Rational(1, 4), + listOf(1u) to Rational(-5, 3), + listOf(2u) to Rational(35, 9), + listOf(3u) to Rational(-100, 27), + listOf(4u) to Rational(100, 81), + listOf(0u, 1u) to Rational(-5, 3), + listOf(1u, 1u) to Rational(14, 9), + listOf(2u, 1u) to Rational(1874, 189), + listOf(3u, 1u) to Rational(-620, 63), + listOf(4u, 1u) to Rational(40, 63), + listOf(0u, 2u) to Rational(16, 9), + listOf(1u, 2u) to Rational(365, 21), + listOf(2u, 2u) to Rational(112, 9), + listOf(3u, 2u) to Rational(-464, 63), + listOf(4u, 2u) to Rational(1996, 441), + listOf(0u, 3u) to Rational(10, 3), + listOf(1u, 3u) to Rational(118, 21), + listOf(2u, 3u) to Rational(-272, 21), + listOf(3u, 3u) to Rational(-764, 49), + listOf(4u, 3u) to Rational(8, 7), + listOf(0u, 4u) to Rational(1, 1), + listOf(1u, 4u) to Rational(-10, 7), + listOf(2u, 4u) to Rational(-171, 49), + listOf(3u, 4u) to Rational(20, 7), + listOf(4u, 4u) to Rational(4, 1) + ) + ), + NumberedPolynomialAsIs( + listOf() to Rational(15, 7), + listOf(1u) to Rational(1, 5), + listOf(2u) to Rational(-7, 4), + listOf(0u, 1u) to Rational(-1, 9), + listOf(1u, 1u) to Rational(-2, 7), + listOf(2u, 1u) to Rational(17, 3), + listOf(0u, 2u) to Rational(2, 6), + listOf(1u, 2u) to Rational(-17, 6), + listOf(2u, 2u) to Rational(-6, 2), + ).substitute(RationalField, mapOf( + 1 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(18, 5), + listOf(1u) to Rational(-17, 5), + listOf(2u) to Rational(-2, 7), + listOf(0u, 1u) to Rational(6, 5), + listOf(1u, 1u) to Rational(-5, 1), + listOf(2u, 1u) to Rational(-9, 1), + listOf(0u, 2u) to Rational(-8, 8), + listOf(1u, 2u) to Rational(2, 7), + listOf(2u, 2u) to Rational(-13, 7), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-4, 8), + listOf(1u) to Rational(15, 9), + listOf(2u) to Rational(-10, 9), + listOf(0u, 1u) to Rational(5, 3), + listOf(1u, 1u) to Rational(4, 1), + listOf(2u, 1u) to Rational(-2, 7), + listOf(0u, 2u) to Rational(2, 2), + listOf(1u, 2u) to Rational(-5, 7), + listOf(2u, 2u) to Rational(-18, 9), + ) + ), + )), + "test 5" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(3539, 700), + listOf(1u) to Rational(-307079, 6300), + listOf(2u) to Rational(451609, 15120), + listOf(3u) to Rational(35287733, 396900), + listOf(4u) to Rational(-37242617, 396900), + listOf(5u) to Rational(382747, 19845), + listOf(6u) to Rational(-2407, 3969), + listOf(0u, 1u) to Rational(-226, 175), + listOf(1u, 1u) to Rational(-74113, 1890), + listOf(2u, 1u) to Rational(250931, 1764), + listOf(3u, 1u) to Rational(30071473, 99225), + listOf(4u, 1u) to Rational(-286466, 1323), + listOf(5u, 1u) to Rational(-2285282, 9261), + listOf(6u, 1u) to Rational(17900, 441), + listOf(0u, 2u) to Rational(3817, 3150), + listOf(1u, 2u) to Rational(577568, 11025), + listOf(2u, 2u) to Rational(9073553, 99225), + listOf(3u, 2u) to Rational(-1415849, 79380), + listOf(4u, 2u) to Rational(-124715629, 277830), + listOf(5u, 2u) to Rational(-1328953, 1890), + listOf(6u, 2u) to Rational(-297148, 1323), + listOf(0u, 3u) to Rational(6043, 945), + listOf(1u, 3u) to Rational(160381, 6615), + listOf(2u, 3u) to Rational(-673249, 13230), + listOf(3u, 3u) to Rational(-319255, 2058), + listOf(4u, 3u) to Rational(-98144, 1029), + listOf(5u, 3u) to Rational(-320239, 5145), + listOf(6u, 3u) to Rational(400, 147), + listOf(0u, 4u) to Rational(163, 63), + listOf(1u, 4u) to Rational(-25183, 4410), + listOf(2u, 4u) to Rational(-21369, 1372), + listOf(3u, 4u) to Rational(127499, 30870), + listOf(4u, 4u) to Rational(86971, 12348), + listOf(5u, 4u) to Rational(-11129, 1470), + listOf(6u, 4u) to Rational(544, 147) + ), + NumberedPolynomialAsIs(listOf() to Rational(0, 1), + listOf() to Rational(1, 4), + listOf(1u) to Rational(-5, 3), + listOf(2u) to Rational(35, 9), + listOf(3u) to Rational(-100, 27), + listOf(4u) to Rational(100, 81), + listOf(0u, 1u) to Rational(-5, 3), + listOf(1u, 1u) to Rational(14, 9), + listOf(2u, 1u) to Rational(1874, 189), + listOf(3u, 1u) to Rational(-620, 63), + listOf(4u, 1u) to Rational(40, 63), + listOf(0u, 2u) to Rational(16, 9), + listOf(1u, 2u) to Rational(365, 21), + listOf(2u, 2u) to Rational(112, 9), + listOf(3u, 2u) to Rational(-464, 63), + listOf(4u, 2u) to Rational(1996, 441), + listOf(0u, 3u) to Rational(10, 3), + listOf(1u, 3u) to Rational(118, 21), + listOf(2u, 3u) to Rational(-272, 21), + listOf(3u, 3u) to Rational(-764, 49), + listOf(4u, 3u) to Rational(8, 7), + listOf(0u, 4u) to Rational(1, 1), + listOf(1u, 4u) to Rational(-10, 7), + listOf(2u, 4u) to Rational(-171, 49), + listOf(3u, 4u) to Rational(20, 7), + listOf(4u, 4u) to Rational(4, 1) + ) + ), + NumberedPolynomialAsIs( + listOf() to Rational(15, 7), + listOf(1u) to Rational(1, 5), + listOf(2u) to Rational(-7, 4), + listOf(0u, 1u) to Rational(-1, 9), + listOf(1u, 1u) to Rational(-2, 7), + listOf(2u, 1u) to Rational(17, 3), + listOf(0u, 2u) to Rational(2, 6), + listOf(1u, 2u) to Rational(-17, 6), + listOf(2u, 2u) to Rational(-6, 2), + ).substitute(RationalField, mapOf( + 1 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(18, 5), + listOf(1u) to Rational(-17, 5), + listOf(2u) to Rational(-2, 7), + listOf(0u, 1u) to Rational(6, 5), + listOf(1u, 1u) to Rational(-5, 1), + listOf(2u, 1u) to Rational(-9, 1), + listOf(0u, 2u) to Rational(-8, 8), + listOf(1u, 2u) to Rational(2, 7), + listOf(2u, 2u) to Rational(-13, 7), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-4, 8), + listOf(1u) to Rational(15, 9), + listOf(2u) to Rational(-10, 9), + listOf(0u, 1u) to Rational(5, 3), + listOf(1u, 1u) to Rational(4, 1), + listOf(2u, 1u) to Rational(-2, 7), + listOf(0u, 2u) to Rational(2, 2), + listOf(1u, 2u) to Rational(-5, 7), + listOf(2u, 2u) to Rational(-18, 9), + ) + ), + 5 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-2, 9), + listOf(1u) to Rational(-6, 3), + listOf(2u) to Rational(10, 9), + listOf(0u, 1u) to Rational(13, 3), + listOf(1u, 1u) to Rational(-12, 4), + listOf(2u, 1u) to Rational(3, 6), + listOf(0u, 2u) to Rational(2, 9), + listOf(1u, 2u) to Rational(7, 3), + listOf(2u, 2u) to Rational(16, 5), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 2), + listOf(1u) to Rational(6, 2), + listOf(2u) to Rational(2, 7), + listOf(0u, 1u) to Rational(-18, 1), + listOf(1u, 1u) to Rational(-11, 3), + listOf(2u, 1u) to Rational(7, 5), + listOf(0u, 2u) to Rational(8, 1), + listOf(1u, 2u) to Rational(6, 7), + listOf(2u, 2u) to Rational(17, 4), + ) + ) + )), + "test 5'" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(15, 7), + listOf(1u) to Rational(1, 5), + listOf(2u) to Rational(-7, 4), + listOf(0u, 1u) to Rational(-1, 9), + listOf(1u, 1u) to Rational(-2, 7), + listOf(2u, 1u) to Rational(17, 3), + listOf(0u, 2u) to Rational(2, 6), + listOf(1u, 2u) to Rational(-17, 6), + listOf(2u, 2u) to Rational(-6, 2), + ), + NumberedPolynomialAsIs(listOf() to Rational(0, 1), + listOf() to Rational(0, 1) + ) + ), + NumberedPolynomialAsIs( + listOf() to Rational(15, 7), + listOf(1u) to Rational(1, 5), + listOf(2u) to Rational(-7, 4), + listOf(0u, 1u) to Rational(-1, 9), + listOf(1u, 1u) to Rational(-2, 7), + listOf(2u, 1u) to Rational(17, 3), + listOf(0u, 2u) to Rational(2, 6), + listOf(1u, 2u) to Rational(-17, 6), + listOf(2u, 2u) to Rational(-6, 2), + ).substitute(RationalField, mapOf>()), + "test 6" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(15, 7), + listOf(1u) to Rational(1, 5), + listOf(2u) to Rational(-7, 4), + listOf(0u, 1u) to Rational(-1, 9), + listOf(1u, 1u) to Rational(-2, 7), + listOf(2u, 1u) to Rational(17, 3), + listOf(0u, 2u) to Rational(2, 6), + listOf(1u, 2u) to Rational(-17, 6), + listOf(2u, 2u) to Rational(-6, 2), + ), + NumberedPolynomialAsIs(listOf() to Rational(0, 1), + listOf() to Rational(0, 1) + ) + ), + NumberedPolynomialAsIs( + listOf() to Rational(15, 7), + listOf(1u) to Rational(1, 5), + listOf(2u) to Rational(-7, 4), + listOf(0u, 1u) to Rational(-1, 9), + listOf(1u, 1u) to Rational(-2, 7), + listOf(2u, 1u) to Rational(17, 3), + listOf(0u, 2u) to Rational(2, 6), + listOf(1u, 2u) to Rational(-17, 6), + listOf(2u, 2u) to Rational(-6, 2), + ).substitute(RationalField, mapOf( + 5 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-2, 9), + listOf(1u) to Rational(-6, 3), + listOf(2u) to Rational(10, 9), + listOf(0u, 1u) to Rational(13, 3), + listOf(1u, 1u) to Rational(-12, 4), + listOf(2u, 1u) to Rational(3, 6), + listOf(0u, 2u) to Rational(2, 9), + listOf(1u, 2u) to Rational(7, 3), + listOf(2u, 2u) to Rational(16, 5), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 2), + listOf(1u) to Rational(6, 2), + listOf(2u) to Rational(2, 7), + listOf(0u, 1u) to Rational(-18, 1), + listOf(1u, 1u) to Rational(-11, 3), + listOf(2u, 1u) to Rational(7, 5), + listOf(0u, 2u) to Rational(8, 1), + listOf(1u, 2u) to Rational(6, 7), + listOf(2u, 2u) to Rational(17, 4), + ) + ) + )), + "test 6'" + ) + } + @Test + @Ignore + fun test_RationalFunction_substitute_Double_Map() { + // TODO + } + @Test + @Ignore + fun test_RationalFunction_substitute_Constant_Map() { + // TODO + } + @Test + @Ignore + fun test_RationalFunction_substitute_Polynomial_Map() { + // TODO + } + @Test + @Ignore // FIXME: This tests work only for sane realisations of the substitutions. Currently, it is not. + // Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should make denominator r^deg(p), + // not r^(deg(p)(deg(p)+1)/2) as it is now. + fun test_RationalFunction_substitute_RationalFunction_Map() { + // TODO + } + @Test + @Ignore + fun test_Polynomial_substitute_Double_Buffer() { + // TODO + } + @Test + @Ignore + fun test_Polynomial_substitute_Constant_Buffer() { + // TODO + } + @Test + @Ignore + fun test_Polynomial_substitute_Polynomial_Buffer() { + // TODO + } + @Test + @Ignore // FIXME: This tests work only for sane realisations of the substitutions. Currently, it is not. + // Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should make denominator r^deg(p), + // not r^(deg(p)(deg(p)+1)/2) as it is now. + fun test_Polynomial_substitute_RationalFunction_Buffer() { + // TODO + } + @Test + @Ignore + fun test_RationalFunction_substitute_Double_Buffer() { + // TODO + } + @Test + @Ignore + fun test_RationalFunction_substitute_Constant_Buffer() { + // TODO + } + @Test + @Ignore + fun test_RationalFunction_substitute_Polynomial_Buffer() { + // TODO + } + @Test + @Ignore // FIXME: This tests work only for sane realisations of the substitutions. Currently, it is not. + // Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should make denominator r^deg(p), + // not r^(deg(p)(deg(p)+1)/2) as it is now. + fun test_RationalFunction_substitute_RationalFunction_Buffer() { + // TODO + } + @Test + @Ignore + fun test_Polynomial_substituteFully_Double_Buffer() { + // TODO + } + @Test + @Ignore + fun test_Polynomial_substituteFully_Constant_Buffer() { + // TODO + } + @Test + @Ignore + fun test_RationalFunction_substituteFully_Double_Buffer() { + // TODO + } + @Test + @Ignore + fun test_RationalFunction_substituteFully_Constant_Buffer() { + // TODO + } + @Test + @Ignore + fun test_Polynomial_derivativeWithRespectTo_variable() { + // TODO + } + @Test + @Ignore + fun test_Polynomial_nthDerivativeWithRespectTo_variable_order() { + // TODO + } + @Test + @Ignore + fun test_Polynomial_nthDerivativeWithRespectTo_variablesAndOrders() { + // TODO + } + @Test + @Ignore + fun test_Polynomial_antiderivativeWithRespectTo_variable() { + // TODO + } + @Test + @Ignore + fun test_Polynomial_nthAntiderivativeWithRespectTo_variable_order() { + // TODO + } + @Test + @Ignore + fun test_Polynomial_nthAntiderivativeWithRespectTo_variablesAndOrders() { + // TODO } } \ No newline at end of file -- 2.34.1 From 672a3c1552332eb8530fbc71a50c72894ddd5073 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sun, 3 Jul 2022 15:47:12 +0300 Subject: [PATCH 091/123] Tests generation for numbered utilities in progress: finish map-wise substitutions. Also: - Upgrade operations on Rational. - Add new assertions. - Changed a bit FIXME comments. --- .../kmath/functions/ListPolynomialUtilTest.kt | 4 +- .../functions/NumberedPolynomialUtilTest.kt | 3248 ++++++++++++++++- .../kscience/kmath/test/misc/Rational.kt | 111 +- .../kscience/kmath/test/misc/assertion.kt | 34 + 4 files changed, 3321 insertions(+), 76 deletions(-) diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt index 314044ba8..9d4f4411b 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt @@ -121,7 +121,7 @@ class ListPolynomialUtilTest { } @Test @Ignore // FIXME: This tests work only for sane realisations of the substitutions. Currently, it is not. - // Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should make denominator r^deg(p), + // Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should return denominator r^deg(p), // not r^(deg(p)(deg(p)+1)/2) as it is now. fun test_Polynomial_substitute_RationalFunction() { assertEquals( @@ -589,7 +589,7 @@ class ListPolynomialUtilTest { } @Test @Ignore // FIXME: This tests work only for sane realisations of the substitutions. Currently, it is not. - // Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should make denominator r^deg(p), + // Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should return denominator r^deg(p), // not r^(deg(p)(deg(p)+1)/2) as it is now. fun test_RationalFunction_substitute_RationalFunction() { assertEquals( diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt index 8ece66145..b6baed6af 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt @@ -7,7 +7,7 @@ package space.kscience.kmath.functions import space.kscience.kmath.test.misc.Rational import space.kscience.kmath.test.misc.RationalField -import space.kscience.kmath.test.misc.assertContentEquals +import space.kscience.kmath.test.misc.assertEquals import kotlin.test.Ignore import kotlin.test.Test import kotlin.test.assertEquals @@ -16,20 +16,20 @@ import kotlin.test.assertEquals class NumberedPolynomialUtilTest { @Test fun test_Polynomial_substitute_Double_Map() { - assertContentEquals( - mapOf(emptyList() to 0.0), + assertEquals( + NumberedPolynomialAsIs(emptyList() to 0.0), NumberedPolynomialAsIs( listOf() to 1.0, listOf(1u) to -2.0, listOf(2u) to 1.0, ).substitute(mapOf( 0 to 1.0 - )).coefficients, + )), 0.001, "test 1" ) - assertContentEquals( - mapOf( + assertEquals( + NumberedPolynomialAsIs( listOf() to 0.8597048543814783, listOf(1u) to 0.22997637465889875, listOf(2u) to 0.32675302591924016, @@ -50,12 +50,12 @@ class NumberedPolynomialUtilTest { listOf(0u, 2u) to 0.2700930201481795, listOf(1u, 2u) to -0.06962351375204712, listOf(2u, 2u) to -0.015206988092131501, - ).substitute(mapOf()).coefficients, + ).substitute(mapOf()), 0.001, "test 2" ) - assertContentEquals( - mapOf( + assertEquals( + NumberedPolynomialAsIs( listOf() to 0.8597048543814783, listOf(1u) to 0.22997637465889875, listOf(2u) to 0.32675302591924016, @@ -78,12 +78,12 @@ class NumberedPolynomialUtilTest { listOf(2u, 2u) to -0.015206988092131501, ).substitute(mapOf( 5 to 0.9211194782050933 - )).coefficients, + )), 0.001, "test 2'" ) - assertContentEquals( - mapOf( + assertEquals( + NumberedPolynomialAsIs( listOf() to 0.8597048543814783, listOf(0u, 1u) to 0.4561746111587508, listOf(0u, 2u) to 0.2700930201481795, @@ -100,12 +100,12 @@ class NumberedPolynomialUtilTest { listOf(2u, 2u) to -0.015206988092131501, ).substitute(mapOf( 0 to 0.0 - )).coefficients, + )), 0.001, "test 3" ) - assertContentEquals( - mapOf( + assertEquals( + NumberedPolynomialAsIs( listOf() to 0.8597048543814783, listOf(0u, 1u) to 0.4561746111587508, listOf(0u, 2u) to 0.2700930201481795, @@ -123,12 +123,12 @@ class NumberedPolynomialUtilTest { ).substitute(mapOf( 0 to 0.0, 5 to 0.9211194782050933 - )).coefficients, + )), 0.001, "test 3'" ) - assertContentEquals( - mapOf( + assertEquals( + NumberedPolynomialAsIs( listOf() to 1.433510890645169, listOf(1u) to 0.6264844682514724, listOf(2u) to 0.8405727903771333, @@ -145,12 +145,12 @@ class NumberedPolynomialUtilTest { listOf(2u, 2u) to -0.015206988092131501, ).substitute(mapOf( 1 to 0.8400458576651112 - )).coefficients, + )), 0.001, "test 4" ) - assertContentEquals( - mapOf( + assertEquals( + NumberedPolynomialAsIs( listOf() to 1.433510890645169, listOf(1u) to 0.6264844682514724, listOf(2u) to 0.8405727903771333, @@ -168,12 +168,12 @@ class NumberedPolynomialUtilTest { ).substitute(mapOf( 1 to 0.8400458576651112, 5 to 0.9211194782050933 - )).coefficients, + )), 0.001, "test 4'" ) - assertContentEquals( - mapOf( + assertEquals( + NumberedPolynomialAsIs( listOf() to 1.934530767358133, ), NumberedPolynomialAsIs( @@ -189,12 +189,12 @@ class NumberedPolynomialUtilTest { ).substitute(mapOf( 0 to 0.4846192734143442, 1 to 0.8400458576651112, - )).coefficients, + )), 0.001, "test 5" ) - assertContentEquals( - mapOf( + assertEquals( + NumberedPolynomialAsIs( listOf() to 1.934530767358133, ), NumberedPolynomialAsIs( @@ -211,7 +211,7 @@ class NumberedPolynomialUtilTest { 0 to 0.4846192734143442, 1 to 0.8400458576651112, 5 to 0.9211194782050933 - )).coefficients, + )), 0.001, "test 5'" ) @@ -1086,7 +1086,7 @@ class NumberedPolynomialUtilTest { } @Test @Ignore // FIXME: This tests work only for sane realisations of the substitutions. Currently, it is not. - // Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should make denominator r^deg(p), + // Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should return denominator r^deg(p), // not r^(deg(p)(deg(p)+1)/2) as it is now. fun test_Polynomial_substitute_RationalFunction_Map() { assertEquals( @@ -2206,26 +2206,3198 @@ class NumberedPolynomialUtilTest { ) } @Test - @Ignore fun test_RationalFunction_substitute_Double_Map() { - // TODO + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs(emptyList() to 0.0), + NumberedPolynomialAsIs(emptyList() to 1.0), + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 1.0, + listOf(1u) to -2.0, + listOf(2u) to 1.0, + ), + NumberedPolynomialAsIs( + listOf() to 1.0, + ) + ).substitute(mapOf( + 0 to 1.0 + )), + 0.001, + "test 1" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 6.593754860231304, + listOf(1u) to -7.853302571550634, + listOf(2u) to 1.2265042281530025, + listOf(0u, 1u) to 3.762648877294904, + listOf(1u, 1u) to -8.945144619305292, + listOf(2u, 1u) to -5.141384718042281, + listOf(0u, 2u) to 7.359794483988782, + listOf(1u, 2u) to -4.3526172680518815, + listOf(2u, 2u) to 0.907910924854372, + ), + NumberedPolynomialAsIs( + listOf() to 9.533292132172562, + listOf(1u) to -1.982814534018857, + listOf(2u) to -5.974248303415283, + listOf(0u, 1u) to 1.5876716499288879, + listOf(1u, 1u) to -7.535152566659664, + listOf(2u, 1u) to 0.7549300500153517, + listOf(0u, 2u) to -5.242030058021028, + listOf(1u, 2u) to -0.7265704289690582, + listOf(2u, 2u) to -7.139677818189821, + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 6.593754860231304, + listOf(1u) to -7.853302571550634, + listOf(2u) to 1.2265042281530025, + listOf(0u, 1u) to 3.762648877294904, + listOf(1u, 1u) to -8.945144619305292, + listOf(2u, 1u) to -5.141384718042281, + listOf(0u, 2u) to 7.359794483988782, + listOf(1u, 2u) to -4.3526172680518815, + listOf(2u, 2u) to 0.907910924854372, + ), + NumberedPolynomialAsIs( + listOf() to 9.533292132172562, + listOf(1u) to -1.982814534018857, + listOf(2u) to -5.974248303415283, + listOf(0u, 1u) to 1.5876716499288879, + listOf(1u, 1u) to -7.535152566659664, + listOf(2u, 1u) to 0.7549300500153517, + listOf(0u, 2u) to -5.242030058021028, + listOf(1u, 2u) to -0.7265704289690582, + listOf(2u, 2u) to -7.139677818189821, + ) + ).substitute(mapOf()), + 0.001, + "test 2" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 6.593754860231304, + listOf(1u) to -7.853302571550634, + listOf(2u) to 1.2265042281530025, + listOf(0u, 1u) to 3.762648877294904, + listOf(1u, 1u) to -8.945144619305292, + listOf(2u, 1u) to -5.141384718042281, + listOf(0u, 2u) to 7.359794483988782, + listOf(1u, 2u) to -4.3526172680518815, + listOf(2u, 2u) to 0.907910924854372, + ), + NumberedPolynomialAsIs( + listOf() to 9.533292132172562, + listOf(1u) to -1.982814534018857, + listOf(2u) to -5.974248303415283, + listOf(0u, 1u) to 1.5876716499288879, + listOf(1u, 1u) to -7.535152566659664, + listOf(2u, 1u) to 0.7549300500153517, + listOf(0u, 2u) to -5.242030058021028, + listOf(1u, 2u) to -0.7265704289690582, + listOf(2u, 2u) to -7.139677818189821, + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 6.593754860231304, + listOf(1u) to -7.853302571550634, + listOf(2u) to 1.2265042281530025, + listOf(0u, 1u) to 3.762648877294904, + listOf(1u, 1u) to -8.945144619305292, + listOf(2u, 1u) to -5.141384718042281, + listOf(0u, 2u) to 7.359794483988782, + listOf(1u, 2u) to -4.3526172680518815, + listOf(2u, 2u) to 0.907910924854372, + ), + NumberedPolynomialAsIs( + listOf() to 9.533292132172562, + listOf(1u) to -1.982814534018857, + listOf(2u) to -5.974248303415283, + listOf(0u, 1u) to 1.5876716499288879, + listOf(1u, 1u) to -7.535152566659664, + listOf(2u, 1u) to 0.7549300500153517, + listOf(0u, 2u) to -5.242030058021028, + listOf(1u, 2u) to -0.7265704289690582, + listOf(2u, 2u) to -7.139677818189821, + ) + ).substitute(mapOf( + 5 to 0.9211194782050933 + )), + 0.001, + "test 2'" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 151.1502229133916, + listOf(0u, 1u) to -262.3790170577034, + listOf(0u, 2u) to 102.5097937392923, + ), + NumberedPolynomialAsIs( + listOf() to -367.9969733169944, + listOf(0u, 1u) to 112.4911133334554, + listOf(0u, 2u) to -469.755906895345, + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 6.593754860231304, + listOf(1u) to -7.853302571550634, + listOf(2u) to 1.2265042281530025, + listOf(0u, 1u) to 3.762648877294904, + listOf(1u, 1u) to -8.945144619305292, + listOf(2u, 1u) to -5.141384718042281, + listOf(0u, 2u) to 7.359794483988782, + listOf(1u, 2u) to -4.3526172680518815, + listOf(2u, 2u) to 0.907910924854372, + ), + NumberedPolynomialAsIs( + listOf() to 9.533292132172562, + listOf(1u) to -1.982814534018857, + listOf(2u) to -5.974248303415283, + listOf(0u, 1u) to 1.5876716499288879, + listOf(1u, 1u) to -7.535152566659664, + listOf(2u, 1u) to 0.7549300500153517, + listOf(0u, 2u) to -5.242030058021028, + listOf(1u, 2u) to -0.7265704289690582, + listOf(2u, 2u) to -7.139677818189821, + ) + ).substitute(mapOf( + 0 to -8.11707689492641, + )), + 0.001, + "test 3" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 151.1502229133916, + listOf(0u, 1u) to -262.3790170577034, + listOf(0u, 2u) to 102.5097937392923, + ), + NumberedPolynomialAsIs( + listOf() to -367.9969733169944, + listOf(0u, 1u) to 112.4911133334554, + listOf(0u, 2u) to -469.755906895345, + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 6.593754860231304, + listOf(1u) to -7.853302571550634, + listOf(2u) to 1.2265042281530025, + listOf(0u, 1u) to 3.762648877294904, + listOf(1u, 1u) to -8.945144619305292, + listOf(2u, 1u) to -5.141384718042281, + listOf(0u, 2u) to 7.359794483988782, + listOf(1u, 2u) to -4.3526172680518815, + listOf(2u, 2u) to 0.907910924854372, + ), + NumberedPolynomialAsIs( + listOf() to 9.533292132172562, + listOf(1u) to -1.982814534018857, + listOf(2u) to -5.974248303415283, + listOf(0u, 1u) to 1.5876716499288879, + listOf(1u, 1u) to -7.535152566659664, + listOf(2u, 1u) to 0.7549300500153517, + listOf(0u, 2u) to -5.242030058021028, + listOf(1u, 2u) to -0.7265704289690582, + listOf(2u, 2u) to -7.139677818189821, + ) + ).substitute(mapOf( + 0 to -8.11707689492641, + 5 to 0.9211194782050933 + )), + 0.001, + "test 3'" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 14.24074356896978, + listOf(1u) to -17.71987055153461, + listOf(2u) to -2.288056483312383, + ), + NumberedPolynomialAsIs( + listOf() to 7.480604285873397, + listOf(1u) to -8.43478016688617, + listOf(2u) to -9.88934943900592, + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 6.593754860231304, + listOf(1u) to -7.853302571550634, + listOf(2u) to 1.2265042281530025, + listOf(0u, 1u) to 3.762648877294904, + listOf(1u, 1u) to -8.945144619305292, + listOf(2u, 1u) to -5.141384718042281, + listOf(0u, 2u) to 7.359794483988782, + listOf(1u, 2u) to -4.3526172680518815, + listOf(2u, 2u) to 0.907910924854372, + ), + NumberedPolynomialAsIs( + listOf() to 9.533292132172562, + listOf(1u) to -1.982814534018857, + listOf(2u) to -5.974248303415283, + listOf(0u, 1u) to 1.5876716499288879, + listOf(1u, 1u) to -7.535152566659664, + listOf(2u, 1u) to 0.7549300500153517, + listOf(0u, 2u) to -5.242030058021028, + listOf(1u, 2u) to -0.7265704289690582, + listOf(2u, 2u) to -7.139677818189821, + ) + ).substitute(mapOf( + 1 to 0.795265651276015, + )), + 0.001, + "test 4" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 14.24074356896978, + listOf(1u) to -17.71987055153461, + listOf(2u) to -2.288056483312383, + ), + NumberedPolynomialAsIs( + listOf() to 7.480604285873397, + listOf(1u) to -8.43478016688617, + listOf(2u) to -9.88934943900592, + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 6.593754860231304, + listOf(1u) to -7.853302571550634, + listOf(2u) to 1.2265042281530025, + listOf(0u, 1u) to 3.762648877294904, + listOf(1u, 1u) to -8.945144619305292, + listOf(2u, 1u) to -5.141384718042281, + listOf(0u, 2u) to 7.359794483988782, + listOf(1u, 2u) to -4.3526172680518815, + listOf(2u, 2u) to 0.907910924854372, + ), + NumberedPolynomialAsIs( + listOf() to 9.533292132172562, + listOf(1u) to -1.982814534018857, + listOf(2u) to -5.974248303415283, + listOf(0u, 1u) to 1.5876716499288879, + listOf(1u, 1u) to -7.535152566659664, + listOf(2u, 1u) to 0.7549300500153517, + listOf(0u, 2u) to -5.242030058021028, + listOf(1u, 2u) to -0.7265704289690582, + listOf(2u, 2u) to -7.139677818189821, + ) + ).substitute(mapOf( + 1 to 0.795265651276015, + 5 to 0.9211194782050933 + )), + 0.001, + "test 4'" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 7.321261307532708, + ), + NumberedPolynomialAsIs( + listOf() to -575.6325831127576, + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 6.593754860231304, + listOf(1u) to -7.853302571550634, + listOf(2u) to 1.2265042281530025, + listOf(0u, 1u) to 3.762648877294904, + listOf(1u, 1u) to -8.945144619305292, + listOf(2u, 1u) to -5.141384718042281, + listOf(0u, 2u) to 7.359794483988782, + listOf(1u, 2u) to -4.3526172680518815, + listOf(2u, 2u) to 0.907910924854372, + ), + NumberedPolynomialAsIs( + listOf() to 9.533292132172562, + listOf(1u) to -1.982814534018857, + listOf(2u) to -5.974248303415283, + listOf(0u, 1u) to 1.5876716499288879, + listOf(1u, 1u) to -7.535152566659664, + listOf(2u, 1u) to 0.7549300500153517, + listOf(0u, 2u) to -5.242030058021028, + listOf(1u, 2u) to -0.7265704289690582, + listOf(2u, 2u) to -7.139677818189821, + ) + ).substitute(mapOf( + 0 to -8.11707689492641, + 1 to 0.795265651276015, + )), + 0.001, + "test 5" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 7.321261307532708, + ), + NumberedPolynomialAsIs( + listOf() to -575.6325831127576, + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 6.593754860231304, + listOf(1u) to -7.853302571550634, + listOf(2u) to 1.2265042281530025, + listOf(0u, 1u) to 3.762648877294904, + listOf(1u, 1u) to -8.945144619305292, + listOf(2u, 1u) to -5.141384718042281, + listOf(0u, 2u) to 7.359794483988782, + listOf(1u, 2u) to -4.3526172680518815, + listOf(2u, 2u) to 0.907910924854372, + ), + NumberedPolynomialAsIs( + listOf() to 9.533292132172562, + listOf(1u) to -1.982814534018857, + listOf(2u) to -5.974248303415283, + listOf(0u, 1u) to 1.5876716499288879, + listOf(1u, 1u) to -7.535152566659664, + listOf(2u, 1u) to 0.7549300500153517, + listOf(0u, 2u) to -5.242030058021028, + listOf(1u, 2u) to -0.7265704289690582, + listOf(2u, 2u) to -7.139677818189821, + ) + ).substitute(mapOf( + 0 to -8.11707689492641, + 1 to 0.795265651276015, + 5 to 0.9211194782050933 + )), + 0.001, + "test 5'" + ) } @Test - @Ignore fun test_RationalFunction_substitute_Constant_Map() { - // TODO + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(0) + ), + NumberedPolynomialAsIs( + listOf() to Rational(1) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1) + ), + NumberedPolynomialAsIs( + listOf() to Rational(1) + ) + ).substitute(RationalField, mapOf( + 0 to Rational(1) + )), + "test 1" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(22047, 2450), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-2204953, 147000), + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 5), + listOf(1u) to Rational(-18, 4), + listOf(2u) to Rational(9, 8), + listOf(0u, 1u) to Rational(-11, 6), + listOf(1u, 1u) to Rational(-16, 3), + listOf(2u, 1u) to Rational(12, 2), + listOf(0u, 2u) to Rational(5, 3), + listOf(1u, 2u) to Rational(17, 8), + listOf(2u, 2u) to Rational(1, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(11, 1), + listOf(1u) to Rational(4, 1), + listOf(2u) to Rational(-18, 3), + listOf(0u, 1u) to Rational(12, 9), + listOf(1u, 1u) to Rational(14, 7), + listOf(2u, 1u) to Rational(-17, 5), + listOf(0u, 2u) to Rational(-4, 1), + listOf(1u, 2u) to Rational(-5, 5), + listOf(2u, 2u) to Rational(-7, 8), + ) + ).substitute(RationalField, mapOf( + 0 to Rational(7, 5), + 1 to Rational(-13, 7), + )), + "test 2" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(22047, 2450), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-2204953, 147000), + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 5), + listOf(1u) to Rational(-18, 4), + listOf(2u) to Rational(9, 8), + listOf(0u, 1u) to Rational(-11, 6), + listOf(1u, 1u) to Rational(-16, 3), + listOf(2u, 1u) to Rational(12, 2), + listOf(0u, 2u) to Rational(5, 3), + listOf(1u, 2u) to Rational(17, 8), + listOf(2u, 2u) to Rational(1, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(11, 1), + listOf(1u) to Rational(4, 1), + listOf(2u) to Rational(-18, 3), + listOf(0u, 1u) to Rational(12, 9), + listOf(1u, 1u) to Rational(14, 7), + listOf(2u, 1u) to Rational(-17, 5), + listOf(0u, 2u) to Rational(-4, 1), + listOf(1u, 2u) to Rational(-5, 5), + listOf(2u, 2u) to Rational(-7, 8), + ) + ).substitute(RationalField, mapOf( + 0 to Rational(7, 5), + 1 to Rational(-13, 7), + 5 to Rational(-16, 4), + )), + "test 2'" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(4191, 490), + listOf(1u) to Rational(14975, 1176), + listOf(2u) to Rational(-10429, 1176) + ), + NumberedPolynomialAsIs( + listOf() to Rational(-775, 147), + listOf(1u) to Rational(-155, 49), + listOf(2u) to Rational(-757, 280) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 5), + listOf(1u) to Rational(-18, 4), + listOf(2u) to Rational(9, 8), + listOf(0u, 1u) to Rational(-11, 6), + listOf(1u, 1u) to Rational(-16, 3), + listOf(2u, 1u) to Rational(12, 2), + listOf(0u, 2u) to Rational(5, 3), + listOf(1u, 2u) to Rational(17, 8), + listOf(2u, 2u) to Rational(1, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(11, 1), + listOf(1u) to Rational(4, 1), + listOf(2u) to Rational(-18, 3), + listOf(0u, 1u) to Rational(12, 9), + listOf(1u, 1u) to Rational(14, 7), + listOf(2u, 1u) to Rational(-17, 5), + listOf(0u, 2u) to Rational(-4, 1), + listOf(1u, 2u) to Rational(-5, 5), + listOf(2u, 2u) to Rational(-7, 8), + ) + ).substitute(RationalField, mapOf( + 1 to Rational(-13, 7), + )), + "test 3" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(4191, 490), + listOf(1u) to Rational(14975, 1176), + listOf(2u) to Rational(-10429, 1176) + ), + NumberedPolynomialAsIs( + listOf() to Rational(-775, 147), + listOf(1u) to Rational(-155, 49), + listOf(2u) to Rational(-757, 280) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 5), + listOf(1u) to Rational(-18, 4), + listOf(2u) to Rational(9, 8), + listOf(0u, 1u) to Rational(-11, 6), + listOf(1u, 1u) to Rational(-16, 3), + listOf(2u, 1u) to Rational(12, 2), + listOf(0u, 2u) to Rational(5, 3), + listOf(1u, 2u) to Rational(17, 8), + listOf(2u, 2u) to Rational(1, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(11, 1), + listOf(1u) to Rational(4, 1), + listOf(2u) to Rational(-18, 3), + listOf(0u, 1u) to Rational(12, 9), + listOf(1u, 1u) to Rational(14, 7), + listOf(2u, 1u) to Rational(-17, 5), + listOf(0u, 2u) to Rational(-4, 1), + listOf(1u, 2u) to Rational(-5, 5), + listOf(2u, 2u) to Rational(-7, 8), + ) + ).substitute(RationalField, mapOf( + 1 to Rational(-13, 7), + 5 to Rational(-16, 4), + )), + "test 3'" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-939, 200), + listOf(0u, 1u) to Rational(123, 50), + listOf(0u, 2u) to Rational(1059, 200) + ), + NumberedPolynomialAsIs( + listOf() to Rational(121, 25), + listOf(0u, 1u) to Rational(-949, 375), + listOf(0u, 2u) to Rational(-1423, 200) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 5), + listOf(1u) to Rational(-18, 4), + listOf(2u) to Rational(9, 8), + listOf(0u, 1u) to Rational(-11, 6), + listOf(1u, 1u) to Rational(-16, 3), + listOf(2u, 1u) to Rational(12, 2), + listOf(0u, 2u) to Rational(5, 3), + listOf(1u, 2u) to Rational(17, 8), + listOf(2u, 2u) to Rational(1, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(11, 1), + listOf(1u) to Rational(4, 1), + listOf(2u) to Rational(-18, 3), + listOf(0u, 1u) to Rational(12, 9), + listOf(1u, 1u) to Rational(14, 7), + listOf(2u, 1u) to Rational(-17, 5), + listOf(0u, 2u) to Rational(-4, 1), + listOf(1u, 2u) to Rational(-5, 5), + listOf(2u, 2u) to Rational(-7, 8), + ) + ).substitute(RationalField, mapOf( + 0 to Rational(7, 5), + )), + "test 4" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-939, 200), + listOf(0u, 1u) to Rational(123, 50), + listOf(0u, 2u) to Rational(1059, 200) + ), + NumberedPolynomialAsIs( + listOf() to Rational(121, 25), + listOf(0u, 1u) to Rational(-949, 375), + listOf(0u, 2u) to Rational(-1423, 200) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 5), + listOf(1u) to Rational(-18, 4), + listOf(2u) to Rational(9, 8), + listOf(0u, 1u) to Rational(-11, 6), + listOf(1u, 1u) to Rational(-16, 3), + listOf(2u, 1u) to Rational(12, 2), + listOf(0u, 2u) to Rational(5, 3), + listOf(1u, 2u) to Rational(17, 8), + listOf(2u, 2u) to Rational(1, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(11, 1), + listOf(1u) to Rational(4, 1), + listOf(2u) to Rational(-18, 3), + listOf(0u, 1u) to Rational(12, 9), + listOf(1u, 1u) to Rational(14, 7), + listOf(2u, 1u) to Rational(-17, 5), + listOf(0u, 2u) to Rational(-4, 1), + listOf(1u, 2u) to Rational(-5, 5), + listOf(2u, 2u) to Rational(-7, 8), + ) + ).substitute(RationalField, mapOf( + 0 to Rational(7, 5), + 5 to Rational(-16, 4), + )), + "test 4'" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 5), + listOf(1u) to Rational(-18, 4), + listOf(2u) to Rational(9, 8), + listOf(0u, 1u) to Rational(-11, 6), + listOf(1u, 1u) to Rational(-16, 3), + listOf(2u, 1u) to Rational(12, 2), + listOf(0u, 2u) to Rational(5, 3), + listOf(1u, 2u) to Rational(17, 8), + listOf(2u, 2u) to Rational(1, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(11, 1), + listOf(1u) to Rational(4, 1), + listOf(2u) to Rational(-18, 3), + listOf(0u, 1u) to Rational(12, 9), + listOf(1u, 1u) to Rational(14, 7), + listOf(2u, 1u) to Rational(-17, 5), + listOf(0u, 2u) to Rational(-4, 1), + listOf(1u, 2u) to Rational(-5, 5), + listOf(2u, 2u) to Rational(-7, 8), + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 5), + listOf(1u) to Rational(-18, 4), + listOf(2u) to Rational(9, 8), + listOf(0u, 1u) to Rational(-11, 6), + listOf(1u, 1u) to Rational(-16, 3), + listOf(2u, 1u) to Rational(12, 2), + listOf(0u, 2u) to Rational(5, 3), + listOf(1u, 2u) to Rational(17, 8), + listOf(2u, 2u) to Rational(1, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(11, 1), + listOf(1u) to Rational(4, 1), + listOf(2u) to Rational(-18, 3), + listOf(0u, 1u) to Rational(12, 9), + listOf(1u, 1u) to Rational(14, 7), + listOf(2u, 1u) to Rational(-17, 5), + listOf(0u, 2u) to Rational(-4, 1), + listOf(1u, 2u) to Rational(-5, 5), + listOf(2u, 2u) to Rational(-7, 8), + ) + ).substitute(RationalField, mapOf()), + "test 5" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 5), + listOf(1u) to Rational(-18, 4), + listOf(2u) to Rational(9, 8), + listOf(0u, 1u) to Rational(-11, 6), + listOf(1u, 1u) to Rational(-16, 3), + listOf(2u, 1u) to Rational(12, 2), + listOf(0u, 2u) to Rational(5, 3), + listOf(1u, 2u) to Rational(17, 8), + listOf(2u, 2u) to Rational(1, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(11, 1), + listOf(1u) to Rational(4, 1), + listOf(2u) to Rational(-18, 3), + listOf(0u, 1u) to Rational(12, 9), + listOf(1u, 1u) to Rational(14, 7), + listOf(2u, 1u) to Rational(-17, 5), + listOf(0u, 2u) to Rational(-4, 1), + listOf(1u, 2u) to Rational(-5, 5), + listOf(2u, 2u) to Rational(-7, 8), + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 5), + listOf(1u) to Rational(-18, 4), + listOf(2u) to Rational(9, 8), + listOf(0u, 1u) to Rational(-11, 6), + listOf(1u, 1u) to Rational(-16, 3), + listOf(2u, 1u) to Rational(12, 2), + listOf(0u, 2u) to Rational(5, 3), + listOf(1u, 2u) to Rational(17, 8), + listOf(2u, 2u) to Rational(1, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(11, 1), + listOf(1u) to Rational(4, 1), + listOf(2u) to Rational(-18, 3), + listOf(0u, 1u) to Rational(12, 9), + listOf(1u, 1u) to Rational(14, 7), + listOf(2u, 1u) to Rational(-17, 5), + listOf(0u, 2u) to Rational(-4, 1), + listOf(1u, 2u) to Rational(-5, 5), + listOf(2u, 2u) to Rational(-7, 8), + ) + ).substitute(RationalField, mapOf( + 5 to Rational(-16, 4), + )), + "test 5'" + ) } @Test - @Ignore fun test_RationalFunction_substitute_Polynomial_Map() { - // TODO + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(0) + ), + NumberedPolynomialAsIs( + listOf() to Rational(1) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1) + ), + NumberedPolynomialAsIs( + listOf() to Rational(1) + ) + ).substitute(RationalField, mapOf( + 0 to NumberedPolynomialAsIs( + listOf() to Rational(1) + ) + )), + "test 1" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(5, 6), + listOf(1u) to Rational(211, 4), + listOf(2u) to Rational(88, 3), + listOf(3u) to Rational(-63, 8), + listOf(4u) to Rational(441, 16), + listOf(0u, 1u) to Rational(-671, 15), + listOf(1u, 1u) to Rational(-551, 21), + listOf(2u, 1u) to Rational(279, 25), + listOf(3u, 1u) to Rational(231, 20), + listOf(0u, 2u) to Rational(-1436, 1575), + listOf(1u, 2u) to Rational(2471, 250), + listOf(2u, 2u) to Rational(-4919, 100), + listOf(0u, 3u) to Rational(-1464, 125), + listOf(1u, 3u) to Rational(-264, 25), + listOf(0u, 4u) to Rational(576, 25), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-11, 9), + listOf(1u) to Rational(-9, 4), + listOf(2u) to Rational(943, 8), + listOf(3u) to Rational(117, 8), + listOf(4u) to Rational(147, 16), + listOf(0u, 1u) to Rational(289, 90), + listOf(1u, 1u) to Rational(-2692, 15), + listOf(2u, 1u) to Rational(-1629, 140), + listOf(3u, 1u) to Rational(77, 20), + listOf(0u, 2u) to Rational(6187, 75), + listOf(1u, 2u) to Rational(-2879, 175), + listOf(2u, 2u) to Rational(-4919, 300), + listOf(0u, 3u) to Rational(336, 25), + listOf(1u, 3u) to Rational(-88, 25), + listOf(0u, 4u) to Rational(192, 25), + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(5, 6), + listOf(1u) to Rational(1, 6), + listOf(2u) to Rational(-2, 9), + listOf(0u, 1u) to Rational(15, 1), + listOf(1u, 1u) to Rational(18, 7), + listOf(2u, 1u) to Rational(2, 5), + listOf(0u, 2u) to Rational(12, 9), + listOf(1u, 2u) to Rational(-3, 5), + listOf(2u, 2u) to Rational(4, 4), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-11, 9), + listOf(1u) to Rational(4, 9), + listOf(2u) to Rational(11, 6), + listOf(0u, 1u) to Rational(-5, 6), + listOf(1u, 1u) to Rational(4, 6), + listOf(2u, 1u) to Rational(-1, 7), + listOf(0u, 2u) to Rational(9, 1), + listOf(1u, 2u) to Rational(6, 7), + listOf(2u, 2u) to Rational(1, 3), + ) + ).substitute(RationalField, mapOf( + 0 to NumberedPolynomialAsIs( + listOf(1u) to Rational(3, 2), + listOf(0u, 1u) to Rational(8, 5), + ), + 1 to NumberedPolynomialAsIs( + listOf(1u) to Rational(7, 2), + listOf(0u, 1u) to Rational(-3, 1), + ) + )), + "test 2" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(1202861, 210), + listOf(1u) to Rational(-215117, 45), + listOf(2u) to Rational(10889651, 19845), + listOf(3u) to Rational(-3503956, 6615), + listOf(4u) to Rational(809066, 2205), + listOf(5u) to Rational(-9056, 735), + listOf(6u) to Rational(5396, 315), + listOf(7u) to Rational(-752, 147), + listOf(8u) to Rational(16, 49), + listOf(0u, 1u) to Rational(1738469, 1470), + listOf(1u, 1u) to Rational(-926238703, 52920), + listOf(2u, 1u) to Rational(-44113982, 6615), + listOf(3u, 1u) to Rational(10423519, 5292), + listOf(4u, 1u) to Rational(3769712, 2205), + listOf(5u, 1u) to Rational(8905046, 6615), + listOf(6u, 1u) to Rational(1186972, 6615), + listOf(7u, 1u) to Rational(22124, 441), + listOf(8u, 1u) to Rational(-1504, 147), + listOf(0u, 2u) to Rational(-54723628, 2205), + listOf(1u, 2u) to Rational(70109407, 1323), + listOf(2u, 2u) to Rational(151072591, 17640), + listOf(3u, 2u) to Rational(1216428107, 52920), + listOf(4u, 2u) to Rational(2587873193, 317520), + listOf(5u, 2u) to Rational(393536369, 79380), + listOf(6u, 2u) to Rational(137614937, 79380), + listOf(7u, 2u) to Rational(566866, 1323), + listOf(8u, 2u) to Rational(41848, 441), + listOf(0u, 3u) to Rational(-19470406, 2205), + listOf(1u, 3u) to Rational(72514195, 882), + listOf(2u, 3u) to Rational(-78090707, 1764), + listOf(3u, 3u) to Rational(-1988237707, 26460), + listOf(4u, 3u) to Rational(-802137919, 17640), + listOf(5u, 3u) to Rational(-139989463, 5880), + listOf(6u, 3u) to Rational(-26066641, 3780), + listOf(7u, 3u) to Rational(-2363369, 1323), + listOf(8u, 3u) to Rational(-108280, 441), + listOf(0u, 4u) to Rational(14878516, 441), + listOf(1u, 4u) to Rational(-253416724, 2205), + listOf(2u, 4u) to Rational(16699157, 840), + listOf(3u, 4u) to Rational(-105220979, 13230), + listOf(4u, 4u) to Rational(208266383, 5880), + listOf(5u, 4u) to Rational(650135309, 26460), + listOf(6u, 4u) to Rational(123808663, 11760), + listOf(7u, 4u) to Rational(8563385, 2646), + listOf(8u, 4u) to Rational(19721, 49), + listOf(0u, 5u) to Rational(675645, 49), + listOf(1u, 5u) to Rational(-70554077, 588), + listOf(2u, 5u) to Rational(157884029, 980), + listOf(3u, 5u) to Rational(489548623, 4410), + listOf(4u, 5u) to Rational(148540519, 17640), + listOf(5u, 5u) to Rational(-5559551, 392), + listOf(6u, 5u) to Rational(-18335711, 1470), + listOf(7u, 5u) to Rational(-38437, 9), + listOf(8u, 5u) to Rational(-29620, 63), + listOf(0u, 6u) to Rational(-727625, 49), + listOf(1u, 6u) to Rational(7046685, 98), + listOf(2u, 6u) to Rational(-334814231, 7056), + listOf(3u, 6u) to Rational(-243971737, 17640), + listOf(4u, 6u) to Rational(-571116659, 35280), + listOf(5u, 6u) to Rational(567538, 315), + listOf(6u, 6u) to Rational(3199768, 315), + listOf(7u, 6u) to Rational(227744, 63), + listOf(8u, 6u) to Rational(23116, 63), + listOf(0u, 7u) to Rational(-27500, 7), + listOf(1u, 7u) to Rational(120125, 3), + listOf(2u, 7u) to Rational(-279200, 3), + listOf(3u, 7u) to Rational(-100160, 7), + listOf(4u, 7u) to Rational(920452, 21), + listOf(5u, 7u) to Rational(226481, 21), + listOf(6u, 7u) to Rational(-34428, 7), + listOf(7u, 7u) to Rational(-6232, 3), + listOf(8u, 7u) to Rational(-608, 3), + listOf(0u, 8u) to Rational(2500, 1), + listOf(1u, 8u) to Rational(-19000, 1), + listOf(2u, 8u) to Rational(37900, 1), + listOf(3u, 8u) to Rational(-1840, 1), + listOf(4u, 8u) to Rational(-17876, 1), + listOf(5u, 8u) to Rational(-1240, 1), + listOf(6u, 8u) to Rational(2788, 1), + listOf(7u, 8u) to Rational(800, 1), + listOf(8u, 8u) to Rational(64, 1) + ), + NumberedPolynomialAsIs( + listOf() to Rational(162487, 63), + listOf(1u) to Rational(-92713, 54), + listOf(2u) to Rational(802436, 1323), + listOf(3u) to Rational(-55088, 441), + listOf(4u) to Rational(1404034, 9261), + listOf(5u) to Rational(-5804, 1029), + listOf(6u) to Rational(51556, 9261), + listOf(7u) to Rational(-752, 441), + listOf(8u) to Rational(16, 147), + listOf(0u, 1u) to Rational(296071, 441), + listOf(1u, 1u) to Rational(-4991281, 882), + listOf(2u, 1u) to Rational(-18702811, 9261), + listOf(3u, 1u) to Rational(40759043, 27783), + listOf(4u, 1u) to Rational(19768501, 27783), + listOf(5u, 1u) to Rational(14307337, 27783), + listOf(6u, 1u) to Rational(1655684, 27783), + listOf(7u, 1u) to Rational(22124, 1323), + listOf(8u, 1u) to Rational(-1504, 441), + listOf(0u, 2u) to Rational(-27667474, 3087), + listOf(1u, 2u) to Rational(265605901, 12348), + listOf(2u, 2u) to Rational(160360775, 98784), + listOf(3u, 2u) to Rational(1169992093, 148176), + listOf(4u, 2u) to Rational(3978014077, 1333584), + listOf(5u, 2u) to Rational(567058123, 333396), + listOf(6u, 2u) to Rational(205132579, 333396), + listOf(7u, 2u) to Rational(566866, 3969), + listOf(8u, 2u) to Rational(41848, 1323), + listOf(0u, 3u) to Rational(-2228822, 1029), + listOf(1u, 3u) to Rational(80179390, 3087), + listOf(2u, 3u) to Rational(-1378630487, 74088), + listOf(3u, 3u) to Rational(-3385811693, 111132), + listOf(4u, 3u) to Rational(-820686977, 49392), + listOf(5u, 3u) to Rational(-89101027, 10584), + listOf(6u, 3u) to Rational(-37847387, 15876), + listOf(7u, 3u) to Rational(-2363369, 3969), + listOf(8u, 3u) to Rational(-108280, 1323), + listOf(0u, 4u) to Rational(12619982, 1029), + listOf(1u, 4u) to Rational(-277723177, 6174), + listOf(2u, 4u) to Rational(649414169, 49392), + listOf(3u, 4u) to Rational(14457595, 63504), + listOf(4u, 4u) to Rational(139270339, 10584), + listOf(5u, 4u) to Rational(140367961, 15876), + listOf(6u, 4u) to Rational(25467083, 7056), + listOf(7u, 4u) to Rational(8563385, 7938), + listOf(8u, 4u) to Rational(19721, 147), + listOf(0u, 5u) to Rational(643850, 147), + listOf(1u, 5u) to Rational(-11818025, 294), + listOf(2u, 5u) to Rational(33963203, 588), + listOf(3u, 5u) to Rational(207216235, 5292), + listOf(4u, 5u) to Rational(2861021, 1512), + listOf(5u, 5u) to Rational(-6302335, 1176), + listOf(6u, 5u) to Rational(-3738587, 882), + listOf(7u, 5u) to Rational(-38437, 27), + listOf(8u, 5u) to Rational(-29620, 189), + listOf(0u, 6u) to Rational(-248725, 49), + listOf(1u, 6u) to Rational(2478535, 98), + listOf(2u, 6u) to Rational(-399721367, 21168), + listOf(3u, 6u) to Rational(-54309317, 10584), + listOf(4u, 6u) to Rational(-95398327, 21168), + listOf(5u, 6u) to Rational(173750, 189), + listOf(6u, 6u) to Rational(92216, 27), + listOf(7u, 6u) to Rational(227744, 189), + listOf(8u, 6u) to Rational(23116, 189), + listOf(0u, 7u) to Rational(-27500, 21), + listOf(1u, 7u) to Rational(120125, 9), + listOf(2u, 7u) to Rational(-279200, 9), + listOf(3u, 7u) to Rational(-100160, 21), + listOf(4u, 7u) to Rational(920452, 63), + listOf(5u, 7u) to Rational(226481, 63), + listOf(6u, 7u) to Rational(-11476, 7), + listOf(7u, 7u) to Rational(-6232, 9), + listOf(8u, 7u) to Rational(-608, 9), + listOf(0u, 8u) to Rational(2500, 3), + listOf(1u, 8u) to Rational(-19000, 3), + listOf(2u, 8u) to Rational(37900, 3), + listOf(3u, 8u) to Rational(-1840, 3), + listOf(4u, 8u) to Rational(-17876, 3), + listOf(5u, 8u) to Rational(-1240, 3), + listOf(6u, 8u) to Rational(2788, 3), + listOf(7u, 8u) to Rational(800, 3), + listOf(8u, 8u) to Rational(64, 3) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(5, 6), + listOf(1u) to Rational(1, 6), + listOf(2u) to Rational(-2, 9), + listOf(0u, 1u) to Rational(15, 1), + listOf(1u, 1u) to Rational(18, 7), + listOf(2u, 1u) to Rational(2, 5), + listOf(0u, 2u) to Rational(12, 9), + listOf(1u, 2u) to Rational(-3, 5), + listOf(2u, 2u) to Rational(4, 4), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-11, 9), + listOf(1u) to Rational(4, 9), + listOf(2u) to Rational(11, 6), + listOf(0u, 1u) to Rational(-5, 6), + listOf(1u, 1u) to Rational(4, 6), + listOf(2u, 1u) to Rational(-1, 7), + listOf(0u, 2u) to Rational(9, 1), + listOf(1u, 2u) to Rational(6, 7), + listOf(2u, 2u) to Rational(1, 3), + ) + ).substitute(RationalField, mapOf( + 0 to NumberedPolynomialAsIs( + listOf() to Rational(18, 1), + listOf(1u) to Rational(16, 3), + listOf(2u) to Rational(12, 6), + listOf(0u, 1u) to Rational(13, 1), + listOf(1u, 1u) to Rational(-11, 4), + listOf(2u, 1u) to Rational(-1, 1), + listOf(0u, 2u) to Rational(-10, 1), + listOf(1u, 2u) to Rational(4, 1), + listOf(2u, 2u) to Rational(2, 1), + ), + 1 to NumberedPolynomialAsIs( + listOf() to Rational(8, 2), + listOf(1u) to Rational(-15, 5), + listOf(2u) to Rational(2, 7), + listOf(0u, 1u) to Rational(-18, 7), + listOf(1u, 1u) to Rational(-16, 6), + listOf(2u, 1u) to Rational(-13, 3), + listOf(0u, 2u) to Rational(-5, 1), + listOf(1u, 2u) to Rational(17, 1), + listOf(2u, 2u) to Rational(8, 2), + ), + )), + "test 3" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(1202861, 210), + listOf(1u) to Rational(-215117, 45), + listOf(2u) to Rational(10889651, 19845), + listOf(3u) to Rational(-3503956, 6615), + listOf(4u) to Rational(809066, 2205), + listOf(5u) to Rational(-9056, 735), + listOf(6u) to Rational(5396, 315), + listOf(7u) to Rational(-752, 147), + listOf(8u) to Rational(16, 49), + listOf(0u, 1u) to Rational(1738469, 1470), + listOf(1u, 1u) to Rational(-926238703, 52920), + listOf(2u, 1u) to Rational(-44113982, 6615), + listOf(3u, 1u) to Rational(10423519, 5292), + listOf(4u, 1u) to Rational(3769712, 2205), + listOf(5u, 1u) to Rational(8905046, 6615), + listOf(6u, 1u) to Rational(1186972, 6615), + listOf(7u, 1u) to Rational(22124, 441), + listOf(8u, 1u) to Rational(-1504, 147), + listOf(0u, 2u) to Rational(-54723628, 2205), + listOf(1u, 2u) to Rational(70109407, 1323), + listOf(2u, 2u) to Rational(151072591, 17640), + listOf(3u, 2u) to Rational(1216428107, 52920), + listOf(4u, 2u) to Rational(2587873193, 317520), + listOf(5u, 2u) to Rational(393536369, 79380), + listOf(6u, 2u) to Rational(137614937, 79380), + listOf(7u, 2u) to Rational(566866, 1323), + listOf(8u, 2u) to Rational(41848, 441), + listOf(0u, 3u) to Rational(-19470406, 2205), + listOf(1u, 3u) to Rational(72514195, 882), + listOf(2u, 3u) to Rational(-78090707, 1764), + listOf(3u, 3u) to Rational(-1988237707, 26460), + listOf(4u, 3u) to Rational(-802137919, 17640), + listOf(5u, 3u) to Rational(-139989463, 5880), + listOf(6u, 3u) to Rational(-26066641, 3780), + listOf(7u, 3u) to Rational(-2363369, 1323), + listOf(8u, 3u) to Rational(-108280, 441), + listOf(0u, 4u) to Rational(14878516, 441), + listOf(1u, 4u) to Rational(-253416724, 2205), + listOf(2u, 4u) to Rational(16699157, 840), + listOf(3u, 4u) to Rational(-105220979, 13230), + listOf(4u, 4u) to Rational(208266383, 5880), + listOf(5u, 4u) to Rational(650135309, 26460), + listOf(6u, 4u) to Rational(123808663, 11760), + listOf(7u, 4u) to Rational(8563385, 2646), + listOf(8u, 4u) to Rational(19721, 49), + listOf(0u, 5u) to Rational(675645, 49), + listOf(1u, 5u) to Rational(-70554077, 588), + listOf(2u, 5u) to Rational(157884029, 980), + listOf(3u, 5u) to Rational(489548623, 4410), + listOf(4u, 5u) to Rational(148540519, 17640), + listOf(5u, 5u) to Rational(-5559551, 392), + listOf(6u, 5u) to Rational(-18335711, 1470), + listOf(7u, 5u) to Rational(-38437, 9), + listOf(8u, 5u) to Rational(-29620, 63), + listOf(0u, 6u) to Rational(-727625, 49), + listOf(1u, 6u) to Rational(7046685, 98), + listOf(2u, 6u) to Rational(-334814231, 7056), + listOf(3u, 6u) to Rational(-243971737, 17640), + listOf(4u, 6u) to Rational(-571116659, 35280), + listOf(5u, 6u) to Rational(567538, 315), + listOf(6u, 6u) to Rational(3199768, 315), + listOf(7u, 6u) to Rational(227744, 63), + listOf(8u, 6u) to Rational(23116, 63), + listOf(0u, 7u) to Rational(-27500, 7), + listOf(1u, 7u) to Rational(120125, 3), + listOf(2u, 7u) to Rational(-279200, 3), + listOf(3u, 7u) to Rational(-100160, 7), + listOf(4u, 7u) to Rational(920452, 21), + listOf(5u, 7u) to Rational(226481, 21), + listOf(6u, 7u) to Rational(-34428, 7), + listOf(7u, 7u) to Rational(-6232, 3), + listOf(8u, 7u) to Rational(-608, 3), + listOf(0u, 8u) to Rational(2500, 1), + listOf(1u, 8u) to Rational(-19000, 1), + listOf(2u, 8u) to Rational(37900, 1), + listOf(3u, 8u) to Rational(-1840, 1), + listOf(4u, 8u) to Rational(-17876, 1), + listOf(5u, 8u) to Rational(-1240, 1), + listOf(6u, 8u) to Rational(2788, 1), + listOf(7u, 8u) to Rational(800, 1), + listOf(8u, 8u) to Rational(64, 1) + ), + NumberedPolynomialAsIs( + listOf() to Rational(162487, 63), + listOf(1u) to Rational(-92713, 54), + listOf(2u) to Rational(802436, 1323), + listOf(3u) to Rational(-55088, 441), + listOf(4u) to Rational(1404034, 9261), + listOf(5u) to Rational(-5804, 1029), + listOf(6u) to Rational(51556, 9261), + listOf(7u) to Rational(-752, 441), + listOf(8u) to Rational(16, 147), + listOf(0u, 1u) to Rational(296071, 441), + listOf(1u, 1u) to Rational(-4991281, 882), + listOf(2u, 1u) to Rational(-18702811, 9261), + listOf(3u, 1u) to Rational(40759043, 27783), + listOf(4u, 1u) to Rational(19768501, 27783), + listOf(5u, 1u) to Rational(14307337, 27783), + listOf(6u, 1u) to Rational(1655684, 27783), + listOf(7u, 1u) to Rational(22124, 1323), + listOf(8u, 1u) to Rational(-1504, 441), + listOf(0u, 2u) to Rational(-27667474, 3087), + listOf(1u, 2u) to Rational(265605901, 12348), + listOf(2u, 2u) to Rational(160360775, 98784), + listOf(3u, 2u) to Rational(1169992093, 148176), + listOf(4u, 2u) to Rational(3978014077, 1333584), + listOf(5u, 2u) to Rational(567058123, 333396), + listOf(6u, 2u) to Rational(205132579, 333396), + listOf(7u, 2u) to Rational(566866, 3969), + listOf(8u, 2u) to Rational(41848, 1323), + listOf(0u, 3u) to Rational(-2228822, 1029), + listOf(1u, 3u) to Rational(80179390, 3087), + listOf(2u, 3u) to Rational(-1378630487, 74088), + listOf(3u, 3u) to Rational(-3385811693, 111132), + listOf(4u, 3u) to Rational(-820686977, 49392), + listOf(5u, 3u) to Rational(-89101027, 10584), + listOf(6u, 3u) to Rational(-37847387, 15876), + listOf(7u, 3u) to Rational(-2363369, 3969), + listOf(8u, 3u) to Rational(-108280, 1323), + listOf(0u, 4u) to Rational(12619982, 1029), + listOf(1u, 4u) to Rational(-277723177, 6174), + listOf(2u, 4u) to Rational(649414169, 49392), + listOf(3u, 4u) to Rational(14457595, 63504), + listOf(4u, 4u) to Rational(139270339, 10584), + listOf(5u, 4u) to Rational(140367961, 15876), + listOf(6u, 4u) to Rational(25467083, 7056), + listOf(7u, 4u) to Rational(8563385, 7938), + listOf(8u, 4u) to Rational(19721, 147), + listOf(0u, 5u) to Rational(643850, 147), + listOf(1u, 5u) to Rational(-11818025, 294), + listOf(2u, 5u) to Rational(33963203, 588), + listOf(3u, 5u) to Rational(207216235, 5292), + listOf(4u, 5u) to Rational(2861021, 1512), + listOf(5u, 5u) to Rational(-6302335, 1176), + listOf(6u, 5u) to Rational(-3738587, 882), + listOf(7u, 5u) to Rational(-38437, 27), + listOf(8u, 5u) to Rational(-29620, 189), + listOf(0u, 6u) to Rational(-248725, 49), + listOf(1u, 6u) to Rational(2478535, 98), + listOf(2u, 6u) to Rational(-399721367, 21168), + listOf(3u, 6u) to Rational(-54309317, 10584), + listOf(4u, 6u) to Rational(-95398327, 21168), + listOf(5u, 6u) to Rational(173750, 189), + listOf(6u, 6u) to Rational(92216, 27), + listOf(7u, 6u) to Rational(227744, 189), + listOf(8u, 6u) to Rational(23116, 189), + listOf(0u, 7u) to Rational(-27500, 21), + listOf(1u, 7u) to Rational(120125, 9), + listOf(2u, 7u) to Rational(-279200, 9), + listOf(3u, 7u) to Rational(-100160, 21), + listOf(4u, 7u) to Rational(920452, 63), + listOf(5u, 7u) to Rational(226481, 63), + listOf(6u, 7u) to Rational(-11476, 7), + listOf(7u, 7u) to Rational(-6232, 9), + listOf(8u, 7u) to Rational(-608, 9), + listOf(0u, 8u) to Rational(2500, 3), + listOf(1u, 8u) to Rational(-19000, 3), + listOf(2u, 8u) to Rational(37900, 3), + listOf(3u, 8u) to Rational(-1840, 3), + listOf(4u, 8u) to Rational(-17876, 3), + listOf(5u, 8u) to Rational(-1240, 3), + listOf(6u, 8u) to Rational(2788, 3), + listOf(7u, 8u) to Rational(800, 3), + listOf(8u, 8u) to Rational(64, 3) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(5, 6), + listOf(1u) to Rational(1, 6), + listOf(2u) to Rational(-2, 9), + listOf(0u, 1u) to Rational(15, 1), + listOf(1u, 1u) to Rational(18, 7), + listOf(2u, 1u) to Rational(2, 5), + listOf(0u, 2u) to Rational(12, 9), + listOf(1u, 2u) to Rational(-3, 5), + listOf(2u, 2u) to Rational(4, 4), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-11, 9), + listOf(1u) to Rational(4, 9), + listOf(2u) to Rational(11, 6), + listOf(0u, 1u) to Rational(-5, 6), + listOf(1u, 1u) to Rational(4, 6), + listOf(2u, 1u) to Rational(-1, 7), + listOf(0u, 2u) to Rational(9, 1), + listOf(1u, 2u) to Rational(6, 7), + listOf(2u, 2u) to Rational(1, 3), + ) + ).substitute(RationalField, mapOf( + 0 to NumberedPolynomialAsIs( + listOf() to Rational(18, 1), + listOf(1u) to Rational(16, 3), + listOf(2u) to Rational(12, 6), + listOf(0u, 1u) to Rational(13, 1), + listOf(1u, 1u) to Rational(-11, 4), + listOf(2u, 1u) to Rational(-1, 1), + listOf(0u, 2u) to Rational(-10, 1), + listOf(1u, 2u) to Rational(4, 1), + listOf(2u, 2u) to Rational(2, 1), + ), + 1 to NumberedPolynomialAsIs( + listOf() to Rational(8, 2), + listOf(1u) to Rational(-15, 5), + listOf(2u) to Rational(2, 7), + listOf(0u, 1u) to Rational(-18, 7), + listOf(1u, 1u) to Rational(-16, 6), + listOf(2u, 1u) to Rational(-13, 3), + listOf(0u, 2u) to Rational(-5, 1), + listOf(1u, 2u) to Rational(17, 1), + listOf(2u, 2u) to Rational(8, 2), + ), + 5 to NumberedPolynomialAsIs( + listOf() to Rational(-6, 1), + listOf(1u) to Rational(-9, 8), + listOf(2u) to Rational(17, 5), + listOf(0u, 1u) to Rational(-2, 3), + listOf(1u, 1u) to Rational(1, 5), + listOf(2u, 1u) to Rational(-11, 7), + listOf(0u, 2u) to Rational(13, 6), + listOf(1u, 2u) to Rational(-15, 2), + listOf(2u, 2u) to Rational(-14, 4), + ) + )), + "test 3'" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(493, 6), + listOf(1u) to Rational(-15991, 210), + listOf(2u) to Rational(2734, 63), + listOf(3u) to Rational(-8213, 245), + listOf(4u) to Rational(1843, 147), + listOf(5u) to Rational(-432, 245), + listOf(6u) to Rational(4, 49), + listOf(0u, 1u) to Rational(-66, 1), + listOf(1u, 1u) to Rational(-92924, 2205), + listOf(2u, 1u) to Rational(-257461, 2205), + listOf(3u, 1u) to Rational(58658, 2205), + listOf(4u, 1u) to Rational(-87884, 2205), + listOf(5u, 1u) to Rational(2726, 105), + listOf(6u, 1u) to Rational(-52, 21), + listOf(0u, 2u) to Rational(-17569, 147), + listOf(1u, 2u) to Rational(368819, 735), + listOf(2u, 2u) to Rational(-644626, 6615), + listOf(3u, 2u) to Rational(221738, 945), + listOf(4u, 2u) to Rational(-18022, 945), + listOf(5u, 2u) to Rational(-1201, 315), + listOf(6u, 2u) to Rational(1327, 63), + listOf(0u, 3u) to Rational(240, 7), + listOf(1u, 3u) to Rational(-868, 9), + listOf(2u, 3u) to Rational(-8936, 315), + listOf(3u, 3u) to Rational(-77146, 315), + listOf(4u, 3u) to Rational(-4072, 315), + listOf(5u, 3u) to Rational(-2218, 15), + listOf(6u, 3u) to Rational(-104, 3), + listOf(0u, 4u) to Rational(100, 3), + listOf(1u, 4u) to Rational(-725, 3), + listOf(2u, 4u) to Rational(459, 1), + listOf(3u, 4u) to Rational(-2071, 15), + listOf(4u, 4u) to Rational(2831, 15), + listOf(5u, 4u) to Rational(632, 5), + listOf(6u, 4u) to Rational(16, 1) + ), + NumberedPolynomialAsIs( + listOf() to Rational(1255, 9), + listOf(1u) to Rational(-24781, 126), + listOf(2u) to Rational(1195, 14), + listOf(3u) to Rational(-1931, 147), + listOf(4u) to Rational(439, 147), + listOf(5u) to Rational(-172, 343), + listOf(6u) to Rational(4, 147), + listOf(0u, 1u) to Rational(-183, 1), + listOf(1u, 1u) to Rational(-30988, 441), + listOf(2u, 1u) to Rational(-56137, 294), + listOf(3u, 1u) to Rational(204308, 1029), + listOf(4u, 1u) to Rational(-3263, 441), + listOf(5u, 1u) to Rational(2662, 441), + listOf(6u, 1u) to Rational(-52, 63), + listOf(0u, 2u) to Rational(-87119, 294), + listOf(1u, 2u) to Rational(1077919, 686), + listOf(2u, 2u) to Rational(-35209, 147), + listOf(3u, 2u) to Rational(15041, 147), + listOf(4u, 2u) to Rational(240889, 1323), + listOf(5u, 2u) to Rational(27778, 1323), + listOf(6u, 2u) to Rational(1327, 189), + listOf(0u, 3u) to Rational(1620, 7), + listOf(1u, 3u) to Rational(-25716, 49), + listOf(2u, 3u) to Rational(-32078, 49), + listOf(3u, 3u) to Rational(-704038, 441), + listOf(4u, 3u) to Rational(-30190, 63), + listOf(5u, 3u) to Rational(-5414, 63), + listOf(6u, 3u) to Rational(-104, 9), + listOf(0u, 4u) to Rational(225, 1), + listOf(1u, 4u) to Rational(-10560, 7), + listOf(2u, 4u) to Rational(44176, 21), + listOf(3u, 4u) to Rational(28996, 21), + listOf(4u, 4u) to Rational(2405, 7), + listOf(5u, 4u) to Rational(1240, 21), + listOf(6u, 4u) to Rational(16, 3) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(5, 6), + listOf(1u) to Rational(1, 6), + listOf(2u) to Rational(-2, 9), + listOf(0u, 1u) to Rational(15, 1), + listOf(1u, 1u) to Rational(18, 7), + listOf(2u, 1u) to Rational(2, 5), + listOf(0u, 2u) to Rational(12, 9), + listOf(1u, 2u) to Rational(-3, 5), + listOf(2u, 2u) to Rational(4, 4), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-11, 9), + listOf(1u) to Rational(4, 9), + listOf(2u) to Rational(11, 6), + listOf(0u, 1u) to Rational(-5, 6), + listOf(1u, 1u) to Rational(4, 6), + listOf(2u, 1u) to Rational(-1, 7), + listOf(0u, 2u) to Rational(9, 1), + listOf(1u, 2u) to Rational(6, 7), + listOf(2u, 2u) to Rational(1, 3), + ) + ).substitute(RationalField, mapOf( + 1 to NumberedPolynomialAsIs( + listOf() to Rational(8, 2), + listOf(1u) to Rational(-15, 5), + listOf(2u) to Rational(2, 7), + listOf(0u, 1u) to Rational(-18, 7), + listOf(1u, 1u) to Rational(-16, 6), + listOf(2u, 1u) to Rational(-13, 3), + listOf(0u, 2u) to Rational(-5, 1), + listOf(1u, 2u) to Rational(17, 1), + listOf(2u, 2u) to Rational(8, 2), + ), + )), + "test 4" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(493, 6), + listOf(1u) to Rational(-15991, 210), + listOf(2u) to Rational(2734, 63), + listOf(3u) to Rational(-8213, 245), + listOf(4u) to Rational(1843, 147), + listOf(5u) to Rational(-432, 245), + listOf(6u) to Rational(4, 49), + listOf(0u, 1u) to Rational(-66, 1), + listOf(1u, 1u) to Rational(-92924, 2205), + listOf(2u, 1u) to Rational(-257461, 2205), + listOf(3u, 1u) to Rational(58658, 2205), + listOf(4u, 1u) to Rational(-87884, 2205), + listOf(5u, 1u) to Rational(2726, 105), + listOf(6u, 1u) to Rational(-52, 21), + listOf(0u, 2u) to Rational(-17569, 147), + listOf(1u, 2u) to Rational(368819, 735), + listOf(2u, 2u) to Rational(-644626, 6615), + listOf(3u, 2u) to Rational(221738, 945), + listOf(4u, 2u) to Rational(-18022, 945), + listOf(5u, 2u) to Rational(-1201, 315), + listOf(6u, 2u) to Rational(1327, 63), + listOf(0u, 3u) to Rational(240, 7), + listOf(1u, 3u) to Rational(-868, 9), + listOf(2u, 3u) to Rational(-8936, 315), + listOf(3u, 3u) to Rational(-77146, 315), + listOf(4u, 3u) to Rational(-4072, 315), + listOf(5u, 3u) to Rational(-2218, 15), + listOf(6u, 3u) to Rational(-104, 3), + listOf(0u, 4u) to Rational(100, 3), + listOf(1u, 4u) to Rational(-725, 3), + listOf(2u, 4u) to Rational(459, 1), + listOf(3u, 4u) to Rational(-2071, 15), + listOf(4u, 4u) to Rational(2831, 15), + listOf(5u, 4u) to Rational(632, 5), + listOf(6u, 4u) to Rational(16, 1) + ), + NumberedPolynomialAsIs( + listOf() to Rational(1255, 9), + listOf(1u) to Rational(-24781, 126), + listOf(2u) to Rational(1195, 14), + listOf(3u) to Rational(-1931, 147), + listOf(4u) to Rational(439, 147), + listOf(5u) to Rational(-172, 343), + listOf(6u) to Rational(4, 147), + listOf(0u, 1u) to Rational(-183, 1), + listOf(1u, 1u) to Rational(-30988, 441), + listOf(2u, 1u) to Rational(-56137, 294), + listOf(3u, 1u) to Rational(204308, 1029), + listOf(4u, 1u) to Rational(-3263, 441), + listOf(5u, 1u) to Rational(2662, 441), + listOf(6u, 1u) to Rational(-52, 63), + listOf(0u, 2u) to Rational(-87119, 294), + listOf(1u, 2u) to Rational(1077919, 686), + listOf(2u, 2u) to Rational(-35209, 147), + listOf(3u, 2u) to Rational(15041, 147), + listOf(4u, 2u) to Rational(240889, 1323), + listOf(5u, 2u) to Rational(27778, 1323), + listOf(6u, 2u) to Rational(1327, 189), + listOf(0u, 3u) to Rational(1620, 7), + listOf(1u, 3u) to Rational(-25716, 49), + listOf(2u, 3u) to Rational(-32078, 49), + listOf(3u, 3u) to Rational(-704038, 441), + listOf(4u, 3u) to Rational(-30190, 63), + listOf(5u, 3u) to Rational(-5414, 63), + listOf(6u, 3u) to Rational(-104, 9), + listOf(0u, 4u) to Rational(225, 1), + listOf(1u, 4u) to Rational(-10560, 7), + listOf(2u, 4u) to Rational(44176, 21), + listOf(3u, 4u) to Rational(28996, 21), + listOf(4u, 4u) to Rational(2405, 7), + listOf(5u, 4u) to Rational(1240, 21), + listOf(6u, 4u) to Rational(16, 3) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(5, 6), + listOf(1u) to Rational(1, 6), + listOf(2u) to Rational(-2, 9), + listOf(0u, 1u) to Rational(15, 1), + listOf(1u, 1u) to Rational(18, 7), + listOf(2u, 1u) to Rational(2, 5), + listOf(0u, 2u) to Rational(12, 9), + listOf(1u, 2u) to Rational(-3, 5), + listOf(2u, 2u) to Rational(4, 4), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-11, 9), + listOf(1u) to Rational(4, 9), + listOf(2u) to Rational(11, 6), + listOf(0u, 1u) to Rational(-5, 6), + listOf(1u, 1u) to Rational(4, 6), + listOf(2u, 1u) to Rational(-1, 7), + listOf(0u, 2u) to Rational(9, 1), + listOf(1u, 2u) to Rational(6, 7), + listOf(2u, 2u) to Rational(1, 3), + ) + ).substitute(RationalField, mapOf( + 1 to NumberedPolynomialAsIs( + listOf() to Rational(8, 2), + listOf(1u) to Rational(-15, 5), + listOf(2u) to Rational(2, 7), + listOf(0u, 1u) to Rational(-18, 7), + listOf(1u, 1u) to Rational(-16, 6), + listOf(2u, 1u) to Rational(-13, 3), + listOf(0u, 2u) to Rational(-5, 1), + listOf(1u, 2u) to Rational(17, 1), + listOf(2u, 2u) to Rational(8, 2), + ), + 5 to NumberedPolynomialAsIs( + listOf() to Rational(-6, 1), + listOf(1u) to Rational(-9, 8), + listOf(2u) to Rational(17, 5), + listOf(0u, 1u) to Rational(-2, 3), + listOf(1u, 1u) to Rational(1, 5), + listOf(2u, 1u) to Rational(-11, 7), + listOf(0u, 2u) to Rational(13, 6), + listOf(1u, 2u) to Rational(-15, 2), + listOf(2u, 2u) to Rational(-14, 4), + ) + )), + "test 4'" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-409, 6), + listOf(1u) to Rational(-376, 9), + listOf(2u) to Rational(-1781, 81), + listOf(3u) to Rational(-128, 27), + listOf(4u) to Rational(-8, 9), + listOf(0u, 1u) to Rational(18701, 210), + listOf(1u, 1u) to Rational(614183, 7560), + listOf(2u, 1u) to Rational(90941, 1890), + listOf(3u, 1u) to Rational(1802, 135), + listOf(4u, 1u) to Rational(112, 45), + listOf(0u, 2u) to Rational(181421, 315), + listOf(1u, 2u) to Rational(77813, 378), + listOf(2u, 2u) to Rational(598583, 7560), + listOf(3u, 2u) to Rational(85, 27), + listOf(4u, 2u) to Rational(2, 5), + listOf(0u, 3u) to Rational(130997, 315), + listOf(1u, 3u) to Rational(1093, 420), + listOf(2u, 3u) to Rational(9551, 2520), + listOf(3u, 3u) to Rational(-14, 45), + listOf(4u, 3u) to Rational(22, 45), + listOf(0u, 4u) to Rational(-2801, 9), + listOf(1u, 4u) to Rational(4033, 90), + listOf(2u, 4u) to Rational(6429, 80), + listOf(3u, 4u) to Rational(2851, 90), + listOf(4u, 4u) to Rational(293, 45), + listOf(0u, 5u) to Rational(-220, 1), + listOf(1u, 5u) to Rational(127, 1), + listOf(2u, 5u) to Rational(202, 5), + listOf(3u, 5u) to Rational(-63, 5), + listOf(4u, 5u) to Rational(-12, 5), + listOf(0u, 6u) to Rational(100, 1), + listOf(1u, 6u) to Rational(-80, 1), + listOf(2u, 6u) to Rational(-24, 1), + listOf(3u, 6u) to Rational(16, 1), + listOf(4u, 6u) to Rational(4, 1) + ), + NumberedPolynomialAsIs( + listOf() to Rational(5407, 9), + listOf(1u) to Rational(9568, 27), + listOf(2u) to Rational(4996, 27), + listOf(3u) to Rational(352, 9), + listOf(4u) to Rational(22, 3), + listOf(0u, 1u) to Rational(104411, 126), + listOf(1u, 1u) to Rational(6001, 126), + listOf(2u, 1u) to Rational(-796, 21), + listOf(3u, 1u) to Rational(-5389, 126), + listOf(4u, 1u) to Rational(-166, 21), + listOf(0u, 2u) to Rational(-35327, 126), + listOf(1u, 2u) to Rational(53, 252), + listOf(2u, 2u) to Rational(849197, 6048), + listOf(3u, 2u) to Rational(22361, 252), + listOf(4u, 2u) to Rational(773, 42), + listOf(0u, 3u) to Rational(-6067, 21), + listOf(1u, 3u) to Rational(39049, 126), + listOf(2u, 3u) to Rational(80303, 1008), + listOf(3u, 3u) to Rational(-3035, 63), + listOf(4u, 3u) to Rational(-209, 21), + listOf(0u, 4u) to Rational(3113, 21), + listOf(1u, 4u) to Rational(-22345, 126), + listOf(2u, 4u) to Rational(-30931, 1008), + listOf(3u, 4u) to Rational(5837, 126), + listOf(4u, 4u) to Rational(229, 21), + listOf(0u, 5u) to Rational(-2120, 21), + listOf(1u, 5u) to Rational(451, 7), + listOf(2u, 5u) to Rational(422, 21), + listOf(3u, 5u) to Rational(-181, 21), + listOf(4u, 5u) to Rational(-40, 21), + listOf(0u, 6u) to Rational(100, 3), + listOf(1u, 6u) to Rational(-80, 3), + listOf(2u, 6u) to Rational(-8, 1), + listOf(3u, 6u) to Rational(16, 3), + listOf(4u, 6u) to Rational(4, 3) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(5, 6), + listOf(1u) to Rational(1, 6), + listOf(2u) to Rational(-2, 9), + listOf(0u, 1u) to Rational(15, 1), + listOf(1u, 1u) to Rational(18, 7), + listOf(2u, 1u) to Rational(2, 5), + listOf(0u, 2u) to Rational(12, 9), + listOf(1u, 2u) to Rational(-3, 5), + listOf(2u, 2u) to Rational(4, 4), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-11, 9), + listOf(1u) to Rational(4, 9), + listOf(2u) to Rational(11, 6), + listOf(0u, 1u) to Rational(-5, 6), + listOf(1u, 1u) to Rational(4, 6), + listOf(2u, 1u) to Rational(-1, 7), + listOf(0u, 2u) to Rational(9, 1), + listOf(1u, 2u) to Rational(6, 7), + listOf(2u, 2u) to Rational(1, 3), + ) + ).substitute(RationalField, mapOf( + 0 to NumberedPolynomialAsIs( + listOf() to Rational(18, 1), + listOf(1u) to Rational(16, 3), + listOf(2u) to Rational(12, 6), + listOf(0u, 1u) to Rational(13, 1), + listOf(1u, 1u) to Rational(-11, 4), + listOf(2u, 1u) to Rational(-1, 1), + listOf(0u, 2u) to Rational(-10, 1), + listOf(1u, 2u) to Rational(4, 1), + listOf(2u, 2u) to Rational(2, 1), + ), + )), + "test 5" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-409, 6), + listOf(1u) to Rational(-376, 9), + listOf(2u) to Rational(-1781, 81), + listOf(3u) to Rational(-128, 27), + listOf(4u) to Rational(-8, 9), + listOf(0u, 1u) to Rational(18701, 210), + listOf(1u, 1u) to Rational(614183, 7560), + listOf(2u, 1u) to Rational(90941, 1890), + listOf(3u, 1u) to Rational(1802, 135), + listOf(4u, 1u) to Rational(112, 45), + listOf(0u, 2u) to Rational(181421, 315), + listOf(1u, 2u) to Rational(77813, 378), + listOf(2u, 2u) to Rational(598583, 7560), + listOf(3u, 2u) to Rational(85, 27), + listOf(4u, 2u) to Rational(2, 5), + listOf(0u, 3u) to Rational(130997, 315), + listOf(1u, 3u) to Rational(1093, 420), + listOf(2u, 3u) to Rational(9551, 2520), + listOf(3u, 3u) to Rational(-14, 45), + listOf(4u, 3u) to Rational(22, 45), + listOf(0u, 4u) to Rational(-2801, 9), + listOf(1u, 4u) to Rational(4033, 90), + listOf(2u, 4u) to Rational(6429, 80), + listOf(3u, 4u) to Rational(2851, 90), + listOf(4u, 4u) to Rational(293, 45), + listOf(0u, 5u) to Rational(-220, 1), + listOf(1u, 5u) to Rational(127, 1), + listOf(2u, 5u) to Rational(202, 5), + listOf(3u, 5u) to Rational(-63, 5), + listOf(4u, 5u) to Rational(-12, 5), + listOf(0u, 6u) to Rational(100, 1), + listOf(1u, 6u) to Rational(-80, 1), + listOf(2u, 6u) to Rational(-24, 1), + listOf(3u, 6u) to Rational(16, 1), + listOf(4u, 6u) to Rational(4, 1) + ), + NumberedPolynomialAsIs( + listOf() to Rational(5407, 9), + listOf(1u) to Rational(9568, 27), + listOf(2u) to Rational(4996, 27), + listOf(3u) to Rational(352, 9), + listOf(4u) to Rational(22, 3), + listOf(0u, 1u) to Rational(104411, 126), + listOf(1u, 1u) to Rational(6001, 126), + listOf(2u, 1u) to Rational(-796, 21), + listOf(3u, 1u) to Rational(-5389, 126), + listOf(4u, 1u) to Rational(-166, 21), + listOf(0u, 2u) to Rational(-35327, 126), + listOf(1u, 2u) to Rational(53, 252), + listOf(2u, 2u) to Rational(849197, 6048), + listOf(3u, 2u) to Rational(22361, 252), + listOf(4u, 2u) to Rational(773, 42), + listOf(0u, 3u) to Rational(-6067, 21), + listOf(1u, 3u) to Rational(39049, 126), + listOf(2u, 3u) to Rational(80303, 1008), + listOf(3u, 3u) to Rational(-3035, 63), + listOf(4u, 3u) to Rational(-209, 21), + listOf(0u, 4u) to Rational(3113, 21), + listOf(1u, 4u) to Rational(-22345, 126), + listOf(2u, 4u) to Rational(-30931, 1008), + listOf(3u, 4u) to Rational(5837, 126), + listOf(4u, 4u) to Rational(229, 21), + listOf(0u, 5u) to Rational(-2120, 21), + listOf(1u, 5u) to Rational(451, 7), + listOf(2u, 5u) to Rational(422, 21), + listOf(3u, 5u) to Rational(-181, 21), + listOf(4u, 5u) to Rational(-40, 21), + listOf(0u, 6u) to Rational(100, 3), + listOf(1u, 6u) to Rational(-80, 3), + listOf(2u, 6u) to Rational(-8, 1), + listOf(3u, 6u) to Rational(16, 3), + listOf(4u, 6u) to Rational(4, 3) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(5, 6), + listOf(1u) to Rational(1, 6), + listOf(2u) to Rational(-2, 9), + listOf(0u, 1u) to Rational(15, 1), + listOf(1u, 1u) to Rational(18, 7), + listOf(2u, 1u) to Rational(2, 5), + listOf(0u, 2u) to Rational(12, 9), + listOf(1u, 2u) to Rational(-3, 5), + listOf(2u, 2u) to Rational(4, 4), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-11, 9), + listOf(1u) to Rational(4, 9), + listOf(2u) to Rational(11, 6), + listOf(0u, 1u) to Rational(-5, 6), + listOf(1u, 1u) to Rational(4, 6), + listOf(2u, 1u) to Rational(-1, 7), + listOf(0u, 2u) to Rational(9, 1), + listOf(1u, 2u) to Rational(6, 7), + listOf(2u, 2u) to Rational(1, 3), + ) + ).substitute(RationalField, mapOf( + 0 to NumberedPolynomialAsIs( + listOf() to Rational(18, 1), + listOf(1u) to Rational(16, 3), + listOf(2u) to Rational(12, 6), + listOf(0u, 1u) to Rational(13, 1), + listOf(1u, 1u) to Rational(-11, 4), + listOf(2u, 1u) to Rational(-1, 1), + listOf(0u, 2u) to Rational(-10, 1), + listOf(1u, 2u) to Rational(4, 1), + listOf(2u, 2u) to Rational(2, 1), + ), + 5 to NumberedPolynomialAsIs( + listOf() to Rational(-6, 1), + listOf(1u) to Rational(-9, 8), + listOf(2u) to Rational(17, 5), + listOf(0u, 1u) to Rational(-2, 3), + listOf(1u, 1u) to Rational(1, 5), + listOf(2u, 1u) to Rational(-11, 7), + listOf(0u, 2u) to Rational(13, 6), + listOf(1u, 2u) to Rational(-15, 2), + listOf(2u, 2u) to Rational(-14, 4), + ) + )), + "test 5'" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(5, 6), + listOf(1u) to Rational(1, 6), + listOf(2u) to Rational(-2, 9), + listOf(0u, 1u) to Rational(15, 1), + listOf(1u, 1u) to Rational(18, 7), + listOf(2u, 1u) to Rational(2, 5), + listOf(0u, 2u) to Rational(12, 9), + listOf(1u, 2u) to Rational(-3, 5), + listOf(2u, 2u) to Rational(4, 4), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-11, 9), + listOf(1u) to Rational(4, 9), + listOf(2u) to Rational(11, 6), + listOf(0u, 1u) to Rational(-5, 6), + listOf(1u, 1u) to Rational(4, 6), + listOf(2u, 1u) to Rational(-1, 7), + listOf(0u, 2u) to Rational(9, 1), + listOf(1u, 2u) to Rational(6, 7), + listOf(2u, 2u) to Rational(1, 3), + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(5, 6), + listOf(1u) to Rational(1, 6), + listOf(2u) to Rational(-2, 9), + listOf(0u, 1u) to Rational(15, 1), + listOf(1u, 1u) to Rational(18, 7), + listOf(2u, 1u) to Rational(2, 5), + listOf(0u, 2u) to Rational(12, 9), + listOf(1u, 2u) to Rational(-3, 5), + listOf(2u, 2u) to Rational(4, 4), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-11, 9), + listOf(1u) to Rational(4, 9), + listOf(2u) to Rational(11, 6), + listOf(0u, 1u) to Rational(-5, 6), + listOf(1u, 1u) to Rational(4, 6), + listOf(2u, 1u) to Rational(-1, 7), + listOf(0u, 2u) to Rational(9, 1), + listOf(1u, 2u) to Rational(6, 7), + listOf(2u, 2u) to Rational(1, 3), + ) + ).substitute(RationalField, mapOf>()), + "test 6" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(5, 6), + listOf(1u) to Rational(1, 6), + listOf(2u) to Rational(-2, 9), + listOf(0u, 1u) to Rational(15, 1), + listOf(1u, 1u) to Rational(18, 7), + listOf(2u, 1u) to Rational(2, 5), + listOf(0u, 2u) to Rational(12, 9), + listOf(1u, 2u) to Rational(-3, 5), + listOf(2u, 2u) to Rational(4, 4), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-11, 9), + listOf(1u) to Rational(4, 9), + listOf(2u) to Rational(11, 6), + listOf(0u, 1u) to Rational(-5, 6), + listOf(1u, 1u) to Rational(4, 6), + listOf(2u, 1u) to Rational(-1, 7), + listOf(0u, 2u) to Rational(9, 1), + listOf(1u, 2u) to Rational(6, 7), + listOf(2u, 2u) to Rational(1, 3), + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(5, 6), + listOf(1u) to Rational(1, 6), + listOf(2u) to Rational(-2, 9), + listOf(0u, 1u) to Rational(15, 1), + listOf(1u, 1u) to Rational(18, 7), + listOf(2u, 1u) to Rational(2, 5), + listOf(0u, 2u) to Rational(12, 9), + listOf(1u, 2u) to Rational(-3, 5), + listOf(2u, 2u) to Rational(4, 4), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-11, 9), + listOf(1u) to Rational(4, 9), + listOf(2u) to Rational(11, 6), + listOf(0u, 1u) to Rational(-5, 6), + listOf(1u, 1u) to Rational(4, 6), + listOf(2u, 1u) to Rational(-1, 7), + listOf(0u, 2u) to Rational(9, 1), + listOf(1u, 2u) to Rational(6, 7), + listOf(2u, 2u) to Rational(1, 3), + ) + ).substitute(RationalField, mapOf( + 5 to NumberedPolynomialAsIs( + listOf() to Rational(-6, 1), + listOf(1u) to Rational(-9, 8), + listOf(2u) to Rational(17, 5), + listOf(0u, 1u) to Rational(-2, 3), + listOf(1u, 1u) to Rational(1, 5), + listOf(2u, 1u) to Rational(-11, 7), + listOf(0u, 2u) to Rational(13, 6), + listOf(1u, 2u) to Rational(-15, 2), + listOf(2u, 2u) to Rational(-14, 4), + ) + )), + "test 6'" + ) } @Test @Ignore // FIXME: This tests work only for sane realisations of the substitutions. Currently, it is not. - // Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should make denominator r^deg(p), + // Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should return denominator r^deg(p), // not r^(deg(p)(deg(p)+1)/2) as it is now. fun test_RationalFunction_substitute_RationalFunction_Map() { // TODO + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(0) + ), + NumberedPolynomialAsIs( + listOf() to Rational(1) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1) + ), + NumberedPolynomialAsIs( + listOf() to Rational(1) + ), + ).substitute(RationalField, mapOf( + 0 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(1) + ), + NumberedPolynomialAsIs( + listOf() to Rational(1) + ) + ) + )), + "test 1" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf(4u) to Rational(-17166109, 793800), + listOf(3u, 1u) to Rational(-930960143, 5556600), + listOf(2u, 2u) to Rational(-144665109691, 350065800), + listOf(1u, 3u) to Rational(-17232577, 52920), + listOf(0u, 4u) to Rational(-68141, 1323), + ), + NumberedPolynomialAsIs( + listOf(4u) to Rational(-57522533, 14288400), + listOf(3u, 1u) to Rational(-13085162953, 300056400), + listOf(2u, 2u) to Rational(-92093367341, 525098700), + listOf(1u, 3u) to Rational(-1979342797, 6667920), + listOf(0u, 4u) to Rational(-3082727, 21168), + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(10, 2), + listOf(1u) to Rational(6, 7), + listOf(2u) to Rational(-16, 1), + listOf(0u, 1u) to Rational(13, 8), + listOf(1u, 1u) to Rational(-12, 1), + listOf(2u, 1u) to Rational(16, 8), + listOf(0u, 2u) to Rational(10, 4), + listOf(1u, 2u) to Rational(4, 1), + listOf(2u, 2u) to Rational(-11, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1, 4), + listOf(1u) to Rational(-17, 4), + listOf(2u) to Rational(-14, 8), + listOf(0u, 1u) to Rational(17, 9), + listOf(1u, 1u) to Rational(1, 3), + listOf(2u, 1u) to Rational(7, 6), + listOf(0u, 2u) to Rational(16, 3), + listOf(1u, 2u) to Rational(-17, 1), + listOf(2u, 2u) to Rational(-10, 8), + ) + ).substitute(RationalField, mapOf( + 0 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf(1u) to Rational(11, 5), + listOf(0u, 1u) to Rational(8, 4), + ), + NumberedPolynomialAsIs( + listOf(1u) to Rational(1, 9), + listOf(0u, 1u) to Rational(11, 7), + ) + ), + 1 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf(1u) to Rational(-2, 7), + listOf(0u, 1u) to Rational(-4, 3), + ), + NumberedPolynomialAsIs( + listOf(1u) to Rational(3, 6), + listOf(0u, 1u) to Rational(12, 8), + ) + ), + )), + "test 2" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-130778291, 76800), + listOf(1u) to Rational(-445270919, 230400), + listOf(2u) to Rational(44578444937, 14515200), + listOf(3u) to Rational(17329402153, 1555200), + listOf(4u) to Rational(89239926809, 2332800), + listOf(5u) to Rational(2808812267, 145152), + listOf(6u) to Rational(-21362661007, 725760), + listOf(7u) to Rational(-258455443, 2016), + listOf(8u) to Rational(-21454693, 96), + listOf(0u, 1u) to Rational(-1002137, 15360), + listOf(1u, 1u) to Rational(-1704849697, 430080), + listOf(2u, 1u) to Rational(-57657676789, 4838400), + listOf(3u, 1u) to Rational(-101331731, 89600), + listOf(4u, 1u) to Rational(5362280079329, 130636800), + listOf(5u, 1u) to Rational(4069896167053, 130636800), + listOf(6u, 1u) to Rational(12011514569, 544320), + listOf(7u, 1u) to Rational(138293195623, 725760), + listOf(8u, 1u) to Rational(6228779419, 48384), + listOf(0u, 2u) to Rational(-32395872823, 8064000), + listOf(1u, 2u) to Rational(-7398505523, 2304000), + listOf(2u, 2u) to Rational(95217051699521, 3048192000), + listOf(3u, 2u) to Rational(198026968812079, 3657830400), + listOf(4u, 2u) to Rational(4291645618499, 228614400), + listOf(5u, 2u) to Rational(-33211690942439, 914457600), + listOf(6u, 2u) to Rational(-637385538163153, 1371686400), + listOf(7u, 2u) to Rational(-138671528276273, 182891520), + listOf(8u, 2u) to Rational(-14566368751, 217728), + listOf(0u, 3u) to Rational(-10538718719, 2016000), + listOf(1u, 3u) to Rational(-1844485375199, 84672000), + listOf(2u, 3u) to Rational(103968665891, 12096000), + listOf(3u, 3u) to Rational(175402107278351, 1828915200), + listOf(4u, 3u) to Rational(8020699588879, 114307200), + listOf(5u, 3u) to Rational(3414841894991, 38102400), + listOf(6u, 3u) to Rational(1848405591611, 4665600), + listOf(7u, 3u) to Rational(39486708738989, 137168640), + listOf(8u, 3u) to Rational(255926289517, 9144576), + listOf(0u, 4u) to Rational(-655379564629, 105840000), + listOf(1u, 4u) to Rational(-208336039441, 127008000), + listOf(2u, 4u) to Rational(40173146771411, 1143072000), + listOf(3u, 4u) to Rational(150473493581239, 2667168000), + listOf(4u, 4u) to Rational(38833783990483, 1143072000), + listOf(5u, 4u) to Rational(-1963676248203053, 4800902400), + listOf(6u, 4u) to Rational(-2598759412825747, 3200601600), + listOf(7u, 4u) to Rational(-192895352019667, 1280240640), + listOf(8u, 4u) to Rational(3737382679, 6858432), + listOf(0u, 5u) to Rational(-16959378721, 1890000), + listOf(1u, 5u) to Rational(-1864802244743, 79380000), + listOf(2u, 5u) to Rational(13449261536489, 666792000), + listOf(3u, 5u) to Rational(215272234137329, 2667168000), + listOf(4u, 5u) to Rational(6040691379277, 83349000), + listOf(5u, 5u) to Rational(153687143525887, 800150400), + listOf(6u, 5u) to Rational(475602854903563, 2400451200), + listOf(7u, 5u) to Rational(27315599358749, 640120320), + listOf(8u, 5u) to Rational(-2630413357, 10668672), + listOf(0u, 6u) to Rational(-6654999511, 2646000), + listOf(1u, 6u) to Rational(-67885252327, 15876000), + listOf(2u, 6u) to Rational(5786776220983, 2667168000), + listOf(3u, 6u) to Rational(60615922629083, 1143072000), + listOf(4u, 6u) to Rational(-34703539637627407, 672126336000), + listOf(5u, 6u) to Rational(-744694192134101, 2240421120), + listOf(6u, 6u) to Rational(-1782470617231, 14817600), + listOf(7u, 6u) to Rational(59123208433, 8890560), + listOf(8u, 6u) to Rational(-141653, 5292), + listOf(0u, 7u) to Rational(-338051969, 441000), + listOf(1u, 7u) to Rational(468850013, 1764000), + listOf(2u, 7u) to Rational(2102343426101, 222264000), + listOf(3u, 7u) to Rational(7836130602007, 1333584000), + listOf(4u, 7u) to Rational(16239111865997, 746807040), + listOf(5u, 7u) to Rational(3824649185383, 88905600), + listOf(6u, 7u) to Rational(56058614459, 3457440), + listOf(7u, 7u) to Rational(-396766339, 493920), + listOf(8u, 7u) to Rational(-165147, 2744), + listOf(0u, 8u) to Rational(-3088619, 58800), + listOf(1u, 8u) to Rational(155343347, 88200), + listOf(2u, 8u) to Rational(100098736469, 7408800), + listOf(3u, 8u) to Rational(109725511381, 7408800), + listOf(4u, 8u) to Rational(-2431199641013, 59270400), + listOf(5u, 8u) to Rational(-102872383249, 3457440), + listOf(6u, 8u) to Rational(1449461309, 576240), + listOf(7u, 8u) to Rational(812775, 1372), + listOf(8u, 8u) to Rational(-16461, 343) + ), + NumberedPolynomialAsIs( + listOf() to Rational(164202773, 230400), + listOf(1u) to Rational(-70345303, 518400), + listOf(2u) to Rational(-4229702731, 4665600), + listOf(3u) to Rational(3262171027, 6998400), + listOf(4u) to Rational(-25423104169, 13996800), + listOf(5u) to Rational(64061869, 349920), + listOf(6u) to Rational(-1655878091, 116640), + listOf(7u) to Rational(-7991441, 648), + listOf(8u) to Rational(-502591, 18), + listOf(0u, 1u) to Rational(-8780429, 3840), + listOf(1u, 1u) to Rational(434272361, 115200), + listOf(2u, 1u) to Rational(429825727, 41472), + listOf(3u, 1u) to Rational(-10066790339, 6998400), + listOf(4u, 1u) to Rational(70022035471, 20995200), + listOf(5u, 1u) to Rational(-32070283493, 1399680), + listOf(6u, 1u) to Rational(-22051101001, 1399680), + listOf(7u, 1u) to Rational(-126493427, 12960), + listOf(8u, 1u) to Rational(3050245, 864), + listOf(0u, 2u) to Rational(-1194654631, 345600), + listOf(1u, 2u) to Rational(-542961452671, 31104000), + listOf(2u, 2u) to Rational(-234000873607, 48988800), + listOf(3u, 2u) to Rational(140520538087, 3628800), + listOf(4u, 2u) to Rational(9215088876563, 130636800), + listOf(5u, 2u) to Rational(27590569647253, 293932800), + listOf(6u, 2u) to Rational(5129057792891, 97977600), + listOf(7u, 2u) to Rational(-106334191, 5103), + listOf(8u, 2u) to Rational(-1024113911, 435456), + listOf(0u, 3u) to Rational(76223843, 6000), + listOf(1u, 3u) to Rational(57425857357, 2592000), + listOf(2u, 3u) to Rational(-2044736497573, 46656000), + listOf(3u, 3u) to Rational(-26155810120031, 293932800), + listOf(4u, 3u) to Rational(-1064419459813, 6998400), + listOf(5u, 3u) to Rational(-753782018389, 4082400), + listOf(6u, 3u) to Rational(-291973360873, 2799360), + listOf(7u, 3u) to Rational(-46372122599, 816480), + listOf(8u, 3u) to Rational(3579859657, 653184), + listOf(0u, 4u) to Rational(-13374241901, 4320000), + listOf(1u, 4u) to Rational(306606499811, 54432000), + listOf(2u, 4u) to Rational(964267124745437, 13716864000), + listOf(3u, 4u) to Rational(21603809415373, 182891520), + listOf(4u, 4u) to Rational(1097860214654027, 6858432000), + listOf(5u, 4u) to Rational(161615254570669, 914457600), + listOf(6u, 4u) to Rational(758415239461, 22861440), + listOf(7u, 4u) to Rational(2585568355471, 274337280), + listOf(8u, 4u) to Rational(-70433747863, 9144576), + listOf(0u, 5u) to Rational(-9582586217, 2520000), + listOf(1u, 5u) to Rational(-19093471394171, 635040000), + listOf(2u, 5u) to Rational(-13010261944411, 381024000), + listOf(3u, 5u) to Rational(-259039825301861, 4572288000), + listOf(4u, 5u) to Rational(-305081119071079, 2286144000), + listOf(5u, 5u) to Rational(-1923114383311, 19595520), + listOf(6u, 5u) to Rational(-14181787253231, 228614400), + listOf(7u, 5u) to Rational(-3959584789, 4354560), + listOf(8u, 5u) to Rational(4691742523, 762048), + listOf(0u, 6u) to Rational(-588323437, 180000), + listOf(1u, 6u) to Rational(5952234691, 52920000), + listOf(2u, 6u) to Rational(21001851056959, 1088640000), + listOf(3u, 6u) to Rational(84668034357563, 2133734400), + listOf(4u, 6u) to Rational(2029754605811557, 25604812800), + listOf(5u, 6u) to Rational(11721216739823, 426746880), + listOf(6u, 6u) to Rational(-8275903187003, 2133734400), + listOf(7u, 6u) to Rational(-4730447299, 2540160), + listOf(8u, 6u) to Rational(-46069985, 21168), + listOf(0u, 7u) to Rational(-75711301, 117600), + listOf(1u, 7u) to Rational(32430417413, 7056000), + listOf(2u, 7u) to Rational(677988533153, 98784000), + listOf(3u, 7u) to Rational(-948417645827, 71124480), + listOf(4u, 7u) to Rational(-11320265215207, 711244800), + listOf(5u, 7u) to Rational(-676438627783, 50803200), + listOf(6u, 7u) to Rational(-7382274253, 1975680), + listOf(7u, 7u) to Rational(6505733, 2205), + listOf(8u, 7u) to Rational(450137, 882), + listOf(0u, 8u) to Rational(-8368253, 78400), + listOf(1u, 8u) to Rational(6833783, 117600), + listOf(2u, 8u) to Rational(4528971133, 5927040), + listOf(3u, 8u) to Rational(146252636617, 29635200), + listOf(4u, 8u) to Rational(8321882556889, 1659571200), + listOf(5u, 8u) to Rational(-4686033011, 1975680), + listOf(6u, 8u) to Rational(-1074445963, 987840), + listOf(7u, 8u) to Rational(-142313, 588), + listOf(8u, 8u) to Rational(-4281, 49) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(10, 2), + listOf(1u) to Rational(6, 7), + listOf(2u) to Rational(-16, 1), + listOf(0u, 1u) to Rational(13, 8), + listOf(1u, 1u) to Rational(-12, 1), + listOf(2u, 1u) to Rational(16, 8), + listOf(0u, 2u) to Rational(10, 4), + listOf(1u, 2u) to Rational(4, 1), + listOf(2u, 2u) to Rational(-11, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1, 4), + listOf(1u) to Rational(-17, 4), + listOf(2u) to Rational(-14, 8), + listOf(0u, 1u) to Rational(17, 9), + listOf(1u, 1u) to Rational(1, 3), + listOf(2u, 1u) to Rational(7, 6), + listOf(0u, 2u) to Rational(16, 3), + listOf(1u, 2u) to Rational(-17, 1), + listOf(2u, 2u) to Rational(-10, 8), + ) + ).substitute(RationalField, mapOf( + 0 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-17, 5), + listOf(1u) to Rational(2, 6), + listOf(2u) to Rational(14, 1), + listOf(0u, 1u) to Rational(-6, 6), + listOf(1u, 1u) to Rational(-7, 3), + listOf(2u, 1u) to Rational(-2, 9), + listOf(0u, 2u) to Rational(-9, 6), + listOf(1u, 2u) to Rational(17, 4), + listOf(2u, 2u) to Rational(2, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(5, 4), + listOf(1u) to Rational(-5, 9), + listOf(2u) to Rational(-3, 6), + listOf(0u, 1u) to Rational(6, 5), + listOf(1u, 1u) to Rational(14, 5), + listOf(2u, 1u) to Rational(5, 2), + listOf(0u, 2u) to Rational(-18, 7), + listOf(1u, 2u) to Rational(-8, 2), + listOf(2u, 2u) to Rational(18, 9), + ) + ), + 1 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(14, 4), + listOf(1u) to Rational(7, 6), + listOf(2u) to Rational(7, 2), + listOf(0u, 1u) to Rational(-15, 2), + listOf(1u, 1u) to Rational(-13, 8), + listOf(2u, 1u) to Rational(-14, 3), + listOf(0u, 2u) to Rational(-7, 6), + listOf(1u, 2u) to Rational(7, 4), + listOf(2u, 2u) to Rational(9, 7), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-7, 4), + listOf(1u) to Rational(-6, 3), + listOf(2u) to Rational(-16, 2), + listOf(0u, 1u) to Rational(-15, 5), + listOf(1u, 1u) to Rational(4, 6), + listOf(2u, 1u) to Rational(5, 4), + listOf(0u, 2u) to Rational(-12, 5), + listOf(1u, 2u) to Rational(-18, 2), + listOf(2u, 2u) to Rational(6, 7), + ) + ), + )), + "test 3" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-130778291, 76800), + listOf(1u) to Rational(-445270919, 230400), + listOf(2u) to Rational(44578444937, 14515200), + listOf(3u) to Rational(17329402153, 1555200), + listOf(4u) to Rational(89239926809, 2332800), + listOf(5u) to Rational(2808812267, 145152), + listOf(6u) to Rational(-21362661007, 725760), + listOf(7u) to Rational(-258455443, 2016), + listOf(8u) to Rational(-21454693, 96), + listOf(0u, 1u) to Rational(-1002137, 15360), + listOf(1u, 1u) to Rational(-1704849697, 430080), + listOf(2u, 1u) to Rational(-57657676789, 4838400), + listOf(3u, 1u) to Rational(-101331731, 89600), + listOf(4u, 1u) to Rational(5362280079329, 130636800), + listOf(5u, 1u) to Rational(4069896167053, 130636800), + listOf(6u, 1u) to Rational(12011514569, 544320), + listOf(7u, 1u) to Rational(138293195623, 725760), + listOf(8u, 1u) to Rational(6228779419, 48384), + listOf(0u, 2u) to Rational(-32395872823, 8064000), + listOf(1u, 2u) to Rational(-7398505523, 2304000), + listOf(2u, 2u) to Rational(95217051699521, 3048192000), + listOf(3u, 2u) to Rational(198026968812079, 3657830400), + listOf(4u, 2u) to Rational(4291645618499, 228614400), + listOf(5u, 2u) to Rational(-33211690942439, 914457600), + listOf(6u, 2u) to Rational(-637385538163153, 1371686400), + listOf(7u, 2u) to Rational(-138671528276273, 182891520), + listOf(8u, 2u) to Rational(-14566368751, 217728), + listOf(0u, 3u) to Rational(-10538718719, 2016000), + listOf(1u, 3u) to Rational(-1844485375199, 84672000), + listOf(2u, 3u) to Rational(103968665891, 12096000), + listOf(3u, 3u) to Rational(175402107278351, 1828915200), + listOf(4u, 3u) to Rational(8020699588879, 114307200), + listOf(5u, 3u) to Rational(3414841894991, 38102400), + listOf(6u, 3u) to Rational(1848405591611, 4665600), + listOf(7u, 3u) to Rational(39486708738989, 137168640), + listOf(8u, 3u) to Rational(255926289517, 9144576), + listOf(0u, 4u) to Rational(-655379564629, 105840000), + listOf(1u, 4u) to Rational(-208336039441, 127008000), + listOf(2u, 4u) to Rational(40173146771411, 1143072000), + listOf(3u, 4u) to Rational(150473493581239, 2667168000), + listOf(4u, 4u) to Rational(38833783990483, 1143072000), + listOf(5u, 4u) to Rational(-1963676248203053, 4800902400), + listOf(6u, 4u) to Rational(-2598759412825747, 3200601600), + listOf(7u, 4u) to Rational(-192895352019667, 1280240640), + listOf(8u, 4u) to Rational(3737382679, 6858432), + listOf(0u, 5u) to Rational(-16959378721, 1890000), + listOf(1u, 5u) to Rational(-1864802244743, 79380000), + listOf(2u, 5u) to Rational(13449261536489, 666792000), + listOf(3u, 5u) to Rational(215272234137329, 2667168000), + listOf(4u, 5u) to Rational(6040691379277, 83349000), + listOf(5u, 5u) to Rational(153687143525887, 800150400), + listOf(6u, 5u) to Rational(475602854903563, 2400451200), + listOf(7u, 5u) to Rational(27315599358749, 640120320), + listOf(8u, 5u) to Rational(-2630413357, 10668672), + listOf(0u, 6u) to Rational(-6654999511, 2646000), + listOf(1u, 6u) to Rational(-67885252327, 15876000), + listOf(2u, 6u) to Rational(5786776220983, 2667168000), + listOf(3u, 6u) to Rational(60615922629083, 1143072000), + listOf(4u, 6u) to Rational(-34703539637627407, 672126336000), + listOf(5u, 6u) to Rational(-744694192134101, 2240421120), + listOf(6u, 6u) to Rational(-1782470617231, 14817600), + listOf(7u, 6u) to Rational(59123208433, 8890560), + listOf(8u, 6u) to Rational(-141653, 5292), + listOf(0u, 7u) to Rational(-338051969, 441000), + listOf(1u, 7u) to Rational(468850013, 1764000), + listOf(2u, 7u) to Rational(2102343426101, 222264000), + listOf(3u, 7u) to Rational(7836130602007, 1333584000), + listOf(4u, 7u) to Rational(16239111865997, 746807040), + listOf(5u, 7u) to Rational(3824649185383, 88905600), + listOf(6u, 7u) to Rational(56058614459, 3457440), + listOf(7u, 7u) to Rational(-396766339, 493920), + listOf(8u, 7u) to Rational(-165147, 2744), + listOf(0u, 8u) to Rational(-3088619, 58800), + listOf(1u, 8u) to Rational(155343347, 88200), + listOf(2u, 8u) to Rational(100098736469, 7408800), + listOf(3u, 8u) to Rational(109725511381, 7408800), + listOf(4u, 8u) to Rational(-2431199641013, 59270400), + listOf(5u, 8u) to Rational(-102872383249, 3457440), + listOf(6u, 8u) to Rational(1449461309, 576240), + listOf(7u, 8u) to Rational(812775, 1372), + listOf(8u, 8u) to Rational(-16461, 343) + ), + NumberedPolynomialAsIs( + listOf() to Rational(164202773, 230400), + listOf(1u) to Rational(-70345303, 518400), + listOf(2u) to Rational(-4229702731, 4665600), + listOf(3u) to Rational(3262171027, 6998400), + listOf(4u) to Rational(-25423104169, 13996800), + listOf(5u) to Rational(64061869, 349920), + listOf(6u) to Rational(-1655878091, 116640), + listOf(7u) to Rational(-7991441, 648), + listOf(8u) to Rational(-502591, 18), + listOf(0u, 1u) to Rational(-8780429, 3840), + listOf(1u, 1u) to Rational(434272361, 115200), + listOf(2u, 1u) to Rational(429825727, 41472), + listOf(3u, 1u) to Rational(-10066790339, 6998400), + listOf(4u, 1u) to Rational(70022035471, 20995200), + listOf(5u, 1u) to Rational(-32070283493, 1399680), + listOf(6u, 1u) to Rational(-22051101001, 1399680), + listOf(7u, 1u) to Rational(-126493427, 12960), + listOf(8u, 1u) to Rational(3050245, 864), + listOf(0u, 2u) to Rational(-1194654631, 345600), + listOf(1u, 2u) to Rational(-542961452671, 31104000), + listOf(2u, 2u) to Rational(-234000873607, 48988800), + listOf(3u, 2u) to Rational(140520538087, 3628800), + listOf(4u, 2u) to Rational(9215088876563, 130636800), + listOf(5u, 2u) to Rational(27590569647253, 293932800), + listOf(6u, 2u) to Rational(5129057792891, 97977600), + listOf(7u, 2u) to Rational(-106334191, 5103), + listOf(8u, 2u) to Rational(-1024113911, 435456), + listOf(0u, 3u) to Rational(76223843, 6000), + listOf(1u, 3u) to Rational(57425857357, 2592000), + listOf(2u, 3u) to Rational(-2044736497573, 46656000), + listOf(3u, 3u) to Rational(-26155810120031, 293932800), + listOf(4u, 3u) to Rational(-1064419459813, 6998400), + listOf(5u, 3u) to Rational(-753782018389, 4082400), + listOf(6u, 3u) to Rational(-291973360873, 2799360), + listOf(7u, 3u) to Rational(-46372122599, 816480), + listOf(8u, 3u) to Rational(3579859657, 653184), + listOf(0u, 4u) to Rational(-13374241901, 4320000), + listOf(1u, 4u) to Rational(306606499811, 54432000), + listOf(2u, 4u) to Rational(964267124745437, 13716864000), + listOf(3u, 4u) to Rational(21603809415373, 182891520), + listOf(4u, 4u) to Rational(1097860214654027, 6858432000), + listOf(5u, 4u) to Rational(161615254570669, 914457600), + listOf(6u, 4u) to Rational(758415239461, 22861440), + listOf(7u, 4u) to Rational(2585568355471, 274337280), + listOf(8u, 4u) to Rational(-70433747863, 9144576), + listOf(0u, 5u) to Rational(-9582586217, 2520000), + listOf(1u, 5u) to Rational(-19093471394171, 635040000), + listOf(2u, 5u) to Rational(-13010261944411, 381024000), + listOf(3u, 5u) to Rational(-259039825301861, 4572288000), + listOf(4u, 5u) to Rational(-305081119071079, 2286144000), + listOf(5u, 5u) to Rational(-1923114383311, 19595520), + listOf(6u, 5u) to Rational(-14181787253231, 228614400), + listOf(7u, 5u) to Rational(-3959584789, 4354560), + listOf(8u, 5u) to Rational(4691742523, 762048), + listOf(0u, 6u) to Rational(-588323437, 180000), + listOf(1u, 6u) to Rational(5952234691, 52920000), + listOf(2u, 6u) to Rational(21001851056959, 1088640000), + listOf(3u, 6u) to Rational(84668034357563, 2133734400), + listOf(4u, 6u) to Rational(2029754605811557, 25604812800), + listOf(5u, 6u) to Rational(11721216739823, 426746880), + listOf(6u, 6u) to Rational(-8275903187003, 2133734400), + listOf(7u, 6u) to Rational(-4730447299, 2540160), + listOf(8u, 6u) to Rational(-46069985, 21168), + listOf(0u, 7u) to Rational(-75711301, 117600), + listOf(1u, 7u) to Rational(32430417413, 7056000), + listOf(2u, 7u) to Rational(677988533153, 98784000), + listOf(3u, 7u) to Rational(-948417645827, 71124480), + listOf(4u, 7u) to Rational(-11320265215207, 711244800), + listOf(5u, 7u) to Rational(-676438627783, 50803200), + listOf(6u, 7u) to Rational(-7382274253, 1975680), + listOf(7u, 7u) to Rational(6505733, 2205), + listOf(8u, 7u) to Rational(450137, 882), + listOf(0u, 8u) to Rational(-8368253, 78400), + listOf(1u, 8u) to Rational(6833783, 117600), + listOf(2u, 8u) to Rational(4528971133, 5927040), + listOf(3u, 8u) to Rational(146252636617, 29635200), + listOf(4u, 8u) to Rational(8321882556889, 1659571200), + listOf(5u, 8u) to Rational(-4686033011, 1975680), + listOf(6u, 8u) to Rational(-1074445963, 987840), + listOf(7u, 8u) to Rational(-142313, 588), + listOf(8u, 8u) to Rational(-4281, 49) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(10, 2), + listOf(1u) to Rational(6, 7), + listOf(2u) to Rational(-16, 1), + listOf(0u, 1u) to Rational(13, 8), + listOf(1u, 1u) to Rational(-12, 1), + listOf(2u, 1u) to Rational(16, 8), + listOf(0u, 2u) to Rational(10, 4), + listOf(1u, 2u) to Rational(4, 1), + listOf(2u, 2u) to Rational(-11, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1, 4), + listOf(1u) to Rational(-17, 4), + listOf(2u) to Rational(-14, 8), + listOf(0u, 1u) to Rational(17, 9), + listOf(1u, 1u) to Rational(1, 3), + listOf(2u, 1u) to Rational(7, 6), + listOf(0u, 2u) to Rational(16, 3), + listOf(1u, 2u) to Rational(-17, 1), + listOf(2u, 2u) to Rational(-10, 8), + ) + ).substitute(RationalField, mapOf( + 0 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-17, 5), + listOf(1u) to Rational(2, 6), + listOf(2u) to Rational(14, 1), + listOf(0u, 1u) to Rational(-6, 6), + listOf(1u, 1u) to Rational(-7, 3), + listOf(2u, 1u) to Rational(-2, 9), + listOf(0u, 2u) to Rational(-9, 6), + listOf(1u, 2u) to Rational(17, 4), + listOf(2u, 2u) to Rational(2, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(5, 4), + listOf(1u) to Rational(-5, 9), + listOf(2u) to Rational(-3, 6), + listOf(0u, 1u) to Rational(6, 5), + listOf(1u, 1u) to Rational(14, 5), + listOf(2u, 1u) to Rational(5, 2), + listOf(0u, 2u) to Rational(-18, 7), + listOf(1u, 2u) to Rational(-8, 2), + listOf(2u, 2u) to Rational(18, 9), + ) + ), + 1 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(14, 4), + listOf(1u) to Rational(7, 6), + listOf(2u) to Rational(7, 2), + listOf(0u, 1u) to Rational(-15, 2), + listOf(1u, 1u) to Rational(-13, 8), + listOf(2u, 1u) to Rational(-14, 3), + listOf(0u, 2u) to Rational(-7, 6), + listOf(1u, 2u) to Rational(7, 4), + listOf(2u, 2u) to Rational(9, 7), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-7, 4), + listOf(1u) to Rational(-6, 3), + listOf(2u) to Rational(-16, 2), + listOf(0u, 1u) to Rational(-15, 5), + listOf(1u, 1u) to Rational(4, 6), + listOf(2u, 1u) to Rational(5, 4), + listOf(0u, 2u) to Rational(-12, 5), + listOf(1u, 2u) to Rational(-18, 2), + listOf(2u, 2u) to Rational(6, 7), + ) + ), + 5 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(5, 8), + listOf(1u) to Rational(-12, 6), + listOf(2u) to Rational(7, 6), + listOf(0u, 1u) to Rational(-10, 4), + listOf(1u, 1u) to Rational(-7, 6), + listOf(2u, 1u) to Rational(8, 9), + listOf(0u, 2u) to Rational(16, 3), + listOf(1u, 2u) to Rational(-13, 4), + listOf(2u, 2u) to Rational(5, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(10, 6), + listOf(1u) to Rational(-18, 6), + listOf(2u) to Rational(5, 1), + listOf(0u, 1u) to Rational(17, 7), + listOf(1u, 1u) to Rational(8, 4), + listOf(2u, 1u) to Rational(-4, 9), + listOf(0u, 2u) to Rational(-6, 5), + listOf(1u, 2u) to Rational(-15, 8), + listOf(2u, 2u) to Rational(-18, 5), + ) + ), + )), + "test 3'" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(2303, 64), + listOf(1u) to Rational(31843, 192), + listOf(2u) to Rational(118891, 576), + listOf(3u) to Rational(94453, 168), + listOf(4u) to Rational(-179203, 1512), + listOf(5u) to Rational(-16979, 126), + listOf(6u) to Rational(-13499, 12), + listOf(0u, 1u) to Rational(-4767, 64), + listOf(1u, 1u) to Rational(-58689, 256), + listOf(2u, 1u) to Rational(-757333, 4032), + listOf(3u, 1u) to Rational(-4921205, 4032), + listOf(4u, 1u) to Rational(-2930815, 4032), + listOf(5u, 1u) to Rational(-398803, 1512), + listOf(6u, 1u) to Rational(18835, 36), + listOf(0u, 2u) to Rational(224101, 960), + listOf(1u, 2u) to Rational(9139699, 40320), + listOf(2u, 2u) to Rational(3848803, 5760), + listOf(3u, 2u) to Rational(93102371, 241920), + listOf(4u, 2u) to Rational(-65821229, 141120), + listOf(5u, 2u) to Rational(-15675899, 7056), + listOf(6u, 2u) to Rational(10459, 189), + listOf(0u, 3u) to Rational(2411, 16), + listOf(1u, 3u) to Rational(1294543, 10080), + listOf(2u, 3u) to Rational(-1740199, 1440), + listOf(3u, 3u) to Rational(-266994841, 282240), + listOf(4u, 3u) to Rational(-41261893, 211680), + listOf(5u, 3u) to Rational(1717357, 3528), + listOf(6u, 3u) to Rational(69, 14), + listOf(0u, 4u) to Rational(13231, 360), + listOf(1u, 4u) to Rational(4858831, 25200), + listOf(2u, 4u) to Rational(15565759, 75600), + listOf(3u, 4u) to Rational(-15583391, 35280), + listOf(4u, 4u) to Rational(-13345747, 11760), + listOf(5u, 4u) to Rational(140103, 686), + listOf(6u, 4u) to Rational(-765, 49) + ), + NumberedPolynomialAsIs( + listOf() to Rational(31409, 576), + listOf(1u) to Rational(-337099, 1728), + listOf(2u) to Rational(-211429, 1728), + listOf(3u) to Rational(-259241, 432), + listOf(4u) to Rational(-13777, 36), + listOf(5u) to Rational(-41389, 72), + listOf(6u) to Rational(-7679, 48), + listOf(0u, 1u) to Rational(-3269, 12), + listOf(1u, 1u) to Rational(629569, 864), + listOf(2u, 1u) to Rational(53867, 324), + listOf(3u, 1u) to Rational(2290577, 1728), + listOf(4u, 1u) to Rational(101507, 216), + listOf(5u, 1u) to Rational(213109, 288), + listOf(6u, 1u) to Rational(17927, 144), + listOf(0u, 2u) to Rational(314587, 1080), + listOf(1u, 2u) to Rational(-109771, 144), + listOf(2u, 2u) to Rational(-6469, 16), + listOf(3u, 2u) to Rational(-298291681, 181440), + listOf(4u, 2u) to Rational(-59147357, 48384), + listOf(5u, 2u) to Rational(-4982365, 6048), + listOf(6u, 2u) to Rational(-18727, 576), + listOf(0u, 3u) to Rational(12379, 90), + listOf(1u, 3u) to Rational(-542911, 1620), + listOf(2u, 3u) to Rational(143123, 1260), + listOf(3u, 3u) to Rational(9859177, 30240), + listOf(4u, 3u) to Rational(9312529, 20160), + listOf(5u, 3u) to Rational(207001, 672), + listOf(6u, 3u) to Rational(203, 24), + listOf(0u, 4u) to Rational(9442, 675), + listOf(1u, 4u) to Rational(-13729, 300), + listOf(2u, 4u) to Rational(-3490471, 25200), + listOf(3u, 4u) to Rational(-333031, 840), + listOf(4u, 4u) to Rational(-7572211, 47040), + listOf(5u, 4u) to Rational(-1189, 56), + listOf(6u, 4u) to Rational(-405, 196) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(10, 2), + listOf(1u) to Rational(6, 7), + listOf(2u) to Rational(-16, 1), + listOf(0u, 1u) to Rational(13, 8), + listOf(1u, 1u) to Rational(-12, 1), + listOf(2u, 1u) to Rational(16, 8), + listOf(0u, 2u) to Rational(10, 4), + listOf(1u, 2u) to Rational(4, 1), + listOf(2u, 2u) to Rational(-11, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1, 4), + listOf(1u) to Rational(-17, 4), + listOf(2u) to Rational(-14, 8), + listOf(0u, 1u) to Rational(17, 9), + listOf(1u, 1u) to Rational(1, 3), + listOf(2u, 1u) to Rational(7, 6), + listOf(0u, 2u) to Rational(16, 3), + listOf(1u, 2u) to Rational(-17, 1), + listOf(2u, 2u) to Rational(-10, 8), + ) + ).substitute(RationalField, mapOf( + 1 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(14, 4), + listOf(1u) to Rational(7, 6), + listOf(2u) to Rational(7, 2), + listOf(0u, 1u) to Rational(-15, 2), + listOf(1u, 1u) to Rational(-13, 8), + listOf(2u, 1u) to Rational(-14, 3), + listOf(0u, 2u) to Rational(-7, 6), + listOf(1u, 2u) to Rational(7, 4), + listOf(2u, 2u) to Rational(9, 7), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-7, 4), + listOf(1u) to Rational(-6, 3), + listOf(2u) to Rational(-16, 2), + listOf(0u, 1u) to Rational(-15, 5), + listOf(1u, 1u) to Rational(4, 6), + listOf(2u, 1u) to Rational(5, 4), + listOf(0u, 2u) to Rational(-12, 5), + listOf(1u, 2u) to Rational(-18, 2), + listOf(2u, 2u) to Rational(6, 7), + ) + ), + )), + "test 4" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(2303, 64), + listOf(1u) to Rational(31843, 192), + listOf(2u) to Rational(118891, 576), + listOf(3u) to Rational(94453, 168), + listOf(4u) to Rational(-179203, 1512), + listOf(5u) to Rational(-16979, 126), + listOf(6u) to Rational(-13499, 12), + listOf(0u, 1u) to Rational(-4767, 64), + listOf(1u, 1u) to Rational(-58689, 256), + listOf(2u, 1u) to Rational(-757333, 4032), + listOf(3u, 1u) to Rational(-4921205, 4032), + listOf(4u, 1u) to Rational(-2930815, 4032), + listOf(5u, 1u) to Rational(-398803, 1512), + listOf(6u, 1u) to Rational(18835, 36), + listOf(0u, 2u) to Rational(224101, 960), + listOf(1u, 2u) to Rational(9139699, 40320), + listOf(2u, 2u) to Rational(3848803, 5760), + listOf(3u, 2u) to Rational(93102371, 241920), + listOf(4u, 2u) to Rational(-65821229, 141120), + listOf(5u, 2u) to Rational(-15675899, 7056), + listOf(6u, 2u) to Rational(10459, 189), + listOf(0u, 3u) to Rational(2411, 16), + listOf(1u, 3u) to Rational(1294543, 10080), + listOf(2u, 3u) to Rational(-1740199, 1440), + listOf(3u, 3u) to Rational(-266994841, 282240), + listOf(4u, 3u) to Rational(-41261893, 211680), + listOf(5u, 3u) to Rational(1717357, 3528), + listOf(6u, 3u) to Rational(69, 14), + listOf(0u, 4u) to Rational(13231, 360), + listOf(1u, 4u) to Rational(4858831, 25200), + listOf(2u, 4u) to Rational(15565759, 75600), + listOf(3u, 4u) to Rational(-15583391, 35280), + listOf(4u, 4u) to Rational(-13345747, 11760), + listOf(5u, 4u) to Rational(140103, 686), + listOf(6u, 4u) to Rational(-765, 49) + ), + NumberedPolynomialAsIs( + listOf() to Rational(31409, 576), + listOf(1u) to Rational(-337099, 1728), + listOf(2u) to Rational(-211429, 1728), + listOf(3u) to Rational(-259241, 432), + listOf(4u) to Rational(-13777, 36), + listOf(5u) to Rational(-41389, 72), + listOf(6u) to Rational(-7679, 48), + listOf(0u, 1u) to Rational(-3269, 12), + listOf(1u, 1u) to Rational(629569, 864), + listOf(2u, 1u) to Rational(53867, 324), + listOf(3u, 1u) to Rational(2290577, 1728), + listOf(4u, 1u) to Rational(101507, 216), + listOf(5u, 1u) to Rational(213109, 288), + listOf(6u, 1u) to Rational(17927, 144), + listOf(0u, 2u) to Rational(314587, 1080), + listOf(1u, 2u) to Rational(-109771, 144), + listOf(2u, 2u) to Rational(-6469, 16), + listOf(3u, 2u) to Rational(-298291681, 181440), + listOf(4u, 2u) to Rational(-59147357, 48384), + listOf(5u, 2u) to Rational(-4982365, 6048), + listOf(6u, 2u) to Rational(-18727, 576), + listOf(0u, 3u) to Rational(12379, 90), + listOf(1u, 3u) to Rational(-542911, 1620), + listOf(2u, 3u) to Rational(143123, 1260), + listOf(3u, 3u) to Rational(9859177, 30240), + listOf(4u, 3u) to Rational(9312529, 20160), + listOf(5u, 3u) to Rational(207001, 672), + listOf(6u, 3u) to Rational(203, 24), + listOf(0u, 4u) to Rational(9442, 675), + listOf(1u, 4u) to Rational(-13729, 300), + listOf(2u, 4u) to Rational(-3490471, 25200), + listOf(3u, 4u) to Rational(-333031, 840), + listOf(4u, 4u) to Rational(-7572211, 47040), + listOf(5u, 4u) to Rational(-1189, 56), + listOf(6u, 4u) to Rational(-405, 196) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(10, 2), + listOf(1u) to Rational(6, 7), + listOf(2u) to Rational(-16, 1), + listOf(0u, 1u) to Rational(13, 8), + listOf(1u, 1u) to Rational(-12, 1), + listOf(2u, 1u) to Rational(16, 8), + listOf(0u, 2u) to Rational(10, 4), + listOf(1u, 2u) to Rational(4, 1), + listOf(2u, 2u) to Rational(-11, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1, 4), + listOf(1u) to Rational(-17, 4), + listOf(2u) to Rational(-14, 8), + listOf(0u, 1u) to Rational(17, 9), + listOf(1u, 1u) to Rational(1, 3), + listOf(2u, 1u) to Rational(7, 6), + listOf(0u, 2u) to Rational(16, 3), + listOf(1u, 2u) to Rational(-17, 1), + listOf(2u, 2u) to Rational(-10, 8), + ) + ).substitute(RationalField, mapOf( + 1 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(14, 4), + listOf(1u) to Rational(7, 6), + listOf(2u) to Rational(7, 2), + listOf(0u, 1u) to Rational(-15, 2), + listOf(1u, 1u) to Rational(-13, 8), + listOf(2u, 1u) to Rational(-14, 3), + listOf(0u, 2u) to Rational(-7, 6), + listOf(1u, 2u) to Rational(7, 4), + listOf(2u, 2u) to Rational(9, 7), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-7, 4), + listOf(1u) to Rational(-6, 3), + listOf(2u) to Rational(-16, 2), + listOf(0u, 1u) to Rational(-15, 5), + listOf(1u, 1u) to Rational(4, 6), + listOf(2u, 1u) to Rational(5, 4), + listOf(0u, 2u) to Rational(-12, 5), + listOf(1u, 2u) to Rational(-18, 2), + listOf(2u, 2u) to Rational(6, 7), + ) + ), + 5 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(5, 8), + listOf(1u) to Rational(-12, 6), + listOf(2u) to Rational(7, 6), + listOf(0u, 1u) to Rational(-10, 4), + listOf(1u, 1u) to Rational(-7, 6), + listOf(2u, 1u) to Rational(8, 9), + listOf(0u, 2u) to Rational(16, 3), + listOf(1u, 2u) to Rational(-13, 4), + listOf(2u, 2u) to Rational(5, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(10, 6), + listOf(1u) to Rational(-18, 6), + listOf(2u) to Rational(5, 1), + listOf(0u, 1u) to Rational(17, 7), + listOf(1u, 1u) to Rational(8, 4), + listOf(2u, 1u) to Rational(-4, 9), + listOf(0u, 2u) to Rational(-6, 5), + listOf(1u, 2u) to Rational(-15, 8), + listOf(2u, 2u) to Rational(-18, 5), + ) + ), + )), + "test 4'" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-506213, 2800), + listOf(1u) to Rational(9859, 315), + listOf(2u) to Rational(17384377, 11340), + listOf(3u) to Rational(-9662, 63), + listOf(4u) to Rational(-12563, 4), + listOf(0u, 1u) to Rational(-486293, 22400), + listOf(1u, 1u) to Rational(-6530947, 25200), + listOf(2u, 1u) to Rational(866125, 18144), + listOf(3u, 1u) to Rational(2948747, 2520), + listOf(4u, 1u) to Rational(1196611, 2016), + listOf(0u, 2u) to Rational(-20266021, 117600), + listOf(1u, 2u) to Rational(26656339, 44100), + listOf(2u, 2u) to Rational(19499183, 18144), + listOf(3u, 2u) to Rational(-19801849, 7560), + listOf(4u, 2u) to Rational(-2639635, 1296), + listOf(0u, 3u) to Rational(-5017697, 29400), + listOf(1u, 3u) to Rational(-606007, 1575), + listOf(2u, 3u) to Rational(127494487, 132300), + listOf(3u, 3u) to Rational(166567, 105), + listOf(4u, 3u) to Rational(486403, 18144), + listOf(0u, 4u) to Rational(-32182, 735), + listOf(1u, 4u) to Rational(2420671, 8820), + listOf(2u, 4u) to Rational(-12619193, 26460), + listOf(3u, 4u) to Rational(-6823067, 5670), + listOf(4u, 4u) to Rational(-2311693, 13608), + listOf(0u, 5u) to Rational(-13324, 245), + listOf(1u, 5u) to Rational(1966, 35), + listOf(2u, 5u) to Rational(1052719, 2520), + listOf(3u, 5u) to Rational(19153, 270), + listOf(4u, 5u) to Rational(701, 54), + listOf(0u, 6u) to Rational(4647, 196), + listOf(1u, 6u) to Rational(2197, 28), + listOf(2u, 6u) to Rational(-43853, 336), + listOf(3u, 6u) to Rational(-301, 3), + listOf(4u, 6u) to Rational(34, 3) + ), + NumberedPolynomialAsIs( + listOf() to Rational(-2843, 1600), + listOf(1u) to Rational(-1483, 240), + listOf(2u) to Rational(110623, 1296), + listOf(3u) to Rational(1265, 72), + listOf(4u) to Rational(-5011, 16), + listOf(0u, 1u) to Rational(47743, 1800), + listOf(1u, 1u) to Rational(619229, 32400), + listOf(2u, 1u) to Rational(-5978369, 58320), + listOf(3u, 1u) to Rational(-86081, 1620), + listOf(4u, 1u) to Rational(6325, 72), + listOf(0u, 2u) to Rational(110951, 3360), + listOf(1u, 2u) to Rational(-9550649, 302400), + listOf(2u, 2u) to Rational(6542933, 85050), + listOf(3u, 2u) to Rational(4708291, 38880), + listOf(4u, 2u) to Rational(-433327, 1296), + listOf(0u, 3u) to Rational(56143, 600), + listOf(1u, 3u) to Rational(94243, 720), + listOf(2u, 3u) to Rational(-46779139, 226800), + listOf(3u, 3u) to Rational(-6948253, 12960), + listOf(4u, 3u) to Rational(-260261, 486), + listOf(0u, 4u) to Rational(-3205317, 19600), + listOf(1u, 4u) to Rational(-201253, 1050), + listOf(2u, 4u) to Rational(332192677, 302400), + listOf(3u, 4u) to Rational(351511, 360), + listOf(4u, 4u) to Rational(-40547, 81), + listOf(0u, 5u) to Rational(-65421, 1960), + listOf(1u, 5u) to Rational(-10118, 35), + listOf(2u, 5u) to Rational(-4341709, 10080), + listOf(3u, 5u) to Rational(-91703, 360), + listOf(4u, 5u) to Rational(-85, 9), + listOf(0u, 6u) to Rational(-25965, 784), + listOf(1u, 6u) to Rational(3351, 16), + listOf(2u, 6u) to Rational(595159, 1344), + listOf(3u, 6u) to Rational(-1381, 12), + listOf(4u, 6u) to Rational(-155, 3) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(10, 2), + listOf(1u) to Rational(6, 7), + listOf(2u) to Rational(-16, 1), + listOf(0u, 1u) to Rational(13, 8), + listOf(1u, 1u) to Rational(-12, 1), + listOf(2u, 1u) to Rational(16, 8), + listOf(0u, 2u) to Rational(10, 4), + listOf(1u, 2u) to Rational(4, 1), + listOf(2u, 2u) to Rational(-11, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1, 4), + listOf(1u) to Rational(-17, 4), + listOf(2u) to Rational(-14, 8), + listOf(0u, 1u) to Rational(17, 9), + listOf(1u, 1u) to Rational(1, 3), + listOf(2u, 1u) to Rational(7, 6), + listOf(0u, 2u) to Rational(16, 3), + listOf(1u, 2u) to Rational(-17, 1), + listOf(2u, 2u) to Rational(-10, 8), + ) + ).substitute(RationalField, mapOf( + 0 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-17, 5), + listOf(1u) to Rational(2, 6), + listOf(2u) to Rational(14, 1), + listOf(0u, 1u) to Rational(-6, 6), + listOf(1u, 1u) to Rational(-7, 3), + listOf(2u, 1u) to Rational(-2, 9), + listOf(0u, 2u) to Rational(-9, 6), + listOf(1u, 2u) to Rational(17, 4), + listOf(2u, 2u) to Rational(2, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(5, 4), + listOf(1u) to Rational(-5, 9), + listOf(2u) to Rational(-3, 6), + listOf(0u, 1u) to Rational(6, 5), + listOf(1u, 1u) to Rational(14, 5), + listOf(2u, 1u) to Rational(5, 2), + listOf(0u, 2u) to Rational(-18, 7), + listOf(1u, 2u) to Rational(-8, 2), + listOf(2u, 2u) to Rational(18, 9), + ) + ), + )), + "test 5" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-506213, 2800), + listOf(1u) to Rational(9859, 315), + listOf(2u) to Rational(17384377, 11340), + listOf(3u) to Rational(-9662, 63), + listOf(4u) to Rational(-12563, 4), + listOf(0u, 1u) to Rational(-486293, 22400), + listOf(1u, 1u) to Rational(-6530947, 25200), + listOf(2u, 1u) to Rational(866125, 18144), + listOf(3u, 1u) to Rational(2948747, 2520), + listOf(4u, 1u) to Rational(1196611, 2016), + listOf(0u, 2u) to Rational(-20266021, 117600), + listOf(1u, 2u) to Rational(26656339, 44100), + listOf(2u, 2u) to Rational(19499183, 18144), + listOf(3u, 2u) to Rational(-19801849, 7560), + listOf(4u, 2u) to Rational(-2639635, 1296), + listOf(0u, 3u) to Rational(-5017697, 29400), + listOf(1u, 3u) to Rational(-606007, 1575), + listOf(2u, 3u) to Rational(127494487, 132300), + listOf(3u, 3u) to Rational(166567, 105), + listOf(4u, 3u) to Rational(486403, 18144), + listOf(0u, 4u) to Rational(-32182, 735), + listOf(1u, 4u) to Rational(2420671, 8820), + listOf(2u, 4u) to Rational(-12619193, 26460), + listOf(3u, 4u) to Rational(-6823067, 5670), + listOf(4u, 4u) to Rational(-2311693, 13608), + listOf(0u, 5u) to Rational(-13324, 245), + listOf(1u, 5u) to Rational(1966, 35), + listOf(2u, 5u) to Rational(1052719, 2520), + listOf(3u, 5u) to Rational(19153, 270), + listOf(4u, 5u) to Rational(701, 54), + listOf(0u, 6u) to Rational(4647, 196), + listOf(1u, 6u) to Rational(2197, 28), + listOf(2u, 6u) to Rational(-43853, 336), + listOf(3u, 6u) to Rational(-301, 3), + listOf(4u, 6u) to Rational(34, 3) + ), + NumberedPolynomialAsIs( + listOf() to Rational(-2843, 1600), + listOf(1u) to Rational(-1483, 240), + listOf(2u) to Rational(110623, 1296), + listOf(3u) to Rational(1265, 72), + listOf(4u) to Rational(-5011, 16), + listOf(0u, 1u) to Rational(47743, 1800), + listOf(1u, 1u) to Rational(619229, 32400), + listOf(2u, 1u) to Rational(-5978369, 58320), + listOf(3u, 1u) to Rational(-86081, 1620), + listOf(4u, 1u) to Rational(6325, 72), + listOf(0u, 2u) to Rational(110951, 3360), + listOf(1u, 2u) to Rational(-9550649, 302400), + listOf(2u, 2u) to Rational(6542933, 85050), + listOf(3u, 2u) to Rational(4708291, 38880), + listOf(4u, 2u) to Rational(-433327, 1296), + listOf(0u, 3u) to Rational(56143, 600), + listOf(1u, 3u) to Rational(94243, 720), + listOf(2u, 3u) to Rational(-46779139, 226800), + listOf(3u, 3u) to Rational(-6948253, 12960), + listOf(4u, 3u) to Rational(-260261, 486), + listOf(0u, 4u) to Rational(-3205317, 19600), + listOf(1u, 4u) to Rational(-201253, 1050), + listOf(2u, 4u) to Rational(332192677, 302400), + listOf(3u, 4u) to Rational(351511, 360), + listOf(4u, 4u) to Rational(-40547, 81), + listOf(0u, 5u) to Rational(-65421, 1960), + listOf(1u, 5u) to Rational(-10118, 35), + listOf(2u, 5u) to Rational(-4341709, 10080), + listOf(3u, 5u) to Rational(-91703, 360), + listOf(4u, 5u) to Rational(-85, 9), + listOf(0u, 6u) to Rational(-25965, 784), + listOf(1u, 6u) to Rational(3351, 16), + listOf(2u, 6u) to Rational(595159, 1344), + listOf(3u, 6u) to Rational(-1381, 12), + listOf(4u, 6u) to Rational(-155, 3) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(10, 2), + listOf(1u) to Rational(6, 7), + listOf(2u) to Rational(-16, 1), + listOf(0u, 1u) to Rational(13, 8), + listOf(1u, 1u) to Rational(-12, 1), + listOf(2u, 1u) to Rational(16, 8), + listOf(0u, 2u) to Rational(10, 4), + listOf(1u, 2u) to Rational(4, 1), + listOf(2u, 2u) to Rational(-11, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1, 4), + listOf(1u) to Rational(-17, 4), + listOf(2u) to Rational(-14, 8), + listOf(0u, 1u) to Rational(17, 9), + listOf(1u, 1u) to Rational(1, 3), + listOf(2u, 1u) to Rational(7, 6), + listOf(0u, 2u) to Rational(16, 3), + listOf(1u, 2u) to Rational(-17, 1), + listOf(2u, 2u) to Rational(-10, 8), + ) + ).substitute(RationalField, mapOf( + 0 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-17, 5), + listOf(1u) to Rational(2, 6), + listOf(2u) to Rational(14, 1), + listOf(0u, 1u) to Rational(-6, 6), + listOf(1u, 1u) to Rational(-7, 3), + listOf(2u, 1u) to Rational(-2, 9), + listOf(0u, 2u) to Rational(-9, 6), + listOf(1u, 2u) to Rational(17, 4), + listOf(2u, 2u) to Rational(2, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(5, 4), + listOf(1u) to Rational(-5, 9), + listOf(2u) to Rational(-3, 6), + listOf(0u, 1u) to Rational(6, 5), + listOf(1u, 1u) to Rational(14, 5), + listOf(2u, 1u) to Rational(5, 2), + listOf(0u, 2u) to Rational(-18, 7), + listOf(1u, 2u) to Rational(-8, 2), + listOf(2u, 2u) to Rational(18, 9), + ) + ), + 5 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(5, 8), + listOf(1u) to Rational(-12, 6), + listOf(2u) to Rational(7, 6), + listOf(0u, 1u) to Rational(-10, 4), + listOf(1u, 1u) to Rational(-7, 6), + listOf(2u, 1u) to Rational(8, 9), + listOf(0u, 2u) to Rational(16, 3), + listOf(1u, 2u) to Rational(-13, 4), + listOf(2u, 2u) to Rational(5, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(10, 6), + listOf(1u) to Rational(-18, 6), + listOf(2u) to Rational(5, 1), + listOf(0u, 1u) to Rational(17, 7), + listOf(1u, 1u) to Rational(8, 4), + listOf(2u, 1u) to Rational(-4, 9), + listOf(0u, 2u) to Rational(-6, 5), + listOf(1u, 2u) to Rational(-15, 8), + listOf(2u, 2u) to Rational(-18, 5), + ) + ), + )), + "test 5'" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(10, 2), + listOf(1u) to Rational(6, 7), + listOf(2u) to Rational(-16, 1), + listOf(0u, 1u) to Rational(13, 8), + listOf(1u, 1u) to Rational(-12, 1), + listOf(2u, 1u) to Rational(16, 8), + listOf(0u, 2u) to Rational(10, 4), + listOf(1u, 2u) to Rational(4, 1), + listOf(2u, 2u) to Rational(-11, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1, 4), + listOf(1u) to Rational(-17, 4), + listOf(2u) to Rational(-14, 8), + listOf(0u, 1u) to Rational(17, 9), + listOf(1u, 1u) to Rational(1, 3), + listOf(2u, 1u) to Rational(7, 6), + listOf(0u, 2u) to Rational(16, 3), + listOf(1u, 2u) to Rational(-17, 1), + listOf(2u, 2u) to Rational(-10, 8), + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(10, 2), + listOf(1u) to Rational(6, 7), + listOf(2u) to Rational(-16, 1), + listOf(0u, 1u) to Rational(13, 8), + listOf(1u, 1u) to Rational(-12, 1), + listOf(2u, 1u) to Rational(16, 8), + listOf(0u, 2u) to Rational(10, 4), + listOf(1u, 2u) to Rational(4, 1), + listOf(2u, 2u) to Rational(-11, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1, 4), + listOf(1u) to Rational(-17, 4), + listOf(2u) to Rational(-14, 8), + listOf(0u, 1u) to Rational(17, 9), + listOf(1u, 1u) to Rational(1, 3), + listOf(2u, 1u) to Rational(7, 6), + listOf(0u, 2u) to Rational(16, 3), + listOf(1u, 2u) to Rational(-17, 1), + listOf(2u, 2u) to Rational(-10, 8), + ) + ).substitute(RationalField, mapOf>()), + "test 6" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(10, 2), + listOf(1u) to Rational(6, 7), + listOf(2u) to Rational(-16, 1), + listOf(0u, 1u) to Rational(13, 8), + listOf(1u, 1u) to Rational(-12, 1), + listOf(2u, 1u) to Rational(16, 8), + listOf(0u, 2u) to Rational(10, 4), + listOf(1u, 2u) to Rational(4, 1), + listOf(2u, 2u) to Rational(-11, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1, 4), + listOf(1u) to Rational(-17, 4), + listOf(2u) to Rational(-14, 8), + listOf(0u, 1u) to Rational(17, 9), + listOf(1u, 1u) to Rational(1, 3), + listOf(2u, 1u) to Rational(7, 6), + listOf(0u, 2u) to Rational(16, 3), + listOf(1u, 2u) to Rational(-17, 1), + listOf(2u, 2u) to Rational(-10, 8), + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(10, 2), + listOf(1u) to Rational(6, 7), + listOf(2u) to Rational(-16, 1), + listOf(0u, 1u) to Rational(13, 8), + listOf(1u, 1u) to Rational(-12, 1), + listOf(2u, 1u) to Rational(16, 8), + listOf(0u, 2u) to Rational(10, 4), + listOf(1u, 2u) to Rational(4, 1), + listOf(2u, 2u) to Rational(-11, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1, 4), + listOf(1u) to Rational(-17, 4), + listOf(2u) to Rational(-14, 8), + listOf(0u, 1u) to Rational(17, 9), + listOf(1u, 1u) to Rational(1, 3), + listOf(2u, 1u) to Rational(7, 6), + listOf(0u, 2u) to Rational(16, 3), + listOf(1u, 2u) to Rational(-17, 1), + listOf(2u, 2u) to Rational(-10, 8), + ) + ).substitute(RationalField, mapOf( + 5 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(5, 8), + listOf(1u) to Rational(-12, 6), + listOf(2u) to Rational(7, 6), + listOf(0u, 1u) to Rational(-10, 4), + listOf(1u, 1u) to Rational(-7, 6), + listOf(2u, 1u) to Rational(8, 9), + listOf(0u, 2u) to Rational(16, 3), + listOf(1u, 2u) to Rational(-13, 4), + listOf(2u, 2u) to Rational(5, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(10, 6), + listOf(1u) to Rational(-18, 6), + listOf(2u) to Rational(5, 1), + listOf(0u, 1u) to Rational(17, 7), + listOf(1u, 1u) to Rational(8, 4), + listOf(2u, 1u) to Rational(-4, 9), + listOf(0u, 2u) to Rational(-6, 5), + listOf(1u, 2u) to Rational(-15, 8), + listOf(2u, 2u) to Rational(-18, 5), + ) + ), + )), + "test 6'" + ) } @Test @Ignore @@ -2244,7 +5416,7 @@ class NumberedPolynomialUtilTest { } @Test @Ignore // FIXME: This tests work only for sane realisations of the substitutions. Currently, it is not. - // Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should make denominator r^deg(p), + // Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should return denominator r^deg(p), // not r^(deg(p)(deg(p)+1)/2) as it is now. fun test_Polynomial_substitute_RationalFunction_Buffer() { // TODO @@ -2266,7 +5438,7 @@ class NumberedPolynomialUtilTest { } @Test @Ignore // FIXME: This tests work only for sane realisations of the substitutions. Currently, it is not. - // Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should make denominator r^deg(p), + // Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should return denominator r^deg(p), // not r^(deg(p)(deg(p)+1)/2) as it is now. fun test_RationalFunction_substitute_RationalFunction_Buffer() { // TODO 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 index 4bdd60704..071701593 100644 --- 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 @@ -41,66 +41,105 @@ class Rational { operator fun unaryPlus(): Rational = this operator fun unaryMinus(): Rational = Rational(-this.numerator, this.denominator) - operator fun plus(other: Rational): Rational = - Rational( - numerator * other.denominator + denominator * other.numerator, - denominator * other.denominator + operator fun plus(other: Rational): Rational { + val denominatorsGcd = gcd(denominator, other.denominator) + val dividedThisDenominator = denominator / denominatorsGcd + val dividedOtherDenominator = other.denominator / denominatorsGcd + val numeratorCandidate = numerator * dividedOtherDenominator + dividedThisDenominator * other.numerator + val secondGcd = gcd(numeratorCandidate, denominatorsGcd) + return Rational( + numeratorCandidate / secondGcd, + dividedThisDenominator * (other.denominator / secondGcd), + toCheckInput = false ) + } operator fun plus(other: Int): Rational = Rational( numerator + denominator * other.toLong(), - denominator + denominator, + toCheckInput = false ) operator fun plus(other: Long): Rational = Rational( numerator + denominator * other, - denominator + denominator, + toCheckInput = false ) - operator fun minus(other: Rational): Rational = - Rational( - numerator * other.denominator - denominator * other.numerator, - denominator * other.denominator + operator fun minus(other: Rational): Rational { + val denominatorsGcd = gcd(denominator, other.denominator) + val dividedThisDenominator = denominator / denominatorsGcd + val dividedOtherDenominator = other.denominator / denominatorsGcd + val numeratorCandidate = numerator * dividedOtherDenominator - dividedThisDenominator * other.numerator + val secondGcd = gcd(numeratorCandidate, denominatorsGcd) + return Rational( + numeratorCandidate / secondGcd, + dividedThisDenominator * (other.denominator / secondGcd), + toCheckInput = false ) + } operator fun minus(other: Int): Rational = Rational( numerator - denominator * other.toLong(), - denominator + denominator, + toCheckInput = false ) operator fun minus(other: Long): Rational = Rational( numerator - denominator * other, - denominator + denominator, + toCheckInput = false ) - operator fun times(other: Rational): Rational = - Rational( - numerator * other.numerator, - denominator * other.denominator + operator fun times(other: Rational): Rational { + val thisDenominatorAndOtherNumeratorGcd = gcd(denominator, other.numerator) + val otherDenominatorAndThisNumeratorGcd = gcd(other.denominator, numerator) + return Rational( + (numerator / otherDenominatorAndThisNumeratorGcd) * (other.numerator / thisDenominatorAndOtherNumeratorGcd), + (denominator / thisDenominatorAndOtherNumeratorGcd) * (other.denominator / otherDenominatorAndThisNumeratorGcd), + toCheckInput = false ) - operator fun times(other: Int): Rational = - Rational( - numerator * other.toLong(), - denominator + } + operator fun times(other: Int): Rational { + val other = other.toLong() + val denominatorAndOtherGcd = gcd(denominator, other) + return Rational( + numerator * (other / denominatorAndOtherGcd), + denominator / denominatorAndOtherGcd, + toCheckInput = false ) - operator fun times(other: Long): Rational = - Rational( - numerator * other, - denominator + } + operator fun times(other: Long): Rational { + val denominatorAndOtherGcd = gcd(denominator, other) + return Rational( + numerator * (other / denominatorAndOtherGcd), + denominator / denominatorAndOtherGcd, + toCheckInput = false ) - operator fun div(other: Rational): Rational = - Rational( - numerator * other.denominator, - denominator * other.numerator + } + operator fun div(other: Rational): Rational { + val denominatorsGcd = gcd(denominator, other.denominator) + val numeratorsGcd = gcd(numerator, other.numerator) + return Rational( + (numerator / numeratorsGcd) * (other.denominator / denominatorsGcd), + (denominator / denominatorsGcd) * (other.numerator / numeratorsGcd) ) - operator fun div(other: Int): Rational = - Rational( - numerator, - denominator * other.toLong() + } + operator fun div(other: Int): Rational { + val other = other.toLong() + val numeratorAndOtherGcd = gcd(numerator, other) + return Rational( + numerator / numeratorAndOtherGcd, + denominator * (other / numeratorAndOtherGcd), + toCheckInput = false ) - operator fun div(other: Long): Rational = - Rational( - numerator, - denominator * other + } + operator fun div(other: Long): Rational { + val numeratorAndOtherGcd = gcd(numerator, other) + return Rational( + numerator / numeratorAndOtherGcd, + denominator * (other / numeratorAndOtherGcd), + toCheckInput = false ) + } override fun equals(other: Any?): Boolean = when (other) { is Rational -> numerator == other.numerator && denominator == other.denominator diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/assertion.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/assertion.kt index 52ecf416a..bf8675675 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/assertion.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/assertion.kt @@ -5,10 +5,44 @@ package space.kscience.kmath.test.misc +import space.kscience.kmath.functions.NumberedPolynomial +import space.kscience.kmath.functions.NumberedRationalFunction import kotlin.test.assertEquals fun assertContentEquals(expected: Map, actual: Map, absoluteTolerance: Double, message: String? = null) { assertEquals(expected.keys, actual.keys, message) for ((key, expectedValue) in expected) assertEquals(expectedValue, actual[key]!!, absoluteTolerance, message) +} + +fun assertEquals( + expected: NumberedPolynomial, + actual: NumberedPolynomial, + absoluteTolerance: Double, + message: String? = null +) = assertContentEquals( + expected.coefficients, + actual.coefficients, + absoluteTolerance, + message +) + +fun assertEquals( + expected: NumberedRationalFunction, + actual: NumberedRationalFunction, + absoluteTolerance: Double, + message: String? = null +) { + assertEquals( + expected.numerator, + actual.numerator, + absoluteTolerance, + message + ) + assertEquals( + expected.denominator, + actual.denominator, + absoluteTolerance, + message + ) } \ No newline at end of file -- 2.34.1 From 102e83b4780209da177053d587aed35aabf7f811 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Mon, 4 Jul 2022 02:24:46 +0300 Subject: [PATCH 092/123] Tests generation for numbered utilities in progress: finish substitutions. --- .../kscience/kmath/functions/numberedUtil.kt | 6 +- .../functions/NumberedPolynomialUtilTest.kt | 3786 ++++++++++++++++- .../kscience/kmath/test/misc/assertion.kt | 14 +- 3 files changed, 3780 insertions(+), 26 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt index e485652f4..9397c1956 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt @@ -262,12 +262,14 @@ public fun NumberedRationalFunction.substitute(ring: Ring, args: Buffe numerator.substitute(ring, args) / denominator.substitute(ring, args) } +internal const val fullSubstitutionExceptionMessage: String = "Fully substituting buffer should cover all variables of the polynomial." + /** * Substitutes provided Double arguments [args] into [this] Double polynomial. */ public fun NumberedPolynomial.substituteFully(args: Buffer): Double = Double.algebra { val lastSubstitutionVariable = args.size - 1 - require(coefficients.keys.all { it.lastIndex <= lastSubstitutionVariable }) { "Fully substituting buffer should cover all variables of the polynomial." } + require(coefficients.keys.all { it.lastIndex <= lastSubstitutionVariable }) { fullSubstitutionExceptionMessage } coefficients.entries.fold(.0) { acc, (degs, c) -> acc + degs.foldIndexed(c) { variable, product, deg -> if (deg == 0u) product else product * args[variable].pow(deg.toInt()) @@ -280,7 +282,7 @@ public fun NumberedPolynomial.substituteFully(args: Buffer): Dou */ public fun NumberedPolynomial.substituteFully(ring: Ring, args: Buffer): C = ring { val lastSubstitutionVariable = args.size - 1 - require(coefficients.keys.all { it.lastIndex <= lastSubstitutionVariable }) { "Fully substituting buffer should cover all variables of the polynomial." } + require(coefficients.keys.all { it.lastIndex <= lastSubstitutionVariable }) { fullSubstitutionExceptionMessage } coefficients.entries.fold(zero) { acc, (degs, c) -> acc + degs.foldIndexed(c) { variable, product, deg -> if (deg == 0u) product else product * power(args[variable], deg) diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt index b6baed6af..9e49f1315 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt @@ -5,14 +5,19 @@ package space.kscience.kmath.functions +import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.asBuffer import space.kscience.kmath.test.misc.Rational import space.kscience.kmath.test.misc.RationalField import space.kscience.kmath.test.misc.assertEquals +import space.kscience.kmath.test.misc.assertFailsWithTypeAndMessage import kotlin.test.Ignore import kotlin.test.Test import kotlin.test.assertEquals +fun bufferOf(vararg elements: T): Buffer = elements.asBuffer() + class NumberedPolynomialUtilTest { @Test fun test_Polynomial_substitute_Double_Map() { @@ -4104,7 +4109,6 @@ class NumberedPolynomialUtilTest { // Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should return denominator r^deg(p), // not r^(deg(p)(deg(p)+1)/2) as it is now. fun test_RationalFunction_substitute_RationalFunction_Map() { - // TODO assertEquals( NumberedRationalFunction( NumberedPolynomialAsIs( @@ -5400,68 +5404,3804 @@ class NumberedPolynomialUtilTest { ) } @Test - @Ignore fun test_Polynomial_substitute_Double_Buffer() { - // TODO + assertEquals( + NumberedPolynomialAsIs(emptyList() to 0.0), + NumberedPolynomialAsIs( + listOf() to 1.0, + listOf(1u) to -2.0, + listOf(2u) to 1.0, + ).substitute(bufferOf( + 1.0 + )), + 0.001, + "test 1" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to 0.8597048543814783, + listOf(1u) to 0.22997637465889875, + listOf(2u) to 0.32675302591924016, + listOf(0u, 1u) to 0.4561746111587508, + listOf(1u, 1u) to 0.5304946210170756, + listOf(2u, 1u) to 0.6244313712888998, + listOf(0u, 2u) to 0.2700930201481795, + listOf(1u, 2u) to -0.06962351375204712, + listOf(2u, 2u) to -0.015206988092131501, + ), + NumberedPolynomialAsIs( + listOf() to 0.8597048543814783, + listOf(1u) to 0.22997637465889875, + listOf(2u) to 0.32675302591924016, + listOf(0u, 1u) to 0.4561746111587508, + listOf(1u, 1u) to 0.5304946210170756, + listOf(2u, 1u) to 0.6244313712888998, + listOf(0u, 2u) to 0.2700930201481795, + listOf(1u, 2u) to -0.06962351375204712, + listOf(2u, 2u) to -0.015206988092131501, + ).substitute(bufferOf()), + 0.001, + "test 2" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to 0.8597048543814783, + listOf(0u, 1u) to 0.4561746111587508, + listOf(0u, 2u) to 0.2700930201481795, + ), + NumberedPolynomialAsIs( + listOf() to 0.8597048543814783, + listOf(1u) to 0.22997637465889875, + listOf(2u) to 0.32675302591924016, + listOf(0u, 1u) to 0.4561746111587508, + listOf(1u, 1u) to 0.5304946210170756, + listOf(2u, 1u) to 0.6244313712888998, + listOf(0u, 2u) to 0.2700930201481795, + listOf(1u, 2u) to -0.06962351375204712, + listOf(2u, 2u) to -0.015206988092131501, + ).substitute(bufferOf( + 0.0, + )), + 0.001, + "test 3" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to 1.047895694399743, + listOf(0u, 1u) to 0.859913883275481, + listOf(0u, 2u) to 0.2327806735363575, + ), + NumberedPolynomialAsIs( + listOf() to 0.8597048543814783, + listOf(1u) to 0.22997637465889875, + listOf(2u) to 0.32675302591924016, + listOf(0u, 1u) to 0.4561746111587508, + listOf(1u, 1u) to 0.5304946210170756, + listOf(2u, 1u) to 0.6244313712888998, + listOf(0u, 2u) to 0.2700930201481795, + listOf(1u, 2u) to -0.06962351375204712, + listOf(2u, 2u) to -0.015206988092131501, + ).substitute(bufferOf( + 0.4846192734143442, + )), + 0.001, + "test 4" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to 1.934530767358133, + ), + NumberedPolynomialAsIs( + listOf() to 0.8597048543814783, + listOf(1u) to 0.22997637465889875, + listOf(2u) to 0.32675302591924016, + listOf(0u, 1u) to 0.4561746111587508, + listOf(1u, 1u) to 0.5304946210170756, + listOf(2u, 1u) to 0.6244313712888998, + listOf(0u, 2u) to 0.2700930201481795, + listOf(1u, 2u) to -0.06962351375204712, + listOf(2u, 2u) to -0.015206988092131501, + ).substitute(bufferOf( + 0.4846192734143442, + 0.8400458576651112, + )), + 0.001, + "test 5" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to 1.934530767358133, + ), + NumberedPolynomialAsIs( + listOf() to 0.8597048543814783, + listOf(1u) to 0.22997637465889875, + listOf(2u) to 0.32675302591924016, + listOf(0u, 1u) to 0.4561746111587508, + listOf(1u, 1u) to 0.5304946210170756, + listOf(2u, 1u) to 0.6244313712888998, + listOf(0u, 2u) to 0.2700930201481795, + listOf(1u, 2u) to -0.06962351375204712, + listOf(2u, 2u) to -0.015206988092131501, + ).substitute(bufferOf( + 0.4846192734143442, + 0.8400458576651112, + 0.9211194782050933 + )), + 0.001, + "test 6" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to 1.934530767358133, + ), + NumberedPolynomialAsIs( + listOf() to 0.8597048543814783, + listOf(1u) to 0.22997637465889875, + listOf(2u) to 0.32675302591924016, + listOf(0u, 1u) to 0.4561746111587508, + listOf(1u, 1u) to 0.5304946210170756, + listOf(2u, 1u) to 0.6244313712888998, + listOf(0u, 2u) to 0.2700930201481795, + listOf(1u, 2u) to -0.06962351375204712, + listOf(2u, 2u) to -0.015206988092131501, + ).substitute(bufferOf( + 0.4846192734143442, + 0.8400458576651112, + 0.9211194782050933, + 0.4752854632152105 + )), + 0.001, + "test 7" + ) } @Test - @Ignore fun test_Polynomial_substitute_Constant_Buffer() { - // TODO + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(0) + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1) + ).substitute(RationalField, bufferOf( + Rational(1) + )), + "test 1" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substitute(RationalField, bufferOf()), + "test 2" + ) + // https://www.wolframalpha.com/input?i=%28-3%2F2+%2B+8%2F6+x+%2B+14%2F6+x%5E2%29+%2B+%28-3%2F1+%2B+-19%2F2+x+%2B+9%2F4+x%5E2%29+y+%2B+%285%2F5+%2B+18%2F9+x+%2B+5%2F2+x%5E2%29+y%5E2+where+x+%3D+-2%2F5 + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(-83, 50), + listOf(0u, 1u) to Rational(29, 25), + listOf(0u, 2u) to Rational(3, 5), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substitute(RationalField, bufferOf( + Rational(-2, 5), + )), + "test 3" + ) + // https://www.wolframalpha.com/input?i=%28-3%2F2+%2B+8%2F6+x+%2B+14%2F6+x%5E2%29+%2B+%28-3%2F1+%2B+-19%2F2+x+%2B+9%2F4+x%5E2%29+y+%2B+%285%2F5+%2B+18%2F9+x+%2B+5%2F2+x%5E2%29+y%5E2+where+x+%3D+-2%2F5%2C+y+%3D+12%2F9 + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(143, 150) + ), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substitute(RationalField, bufferOf( + Rational(-2, 5), + Rational(12, 9), + )), + "test 4" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(143, 150) + ), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substitute(RationalField, bufferOf( + Rational(-2, 5), + Rational(12, 9), + Rational(57, 179), + )), + "test 5" + ) + // https://www.wolframalpha.com/input?i=%28%28-3%2F2+%2B+8%2F6+x+%2B+14%2F6+x%5E2%29+%2B+%28-3%2F1+%2B+-19%2F2+x+%2B+9%2F4+x%5E2%29+y+%2B+%285%2F5+%2B+18%2F9+x+%2B+5%2F2+x%5E2%29+y%5E2%29+p%5E8+where+x+%3D+q%2Fp%2C+y+%3D+x%5E3%2C+p+%3D+-2%2F5%2C+q+%3D+12%2F9 + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(47639065216, 2562890625) + ), + NumberedPolynomialAsIs( + listOf(8u) to Rational(-3, 2), + listOf(7u, 1u) to Rational(8, 6), + listOf(6u, 2u) to Rational(14, 6), + listOf(5u, 3u) to Rational(-3, 1), + listOf(4u, 4u) to Rational(-19, 2), + listOf(3u, 5u) to Rational(9, 4), + listOf(2u, 6u) to Rational(5, 5), + listOf(1u, 7u) to Rational(18, 9), + listOf(0u, 8u) to Rational(5, 2), + ).substitute(RationalField, bufferOf( + Rational(-2, 5), + Rational(12, 9), + )), + "test 6" + ) } @Test - @Ignore fun test_Polynomial_substitute_Polynomial_Buffer() { - // TODO + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(0) + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1) + ).substitute(RationalField, bufferOf( + NumberedPolynomialAsIs( + listOf() to Rational(1) + ) + )), + "test 1" + ) + // https://www.wolframalpha.com/input?i=%28-3%2F2+%2B+8%2F6+x+%2B+14%2F6+x%5E2%29+%2B+%28-3%2F1+%2B+-19%2F2+x+%2B+9%2F4+x%5E2%29+y+%2B+%285%2F5+%2B+18%2F9+x+%2B+5%2F2+x%5E2%29+y%5E2+where+x+%3D+-5%2F1+s+%2B+2%2F8+t%2C+y+%3D+11%2F7+t + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(0u, 1u) to Rational(-92, 21), + listOf(0u, 2u) to Rational(-2627, 2352), + listOf(0u, 3u) to Rational(4565, 3136), + listOf(0u, 4u) to Rational(605, 1568), + listOf(1u) to Rational(-20, 3), + listOf(1u, 1u) to Rational(1445, 21), + listOf(1u, 2u) to Rational(-13145, 392), + listOf(1u, 3u) to Rational(-3025, 196), + listOf(2u) to Rational(175, 3), + listOf(2u, 1u) to Rational(2475, 28), + listOf(2u, 2u) to Rational(15125, 98), + listOf(3u) to Rational(0), + listOf(3u, 1u) to Rational(0), + listOf(4u) to Rational(0), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substitute(RationalField, bufferOf( + NumberedPolynomialAsIs( + listOf(1u) to Rational(-5, 1), + listOf(0u, 1u) to Rational(2, 8), + ), + NumberedPolynomialAsIs( + listOf(1u) to Rational(0, 5), + listOf(0u, 1u) to Rational(11, 7), + ), + )), + "test 2" + ) + // (-3/2 + 8/6 x + 14/6 x^2) + (-3/1 + -19/2 x + 9/4 x^2) y + (5/5 + 18/9 x + 5/2 x^2) y^2 where x = (0/6 + 14/8 s + -14/2 s^2) + (-3/5 + 11/1 s + 3/7 s^2) t + (-3/7 + -18/5 s + -9/1 s^2) t^2, y = (-9/2 + 2/7 s + 9/1 s^2) + (13/1 + -1/8 s + 2/8 s^2) t + (19/4 + 15/7 s + -19/4 s^2) t^2 + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(129, 4), + listOf(1u) to Rational(48583, 336), + listOf(2u) to Rational(-913477, 1568), + listOf(3u) to Rational(-967567, 672), + listOf(4u) to Rational(4722043, 1344), + listOf(5u) to Rational(8855, 2), + listOf(6u) to Rational(-311971, 32), + listOf(7u) to Rational(-17325, 4), + listOf(8u) to Rational(19845, 2), + listOf(0u, 1u) to Rational(-827, 4), + listOf(1u, 1u) to Rational(191927, 840), + listOf(2u, 1u) to Rational(9592627, 2352), + listOf(3u, 1u) to Rational(-105400711, 53760), + listOf(4u, 1u) to Rational(-10054101459, 439040), + listOf(5u, 1u) to Rational(2127351, 128), + listOf(6u, 1u) to Rational(116680973, 3136), + listOf(7u, 1u) to Rational(-220445, 7), + listOf(8u, 1u) to Rational(-2655, 4), + listOf(0u, 2u) to Rational(30567, 100), + listOf(1u, 2u) to Rational(-156284953, 39200), + listOf(2u, 2u) to Rational(-57661541711, 6585600), + listOf(3u, 2u) to Rational(131931579, 3136), + listOf(4u, 2u) to Rational(98818124791, 3512320), + listOf(5u, 2u) to Rational(-94458855053, 878080), + listOf(6u, 2u) to Rational(13937705305, 1229312), + listOf(7u, 2u) to Rational(335706887, 21952), + listOf(8u, 2u) to Rational(23549165, 1568), + listOf(0u, 3u) to Rational(111367, 1400), + listOf(1u, 3u) to Rational(4937369, 700), + listOf(2u, 3u) to Rational(-4449423711, 274400), + listOf(3u, 3u) to Rational(-351873325703, 4390400), + listOf(4u, 3u) to Rational(23495875029, 307328), + listOf(5u, 3u) to Rational(17576300919, 878080), + listOf(6u, 3u) to Rational(230316993, 12544), + listOf(7u, 3u) to Rational(-191130515, 21952), + listOf(8u, 3u) to Rational(332435, 392), + listOf(0u, 4u) to Rational(-275084, 1225), + listOf(1u, 4u) to Rational(-266774603, 137200), + listOf(2u, 4u) to Rational(2176279167121, 30732800), + listOf(3u, 4u) to Rational(10904913303, 2195200), + listOf(4u, 4u) to Rational(-10769286147, 2195200), + listOf(5u, 4u) to Rational(-26277119793, 439040), + listOf(6u, 4u) to Rational(25859735869, 6146560), + listOf(7u, 4u) to Rational(38906289, 2744), + listOf(8u, 4u) to Rational(-3072025, 392), + listOf(0u, 5u) to Rational(9573, 98), + listOf(1u, 5u) to Rational(-4154651399, 548800), + listOf(2u, 5u) to Rational(3446069019, 548800), + listOf(3u, 5u) to Rational(-7851500623, 137200), + listOf(4u, 5u) to Rational(-53205142903, 1920800), + listOf(5u, 5u) to Rational(-31953611, 3430), + listOf(6u, 5u) to Rational(1447380313, 109760), + listOf(7u, 5u) to Rational(764158625, 21952), + listOf(8u, 5u) to Rational(1153515, 784), + listOf(0u, 6u) to Rational(1722351, 7840), + listOf(1u, 6u) to Rational(-164554821, 109760), + listOf(2u, 6u) to Rational(-79096147243, 7683200), + listOf(3u, 6u) to Rational(-624721089, 15680), + listOf(4u, 6u) to Rational(11147305567, 548800), + listOf(5u, 6u) to Rational(8318333679, 109760), + listOf(6u, 6u) to Rational(32981871553, 1536640), + listOf(7u, 6u) to Rational(-225359619, 21952), + listOf(8u, 6u) to Rational(-3973995, 392), + listOf(0u, 7u) to Rational(67203, 784), + listOf(1u, 7u) to Rational(39281469, 54880), + listOf(2u, 7u) to Rational(70162551, 27440), + listOf(3u, 7u) to Rational(413630709, 54880), + listOf(4u, 7u) to Rational(4640410269, 192080), + listOf(5u, 7u) to Rational(802712247, 54880), + listOf(6u, 7u) to Rational(-473517603, 27440), + listOf(7u, 7u) to Rational(-17055459, 1568), + listOf(8u, 7u) to Rational(-12825, 14), + listOf(0u, 8u) to Rational(16245, 1568), + listOf(1u, 8u) to Rational(503253, 2744), + listOf(2u, 8u) to Rational(125292591, 96040), + listOf(3u, 8u) to Rational(12033171, 2744), + listOf(4u, 8u) to Rational(154352673, 27440), + listOf(5u, 8u) to Rational(-1302291, 392), + listOf(6u, 8u) to Rational(-20265741, 1960), + listOf(7u, 8u) to Rational(-26163, 56), + listOf(8u, 8u) to Rational(146205, 32), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substitute(RationalField, bufferOf( + NumberedPolynomialAsIs( + listOf() to Rational(0, 6), + listOf(1u) to Rational(14, 8), + listOf(2u) to Rational(-14, 2), + listOf(0u, 1u) to Rational(-3, 5), + listOf(1u, 1u) to Rational(11, 1), + listOf(2u, 1u) to Rational(3, 7), + listOf(0u, 2u) to Rational(-3, 7), + listOf(1u, 2u) to Rational(-18, 5), + listOf(2u, 2u) to Rational(-9, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-9, 2), + listOf(1u) to Rational(2, 7), + listOf(2u) to Rational(9, 1), + listOf(0u, 1u) to Rational(13, 1), + listOf(1u, 1u) to Rational(-1, 8), + listOf(2u, 1u) to Rational(2, 8), + listOf(0u, 2u) to Rational(19, 4), + listOf(1u, 2u) to Rational(15, 7), + listOf(2u, 2u) to Rational(-19, 4), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-11, 3), + listOf(1u) to Rational(5, 2), + listOf(2u) to Rational(13, 7), + listOf(0u, 1u) to Rational(16, 9), + listOf(1u, 1u) to Rational(14, 7), + listOf(2u, 1u) to Rational(6, 1), + listOf(0u, 2u) to Rational(-14, 3), + listOf(1u, 2u) to Rational(-2, 7), + listOf(2u, 2u) to Rational(-10, 8), + ) + )), + "test 3" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(129, 4), + listOf(1u) to Rational(48583, 336), + listOf(2u) to Rational(-913477, 1568), + listOf(3u) to Rational(-967567, 672), + listOf(4u) to Rational(4722043, 1344), + listOf(5u) to Rational(8855, 2), + listOf(6u) to Rational(-311971, 32), + listOf(7u) to Rational(-17325, 4), + listOf(8u) to Rational(19845, 2), + listOf(0u, 1u) to Rational(-827, 4), + listOf(1u, 1u) to Rational(191927, 840), + listOf(2u, 1u) to Rational(9592627, 2352), + listOf(3u, 1u) to Rational(-105400711, 53760), + listOf(4u, 1u) to Rational(-10054101459, 439040), + listOf(5u, 1u) to Rational(2127351, 128), + listOf(6u, 1u) to Rational(116680973, 3136), + listOf(7u, 1u) to Rational(-220445, 7), + listOf(8u, 1u) to Rational(-2655, 4), + listOf(0u, 2u) to Rational(30567, 100), + listOf(1u, 2u) to Rational(-156284953, 39200), + listOf(2u, 2u) to Rational(-57661541711, 6585600), + listOf(3u, 2u) to Rational(131931579, 3136), + listOf(4u, 2u) to Rational(98818124791, 3512320), + listOf(5u, 2u) to Rational(-94458855053, 878080), + listOf(6u, 2u) to Rational(13937705305, 1229312), + listOf(7u, 2u) to Rational(335706887, 21952), + listOf(8u, 2u) to Rational(23549165, 1568), + listOf(0u, 3u) to Rational(111367, 1400), + listOf(1u, 3u) to Rational(4937369, 700), + listOf(2u, 3u) to Rational(-4449423711, 274400), + listOf(3u, 3u) to Rational(-351873325703, 4390400), + listOf(4u, 3u) to Rational(23495875029, 307328), + listOf(5u, 3u) to Rational(17576300919, 878080), + listOf(6u, 3u) to Rational(230316993, 12544), + listOf(7u, 3u) to Rational(-191130515, 21952), + listOf(8u, 3u) to Rational(332435, 392), + listOf(0u, 4u) to Rational(-275084, 1225), + listOf(1u, 4u) to Rational(-266774603, 137200), + listOf(2u, 4u) to Rational(2176279167121, 30732800), + listOf(3u, 4u) to Rational(10904913303, 2195200), + listOf(4u, 4u) to Rational(-10769286147, 2195200), + listOf(5u, 4u) to Rational(-26277119793, 439040), + listOf(6u, 4u) to Rational(25859735869, 6146560), + listOf(7u, 4u) to Rational(38906289, 2744), + listOf(8u, 4u) to Rational(-3072025, 392), + listOf(0u, 5u) to Rational(9573, 98), + listOf(1u, 5u) to Rational(-4154651399, 548800), + listOf(2u, 5u) to Rational(3446069019, 548800), + listOf(3u, 5u) to Rational(-7851500623, 137200), + listOf(4u, 5u) to Rational(-53205142903, 1920800), + listOf(5u, 5u) to Rational(-31953611, 3430), + listOf(6u, 5u) to Rational(1447380313, 109760), + listOf(7u, 5u) to Rational(764158625, 21952), + listOf(8u, 5u) to Rational(1153515, 784), + listOf(0u, 6u) to Rational(1722351, 7840), + listOf(1u, 6u) to Rational(-164554821, 109760), + listOf(2u, 6u) to Rational(-79096147243, 7683200), + listOf(3u, 6u) to Rational(-624721089, 15680), + listOf(4u, 6u) to Rational(11147305567, 548800), + listOf(5u, 6u) to Rational(8318333679, 109760), + listOf(6u, 6u) to Rational(32981871553, 1536640), + listOf(7u, 6u) to Rational(-225359619, 21952), + listOf(8u, 6u) to Rational(-3973995, 392), + listOf(0u, 7u) to Rational(67203, 784), + listOf(1u, 7u) to Rational(39281469, 54880), + listOf(2u, 7u) to Rational(70162551, 27440), + listOf(3u, 7u) to Rational(413630709, 54880), + listOf(4u, 7u) to Rational(4640410269, 192080), + listOf(5u, 7u) to Rational(802712247, 54880), + listOf(6u, 7u) to Rational(-473517603, 27440), + listOf(7u, 7u) to Rational(-17055459, 1568), + listOf(8u, 7u) to Rational(-12825, 14), + listOf(0u, 8u) to Rational(16245, 1568), + listOf(1u, 8u) to Rational(503253, 2744), + listOf(2u, 8u) to Rational(125292591, 96040), + listOf(3u, 8u) to Rational(12033171, 2744), + listOf(4u, 8u) to Rational(154352673, 27440), + listOf(5u, 8u) to Rational(-1302291, 392), + listOf(6u, 8u) to Rational(-20265741, 1960), + listOf(7u, 8u) to Rational(-26163, 56), + listOf(8u, 8u) to Rational(146205, 32), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substitute(RationalField, bufferOf( + NumberedPolynomialAsIs( + listOf() to Rational(0, 6), + listOf(1u) to Rational(14, 8), + listOf(2u) to Rational(-14, 2), + listOf(0u, 1u) to Rational(-3, 5), + listOf(1u, 1u) to Rational(11, 1), + listOf(2u, 1u) to Rational(3, 7), + listOf(0u, 2u) to Rational(-3, 7), + listOf(1u, 2u) to Rational(-18, 5), + listOf(2u, 2u) to Rational(-9, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-9, 2), + listOf(1u) to Rational(2, 7), + listOf(2u) to Rational(9, 1), + listOf(0u, 1u) to Rational(13, 1), + listOf(1u, 1u) to Rational(-1, 8), + listOf(2u, 1u) to Rational(2, 8), + listOf(0u, 2u) to Rational(19, 4), + listOf(1u, 2u) to Rational(15, 7), + listOf(2u, 2u) to Rational(-19, 4), + ), + )), + "test 4" + ) + // (-3/2 + 8/6 x + 14/6 x^2) + (-3/1 + -19/2 x + 9/4 x^2) y + (5/5 + 18/9 x + 5/2 x^2) y^2 where x = (0/6 + 14/8 s + -14/2 s^2) + (-3/5 + 11/1 s + 3/7 s^2) t + (-3/7 + -18/5 s + -9/1 s^2) t^2, y = t + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(7, 3), + listOf(2u) to Rational(-35, 16), + listOf(3u) to Rational(-343, 6), + listOf(4u) to Rational(343, 3), + listOf(0u, 1u) to Rational(-19, 5), + listOf(1u, 1u) to Rational(-823, 120), + listOf(2u, 1u) to Rational(1232417, 6720), + listOf(3u, 1u) to Rational(-9863, 24), + listOf(4u, 1u) to Rational(385, 4), + listOf(0u, 2u) to Rational(2439, 350), + listOf(1u, 2u) to Rational(-5793, 40), + listOf(2u, 2u) to Rational(1172113, 3360), + listOf(3u, 2u) to Rational(-13531, 40), + listOf(4u, 2u) to Rational(2824, 7), + listOf(0u, 3u) to Rational(3417, 700), + listOf(1u, 3u) to Rational(1191, 200), + listOf(2u, 3u) to Rational(8383, 28), + listOf(3u, 3u) to Rational(-220279, 280), + listOf(4u, 3u) to Rational(49179, 196), + listOf(0u, 4u) to Rational(57, 35), + listOf(1u, 4u) to Rational(-33771, 700), + listOf(2u, 4u) to Rational(196279, 1225), + listOf(3u, 4u) to Rational(-32259, 140), + listOf(4u, 4u) to Rational(23868, 49), + listOf(0u, 5u) to Rational(333, 196), + listOf(1u, 5u) to Rational(-204, 35), + listOf(2u, 5u) to Rational(-307233, 2450), + listOf(3u, 5u) to Rational(-12492, 35), + listOf(4u, 5u) to Rational(4563, 28), + listOf(0u, 6u) to Rational(45, 98), + listOf(1u, 6u) to Rational(54, 7), + listOf(2u, 6u) to Rational(1809, 35), + listOf(3u, 6u) to Rational(162), + listOf(4u, 6u) to Rational(405, 2), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substitute(RationalField, bufferOf( + NumberedPolynomialAsIs( + listOf() to Rational(0, 6), + listOf(1u) to Rational(14, 8), + listOf(2u) to Rational(-14, 2), + listOf(0u, 1u) to Rational(-3, 5), + listOf(1u, 1u) to Rational(11, 1), + listOf(2u, 1u) to Rational(3, 7), + listOf(0u, 2u) to Rational(-3, 7), + listOf(1u, 2u) to Rational(-18, 5), + listOf(2u, 2u) to Rational(-9, 1), + ), + )), + "test 5" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substitute(RationalField, bufferOf>()), + "test 6" + ) } @Test @Ignore // FIXME: This tests work only for sane realisations of the substitutions. Currently, it is not. // Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should return denominator r^deg(p), // not r^(deg(p)(deg(p)+1)/2) as it is now. fun test_Polynomial_substitute_RationalFunction_Buffer() { - // TODO + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(0) + ), + NumberedPolynomialAsIs( + listOf() to Rational(1) + ) + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1) + ).substitute(RationalField, bufferOf( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(1) + ), + NumberedPolynomialAsIs( + listOf() to Rational(1) + ) + ) + )), + "test 1" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf(4u) to Rational(-194071, 4900), + listOf(3u, 1u) to Rational(394811, 225), + listOf(2u, 2u) to Rational(-444183161, 66150), + listOf(1u, 3u) to Rational(70537618, 59535), + listOf(0u, 4u) to Rational(9655504, 2835), + ), + NumberedPolynomialAsIs( + listOf(4u) to Rational(9, 1), + listOf(3u, 1u) to Rational(61, 1), + listOf(2u, 2u) to Rational(2137, 36), + listOf(1u, 3u) to Rational(-1342, 9), + listOf(0u, 4u) to Rational(484, 9), + ) + ), + NumberedPolynomialAsIs( + listOf() to Rational(15, 7), + listOf(1u) to Rational(1, 5), + listOf(2u) to Rational(-7, 4), + listOf(0u, 1u) to Rational(-1, 9), + listOf(1u, 1u) to Rational(-2, 7), + listOf(2u, 1u) to Rational(17, 3), + listOf(0u, 2u) to Rational(2, 6), + listOf(1u, 2u) to Rational(-17, 6), + listOf(2u, 2u) to Rational(-6, 2), + ).substitute(RationalField, bufferOf( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf(1u) to Rational(17, 7), + listOf(0u, 1u) to Rational(-13, 1), + ), + NumberedPolynomialAsIs( + listOf(1u) to Rational(-18, 6), + listOf(0u, 1u) to Rational(11, 6), + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf(1u) to Rational(18, 5), + listOf(0u, 1u) to Rational(-16, 3), + ), + NumberedPolynomialAsIs( + listOf(1u) to Rational(-1, 1), + listOf(0u, 1u) to Rational(-4, 1), + ) + ), + )), + "test 2" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-6443599, 10000), + listOf(1u) to Rational(166251223, 210000), + listOf(2u) to Rational(-4606805099, 3528000), + listOf(3u) to Rational(51204379, 19600), + listOf(4u) to Rational(-529045460659, 277830000), + listOf(5u) to Rational(2630836709, 1488375), + listOf(6u) to Rational(-42675691369, 25004700), + listOf(7u) to Rational(495825223, 1250235), + listOf(8u) to Rational(-22531756, 1750329), + listOf(0u, 1u) to Rational(-2526552797, 420000), + listOf(1u, 1u) to Rational(31108840471, 2520000), + listOf(2u, 1u) to Rational(-4789740847, 1102500), + listOf(3u, 1u) to Rational(186594307807, 11340000), + listOf(4u, 1u) to Rational(-11677815943, 1488375), + listOf(5u, 1u) to Rational(-181118486447, 27783000), + listOf(6u, 1u) to Rational(-16123292162, 14586075), + listOf(7u, 1u) to Rational(-140339343808, 26254935), + listOf(8u, 1u) to Rational(4570171616, 5250987), + listOf(0u, 2u) to Rational(-181436530573, 10080000), + listOf(1u, 2u) to Rational(6700437957491, 105840000), + listOf(2u, 2u) to Rational(-3527267461, 1417500), + listOf(3u, 2u) to Rational(-38084563451, 5556600), + listOf(4u, 2u) to Rational(-565662040631, 13891500), + listOf(5u, 2u) to Rational(-35479071126397, 583443000), + listOf(6u, 2u) to Rational(-11717559078469, 525098700), + listOf(7u, 2u) to Rational(-2043385293517, 225042300), + listOf(8u, 2u) to Rational(-3644439630451, 551353635), + listOf(0u, 3u) to Rational(-1760423269, 126000), + listOf(1u, 3u) to Rational(310176758299, 2352000), + listOf(2u, 3u) to Rational(-907229584837, 21168000), + listOf(3u, 3u) to Rational(-16717135885963, 95256000), + listOf(4u, 3u) to Rational(-43762928025353, 333396000), + listOf(5u, 3u) to Rational(-328427480571607, 3000564000), + listOf(6u, 3u) to Rational(-7722675917197, 210039480), + listOf(7u, 3u) to Rational(1713350137019, 1225230300), + listOf(8u, 3u) to Rational(156695935643, 31505922), + listOf(0u, 4u) to Rational(18362364269, 1008000), + listOf(1u, 4u) to Rational(955674858553, 10584000), + listOf(2u, 4u) to Rational(-71937470607371, 444528000), + listOf(3u, 4u) to Rational(-34097985615163, 95256000), + listOf(4u, 4u) to Rational(-340736178775883, 2000376000), + listOf(5u, 4u) to Rational(-511324523441897, 10501974000), + listOf(6u, 4u) to Rational(-125375649409151, 8821658160), + listOf(7u, 4u) to Rational(-2813518533421, 1575296100), + listOf(8u, 4u) to Rational(-17044089109, 5250987), + listOf(0u, 5u) to Rational(600086461, 20160), + listOf(1u, 5u) to Rational(-18959931367, 423360), + listOf(2u, 5u) to Rational(-9178804929607, 44452800), + listOf(3u, 5u) to Rational(-1460114275979, 5334336), + listOf(4u, 5u) to Rational(-342533479090169, 4200789600), + listOf(5u, 5u) to Rational(20335453022963, 4200789600), + listOf(6u, 5u) to Rational(-21649775090197, 6301184400), + listOf(7u, 5u) to Rational(-197301716069, 131274675), + listOf(8u, 5u) to Rational(18711357470, 15752961), + listOf(0u, 6u) to Rational(621417991, 100800), + listOf(1u, 6u) to Rational(-159236792977, 2116800), + listOf(2u, 6u) to Rational(-6602528890883, 66679200), + listOf(3u, 6u) to Rational(-1086091664047, 19051200), + listOf(4u, 6u) to Rational(3769375009003, 1680315840), + listOf(5u, 6u) to Rational(-12920385574769, 1050197400), + listOf(6u, 6u) to Rational(-90219591809287, 6301184400), + listOf(7u, 6u) to Rational(656361553391, 1575296100), + listOf(8u, 6u) to Rational(757900793, 2250423), + listOf(0u, 7u) to Rational(-100770017, 15120), + listOf(1u, 7u) to Rational(-316364851, 17640), + listOf(2u, 7u) to Rational(-85118560057, 6667920), + listOf(3u, 7u) to Rational(6286563719, 416745), + listOf(4u, 7u) to Rational(26803885301, 1714608), + listOf(5u, 7u) to Rational(-13767154393, 4286520), + listOf(6u, 7u) to Rational(-3875138933, 1224720), + listOf(7u, 7u) to Rational(65193755, 333396), + listOf(8u, 7u) to Rational(90974351, 2500470), + listOf(0u, 8u) to Rational(-3182197, 1260), + listOf(1u, 8u) to Rational(24899923, 8820), + listOf(2u, 8u) to Rational(-19999556, 19845), + listOf(3u, 8u) to Rational(3276587, 3969), + listOf(4u, 8u) to Rational(13719549239, 5000940), + listOf(5u, 8u) to Rational(-961839938, 1250235), + listOf(6u, 8u) to Rational(-198184871, 833490), + listOf(7u, 8u) to Rational(230659711, 5000940), + listOf(8u, 8u) to Rational(292447, 35721) + ), + NumberedPolynomialAsIs( + listOf() to Rational(9, 100), + listOf(1u) to Rational(-21, 50), + listOf(2u) to Rational(293, 700), + listOf(3u) to Rational(29, 210), + listOf(4u) to Rational(3233, 8820), + listOf(5u) to Rational(-289, 441), + listOf(6u) to Rational(-1, 9), + listOf(7u) to Rational(-20, 441), + listOf(8u) to Rational(100, 441), + listOf(0u, 1u) to Rational(-57, 80), + listOf(1u, 1u) to Rational(-121, 400), + listOf(2u, 1u) to Rational(37117, 8400), + listOf(3u, 1u) to Rational(-4853, 3150), + listOf(4u, 1u) to Rational(1166203, 132300), + listOf(5u, 1u) to Rational(-2708, 567), + listOf(6u, 1u) to Rational(-287159, 416745), + listOf(7u, 1u) to Rational(-478204, 83349), + listOf(8u, 1u) to Rational(176320, 83349), + listOf(0u, 2u) to Rational(-6239, 6400), + listOf(1u, 2u) to Rational(264211, 11200), + listOf(2u, 2u) to Rational(-1591999, 100800), + listOf(3u, 2u) to Rational(12450091, 529200), + listOf(4u, 2u) to Rational(9230759, 226800), + listOf(5u, 2u) to Rational(18995554, 2083725), + listOf(6u, 2u) to Rational(136706258, 6251175), + listOf(7u, 2u) to Rational(-120907496, 3750705), + listOf(8u, 2u) to Rational(117200176, 15752961), + listOf(0u, 3u) to Rational(5653, 320), + listOf(1u, 3u) to Rational(-130853, 8400), + listOf(2u, 3u) to Rational(-20939327, 151200), + listOf(3u, 3u) to Rational(2566691, 25200), + listOf(4u, 3u) to Rational(-68441519, 476280), + listOf(5u, 3u) to Rational(2462904247, 12502350), + listOf(6u, 3u) to Rational(353667161, 18753525), + listOf(7u, 3u) to Rational(-1689134372, 26254935), + listOf(8u, 3u) to Rational(35084104, 2250423), + listOf(0u, 4u) to Rational(-3587, 300), + listOf(1u, 4u) to Rational(-10513243, 33600), + listOf(2u, 4u) to Rational(30766733, 176400), + listOf(3u, 4u) to Rational(-65680021, 198450), + listOf(4u, 4u) to Rational(-8108910547, 20003760), + listOf(5u, 4u) to Rational(2922125159, 6251175), + listOf(6u, 4u) to Rational(-4245279943, 131274675), + listOf(7u, 4u) to Rational(-371946872, 3750705), + listOf(8u, 4u) to Rational(61286752, 2250423), + listOf(0u, 5u) to Rational(-20477, 160), + listOf(1u, 5u) to Rational(215741, 1120), + listOf(2u, 5u) to Rational(30785843, 31752), + listOf(3u, 5u) to Rational(-357495959, 317520), + listOf(4u, 5u) to Rational(-1611242993, 10001880), + listOf(5u, 5u) to Rational(345925495, 500094), + listOf(6u, 5u) to Rational(-755948411, 3750705), + listOf(7u, 5u) to Rational(-108643496, 1250235), + listOf(8u, 5u) to Rational(1122512, 35721), + listOf(0u, 6u) to Rational(358037, 2880), + listOf(1u, 6u) to Rational(3895837, 3360), + listOf(2u, 6u) to Rational(359419201, 1270080), + listOf(3u, 6u) to Rational(-158522587, 105840), + listOf(4u, 6u) to Rational(10909002599, 20003760), + listOf(5u, 6u) to Rational(76846972, 138915), + listOf(6u, 6u) to Rational(-327696553, 1250235), + listOf(7u, 6u) to Rational(-1687328, 35721), + listOf(8u, 6u) to Rational(1016836, 35721), + listOf(0u, 7u) to Rational(658, 3), + listOf(1u, 7u) to Rational(48035, 168), + listOf(2u, 7u) to Rational(-5777875, 5292), + listOf(3u, 7u) to Rational(-7893899, 10584), + listOf(4u, 7u) to Rational(10191652, 11907), + listOf(5u, 7u) to Rational(2920121, 23814), + listOf(6u, 7u) to Rational(-2699780, 11907), + listOf(7u, 7u) to Rational(4556, 441), + listOf(8u, 7u) to Rational(3440, 189), + listOf(0u, 8u) to Rational(64, 1), + listOf(1u, 8u) to Rational(-808, 7), + listOf(2u, 8u) to Rational(-360895, 1764), + listOf(3u, 8u) to Rational(257657, 882), + listOf(4u, 8u) to Rational(3779917, 15876), + listOf(5u, 8u) to Rational(-610279, 3969), + listOf(6u, 8u) to Rational(-25091, 441), + listOf(7u, 8u) to Rational(9560, 567), + listOf(8u, 8u) to Rational(400, 81) + ) + ), + NumberedPolynomialAsIs( + listOf() to Rational(15, 7), + listOf(1u) to Rational(1, 5), + listOf(2u) to Rational(-7, 4), + listOf(0u, 1u) to Rational(-1, 9), + listOf(1u, 1u) to Rational(-2, 7), + listOf(2u, 1u) to Rational(17, 3), + listOf(0u, 2u) to Rational(2, 6), + listOf(1u, 2u) to Rational(-17, 6), + listOf(2u, 2u) to Rational(-6, 2), + ).substitute(RationalField, bufferOf( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(17, 5), + listOf(1u) to Rational(11, 6), + listOf(2u) to Rational(14, 3), + listOf(0u, 1u) to Rational(17, 1), + listOf(1u, 1u) to Rational(12, 3), + listOf(2u, 1u) to Rational(-6, 2), + listOf(0u, 2u) to Rational(17, 1), + listOf(1u, 2u) to Rational(-4, 3), + listOf(2u, 2u) to Rational(2, 6), + ), + NumberedPolynomialAsIs( + listOf() to Rational(3, 5), + listOf(1u) to Rational(3, 5), + listOf(2u) to Rational(3, 7), + listOf(0u, 1u) to Rational(-3, 8), + listOf(1u, 1u) to Rational(-1, 1), + listOf(2u, 1u) to Rational(17, 9), + listOf(0u, 2u) to Rational(-8, 1), + listOf(1u, 2u) to Rational(6, 4), + listOf(2u, 2u) to Rational(10, 9), + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(18, 5), + listOf(1u) to Rational(-17, 5), + listOf(2u) to Rational(-2, 7), + listOf(0u, 1u) to Rational(6, 5), + listOf(1u, 1u) to Rational(-5, 1), + listOf(2u, 1u) to Rational(-9, 1), + listOf(0u, 2u) to Rational(-8, 8), + listOf(1u, 2u) to Rational(2, 7), + listOf(2u, 2u) to Rational(-13, 7), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-4, 8), + listOf(1u) to Rational(15, 9), + listOf(2u) to Rational(-10, 9), + listOf(0u, 1u) to Rational(5, 3), + listOf(1u, 1u) to Rational(4, 1), + listOf(2u, 1u) to Rational(-2, 7), + listOf(0u, 2u) to Rational(2, 2), + listOf(1u, 2u) to Rational(-5, 7), + listOf(2u, 2u) to Rational(-18, 9), + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-2, 9), + listOf(1u) to Rational(-6, 3), + listOf(2u) to Rational(10, 9), + listOf(0u, 1u) to Rational(13, 3), + listOf(1u, 1u) to Rational(-12, 4), + listOf(2u, 1u) to Rational(3, 6), + listOf(0u, 2u) to Rational(2, 9), + listOf(1u, 2u) to Rational(7, 3), + listOf(2u, 2u) to Rational(16, 5), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 2), + listOf(1u) to Rational(6, 2), + listOf(2u) to Rational(2, 7), + listOf(0u, 1u) to Rational(-18, 1), + listOf(1u, 1u) to Rational(-11, 3), + listOf(2u, 1u) to Rational(7, 5), + listOf(0u, 2u) to Rational(8, 1), + listOf(1u, 2u) to Rational(6, 7), + listOf(2u, 2u) to Rational(17, 4), + ) + ) + )), + "test 3" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-6443599, 10000), + listOf(1u) to Rational(166251223, 210000), + listOf(2u) to Rational(-4606805099, 3528000), + listOf(3u) to Rational(51204379, 19600), + listOf(4u) to Rational(-529045460659, 277830000), + listOf(5u) to Rational(2630836709, 1488375), + listOf(6u) to Rational(-42675691369, 25004700), + listOf(7u) to Rational(495825223, 1250235), + listOf(8u) to Rational(-22531756, 1750329), + listOf(0u, 1u) to Rational(-2526552797, 420000), + listOf(1u, 1u) to Rational(31108840471, 2520000), + listOf(2u, 1u) to Rational(-4789740847, 1102500), + listOf(3u, 1u) to Rational(186594307807, 11340000), + listOf(4u, 1u) to Rational(-11677815943, 1488375), + listOf(5u, 1u) to Rational(-181118486447, 27783000), + listOf(6u, 1u) to Rational(-16123292162, 14586075), + listOf(7u, 1u) to Rational(-140339343808, 26254935), + listOf(8u, 1u) to Rational(4570171616, 5250987), + listOf(0u, 2u) to Rational(-181436530573, 10080000), + listOf(1u, 2u) to Rational(6700437957491, 105840000), + listOf(2u, 2u) to Rational(-3527267461, 1417500), + listOf(3u, 2u) to Rational(-38084563451, 5556600), + listOf(4u, 2u) to Rational(-565662040631, 13891500), + listOf(5u, 2u) to Rational(-35479071126397, 583443000), + listOf(6u, 2u) to Rational(-11717559078469, 525098700), + listOf(7u, 2u) to Rational(-2043385293517, 225042300), + listOf(8u, 2u) to Rational(-3644439630451, 551353635), + listOf(0u, 3u) to Rational(-1760423269, 126000), + listOf(1u, 3u) to Rational(310176758299, 2352000), + listOf(2u, 3u) to Rational(-907229584837, 21168000), + listOf(3u, 3u) to Rational(-16717135885963, 95256000), + listOf(4u, 3u) to Rational(-43762928025353, 333396000), + listOf(5u, 3u) to Rational(-328427480571607, 3000564000), + listOf(6u, 3u) to Rational(-7722675917197, 210039480), + listOf(7u, 3u) to Rational(1713350137019, 1225230300), + listOf(8u, 3u) to Rational(156695935643, 31505922), + listOf(0u, 4u) to Rational(18362364269, 1008000), + listOf(1u, 4u) to Rational(955674858553, 10584000), + listOf(2u, 4u) to Rational(-71937470607371, 444528000), + listOf(3u, 4u) to Rational(-34097985615163, 95256000), + listOf(4u, 4u) to Rational(-340736178775883, 2000376000), + listOf(5u, 4u) to Rational(-511324523441897, 10501974000), + listOf(6u, 4u) to Rational(-125375649409151, 8821658160), + listOf(7u, 4u) to Rational(-2813518533421, 1575296100), + listOf(8u, 4u) to Rational(-17044089109, 5250987), + listOf(0u, 5u) to Rational(600086461, 20160), + listOf(1u, 5u) to Rational(-18959931367, 423360), + listOf(2u, 5u) to Rational(-9178804929607, 44452800), + listOf(3u, 5u) to Rational(-1460114275979, 5334336), + listOf(4u, 5u) to Rational(-342533479090169, 4200789600), + listOf(5u, 5u) to Rational(20335453022963, 4200789600), + listOf(6u, 5u) to Rational(-21649775090197, 6301184400), + listOf(7u, 5u) to Rational(-197301716069, 131274675), + listOf(8u, 5u) to Rational(18711357470, 15752961), + listOf(0u, 6u) to Rational(621417991, 100800), + listOf(1u, 6u) to Rational(-159236792977, 2116800), + listOf(2u, 6u) to Rational(-6602528890883, 66679200), + listOf(3u, 6u) to Rational(-1086091664047, 19051200), + listOf(4u, 6u) to Rational(3769375009003, 1680315840), + listOf(5u, 6u) to Rational(-12920385574769, 1050197400), + listOf(6u, 6u) to Rational(-90219591809287, 6301184400), + listOf(7u, 6u) to Rational(656361553391, 1575296100), + listOf(8u, 6u) to Rational(757900793, 2250423), + listOf(0u, 7u) to Rational(-100770017, 15120), + listOf(1u, 7u) to Rational(-316364851, 17640), + listOf(2u, 7u) to Rational(-85118560057, 6667920), + listOf(3u, 7u) to Rational(6286563719, 416745), + listOf(4u, 7u) to Rational(26803885301, 1714608), + listOf(5u, 7u) to Rational(-13767154393, 4286520), + listOf(6u, 7u) to Rational(-3875138933, 1224720), + listOf(7u, 7u) to Rational(65193755, 333396), + listOf(8u, 7u) to Rational(90974351, 2500470), + listOf(0u, 8u) to Rational(-3182197, 1260), + listOf(1u, 8u) to Rational(24899923, 8820), + listOf(2u, 8u) to Rational(-19999556, 19845), + listOf(3u, 8u) to Rational(3276587, 3969), + listOf(4u, 8u) to Rational(13719549239, 5000940), + listOf(5u, 8u) to Rational(-961839938, 1250235), + listOf(6u, 8u) to Rational(-198184871, 833490), + listOf(7u, 8u) to Rational(230659711, 5000940), + listOf(8u, 8u) to Rational(292447, 35721) + ), + NumberedPolynomialAsIs( + listOf() to Rational(9, 100), + listOf(1u) to Rational(-21, 50), + listOf(2u) to Rational(293, 700), + listOf(3u) to Rational(29, 210), + listOf(4u) to Rational(3233, 8820), + listOf(5u) to Rational(-289, 441), + listOf(6u) to Rational(-1, 9), + listOf(7u) to Rational(-20, 441), + listOf(8u) to Rational(100, 441), + listOf(0u, 1u) to Rational(-57, 80), + listOf(1u, 1u) to Rational(-121, 400), + listOf(2u, 1u) to Rational(37117, 8400), + listOf(3u, 1u) to Rational(-4853, 3150), + listOf(4u, 1u) to Rational(1166203, 132300), + listOf(5u, 1u) to Rational(-2708, 567), + listOf(6u, 1u) to Rational(-287159, 416745), + listOf(7u, 1u) to Rational(-478204, 83349), + listOf(8u, 1u) to Rational(176320, 83349), + listOf(0u, 2u) to Rational(-6239, 6400), + listOf(1u, 2u) to Rational(264211, 11200), + listOf(2u, 2u) to Rational(-1591999, 100800), + listOf(3u, 2u) to Rational(12450091, 529200), + listOf(4u, 2u) to Rational(9230759, 226800), + listOf(5u, 2u) to Rational(18995554, 2083725), + listOf(6u, 2u) to Rational(136706258, 6251175), + listOf(7u, 2u) to Rational(-120907496, 3750705), + listOf(8u, 2u) to Rational(117200176, 15752961), + listOf(0u, 3u) to Rational(5653, 320), + listOf(1u, 3u) to Rational(-130853, 8400), + listOf(2u, 3u) to Rational(-20939327, 151200), + listOf(3u, 3u) to Rational(2566691, 25200), + listOf(4u, 3u) to Rational(-68441519, 476280), + listOf(5u, 3u) to Rational(2462904247, 12502350), + listOf(6u, 3u) to Rational(353667161, 18753525), + listOf(7u, 3u) to Rational(-1689134372, 26254935), + listOf(8u, 3u) to Rational(35084104, 2250423), + listOf(0u, 4u) to Rational(-3587, 300), + listOf(1u, 4u) to Rational(-10513243, 33600), + listOf(2u, 4u) to Rational(30766733, 176400), + listOf(3u, 4u) to Rational(-65680021, 198450), + listOf(4u, 4u) to Rational(-8108910547, 20003760), + listOf(5u, 4u) to Rational(2922125159, 6251175), + listOf(6u, 4u) to Rational(-4245279943, 131274675), + listOf(7u, 4u) to Rational(-371946872, 3750705), + listOf(8u, 4u) to Rational(61286752, 2250423), + listOf(0u, 5u) to Rational(-20477, 160), + listOf(1u, 5u) to Rational(215741, 1120), + listOf(2u, 5u) to Rational(30785843, 31752), + listOf(3u, 5u) to Rational(-357495959, 317520), + listOf(4u, 5u) to Rational(-1611242993, 10001880), + listOf(5u, 5u) to Rational(345925495, 500094), + listOf(6u, 5u) to Rational(-755948411, 3750705), + listOf(7u, 5u) to Rational(-108643496, 1250235), + listOf(8u, 5u) to Rational(1122512, 35721), + listOf(0u, 6u) to Rational(358037, 2880), + listOf(1u, 6u) to Rational(3895837, 3360), + listOf(2u, 6u) to Rational(359419201, 1270080), + listOf(3u, 6u) to Rational(-158522587, 105840), + listOf(4u, 6u) to Rational(10909002599, 20003760), + listOf(5u, 6u) to Rational(76846972, 138915), + listOf(6u, 6u) to Rational(-327696553, 1250235), + listOf(7u, 6u) to Rational(-1687328, 35721), + listOf(8u, 6u) to Rational(1016836, 35721), + listOf(0u, 7u) to Rational(658, 3), + listOf(1u, 7u) to Rational(48035, 168), + listOf(2u, 7u) to Rational(-5777875, 5292), + listOf(3u, 7u) to Rational(-7893899, 10584), + listOf(4u, 7u) to Rational(10191652, 11907), + listOf(5u, 7u) to Rational(2920121, 23814), + listOf(6u, 7u) to Rational(-2699780, 11907), + listOf(7u, 7u) to Rational(4556, 441), + listOf(8u, 7u) to Rational(3440, 189), + listOf(0u, 8u) to Rational(64, 1), + listOf(1u, 8u) to Rational(-808, 7), + listOf(2u, 8u) to Rational(-360895, 1764), + listOf(3u, 8u) to Rational(257657, 882), + listOf(4u, 8u) to Rational(3779917, 15876), + listOf(5u, 8u) to Rational(-610279, 3969), + listOf(6u, 8u) to Rational(-25091, 441), + listOf(7u, 8u) to Rational(9560, 567), + listOf(8u, 8u) to Rational(400, 81) + ) + ), + NumberedPolynomialAsIs( + listOf() to Rational(15, 7), + listOf(1u) to Rational(1, 5), + listOf(2u) to Rational(-7, 4), + listOf(0u, 1u) to Rational(-1, 9), + listOf(1u, 1u) to Rational(-2, 7), + listOf(2u, 1u) to Rational(17, 3), + listOf(0u, 2u) to Rational(2, 6), + listOf(1u, 2u) to Rational(-17, 6), + listOf(2u, 2u) to Rational(-6, 2), + ).substitute(RationalField, bufferOf( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(17, 5), + listOf(1u) to Rational(11, 6), + listOf(2u) to Rational(14, 3), + listOf(0u, 1u) to Rational(17, 1), + listOf(1u, 1u) to Rational(12, 3), + listOf(2u, 1u) to Rational(-6, 2), + listOf(0u, 2u) to Rational(17, 1), + listOf(1u, 2u) to Rational(-4, 3), + listOf(2u, 2u) to Rational(2, 6), + ), + NumberedPolynomialAsIs( + listOf() to Rational(3, 5), + listOf(1u) to Rational(3, 5), + listOf(2u) to Rational(3, 7), + listOf(0u, 1u) to Rational(-3, 8), + listOf(1u, 1u) to Rational(-1, 1), + listOf(2u, 1u) to Rational(17, 9), + listOf(0u, 2u) to Rational(-8, 1), + listOf(1u, 2u) to Rational(6, 4), + listOf(2u, 2u) to Rational(10, 9), + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(18, 5), + listOf(1u) to Rational(-17, 5), + listOf(2u) to Rational(-2, 7), + listOf(0u, 1u) to Rational(6, 5), + listOf(1u, 1u) to Rational(-5, 1), + listOf(2u, 1u) to Rational(-9, 1), + listOf(0u, 2u) to Rational(-8, 8), + listOf(1u, 2u) to Rational(2, 7), + listOf(2u, 2u) to Rational(-13, 7), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-4, 8), + listOf(1u) to Rational(15, 9), + listOf(2u) to Rational(-10, 9), + listOf(0u, 1u) to Rational(5, 3), + listOf(1u, 1u) to Rational(4, 1), + listOf(2u, 1u) to Rational(-2, 7), + listOf(0u, 2u) to Rational(2, 2), + listOf(1u, 2u) to Rational(-5, 7), + listOf(2u, 2u) to Rational(-18, 9), + ) + ), + )), + "test 4" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-66677, 3500), + listOf(1u) to Rational(-206281, 10500), + listOf(2u) to Rational(-412567, 7056), + listOf(3u) to Rational(-310081, 11025), + listOf(4u) to Rational(-575996, 15435), + listOf(0u, 1u) to Rational(-573701, 4200), + listOf(1u, 1u) to Rational(-2239001, 25200), + listOf(2u, 1u) to Rational(-8817889, 132300), + listOf(3u, 1u) to Rational(2317919, 44100), + listOf(4u, 1u) to Rational(1169471, 6615), + listOf(0u, 2u) to Rational(-4057819, 33600), + listOf(1u, 2u) to Rational(1373311, 12600), + listOf(2u, 2u) to Rational(32433493, 52920), + listOf(3u, 2u) to Rational(4998053, 33075), + listOf(4u, 2u) to Rational(-2147779, 8820), + listOf(0u, 3u) to Rational(2018481, 2240), + listOf(1u, 3u) to Rational(941713, 1440), + listOf(2u, 3u) to Rational(183749, 6615), + listOf(3u, 3u) to Rational(-4631023, 15876), + listOf(4u, 3u) to Rational(25609336, 178605), + listOf(0u, 4u) to Rational(11886431, 6720), + listOf(1u, 4u) to Rational(18433, 504), + listOf(2u, 4u) to Rational(-39613331, 45360), + listOf(3u, 4u) to Rational(681619, 5670), + listOf(4u, 4u) to Rational(-864841, 20412), + listOf(0u, 5u) to Rational(343535, 1008), + listOf(1u, 5u) to Rational(-33583, 72), + listOf(2u, 5u) to Rational(1194625, 9072), + listOf(3u, 5u) to Rational(-62917, 2268), + listOf(4u, 5u) to Rational(157645, 10206), + listOf(0u, 6u) to Rational(-1381, 3), + listOf(1u, 6u) to Rational(919, 36), + listOf(2u, 6u) to Rational(-3053, 36), + listOf(3u, 6u) to Rational(2125, 324), + listOf(4u, 6u) to Rational(-236, 243) + ), + NumberedPolynomialAsIs(listOf() to Rational(0, 1), + listOf() to Rational(1, 4), + listOf(1u) to Rational(-5, 3), + listOf(2u) to Rational(35, 9), + listOf(3u) to Rational(-100, 27), + listOf(4u) to Rational(100, 81), + listOf(0u, 1u) to Rational(-5, 3), + listOf(1u, 1u) to Rational(14, 9), + listOf(2u, 1u) to Rational(1874, 189), + listOf(3u, 1u) to Rational(-620, 63), + listOf(4u, 1u) to Rational(40, 63), + listOf(0u, 2u) to Rational(16, 9), + listOf(1u, 2u) to Rational(365, 21), + listOf(2u, 2u) to Rational(112, 9), + listOf(3u, 2u) to Rational(-464, 63), + listOf(4u, 2u) to Rational(1996, 441), + listOf(0u, 3u) to Rational(10, 3), + listOf(1u, 3u) to Rational(118, 21), + listOf(2u, 3u) to Rational(-272, 21), + listOf(3u, 3u) to Rational(-764, 49), + listOf(4u, 3u) to Rational(8, 7), + listOf(0u, 4u) to Rational(1, 1), + listOf(1u, 4u) to Rational(-10, 7), + listOf(2u, 4u) to Rational(-171, 49), + listOf(3u, 4u) to Rational(20, 7), + listOf(4u, 4u) to Rational(4, 1) + ) + ), + NumberedPolynomialAsIs( + listOf() to Rational(15, 7), + listOf(1u) to Rational(1, 5), + listOf(2u) to Rational(-7, 4), + listOf(0u, 1u) to Rational(-1, 9), + listOf(1u, 1u) to Rational(-2, 7), + listOf(2u, 1u) to Rational(17, 3), + listOf(0u, 2u) to Rational(2, 6), + listOf(1u, 2u) to Rational(-17, 6), + listOf(2u, 2u) to Rational(-6, 2), + ).substitute(RationalField, bufferOf( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(17, 5), + listOf(1u) to Rational(11, 6), + listOf(2u) to Rational(14, 3), + listOf(0u, 1u) to Rational(17, 1), + listOf(1u, 1u) to Rational(12, 3), + listOf(2u, 1u) to Rational(-6, 2), + listOf(0u, 2u) to Rational(17, 1), + listOf(1u, 2u) to Rational(-4, 3), + listOf(2u, 2u) to Rational(2, 6), + ), + NumberedPolynomialAsIs( + listOf() to Rational(3, 5), + listOf(1u) to Rational(3, 5), + listOf(2u) to Rational(3, 7), + listOf(0u, 1u) to Rational(-3, 8), + listOf(1u, 1u) to Rational(-1, 1), + listOf(2u, 1u) to Rational(17, 9), + listOf(0u, 2u) to Rational(-8, 1), + listOf(1u, 2u) to Rational(6, 4), + listOf(2u, 2u) to Rational(10, 9), + ) + ), + )), + "test 5" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(15, 7), + listOf(1u) to Rational(1, 5), + listOf(2u) to Rational(-7, 4), + listOf(0u, 1u) to Rational(-1, 9), + listOf(1u, 1u) to Rational(-2, 7), + listOf(2u, 1u) to Rational(17, 3), + listOf(0u, 2u) to Rational(2, 6), + listOf(1u, 2u) to Rational(-17, 6), + listOf(2u, 2u) to Rational(-6, 2), + ), + NumberedPolynomialAsIs(listOf() to Rational(0, 1), + listOf() to Rational(0, 1) + ) + ), + NumberedPolynomialAsIs( + listOf() to Rational(15, 7), + listOf(1u) to Rational(1, 5), + listOf(2u) to Rational(-7, 4), + listOf(0u, 1u) to Rational(-1, 9), + listOf(1u, 1u) to Rational(-2, 7), + listOf(2u, 1u) to Rational(17, 3), + listOf(0u, 2u) to Rational(2, 6), + listOf(1u, 2u) to Rational(-17, 6), + listOf(2u, 2u) to Rational(-6, 2), + ).substitute(RationalField, bufferOf>()), + "test 6" + ) } @Test - @Ignore fun test_RationalFunction_substitute_Double_Buffer() { - // TODO + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs(emptyList() to 0.0), + NumberedPolynomialAsIs(emptyList() to 1.0), + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 1.0, + listOf(1u) to -2.0, + listOf(2u) to 1.0, + ), + NumberedPolynomialAsIs( + listOf() to 1.0, + ) + ).substitute(bufferOf( + 1.0 + )), + 0.001, + "test 1" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 6.593754860231304, + listOf(1u) to -7.853302571550634, + listOf(2u) to 1.2265042281530025, + listOf(0u, 1u) to 3.762648877294904, + listOf(1u, 1u) to -8.945144619305292, + listOf(2u, 1u) to -5.141384718042281, + listOf(0u, 2u) to 7.359794483988782, + listOf(1u, 2u) to -4.3526172680518815, + listOf(2u, 2u) to 0.907910924854372, + ), + NumberedPolynomialAsIs( + listOf() to 9.533292132172562, + listOf(1u) to -1.982814534018857, + listOf(2u) to -5.974248303415283, + listOf(0u, 1u) to 1.5876716499288879, + listOf(1u, 1u) to -7.535152566659664, + listOf(2u, 1u) to 0.7549300500153517, + listOf(0u, 2u) to -5.242030058021028, + listOf(1u, 2u) to -0.7265704289690582, + listOf(2u, 2u) to -7.139677818189821, + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 6.593754860231304, + listOf(1u) to -7.853302571550634, + listOf(2u) to 1.2265042281530025, + listOf(0u, 1u) to 3.762648877294904, + listOf(1u, 1u) to -8.945144619305292, + listOf(2u, 1u) to -5.141384718042281, + listOf(0u, 2u) to 7.359794483988782, + listOf(1u, 2u) to -4.3526172680518815, + listOf(2u, 2u) to 0.907910924854372, + ), + NumberedPolynomialAsIs( + listOf() to 9.533292132172562, + listOf(1u) to -1.982814534018857, + listOf(2u) to -5.974248303415283, + listOf(0u, 1u) to 1.5876716499288879, + listOf(1u, 1u) to -7.535152566659664, + listOf(2u, 1u) to 0.7549300500153517, + listOf(0u, 2u) to -5.242030058021028, + listOf(1u, 2u) to -0.7265704289690582, + listOf(2u, 2u) to -7.139677818189821, + ) + ).substitute(bufferOf()), + 0.001, + "test 2" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 151.1502229133916, + listOf(0u, 1u) to -262.3790170577034, + listOf(0u, 2u) to 102.5097937392923, + ), + NumberedPolynomialAsIs( + listOf() to -367.9969733169944, + listOf(0u, 1u) to 112.4911133334554, + listOf(0u, 2u) to -469.755906895345, + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 6.593754860231304, + listOf(1u) to -7.853302571550634, + listOf(2u) to 1.2265042281530025, + listOf(0u, 1u) to 3.762648877294904, + listOf(1u, 1u) to -8.945144619305292, + listOf(2u, 1u) to -5.141384718042281, + listOf(0u, 2u) to 7.359794483988782, + listOf(1u, 2u) to -4.3526172680518815, + listOf(2u, 2u) to 0.907910924854372, + ), + NumberedPolynomialAsIs( + listOf() to 9.533292132172562, + listOf(1u) to -1.982814534018857, + listOf(2u) to -5.974248303415283, + listOf(0u, 1u) to 1.5876716499288879, + listOf(1u, 1u) to -7.535152566659664, + listOf(2u, 1u) to 0.7549300500153517, + listOf(0u, 2u) to -5.242030058021028, + listOf(1u, 2u) to -0.7265704289690582, + listOf(2u, 2u) to -7.139677818189821, + ) + ).substitute(bufferOf( + -8.11707689492641, + )), + 0.001, + "test 3" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 7.321261307532708, + ), + NumberedPolynomialAsIs( + listOf() to -575.6325831127576, + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 6.593754860231304, + listOf(1u) to -7.853302571550634, + listOf(2u) to 1.2265042281530025, + listOf(0u, 1u) to 3.762648877294904, + listOf(1u, 1u) to -8.945144619305292, + listOf(2u, 1u) to -5.141384718042281, + listOf(0u, 2u) to 7.359794483988782, + listOf(1u, 2u) to -4.3526172680518815, + listOf(2u, 2u) to 0.907910924854372, + ), + NumberedPolynomialAsIs( + listOf() to 9.533292132172562, + listOf(1u) to -1.982814534018857, + listOf(2u) to -5.974248303415283, + listOf(0u, 1u) to 1.5876716499288879, + listOf(1u, 1u) to -7.535152566659664, + listOf(2u, 1u) to 0.7549300500153517, + listOf(0u, 2u) to -5.242030058021028, + listOf(1u, 2u) to -0.7265704289690582, + listOf(2u, 2u) to -7.139677818189821, + ) + ).substitute(bufferOf( + -8.11707689492641, + 0.795265651276015, + )), + 0.001, + "test 4" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 7.321261307532708, + ), + NumberedPolynomialAsIs( + listOf() to -575.6325831127576, + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 6.593754860231304, + listOf(1u) to -7.853302571550634, + listOf(2u) to 1.2265042281530025, + listOf(0u, 1u) to 3.762648877294904, + listOf(1u, 1u) to -8.945144619305292, + listOf(2u, 1u) to -5.141384718042281, + listOf(0u, 2u) to 7.359794483988782, + listOf(1u, 2u) to -4.3526172680518815, + listOf(2u, 2u) to 0.907910924854372, + ), + NumberedPolynomialAsIs( + listOf() to 9.533292132172562, + listOf(1u) to -1.982814534018857, + listOf(2u) to -5.974248303415283, + listOf(0u, 1u) to 1.5876716499288879, + listOf(1u, 1u) to -7.535152566659664, + listOf(2u, 1u) to 0.7549300500153517, + listOf(0u, 2u) to -5.242030058021028, + listOf(1u, 2u) to -0.7265704289690582, + listOf(2u, 2u) to -7.139677818189821, + ) + ).substitute(bufferOf( + -8.11707689492641, + 0.795265651276015, + 0.9211194782050933 + )), + 0.001, + "test 5" + ) } @Test - @Ignore fun test_RationalFunction_substitute_Constant_Buffer() { - // TODO + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(0) + ), + NumberedPolynomialAsIs( + listOf() to Rational(1) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1) + ), + NumberedPolynomialAsIs( + listOf() to Rational(1) + ) + ).substitute(RationalField, bufferOf( + Rational(1) + )), + "test 1" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(22047, 2450), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-2204953, 147000), + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 5), + listOf(1u) to Rational(-18, 4), + listOf(2u) to Rational(9, 8), + listOf(0u, 1u) to Rational(-11, 6), + listOf(1u, 1u) to Rational(-16, 3), + listOf(2u, 1u) to Rational(12, 2), + listOf(0u, 2u) to Rational(5, 3), + listOf(1u, 2u) to Rational(17, 8), + listOf(2u, 2u) to Rational(1, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(11, 1), + listOf(1u) to Rational(4, 1), + listOf(2u) to Rational(-18, 3), + listOf(0u, 1u) to Rational(12, 9), + listOf(1u, 1u) to Rational(14, 7), + listOf(2u, 1u) to Rational(-17, 5), + listOf(0u, 2u) to Rational(-4, 1), + listOf(1u, 2u) to Rational(-5, 5), + listOf(2u, 2u) to Rational(-7, 8), + ) + ).substitute(RationalField, bufferOf( + Rational(7, 5), + Rational(-13, 7), + Rational(-16, 4), + )), + "test 2" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(22047, 2450), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-2204953, 147000), + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 5), + listOf(1u) to Rational(-18, 4), + listOf(2u) to Rational(9, 8), + listOf(0u, 1u) to Rational(-11, 6), + listOf(1u, 1u) to Rational(-16, 3), + listOf(2u, 1u) to Rational(12, 2), + listOf(0u, 2u) to Rational(5, 3), + listOf(1u, 2u) to Rational(17, 8), + listOf(2u, 2u) to Rational(1, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(11, 1), + listOf(1u) to Rational(4, 1), + listOf(2u) to Rational(-18, 3), + listOf(0u, 1u) to Rational(12, 9), + listOf(1u, 1u) to Rational(14, 7), + listOf(2u, 1u) to Rational(-17, 5), + listOf(0u, 2u) to Rational(-4, 1), + listOf(1u, 2u) to Rational(-5, 5), + listOf(2u, 2u) to Rational(-7, 8), + ) + ).substitute(RationalField, bufferOf( + Rational(7, 5), + Rational(-13, 7), + )), + "test 3" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-939, 200), + listOf(0u, 1u) to Rational(123, 50), + listOf(0u, 2u) to Rational(1059, 200) + ), + NumberedPolynomialAsIs( + listOf() to Rational(121, 25), + listOf(0u, 1u) to Rational(-949, 375), + listOf(0u, 2u) to Rational(-1423, 200) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 5), + listOf(1u) to Rational(-18, 4), + listOf(2u) to Rational(9, 8), + listOf(0u, 1u) to Rational(-11, 6), + listOf(1u, 1u) to Rational(-16, 3), + listOf(2u, 1u) to Rational(12, 2), + listOf(0u, 2u) to Rational(5, 3), + listOf(1u, 2u) to Rational(17, 8), + listOf(2u, 2u) to Rational(1, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(11, 1), + listOf(1u) to Rational(4, 1), + listOf(2u) to Rational(-18, 3), + listOf(0u, 1u) to Rational(12, 9), + listOf(1u, 1u) to Rational(14, 7), + listOf(2u, 1u) to Rational(-17, 5), + listOf(0u, 2u) to Rational(-4, 1), + listOf(1u, 2u) to Rational(-5, 5), + listOf(2u, 2u) to Rational(-7, 8), + ) + ).substitute(RationalField, bufferOf( + Rational(7, 5), + )), + "test 4" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 5), + listOf(1u) to Rational(-18, 4), + listOf(2u) to Rational(9, 8), + listOf(0u, 1u) to Rational(-11, 6), + listOf(1u, 1u) to Rational(-16, 3), + listOf(2u, 1u) to Rational(12, 2), + listOf(0u, 2u) to Rational(5, 3), + listOf(1u, 2u) to Rational(17, 8), + listOf(2u, 2u) to Rational(1, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(11, 1), + listOf(1u) to Rational(4, 1), + listOf(2u) to Rational(-18, 3), + listOf(0u, 1u) to Rational(12, 9), + listOf(1u, 1u) to Rational(14, 7), + listOf(2u, 1u) to Rational(-17, 5), + listOf(0u, 2u) to Rational(-4, 1), + listOf(1u, 2u) to Rational(-5, 5), + listOf(2u, 2u) to Rational(-7, 8), + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 5), + listOf(1u) to Rational(-18, 4), + listOf(2u) to Rational(9, 8), + listOf(0u, 1u) to Rational(-11, 6), + listOf(1u, 1u) to Rational(-16, 3), + listOf(2u, 1u) to Rational(12, 2), + listOf(0u, 2u) to Rational(5, 3), + listOf(1u, 2u) to Rational(17, 8), + listOf(2u, 2u) to Rational(1, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(11, 1), + listOf(1u) to Rational(4, 1), + listOf(2u) to Rational(-18, 3), + listOf(0u, 1u) to Rational(12, 9), + listOf(1u, 1u) to Rational(14, 7), + listOf(2u, 1u) to Rational(-17, 5), + listOf(0u, 2u) to Rational(-4, 1), + listOf(1u, 2u) to Rational(-5, 5), + listOf(2u, 2u) to Rational(-7, 8), + ) + ).substitute(RationalField, bufferOf()), + "test 5" + ) } @Test - @Ignore fun test_RationalFunction_substitute_Polynomial_Buffer() { - // TODO + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(0) + ), + NumberedPolynomialAsIs( + listOf() to Rational(1) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1) + ), + NumberedPolynomialAsIs( + listOf() to Rational(1) + ) + ).substitute(RationalField, bufferOf( + NumberedPolynomialAsIs( + listOf() to Rational(1) + ) + )), + "test 1" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(5, 6), + listOf(1u) to Rational(211, 4), + listOf(2u) to Rational(88, 3), + listOf(3u) to Rational(-63, 8), + listOf(4u) to Rational(441, 16), + listOf(0u, 1u) to Rational(-671, 15), + listOf(1u, 1u) to Rational(-551, 21), + listOf(2u, 1u) to Rational(279, 25), + listOf(3u, 1u) to Rational(231, 20), + listOf(0u, 2u) to Rational(-1436, 1575), + listOf(1u, 2u) to Rational(2471, 250), + listOf(2u, 2u) to Rational(-4919, 100), + listOf(0u, 3u) to Rational(-1464, 125), + listOf(1u, 3u) to Rational(-264, 25), + listOf(0u, 4u) to Rational(576, 25), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-11, 9), + listOf(1u) to Rational(-9, 4), + listOf(2u) to Rational(943, 8), + listOf(3u) to Rational(117, 8), + listOf(4u) to Rational(147, 16), + listOf(0u, 1u) to Rational(289, 90), + listOf(1u, 1u) to Rational(-2692, 15), + listOf(2u, 1u) to Rational(-1629, 140), + listOf(3u, 1u) to Rational(77, 20), + listOf(0u, 2u) to Rational(6187, 75), + listOf(1u, 2u) to Rational(-2879, 175), + listOf(2u, 2u) to Rational(-4919, 300), + listOf(0u, 3u) to Rational(336, 25), + listOf(1u, 3u) to Rational(-88, 25), + listOf(0u, 4u) to Rational(192, 25), + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(5, 6), + listOf(1u) to Rational(1, 6), + listOf(2u) to Rational(-2, 9), + listOf(0u, 1u) to Rational(15, 1), + listOf(1u, 1u) to Rational(18, 7), + listOf(2u, 1u) to Rational(2, 5), + listOf(0u, 2u) to Rational(12, 9), + listOf(1u, 2u) to Rational(-3, 5), + listOf(2u, 2u) to Rational(4, 4), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-11, 9), + listOf(1u) to Rational(4, 9), + listOf(2u) to Rational(11, 6), + listOf(0u, 1u) to Rational(-5, 6), + listOf(1u, 1u) to Rational(4, 6), + listOf(2u, 1u) to Rational(-1, 7), + listOf(0u, 2u) to Rational(9, 1), + listOf(1u, 2u) to Rational(6, 7), + listOf(2u, 2u) to Rational(1, 3), + ) + ).substitute(RationalField, bufferOf( + NumberedPolynomialAsIs( + listOf(1u) to Rational(3, 2), + listOf(0u, 1u) to Rational(8, 5), + ), + NumberedPolynomialAsIs( + listOf(1u) to Rational(7, 2), + listOf(0u, 1u) to Rational(-3, 1), + ) + )), + "test 2" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(1202861, 210), + listOf(1u) to Rational(-215117, 45), + listOf(2u) to Rational(10889651, 19845), + listOf(3u) to Rational(-3503956, 6615), + listOf(4u) to Rational(809066, 2205), + listOf(5u) to Rational(-9056, 735), + listOf(6u) to Rational(5396, 315), + listOf(7u) to Rational(-752, 147), + listOf(8u) to Rational(16, 49), + listOf(0u, 1u) to Rational(1738469, 1470), + listOf(1u, 1u) to Rational(-926238703, 52920), + listOf(2u, 1u) to Rational(-44113982, 6615), + listOf(3u, 1u) to Rational(10423519, 5292), + listOf(4u, 1u) to Rational(3769712, 2205), + listOf(5u, 1u) to Rational(8905046, 6615), + listOf(6u, 1u) to Rational(1186972, 6615), + listOf(7u, 1u) to Rational(22124, 441), + listOf(8u, 1u) to Rational(-1504, 147), + listOf(0u, 2u) to Rational(-54723628, 2205), + listOf(1u, 2u) to Rational(70109407, 1323), + listOf(2u, 2u) to Rational(151072591, 17640), + listOf(3u, 2u) to Rational(1216428107, 52920), + listOf(4u, 2u) to Rational(2587873193, 317520), + listOf(5u, 2u) to Rational(393536369, 79380), + listOf(6u, 2u) to Rational(137614937, 79380), + listOf(7u, 2u) to Rational(566866, 1323), + listOf(8u, 2u) to Rational(41848, 441), + listOf(0u, 3u) to Rational(-19470406, 2205), + listOf(1u, 3u) to Rational(72514195, 882), + listOf(2u, 3u) to Rational(-78090707, 1764), + listOf(3u, 3u) to Rational(-1988237707, 26460), + listOf(4u, 3u) to Rational(-802137919, 17640), + listOf(5u, 3u) to Rational(-139989463, 5880), + listOf(6u, 3u) to Rational(-26066641, 3780), + listOf(7u, 3u) to Rational(-2363369, 1323), + listOf(8u, 3u) to Rational(-108280, 441), + listOf(0u, 4u) to Rational(14878516, 441), + listOf(1u, 4u) to Rational(-253416724, 2205), + listOf(2u, 4u) to Rational(16699157, 840), + listOf(3u, 4u) to Rational(-105220979, 13230), + listOf(4u, 4u) to Rational(208266383, 5880), + listOf(5u, 4u) to Rational(650135309, 26460), + listOf(6u, 4u) to Rational(123808663, 11760), + listOf(7u, 4u) to Rational(8563385, 2646), + listOf(8u, 4u) to Rational(19721, 49), + listOf(0u, 5u) to Rational(675645, 49), + listOf(1u, 5u) to Rational(-70554077, 588), + listOf(2u, 5u) to Rational(157884029, 980), + listOf(3u, 5u) to Rational(489548623, 4410), + listOf(4u, 5u) to Rational(148540519, 17640), + listOf(5u, 5u) to Rational(-5559551, 392), + listOf(6u, 5u) to Rational(-18335711, 1470), + listOf(7u, 5u) to Rational(-38437, 9), + listOf(8u, 5u) to Rational(-29620, 63), + listOf(0u, 6u) to Rational(-727625, 49), + listOf(1u, 6u) to Rational(7046685, 98), + listOf(2u, 6u) to Rational(-334814231, 7056), + listOf(3u, 6u) to Rational(-243971737, 17640), + listOf(4u, 6u) to Rational(-571116659, 35280), + listOf(5u, 6u) to Rational(567538, 315), + listOf(6u, 6u) to Rational(3199768, 315), + listOf(7u, 6u) to Rational(227744, 63), + listOf(8u, 6u) to Rational(23116, 63), + listOf(0u, 7u) to Rational(-27500, 7), + listOf(1u, 7u) to Rational(120125, 3), + listOf(2u, 7u) to Rational(-279200, 3), + listOf(3u, 7u) to Rational(-100160, 7), + listOf(4u, 7u) to Rational(920452, 21), + listOf(5u, 7u) to Rational(226481, 21), + listOf(6u, 7u) to Rational(-34428, 7), + listOf(7u, 7u) to Rational(-6232, 3), + listOf(8u, 7u) to Rational(-608, 3), + listOf(0u, 8u) to Rational(2500, 1), + listOf(1u, 8u) to Rational(-19000, 1), + listOf(2u, 8u) to Rational(37900, 1), + listOf(3u, 8u) to Rational(-1840, 1), + listOf(4u, 8u) to Rational(-17876, 1), + listOf(5u, 8u) to Rational(-1240, 1), + listOf(6u, 8u) to Rational(2788, 1), + listOf(7u, 8u) to Rational(800, 1), + listOf(8u, 8u) to Rational(64, 1) + ), + NumberedPolynomialAsIs( + listOf() to Rational(162487, 63), + listOf(1u) to Rational(-92713, 54), + listOf(2u) to Rational(802436, 1323), + listOf(3u) to Rational(-55088, 441), + listOf(4u) to Rational(1404034, 9261), + listOf(5u) to Rational(-5804, 1029), + listOf(6u) to Rational(51556, 9261), + listOf(7u) to Rational(-752, 441), + listOf(8u) to Rational(16, 147), + listOf(0u, 1u) to Rational(296071, 441), + listOf(1u, 1u) to Rational(-4991281, 882), + listOf(2u, 1u) to Rational(-18702811, 9261), + listOf(3u, 1u) to Rational(40759043, 27783), + listOf(4u, 1u) to Rational(19768501, 27783), + listOf(5u, 1u) to Rational(14307337, 27783), + listOf(6u, 1u) to Rational(1655684, 27783), + listOf(7u, 1u) to Rational(22124, 1323), + listOf(8u, 1u) to Rational(-1504, 441), + listOf(0u, 2u) to Rational(-27667474, 3087), + listOf(1u, 2u) to Rational(265605901, 12348), + listOf(2u, 2u) to Rational(160360775, 98784), + listOf(3u, 2u) to Rational(1169992093, 148176), + listOf(4u, 2u) to Rational(3978014077, 1333584), + listOf(5u, 2u) to Rational(567058123, 333396), + listOf(6u, 2u) to Rational(205132579, 333396), + listOf(7u, 2u) to Rational(566866, 3969), + listOf(8u, 2u) to Rational(41848, 1323), + listOf(0u, 3u) to Rational(-2228822, 1029), + listOf(1u, 3u) to Rational(80179390, 3087), + listOf(2u, 3u) to Rational(-1378630487, 74088), + listOf(3u, 3u) to Rational(-3385811693, 111132), + listOf(4u, 3u) to Rational(-820686977, 49392), + listOf(5u, 3u) to Rational(-89101027, 10584), + listOf(6u, 3u) to Rational(-37847387, 15876), + listOf(7u, 3u) to Rational(-2363369, 3969), + listOf(8u, 3u) to Rational(-108280, 1323), + listOf(0u, 4u) to Rational(12619982, 1029), + listOf(1u, 4u) to Rational(-277723177, 6174), + listOf(2u, 4u) to Rational(649414169, 49392), + listOf(3u, 4u) to Rational(14457595, 63504), + listOf(4u, 4u) to Rational(139270339, 10584), + listOf(5u, 4u) to Rational(140367961, 15876), + listOf(6u, 4u) to Rational(25467083, 7056), + listOf(7u, 4u) to Rational(8563385, 7938), + listOf(8u, 4u) to Rational(19721, 147), + listOf(0u, 5u) to Rational(643850, 147), + listOf(1u, 5u) to Rational(-11818025, 294), + listOf(2u, 5u) to Rational(33963203, 588), + listOf(3u, 5u) to Rational(207216235, 5292), + listOf(4u, 5u) to Rational(2861021, 1512), + listOf(5u, 5u) to Rational(-6302335, 1176), + listOf(6u, 5u) to Rational(-3738587, 882), + listOf(7u, 5u) to Rational(-38437, 27), + listOf(8u, 5u) to Rational(-29620, 189), + listOf(0u, 6u) to Rational(-248725, 49), + listOf(1u, 6u) to Rational(2478535, 98), + listOf(2u, 6u) to Rational(-399721367, 21168), + listOf(3u, 6u) to Rational(-54309317, 10584), + listOf(4u, 6u) to Rational(-95398327, 21168), + listOf(5u, 6u) to Rational(173750, 189), + listOf(6u, 6u) to Rational(92216, 27), + listOf(7u, 6u) to Rational(227744, 189), + listOf(8u, 6u) to Rational(23116, 189), + listOf(0u, 7u) to Rational(-27500, 21), + listOf(1u, 7u) to Rational(120125, 9), + listOf(2u, 7u) to Rational(-279200, 9), + listOf(3u, 7u) to Rational(-100160, 21), + listOf(4u, 7u) to Rational(920452, 63), + listOf(5u, 7u) to Rational(226481, 63), + listOf(6u, 7u) to Rational(-11476, 7), + listOf(7u, 7u) to Rational(-6232, 9), + listOf(8u, 7u) to Rational(-608, 9), + listOf(0u, 8u) to Rational(2500, 3), + listOf(1u, 8u) to Rational(-19000, 3), + listOf(2u, 8u) to Rational(37900, 3), + listOf(3u, 8u) to Rational(-1840, 3), + listOf(4u, 8u) to Rational(-17876, 3), + listOf(5u, 8u) to Rational(-1240, 3), + listOf(6u, 8u) to Rational(2788, 3), + listOf(7u, 8u) to Rational(800, 3), + listOf(8u, 8u) to Rational(64, 3) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(5, 6), + listOf(1u) to Rational(1, 6), + listOf(2u) to Rational(-2, 9), + listOf(0u, 1u) to Rational(15, 1), + listOf(1u, 1u) to Rational(18, 7), + listOf(2u, 1u) to Rational(2, 5), + listOf(0u, 2u) to Rational(12, 9), + listOf(1u, 2u) to Rational(-3, 5), + listOf(2u, 2u) to Rational(4, 4), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-11, 9), + listOf(1u) to Rational(4, 9), + listOf(2u) to Rational(11, 6), + listOf(0u, 1u) to Rational(-5, 6), + listOf(1u, 1u) to Rational(4, 6), + listOf(2u, 1u) to Rational(-1, 7), + listOf(0u, 2u) to Rational(9, 1), + listOf(1u, 2u) to Rational(6, 7), + listOf(2u, 2u) to Rational(1, 3), + ) + ).substitute(RationalField, bufferOf( + NumberedPolynomialAsIs( + listOf() to Rational(18, 1), + listOf(1u) to Rational(16, 3), + listOf(2u) to Rational(12, 6), + listOf(0u, 1u) to Rational(13, 1), + listOf(1u, 1u) to Rational(-11, 4), + listOf(2u, 1u) to Rational(-1, 1), + listOf(0u, 2u) to Rational(-10, 1), + listOf(1u, 2u) to Rational(4, 1), + listOf(2u, 2u) to Rational(2, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(8, 2), + listOf(1u) to Rational(-15, 5), + listOf(2u) to Rational(2, 7), + listOf(0u, 1u) to Rational(-18, 7), + listOf(1u, 1u) to Rational(-16, 6), + listOf(2u, 1u) to Rational(-13, 3), + listOf(0u, 2u) to Rational(-5, 1), + listOf(1u, 2u) to Rational(17, 1), + listOf(2u, 2u) to Rational(8, 2), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 1), + listOf(1u) to Rational(-9, 8), + listOf(2u) to Rational(17, 5), + listOf(0u, 1u) to Rational(-2, 3), + listOf(1u, 1u) to Rational(1, 5), + listOf(2u, 1u) to Rational(-11, 7), + listOf(0u, 2u) to Rational(13, 6), + listOf(1u, 2u) to Rational(-15, 2), + listOf(2u, 2u) to Rational(-14, 4), + ) + )), + "test 3" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(1202861, 210), + listOf(1u) to Rational(-215117, 45), + listOf(2u) to Rational(10889651, 19845), + listOf(3u) to Rational(-3503956, 6615), + listOf(4u) to Rational(809066, 2205), + listOf(5u) to Rational(-9056, 735), + listOf(6u) to Rational(5396, 315), + listOf(7u) to Rational(-752, 147), + listOf(8u) to Rational(16, 49), + listOf(0u, 1u) to Rational(1738469, 1470), + listOf(1u, 1u) to Rational(-926238703, 52920), + listOf(2u, 1u) to Rational(-44113982, 6615), + listOf(3u, 1u) to Rational(10423519, 5292), + listOf(4u, 1u) to Rational(3769712, 2205), + listOf(5u, 1u) to Rational(8905046, 6615), + listOf(6u, 1u) to Rational(1186972, 6615), + listOf(7u, 1u) to Rational(22124, 441), + listOf(8u, 1u) to Rational(-1504, 147), + listOf(0u, 2u) to Rational(-54723628, 2205), + listOf(1u, 2u) to Rational(70109407, 1323), + listOf(2u, 2u) to Rational(151072591, 17640), + listOf(3u, 2u) to Rational(1216428107, 52920), + listOf(4u, 2u) to Rational(2587873193, 317520), + listOf(5u, 2u) to Rational(393536369, 79380), + listOf(6u, 2u) to Rational(137614937, 79380), + listOf(7u, 2u) to Rational(566866, 1323), + listOf(8u, 2u) to Rational(41848, 441), + listOf(0u, 3u) to Rational(-19470406, 2205), + listOf(1u, 3u) to Rational(72514195, 882), + listOf(2u, 3u) to Rational(-78090707, 1764), + listOf(3u, 3u) to Rational(-1988237707, 26460), + listOf(4u, 3u) to Rational(-802137919, 17640), + listOf(5u, 3u) to Rational(-139989463, 5880), + listOf(6u, 3u) to Rational(-26066641, 3780), + listOf(7u, 3u) to Rational(-2363369, 1323), + listOf(8u, 3u) to Rational(-108280, 441), + listOf(0u, 4u) to Rational(14878516, 441), + listOf(1u, 4u) to Rational(-253416724, 2205), + listOf(2u, 4u) to Rational(16699157, 840), + listOf(3u, 4u) to Rational(-105220979, 13230), + listOf(4u, 4u) to Rational(208266383, 5880), + listOf(5u, 4u) to Rational(650135309, 26460), + listOf(6u, 4u) to Rational(123808663, 11760), + listOf(7u, 4u) to Rational(8563385, 2646), + listOf(8u, 4u) to Rational(19721, 49), + listOf(0u, 5u) to Rational(675645, 49), + listOf(1u, 5u) to Rational(-70554077, 588), + listOf(2u, 5u) to Rational(157884029, 980), + listOf(3u, 5u) to Rational(489548623, 4410), + listOf(4u, 5u) to Rational(148540519, 17640), + listOf(5u, 5u) to Rational(-5559551, 392), + listOf(6u, 5u) to Rational(-18335711, 1470), + listOf(7u, 5u) to Rational(-38437, 9), + listOf(8u, 5u) to Rational(-29620, 63), + listOf(0u, 6u) to Rational(-727625, 49), + listOf(1u, 6u) to Rational(7046685, 98), + listOf(2u, 6u) to Rational(-334814231, 7056), + listOf(3u, 6u) to Rational(-243971737, 17640), + listOf(4u, 6u) to Rational(-571116659, 35280), + listOf(5u, 6u) to Rational(567538, 315), + listOf(6u, 6u) to Rational(3199768, 315), + listOf(7u, 6u) to Rational(227744, 63), + listOf(8u, 6u) to Rational(23116, 63), + listOf(0u, 7u) to Rational(-27500, 7), + listOf(1u, 7u) to Rational(120125, 3), + listOf(2u, 7u) to Rational(-279200, 3), + listOf(3u, 7u) to Rational(-100160, 7), + listOf(4u, 7u) to Rational(920452, 21), + listOf(5u, 7u) to Rational(226481, 21), + listOf(6u, 7u) to Rational(-34428, 7), + listOf(7u, 7u) to Rational(-6232, 3), + listOf(8u, 7u) to Rational(-608, 3), + listOf(0u, 8u) to Rational(2500, 1), + listOf(1u, 8u) to Rational(-19000, 1), + listOf(2u, 8u) to Rational(37900, 1), + listOf(3u, 8u) to Rational(-1840, 1), + listOf(4u, 8u) to Rational(-17876, 1), + listOf(5u, 8u) to Rational(-1240, 1), + listOf(6u, 8u) to Rational(2788, 1), + listOf(7u, 8u) to Rational(800, 1), + listOf(8u, 8u) to Rational(64, 1) + ), + NumberedPolynomialAsIs( + listOf() to Rational(162487, 63), + listOf(1u) to Rational(-92713, 54), + listOf(2u) to Rational(802436, 1323), + listOf(3u) to Rational(-55088, 441), + listOf(4u) to Rational(1404034, 9261), + listOf(5u) to Rational(-5804, 1029), + listOf(6u) to Rational(51556, 9261), + listOf(7u) to Rational(-752, 441), + listOf(8u) to Rational(16, 147), + listOf(0u, 1u) to Rational(296071, 441), + listOf(1u, 1u) to Rational(-4991281, 882), + listOf(2u, 1u) to Rational(-18702811, 9261), + listOf(3u, 1u) to Rational(40759043, 27783), + listOf(4u, 1u) to Rational(19768501, 27783), + listOf(5u, 1u) to Rational(14307337, 27783), + listOf(6u, 1u) to Rational(1655684, 27783), + listOf(7u, 1u) to Rational(22124, 1323), + listOf(8u, 1u) to Rational(-1504, 441), + listOf(0u, 2u) to Rational(-27667474, 3087), + listOf(1u, 2u) to Rational(265605901, 12348), + listOf(2u, 2u) to Rational(160360775, 98784), + listOf(3u, 2u) to Rational(1169992093, 148176), + listOf(4u, 2u) to Rational(3978014077, 1333584), + listOf(5u, 2u) to Rational(567058123, 333396), + listOf(6u, 2u) to Rational(205132579, 333396), + listOf(7u, 2u) to Rational(566866, 3969), + listOf(8u, 2u) to Rational(41848, 1323), + listOf(0u, 3u) to Rational(-2228822, 1029), + listOf(1u, 3u) to Rational(80179390, 3087), + listOf(2u, 3u) to Rational(-1378630487, 74088), + listOf(3u, 3u) to Rational(-3385811693, 111132), + listOf(4u, 3u) to Rational(-820686977, 49392), + listOf(5u, 3u) to Rational(-89101027, 10584), + listOf(6u, 3u) to Rational(-37847387, 15876), + listOf(7u, 3u) to Rational(-2363369, 3969), + listOf(8u, 3u) to Rational(-108280, 1323), + listOf(0u, 4u) to Rational(12619982, 1029), + listOf(1u, 4u) to Rational(-277723177, 6174), + listOf(2u, 4u) to Rational(649414169, 49392), + listOf(3u, 4u) to Rational(14457595, 63504), + listOf(4u, 4u) to Rational(139270339, 10584), + listOf(5u, 4u) to Rational(140367961, 15876), + listOf(6u, 4u) to Rational(25467083, 7056), + listOf(7u, 4u) to Rational(8563385, 7938), + listOf(8u, 4u) to Rational(19721, 147), + listOf(0u, 5u) to Rational(643850, 147), + listOf(1u, 5u) to Rational(-11818025, 294), + listOf(2u, 5u) to Rational(33963203, 588), + listOf(3u, 5u) to Rational(207216235, 5292), + listOf(4u, 5u) to Rational(2861021, 1512), + listOf(5u, 5u) to Rational(-6302335, 1176), + listOf(6u, 5u) to Rational(-3738587, 882), + listOf(7u, 5u) to Rational(-38437, 27), + listOf(8u, 5u) to Rational(-29620, 189), + listOf(0u, 6u) to Rational(-248725, 49), + listOf(1u, 6u) to Rational(2478535, 98), + listOf(2u, 6u) to Rational(-399721367, 21168), + listOf(3u, 6u) to Rational(-54309317, 10584), + listOf(4u, 6u) to Rational(-95398327, 21168), + listOf(5u, 6u) to Rational(173750, 189), + listOf(6u, 6u) to Rational(92216, 27), + listOf(7u, 6u) to Rational(227744, 189), + listOf(8u, 6u) to Rational(23116, 189), + listOf(0u, 7u) to Rational(-27500, 21), + listOf(1u, 7u) to Rational(120125, 9), + listOf(2u, 7u) to Rational(-279200, 9), + listOf(3u, 7u) to Rational(-100160, 21), + listOf(4u, 7u) to Rational(920452, 63), + listOf(5u, 7u) to Rational(226481, 63), + listOf(6u, 7u) to Rational(-11476, 7), + listOf(7u, 7u) to Rational(-6232, 9), + listOf(8u, 7u) to Rational(-608, 9), + listOf(0u, 8u) to Rational(2500, 3), + listOf(1u, 8u) to Rational(-19000, 3), + listOf(2u, 8u) to Rational(37900, 3), + listOf(3u, 8u) to Rational(-1840, 3), + listOf(4u, 8u) to Rational(-17876, 3), + listOf(5u, 8u) to Rational(-1240, 3), + listOf(6u, 8u) to Rational(2788, 3), + listOf(7u, 8u) to Rational(800, 3), + listOf(8u, 8u) to Rational(64, 3) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(5, 6), + listOf(1u) to Rational(1, 6), + listOf(2u) to Rational(-2, 9), + listOf(0u, 1u) to Rational(15, 1), + listOf(1u, 1u) to Rational(18, 7), + listOf(2u, 1u) to Rational(2, 5), + listOf(0u, 2u) to Rational(12, 9), + listOf(1u, 2u) to Rational(-3, 5), + listOf(2u, 2u) to Rational(4, 4), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-11, 9), + listOf(1u) to Rational(4, 9), + listOf(2u) to Rational(11, 6), + listOf(0u, 1u) to Rational(-5, 6), + listOf(1u, 1u) to Rational(4, 6), + listOf(2u, 1u) to Rational(-1, 7), + listOf(0u, 2u) to Rational(9, 1), + listOf(1u, 2u) to Rational(6, 7), + listOf(2u, 2u) to Rational(1, 3), + ) + ).substitute(RationalField, bufferOf( + NumberedPolynomialAsIs( + listOf() to Rational(18, 1), + listOf(1u) to Rational(16, 3), + listOf(2u) to Rational(12, 6), + listOf(0u, 1u) to Rational(13, 1), + listOf(1u, 1u) to Rational(-11, 4), + listOf(2u, 1u) to Rational(-1, 1), + listOf(0u, 2u) to Rational(-10, 1), + listOf(1u, 2u) to Rational(4, 1), + listOf(2u, 2u) to Rational(2, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(8, 2), + listOf(1u) to Rational(-15, 5), + listOf(2u) to Rational(2, 7), + listOf(0u, 1u) to Rational(-18, 7), + listOf(1u, 1u) to Rational(-16, 6), + listOf(2u, 1u) to Rational(-13, 3), + listOf(0u, 2u) to Rational(-5, 1), + listOf(1u, 2u) to Rational(17, 1), + listOf(2u, 2u) to Rational(8, 2), + ), + )), + "test 4" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-409, 6), + listOf(1u) to Rational(-376, 9), + listOf(2u) to Rational(-1781, 81), + listOf(3u) to Rational(-128, 27), + listOf(4u) to Rational(-8, 9), + listOf(0u, 1u) to Rational(18701, 210), + listOf(1u, 1u) to Rational(614183, 7560), + listOf(2u, 1u) to Rational(90941, 1890), + listOf(3u, 1u) to Rational(1802, 135), + listOf(4u, 1u) to Rational(112, 45), + listOf(0u, 2u) to Rational(181421, 315), + listOf(1u, 2u) to Rational(77813, 378), + listOf(2u, 2u) to Rational(598583, 7560), + listOf(3u, 2u) to Rational(85, 27), + listOf(4u, 2u) to Rational(2, 5), + listOf(0u, 3u) to Rational(130997, 315), + listOf(1u, 3u) to Rational(1093, 420), + listOf(2u, 3u) to Rational(9551, 2520), + listOf(3u, 3u) to Rational(-14, 45), + listOf(4u, 3u) to Rational(22, 45), + listOf(0u, 4u) to Rational(-2801, 9), + listOf(1u, 4u) to Rational(4033, 90), + listOf(2u, 4u) to Rational(6429, 80), + listOf(3u, 4u) to Rational(2851, 90), + listOf(4u, 4u) to Rational(293, 45), + listOf(0u, 5u) to Rational(-220, 1), + listOf(1u, 5u) to Rational(127, 1), + listOf(2u, 5u) to Rational(202, 5), + listOf(3u, 5u) to Rational(-63, 5), + listOf(4u, 5u) to Rational(-12, 5), + listOf(0u, 6u) to Rational(100, 1), + listOf(1u, 6u) to Rational(-80, 1), + listOf(2u, 6u) to Rational(-24, 1), + listOf(3u, 6u) to Rational(16, 1), + listOf(4u, 6u) to Rational(4, 1) + ), + NumberedPolynomialAsIs( + listOf() to Rational(5407, 9), + listOf(1u) to Rational(9568, 27), + listOf(2u) to Rational(4996, 27), + listOf(3u) to Rational(352, 9), + listOf(4u) to Rational(22, 3), + listOf(0u, 1u) to Rational(104411, 126), + listOf(1u, 1u) to Rational(6001, 126), + listOf(2u, 1u) to Rational(-796, 21), + listOf(3u, 1u) to Rational(-5389, 126), + listOf(4u, 1u) to Rational(-166, 21), + listOf(0u, 2u) to Rational(-35327, 126), + listOf(1u, 2u) to Rational(53, 252), + listOf(2u, 2u) to Rational(849197, 6048), + listOf(3u, 2u) to Rational(22361, 252), + listOf(4u, 2u) to Rational(773, 42), + listOf(0u, 3u) to Rational(-6067, 21), + listOf(1u, 3u) to Rational(39049, 126), + listOf(2u, 3u) to Rational(80303, 1008), + listOf(3u, 3u) to Rational(-3035, 63), + listOf(4u, 3u) to Rational(-209, 21), + listOf(0u, 4u) to Rational(3113, 21), + listOf(1u, 4u) to Rational(-22345, 126), + listOf(2u, 4u) to Rational(-30931, 1008), + listOf(3u, 4u) to Rational(5837, 126), + listOf(4u, 4u) to Rational(229, 21), + listOf(0u, 5u) to Rational(-2120, 21), + listOf(1u, 5u) to Rational(451, 7), + listOf(2u, 5u) to Rational(422, 21), + listOf(3u, 5u) to Rational(-181, 21), + listOf(4u, 5u) to Rational(-40, 21), + listOf(0u, 6u) to Rational(100, 3), + listOf(1u, 6u) to Rational(-80, 3), + listOf(2u, 6u) to Rational(-8, 1), + listOf(3u, 6u) to Rational(16, 3), + listOf(4u, 6u) to Rational(4, 3) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(5, 6), + listOf(1u) to Rational(1, 6), + listOf(2u) to Rational(-2, 9), + listOf(0u, 1u) to Rational(15, 1), + listOf(1u, 1u) to Rational(18, 7), + listOf(2u, 1u) to Rational(2, 5), + listOf(0u, 2u) to Rational(12, 9), + listOf(1u, 2u) to Rational(-3, 5), + listOf(2u, 2u) to Rational(4, 4), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-11, 9), + listOf(1u) to Rational(4, 9), + listOf(2u) to Rational(11, 6), + listOf(0u, 1u) to Rational(-5, 6), + listOf(1u, 1u) to Rational(4, 6), + listOf(2u, 1u) to Rational(-1, 7), + listOf(0u, 2u) to Rational(9, 1), + listOf(1u, 2u) to Rational(6, 7), + listOf(2u, 2u) to Rational(1, 3), + ) + ).substitute(RationalField, bufferOf( + NumberedPolynomialAsIs( + listOf() to Rational(18, 1), + listOf(1u) to Rational(16, 3), + listOf(2u) to Rational(12, 6), + listOf(0u, 1u) to Rational(13, 1), + listOf(1u, 1u) to Rational(-11, 4), + listOf(2u, 1u) to Rational(-1, 1), + listOf(0u, 2u) to Rational(-10, 1), + listOf(1u, 2u) to Rational(4, 1), + listOf(2u, 2u) to Rational(2, 1), + ), + )), + "test 5" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(5, 6), + listOf(1u) to Rational(1, 6), + listOf(2u) to Rational(-2, 9), + listOf(0u, 1u) to Rational(15, 1), + listOf(1u, 1u) to Rational(18, 7), + listOf(2u, 1u) to Rational(2, 5), + listOf(0u, 2u) to Rational(12, 9), + listOf(1u, 2u) to Rational(-3, 5), + listOf(2u, 2u) to Rational(4, 4), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-11, 9), + listOf(1u) to Rational(4, 9), + listOf(2u) to Rational(11, 6), + listOf(0u, 1u) to Rational(-5, 6), + listOf(1u, 1u) to Rational(4, 6), + listOf(2u, 1u) to Rational(-1, 7), + listOf(0u, 2u) to Rational(9, 1), + listOf(1u, 2u) to Rational(6, 7), + listOf(2u, 2u) to Rational(1, 3), + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(5, 6), + listOf(1u) to Rational(1, 6), + listOf(2u) to Rational(-2, 9), + listOf(0u, 1u) to Rational(15, 1), + listOf(1u, 1u) to Rational(18, 7), + listOf(2u, 1u) to Rational(2, 5), + listOf(0u, 2u) to Rational(12, 9), + listOf(1u, 2u) to Rational(-3, 5), + listOf(2u, 2u) to Rational(4, 4), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-11, 9), + listOf(1u) to Rational(4, 9), + listOf(2u) to Rational(11, 6), + listOf(0u, 1u) to Rational(-5, 6), + listOf(1u, 1u) to Rational(4, 6), + listOf(2u, 1u) to Rational(-1, 7), + listOf(0u, 2u) to Rational(9, 1), + listOf(1u, 2u) to Rational(6, 7), + listOf(2u, 2u) to Rational(1, 3), + ) + ).substitute(RationalField, bufferOf>()), + "test 6" + ) } @Test @Ignore // FIXME: This tests work only for sane realisations of the substitutions. Currently, it is not. // Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should return denominator r^deg(p), // not r^(deg(p)(deg(p)+1)/2) as it is now. fun test_RationalFunction_substitute_RationalFunction_Buffer() { - // TODO + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(0) + ), + NumberedPolynomialAsIs( + listOf() to Rational(1) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1) + ), + NumberedPolynomialAsIs( + listOf() to Rational(1) + ), + ).substitute(RationalField, bufferOf( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(1) + ), + NumberedPolynomialAsIs( + listOf() to Rational(1) + ) + ) + )), + "test 1" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf(4u) to Rational(-17166109, 793800), + listOf(3u, 1u) to Rational(-930960143, 5556600), + listOf(2u, 2u) to Rational(-144665109691, 350065800), + listOf(1u, 3u) to Rational(-17232577, 52920), + listOf(0u, 4u) to Rational(-68141, 1323), + ), + NumberedPolynomialAsIs( + listOf(4u) to Rational(-57522533, 14288400), + listOf(3u, 1u) to Rational(-13085162953, 300056400), + listOf(2u, 2u) to Rational(-92093367341, 525098700), + listOf(1u, 3u) to Rational(-1979342797, 6667920), + listOf(0u, 4u) to Rational(-3082727, 21168), + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(10, 2), + listOf(1u) to Rational(6, 7), + listOf(2u) to Rational(-16, 1), + listOf(0u, 1u) to Rational(13, 8), + listOf(1u, 1u) to Rational(-12, 1), + listOf(2u, 1u) to Rational(16, 8), + listOf(0u, 2u) to Rational(10, 4), + listOf(1u, 2u) to Rational(4, 1), + listOf(2u, 2u) to Rational(-11, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1, 4), + listOf(1u) to Rational(-17, 4), + listOf(2u) to Rational(-14, 8), + listOf(0u, 1u) to Rational(17, 9), + listOf(1u, 1u) to Rational(1, 3), + listOf(2u, 1u) to Rational(7, 6), + listOf(0u, 2u) to Rational(16, 3), + listOf(1u, 2u) to Rational(-17, 1), + listOf(2u, 2u) to Rational(-10, 8), + ) + ).substitute(RationalField, bufferOf( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf(1u) to Rational(11, 5), + listOf(0u, 1u) to Rational(8, 4), + ), + NumberedPolynomialAsIs( + listOf(1u) to Rational(1, 9), + listOf(0u, 1u) to Rational(11, 7), + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf(1u) to Rational(-2, 7), + listOf(0u, 1u) to Rational(-4, 3), + ), + NumberedPolynomialAsIs( + listOf(1u) to Rational(3, 6), + listOf(0u, 1u) to Rational(12, 8), + ) + ), + )), + "test 2" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-130778291, 76800), + listOf(1u) to Rational(-445270919, 230400), + listOf(2u) to Rational(44578444937, 14515200), + listOf(3u) to Rational(17329402153, 1555200), + listOf(4u) to Rational(89239926809, 2332800), + listOf(5u) to Rational(2808812267, 145152), + listOf(6u) to Rational(-21362661007, 725760), + listOf(7u) to Rational(-258455443, 2016), + listOf(8u) to Rational(-21454693, 96), + listOf(0u, 1u) to Rational(-1002137, 15360), + listOf(1u, 1u) to Rational(-1704849697, 430080), + listOf(2u, 1u) to Rational(-57657676789, 4838400), + listOf(3u, 1u) to Rational(-101331731, 89600), + listOf(4u, 1u) to Rational(5362280079329, 130636800), + listOf(5u, 1u) to Rational(4069896167053, 130636800), + listOf(6u, 1u) to Rational(12011514569, 544320), + listOf(7u, 1u) to Rational(138293195623, 725760), + listOf(8u, 1u) to Rational(6228779419, 48384), + listOf(0u, 2u) to Rational(-32395872823, 8064000), + listOf(1u, 2u) to Rational(-7398505523, 2304000), + listOf(2u, 2u) to Rational(95217051699521, 3048192000), + listOf(3u, 2u) to Rational(198026968812079, 3657830400), + listOf(4u, 2u) to Rational(4291645618499, 228614400), + listOf(5u, 2u) to Rational(-33211690942439, 914457600), + listOf(6u, 2u) to Rational(-637385538163153, 1371686400), + listOf(7u, 2u) to Rational(-138671528276273, 182891520), + listOf(8u, 2u) to Rational(-14566368751, 217728), + listOf(0u, 3u) to Rational(-10538718719, 2016000), + listOf(1u, 3u) to Rational(-1844485375199, 84672000), + listOf(2u, 3u) to Rational(103968665891, 12096000), + listOf(3u, 3u) to Rational(175402107278351, 1828915200), + listOf(4u, 3u) to Rational(8020699588879, 114307200), + listOf(5u, 3u) to Rational(3414841894991, 38102400), + listOf(6u, 3u) to Rational(1848405591611, 4665600), + listOf(7u, 3u) to Rational(39486708738989, 137168640), + listOf(8u, 3u) to Rational(255926289517, 9144576), + listOf(0u, 4u) to Rational(-655379564629, 105840000), + listOf(1u, 4u) to Rational(-208336039441, 127008000), + listOf(2u, 4u) to Rational(40173146771411, 1143072000), + listOf(3u, 4u) to Rational(150473493581239, 2667168000), + listOf(4u, 4u) to Rational(38833783990483, 1143072000), + listOf(5u, 4u) to Rational(-1963676248203053, 4800902400), + listOf(6u, 4u) to Rational(-2598759412825747, 3200601600), + listOf(7u, 4u) to Rational(-192895352019667, 1280240640), + listOf(8u, 4u) to Rational(3737382679, 6858432), + listOf(0u, 5u) to Rational(-16959378721, 1890000), + listOf(1u, 5u) to Rational(-1864802244743, 79380000), + listOf(2u, 5u) to Rational(13449261536489, 666792000), + listOf(3u, 5u) to Rational(215272234137329, 2667168000), + listOf(4u, 5u) to Rational(6040691379277, 83349000), + listOf(5u, 5u) to Rational(153687143525887, 800150400), + listOf(6u, 5u) to Rational(475602854903563, 2400451200), + listOf(7u, 5u) to Rational(27315599358749, 640120320), + listOf(8u, 5u) to Rational(-2630413357, 10668672), + listOf(0u, 6u) to Rational(-6654999511, 2646000), + listOf(1u, 6u) to Rational(-67885252327, 15876000), + listOf(2u, 6u) to Rational(5786776220983, 2667168000), + listOf(3u, 6u) to Rational(60615922629083, 1143072000), + listOf(4u, 6u) to Rational(-34703539637627407, 672126336000), + listOf(5u, 6u) to Rational(-744694192134101, 2240421120), + listOf(6u, 6u) to Rational(-1782470617231, 14817600), + listOf(7u, 6u) to Rational(59123208433, 8890560), + listOf(8u, 6u) to Rational(-141653, 5292), + listOf(0u, 7u) to Rational(-338051969, 441000), + listOf(1u, 7u) to Rational(468850013, 1764000), + listOf(2u, 7u) to Rational(2102343426101, 222264000), + listOf(3u, 7u) to Rational(7836130602007, 1333584000), + listOf(4u, 7u) to Rational(16239111865997, 746807040), + listOf(5u, 7u) to Rational(3824649185383, 88905600), + listOf(6u, 7u) to Rational(56058614459, 3457440), + listOf(7u, 7u) to Rational(-396766339, 493920), + listOf(8u, 7u) to Rational(-165147, 2744), + listOf(0u, 8u) to Rational(-3088619, 58800), + listOf(1u, 8u) to Rational(155343347, 88200), + listOf(2u, 8u) to Rational(100098736469, 7408800), + listOf(3u, 8u) to Rational(109725511381, 7408800), + listOf(4u, 8u) to Rational(-2431199641013, 59270400), + listOf(5u, 8u) to Rational(-102872383249, 3457440), + listOf(6u, 8u) to Rational(1449461309, 576240), + listOf(7u, 8u) to Rational(812775, 1372), + listOf(8u, 8u) to Rational(-16461, 343) + ), + NumberedPolynomialAsIs( + listOf() to Rational(164202773, 230400), + listOf(1u) to Rational(-70345303, 518400), + listOf(2u) to Rational(-4229702731, 4665600), + listOf(3u) to Rational(3262171027, 6998400), + listOf(4u) to Rational(-25423104169, 13996800), + listOf(5u) to Rational(64061869, 349920), + listOf(6u) to Rational(-1655878091, 116640), + listOf(7u) to Rational(-7991441, 648), + listOf(8u) to Rational(-502591, 18), + listOf(0u, 1u) to Rational(-8780429, 3840), + listOf(1u, 1u) to Rational(434272361, 115200), + listOf(2u, 1u) to Rational(429825727, 41472), + listOf(3u, 1u) to Rational(-10066790339, 6998400), + listOf(4u, 1u) to Rational(70022035471, 20995200), + listOf(5u, 1u) to Rational(-32070283493, 1399680), + listOf(6u, 1u) to Rational(-22051101001, 1399680), + listOf(7u, 1u) to Rational(-126493427, 12960), + listOf(8u, 1u) to Rational(3050245, 864), + listOf(0u, 2u) to Rational(-1194654631, 345600), + listOf(1u, 2u) to Rational(-542961452671, 31104000), + listOf(2u, 2u) to Rational(-234000873607, 48988800), + listOf(3u, 2u) to Rational(140520538087, 3628800), + listOf(4u, 2u) to Rational(9215088876563, 130636800), + listOf(5u, 2u) to Rational(27590569647253, 293932800), + listOf(6u, 2u) to Rational(5129057792891, 97977600), + listOf(7u, 2u) to Rational(-106334191, 5103), + listOf(8u, 2u) to Rational(-1024113911, 435456), + listOf(0u, 3u) to Rational(76223843, 6000), + listOf(1u, 3u) to Rational(57425857357, 2592000), + listOf(2u, 3u) to Rational(-2044736497573, 46656000), + listOf(3u, 3u) to Rational(-26155810120031, 293932800), + listOf(4u, 3u) to Rational(-1064419459813, 6998400), + listOf(5u, 3u) to Rational(-753782018389, 4082400), + listOf(6u, 3u) to Rational(-291973360873, 2799360), + listOf(7u, 3u) to Rational(-46372122599, 816480), + listOf(8u, 3u) to Rational(3579859657, 653184), + listOf(0u, 4u) to Rational(-13374241901, 4320000), + listOf(1u, 4u) to Rational(306606499811, 54432000), + listOf(2u, 4u) to Rational(964267124745437, 13716864000), + listOf(3u, 4u) to Rational(21603809415373, 182891520), + listOf(4u, 4u) to Rational(1097860214654027, 6858432000), + listOf(5u, 4u) to Rational(161615254570669, 914457600), + listOf(6u, 4u) to Rational(758415239461, 22861440), + listOf(7u, 4u) to Rational(2585568355471, 274337280), + listOf(8u, 4u) to Rational(-70433747863, 9144576), + listOf(0u, 5u) to Rational(-9582586217, 2520000), + listOf(1u, 5u) to Rational(-19093471394171, 635040000), + listOf(2u, 5u) to Rational(-13010261944411, 381024000), + listOf(3u, 5u) to Rational(-259039825301861, 4572288000), + listOf(4u, 5u) to Rational(-305081119071079, 2286144000), + listOf(5u, 5u) to Rational(-1923114383311, 19595520), + listOf(6u, 5u) to Rational(-14181787253231, 228614400), + listOf(7u, 5u) to Rational(-3959584789, 4354560), + listOf(8u, 5u) to Rational(4691742523, 762048), + listOf(0u, 6u) to Rational(-588323437, 180000), + listOf(1u, 6u) to Rational(5952234691, 52920000), + listOf(2u, 6u) to Rational(21001851056959, 1088640000), + listOf(3u, 6u) to Rational(84668034357563, 2133734400), + listOf(4u, 6u) to Rational(2029754605811557, 25604812800), + listOf(5u, 6u) to Rational(11721216739823, 426746880), + listOf(6u, 6u) to Rational(-8275903187003, 2133734400), + listOf(7u, 6u) to Rational(-4730447299, 2540160), + listOf(8u, 6u) to Rational(-46069985, 21168), + listOf(0u, 7u) to Rational(-75711301, 117600), + listOf(1u, 7u) to Rational(32430417413, 7056000), + listOf(2u, 7u) to Rational(677988533153, 98784000), + listOf(3u, 7u) to Rational(-948417645827, 71124480), + listOf(4u, 7u) to Rational(-11320265215207, 711244800), + listOf(5u, 7u) to Rational(-676438627783, 50803200), + listOf(6u, 7u) to Rational(-7382274253, 1975680), + listOf(7u, 7u) to Rational(6505733, 2205), + listOf(8u, 7u) to Rational(450137, 882), + listOf(0u, 8u) to Rational(-8368253, 78400), + listOf(1u, 8u) to Rational(6833783, 117600), + listOf(2u, 8u) to Rational(4528971133, 5927040), + listOf(3u, 8u) to Rational(146252636617, 29635200), + listOf(4u, 8u) to Rational(8321882556889, 1659571200), + listOf(5u, 8u) to Rational(-4686033011, 1975680), + listOf(6u, 8u) to Rational(-1074445963, 987840), + listOf(7u, 8u) to Rational(-142313, 588), + listOf(8u, 8u) to Rational(-4281, 49) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(10, 2), + listOf(1u) to Rational(6, 7), + listOf(2u) to Rational(-16, 1), + listOf(0u, 1u) to Rational(13, 8), + listOf(1u, 1u) to Rational(-12, 1), + listOf(2u, 1u) to Rational(16, 8), + listOf(0u, 2u) to Rational(10, 4), + listOf(1u, 2u) to Rational(4, 1), + listOf(2u, 2u) to Rational(-11, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1, 4), + listOf(1u) to Rational(-17, 4), + listOf(2u) to Rational(-14, 8), + listOf(0u, 1u) to Rational(17, 9), + listOf(1u, 1u) to Rational(1, 3), + listOf(2u, 1u) to Rational(7, 6), + listOf(0u, 2u) to Rational(16, 3), + listOf(1u, 2u) to Rational(-17, 1), + listOf(2u, 2u) to Rational(-10, 8), + ) + ).substitute(RationalField, bufferOf( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-17, 5), + listOf(1u) to Rational(2, 6), + listOf(2u) to Rational(14, 1), + listOf(0u, 1u) to Rational(-6, 6), + listOf(1u, 1u) to Rational(-7, 3), + listOf(2u, 1u) to Rational(-2, 9), + listOf(0u, 2u) to Rational(-9, 6), + listOf(1u, 2u) to Rational(17, 4), + listOf(2u, 2u) to Rational(2, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(5, 4), + listOf(1u) to Rational(-5, 9), + listOf(2u) to Rational(-3, 6), + listOf(0u, 1u) to Rational(6, 5), + listOf(1u, 1u) to Rational(14, 5), + listOf(2u, 1u) to Rational(5, 2), + listOf(0u, 2u) to Rational(-18, 7), + listOf(1u, 2u) to Rational(-8, 2), + listOf(2u, 2u) to Rational(18, 9), + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(14, 4), + listOf(1u) to Rational(7, 6), + listOf(2u) to Rational(7, 2), + listOf(0u, 1u) to Rational(-15, 2), + listOf(1u, 1u) to Rational(-13, 8), + listOf(2u, 1u) to Rational(-14, 3), + listOf(0u, 2u) to Rational(-7, 6), + listOf(1u, 2u) to Rational(7, 4), + listOf(2u, 2u) to Rational(9, 7), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-7, 4), + listOf(1u) to Rational(-6, 3), + listOf(2u) to Rational(-16, 2), + listOf(0u, 1u) to Rational(-15, 5), + listOf(1u, 1u) to Rational(4, 6), + listOf(2u, 1u) to Rational(5, 4), + listOf(0u, 2u) to Rational(-12, 5), + listOf(1u, 2u) to Rational(-18, 2), + listOf(2u, 2u) to Rational(6, 7), + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(5, 8), + listOf(1u) to Rational(-12, 6), + listOf(2u) to Rational(7, 6), + listOf(0u, 1u) to Rational(-10, 4), + listOf(1u, 1u) to Rational(-7, 6), + listOf(2u, 1u) to Rational(8, 9), + listOf(0u, 2u) to Rational(16, 3), + listOf(1u, 2u) to Rational(-13, 4), + listOf(2u, 2u) to Rational(5, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(10, 6), + listOf(1u) to Rational(-18, 6), + listOf(2u) to Rational(5, 1), + listOf(0u, 1u) to Rational(17, 7), + listOf(1u, 1u) to Rational(8, 4), + listOf(2u, 1u) to Rational(-4, 9), + listOf(0u, 2u) to Rational(-6, 5), + listOf(1u, 2u) to Rational(-15, 8), + listOf(2u, 2u) to Rational(-18, 5), + ) + ), + )), + "test 3" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-130778291, 76800), + listOf(1u) to Rational(-445270919, 230400), + listOf(2u) to Rational(44578444937, 14515200), + listOf(3u) to Rational(17329402153, 1555200), + listOf(4u) to Rational(89239926809, 2332800), + listOf(5u) to Rational(2808812267, 145152), + listOf(6u) to Rational(-21362661007, 725760), + listOf(7u) to Rational(-258455443, 2016), + listOf(8u) to Rational(-21454693, 96), + listOf(0u, 1u) to Rational(-1002137, 15360), + listOf(1u, 1u) to Rational(-1704849697, 430080), + listOf(2u, 1u) to Rational(-57657676789, 4838400), + listOf(3u, 1u) to Rational(-101331731, 89600), + listOf(4u, 1u) to Rational(5362280079329, 130636800), + listOf(5u, 1u) to Rational(4069896167053, 130636800), + listOf(6u, 1u) to Rational(12011514569, 544320), + listOf(7u, 1u) to Rational(138293195623, 725760), + listOf(8u, 1u) to Rational(6228779419, 48384), + listOf(0u, 2u) to Rational(-32395872823, 8064000), + listOf(1u, 2u) to Rational(-7398505523, 2304000), + listOf(2u, 2u) to Rational(95217051699521, 3048192000), + listOf(3u, 2u) to Rational(198026968812079, 3657830400), + listOf(4u, 2u) to Rational(4291645618499, 228614400), + listOf(5u, 2u) to Rational(-33211690942439, 914457600), + listOf(6u, 2u) to Rational(-637385538163153, 1371686400), + listOf(7u, 2u) to Rational(-138671528276273, 182891520), + listOf(8u, 2u) to Rational(-14566368751, 217728), + listOf(0u, 3u) to Rational(-10538718719, 2016000), + listOf(1u, 3u) to Rational(-1844485375199, 84672000), + listOf(2u, 3u) to Rational(103968665891, 12096000), + listOf(3u, 3u) to Rational(175402107278351, 1828915200), + listOf(4u, 3u) to Rational(8020699588879, 114307200), + listOf(5u, 3u) to Rational(3414841894991, 38102400), + listOf(6u, 3u) to Rational(1848405591611, 4665600), + listOf(7u, 3u) to Rational(39486708738989, 137168640), + listOf(8u, 3u) to Rational(255926289517, 9144576), + listOf(0u, 4u) to Rational(-655379564629, 105840000), + listOf(1u, 4u) to Rational(-208336039441, 127008000), + listOf(2u, 4u) to Rational(40173146771411, 1143072000), + listOf(3u, 4u) to Rational(150473493581239, 2667168000), + listOf(4u, 4u) to Rational(38833783990483, 1143072000), + listOf(5u, 4u) to Rational(-1963676248203053, 4800902400), + listOf(6u, 4u) to Rational(-2598759412825747, 3200601600), + listOf(7u, 4u) to Rational(-192895352019667, 1280240640), + listOf(8u, 4u) to Rational(3737382679, 6858432), + listOf(0u, 5u) to Rational(-16959378721, 1890000), + listOf(1u, 5u) to Rational(-1864802244743, 79380000), + listOf(2u, 5u) to Rational(13449261536489, 666792000), + listOf(3u, 5u) to Rational(215272234137329, 2667168000), + listOf(4u, 5u) to Rational(6040691379277, 83349000), + listOf(5u, 5u) to Rational(153687143525887, 800150400), + listOf(6u, 5u) to Rational(475602854903563, 2400451200), + listOf(7u, 5u) to Rational(27315599358749, 640120320), + listOf(8u, 5u) to Rational(-2630413357, 10668672), + listOf(0u, 6u) to Rational(-6654999511, 2646000), + listOf(1u, 6u) to Rational(-67885252327, 15876000), + listOf(2u, 6u) to Rational(5786776220983, 2667168000), + listOf(3u, 6u) to Rational(60615922629083, 1143072000), + listOf(4u, 6u) to Rational(-34703539637627407, 672126336000), + listOf(5u, 6u) to Rational(-744694192134101, 2240421120), + listOf(6u, 6u) to Rational(-1782470617231, 14817600), + listOf(7u, 6u) to Rational(59123208433, 8890560), + listOf(8u, 6u) to Rational(-141653, 5292), + listOf(0u, 7u) to Rational(-338051969, 441000), + listOf(1u, 7u) to Rational(468850013, 1764000), + listOf(2u, 7u) to Rational(2102343426101, 222264000), + listOf(3u, 7u) to Rational(7836130602007, 1333584000), + listOf(4u, 7u) to Rational(16239111865997, 746807040), + listOf(5u, 7u) to Rational(3824649185383, 88905600), + listOf(6u, 7u) to Rational(56058614459, 3457440), + listOf(7u, 7u) to Rational(-396766339, 493920), + listOf(8u, 7u) to Rational(-165147, 2744), + listOf(0u, 8u) to Rational(-3088619, 58800), + listOf(1u, 8u) to Rational(155343347, 88200), + listOf(2u, 8u) to Rational(100098736469, 7408800), + listOf(3u, 8u) to Rational(109725511381, 7408800), + listOf(4u, 8u) to Rational(-2431199641013, 59270400), + listOf(5u, 8u) to Rational(-102872383249, 3457440), + listOf(6u, 8u) to Rational(1449461309, 576240), + listOf(7u, 8u) to Rational(812775, 1372), + listOf(8u, 8u) to Rational(-16461, 343) + ), + NumberedPolynomialAsIs( + listOf() to Rational(164202773, 230400), + listOf(1u) to Rational(-70345303, 518400), + listOf(2u) to Rational(-4229702731, 4665600), + listOf(3u) to Rational(3262171027, 6998400), + listOf(4u) to Rational(-25423104169, 13996800), + listOf(5u) to Rational(64061869, 349920), + listOf(6u) to Rational(-1655878091, 116640), + listOf(7u) to Rational(-7991441, 648), + listOf(8u) to Rational(-502591, 18), + listOf(0u, 1u) to Rational(-8780429, 3840), + listOf(1u, 1u) to Rational(434272361, 115200), + listOf(2u, 1u) to Rational(429825727, 41472), + listOf(3u, 1u) to Rational(-10066790339, 6998400), + listOf(4u, 1u) to Rational(70022035471, 20995200), + listOf(5u, 1u) to Rational(-32070283493, 1399680), + listOf(6u, 1u) to Rational(-22051101001, 1399680), + listOf(7u, 1u) to Rational(-126493427, 12960), + listOf(8u, 1u) to Rational(3050245, 864), + listOf(0u, 2u) to Rational(-1194654631, 345600), + listOf(1u, 2u) to Rational(-542961452671, 31104000), + listOf(2u, 2u) to Rational(-234000873607, 48988800), + listOf(3u, 2u) to Rational(140520538087, 3628800), + listOf(4u, 2u) to Rational(9215088876563, 130636800), + listOf(5u, 2u) to Rational(27590569647253, 293932800), + listOf(6u, 2u) to Rational(5129057792891, 97977600), + listOf(7u, 2u) to Rational(-106334191, 5103), + listOf(8u, 2u) to Rational(-1024113911, 435456), + listOf(0u, 3u) to Rational(76223843, 6000), + listOf(1u, 3u) to Rational(57425857357, 2592000), + listOf(2u, 3u) to Rational(-2044736497573, 46656000), + listOf(3u, 3u) to Rational(-26155810120031, 293932800), + listOf(4u, 3u) to Rational(-1064419459813, 6998400), + listOf(5u, 3u) to Rational(-753782018389, 4082400), + listOf(6u, 3u) to Rational(-291973360873, 2799360), + listOf(7u, 3u) to Rational(-46372122599, 816480), + listOf(8u, 3u) to Rational(3579859657, 653184), + listOf(0u, 4u) to Rational(-13374241901, 4320000), + listOf(1u, 4u) to Rational(306606499811, 54432000), + listOf(2u, 4u) to Rational(964267124745437, 13716864000), + listOf(3u, 4u) to Rational(21603809415373, 182891520), + listOf(4u, 4u) to Rational(1097860214654027, 6858432000), + listOf(5u, 4u) to Rational(161615254570669, 914457600), + listOf(6u, 4u) to Rational(758415239461, 22861440), + listOf(7u, 4u) to Rational(2585568355471, 274337280), + listOf(8u, 4u) to Rational(-70433747863, 9144576), + listOf(0u, 5u) to Rational(-9582586217, 2520000), + listOf(1u, 5u) to Rational(-19093471394171, 635040000), + listOf(2u, 5u) to Rational(-13010261944411, 381024000), + listOf(3u, 5u) to Rational(-259039825301861, 4572288000), + listOf(4u, 5u) to Rational(-305081119071079, 2286144000), + listOf(5u, 5u) to Rational(-1923114383311, 19595520), + listOf(6u, 5u) to Rational(-14181787253231, 228614400), + listOf(7u, 5u) to Rational(-3959584789, 4354560), + listOf(8u, 5u) to Rational(4691742523, 762048), + listOf(0u, 6u) to Rational(-588323437, 180000), + listOf(1u, 6u) to Rational(5952234691, 52920000), + listOf(2u, 6u) to Rational(21001851056959, 1088640000), + listOf(3u, 6u) to Rational(84668034357563, 2133734400), + listOf(4u, 6u) to Rational(2029754605811557, 25604812800), + listOf(5u, 6u) to Rational(11721216739823, 426746880), + listOf(6u, 6u) to Rational(-8275903187003, 2133734400), + listOf(7u, 6u) to Rational(-4730447299, 2540160), + listOf(8u, 6u) to Rational(-46069985, 21168), + listOf(0u, 7u) to Rational(-75711301, 117600), + listOf(1u, 7u) to Rational(32430417413, 7056000), + listOf(2u, 7u) to Rational(677988533153, 98784000), + listOf(3u, 7u) to Rational(-948417645827, 71124480), + listOf(4u, 7u) to Rational(-11320265215207, 711244800), + listOf(5u, 7u) to Rational(-676438627783, 50803200), + listOf(6u, 7u) to Rational(-7382274253, 1975680), + listOf(7u, 7u) to Rational(6505733, 2205), + listOf(8u, 7u) to Rational(450137, 882), + listOf(0u, 8u) to Rational(-8368253, 78400), + listOf(1u, 8u) to Rational(6833783, 117600), + listOf(2u, 8u) to Rational(4528971133, 5927040), + listOf(3u, 8u) to Rational(146252636617, 29635200), + listOf(4u, 8u) to Rational(8321882556889, 1659571200), + listOf(5u, 8u) to Rational(-4686033011, 1975680), + listOf(6u, 8u) to Rational(-1074445963, 987840), + listOf(7u, 8u) to Rational(-142313, 588), + listOf(8u, 8u) to Rational(-4281, 49) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(10, 2), + listOf(1u) to Rational(6, 7), + listOf(2u) to Rational(-16, 1), + listOf(0u, 1u) to Rational(13, 8), + listOf(1u, 1u) to Rational(-12, 1), + listOf(2u, 1u) to Rational(16, 8), + listOf(0u, 2u) to Rational(10, 4), + listOf(1u, 2u) to Rational(4, 1), + listOf(2u, 2u) to Rational(-11, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1, 4), + listOf(1u) to Rational(-17, 4), + listOf(2u) to Rational(-14, 8), + listOf(0u, 1u) to Rational(17, 9), + listOf(1u, 1u) to Rational(1, 3), + listOf(2u, 1u) to Rational(7, 6), + listOf(0u, 2u) to Rational(16, 3), + listOf(1u, 2u) to Rational(-17, 1), + listOf(2u, 2u) to Rational(-10, 8), + ) + ).substitute(RationalField, bufferOf( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-17, 5), + listOf(1u) to Rational(2, 6), + listOf(2u) to Rational(14, 1), + listOf(0u, 1u) to Rational(-6, 6), + listOf(1u, 1u) to Rational(-7, 3), + listOf(2u, 1u) to Rational(-2, 9), + listOf(0u, 2u) to Rational(-9, 6), + listOf(1u, 2u) to Rational(17, 4), + listOf(2u, 2u) to Rational(2, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(5, 4), + listOf(1u) to Rational(-5, 9), + listOf(2u) to Rational(-3, 6), + listOf(0u, 1u) to Rational(6, 5), + listOf(1u, 1u) to Rational(14, 5), + listOf(2u, 1u) to Rational(5, 2), + listOf(0u, 2u) to Rational(-18, 7), + listOf(1u, 2u) to Rational(-8, 2), + listOf(2u, 2u) to Rational(18, 9), + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(14, 4), + listOf(1u) to Rational(7, 6), + listOf(2u) to Rational(7, 2), + listOf(0u, 1u) to Rational(-15, 2), + listOf(1u, 1u) to Rational(-13, 8), + listOf(2u, 1u) to Rational(-14, 3), + listOf(0u, 2u) to Rational(-7, 6), + listOf(1u, 2u) to Rational(7, 4), + listOf(2u, 2u) to Rational(9, 7), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-7, 4), + listOf(1u) to Rational(-6, 3), + listOf(2u) to Rational(-16, 2), + listOf(0u, 1u) to Rational(-15, 5), + listOf(1u, 1u) to Rational(4, 6), + listOf(2u, 1u) to Rational(5, 4), + listOf(0u, 2u) to Rational(-12, 5), + listOf(1u, 2u) to Rational(-18, 2), + listOf(2u, 2u) to Rational(6, 7), + ) + ), + )), + "test 4" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-506213, 2800), + listOf(1u) to Rational(9859, 315), + listOf(2u) to Rational(17384377, 11340), + listOf(3u) to Rational(-9662, 63), + listOf(4u) to Rational(-12563, 4), + listOf(0u, 1u) to Rational(-486293, 22400), + listOf(1u, 1u) to Rational(-6530947, 25200), + listOf(2u, 1u) to Rational(866125, 18144), + listOf(3u, 1u) to Rational(2948747, 2520), + listOf(4u, 1u) to Rational(1196611, 2016), + listOf(0u, 2u) to Rational(-20266021, 117600), + listOf(1u, 2u) to Rational(26656339, 44100), + listOf(2u, 2u) to Rational(19499183, 18144), + listOf(3u, 2u) to Rational(-19801849, 7560), + listOf(4u, 2u) to Rational(-2639635, 1296), + listOf(0u, 3u) to Rational(-5017697, 29400), + listOf(1u, 3u) to Rational(-606007, 1575), + listOf(2u, 3u) to Rational(127494487, 132300), + listOf(3u, 3u) to Rational(166567, 105), + listOf(4u, 3u) to Rational(486403, 18144), + listOf(0u, 4u) to Rational(-32182, 735), + listOf(1u, 4u) to Rational(2420671, 8820), + listOf(2u, 4u) to Rational(-12619193, 26460), + listOf(3u, 4u) to Rational(-6823067, 5670), + listOf(4u, 4u) to Rational(-2311693, 13608), + listOf(0u, 5u) to Rational(-13324, 245), + listOf(1u, 5u) to Rational(1966, 35), + listOf(2u, 5u) to Rational(1052719, 2520), + listOf(3u, 5u) to Rational(19153, 270), + listOf(4u, 5u) to Rational(701, 54), + listOf(0u, 6u) to Rational(4647, 196), + listOf(1u, 6u) to Rational(2197, 28), + listOf(2u, 6u) to Rational(-43853, 336), + listOf(3u, 6u) to Rational(-301, 3), + listOf(4u, 6u) to Rational(34, 3) + ), + NumberedPolynomialAsIs( + listOf() to Rational(-2843, 1600), + listOf(1u) to Rational(-1483, 240), + listOf(2u) to Rational(110623, 1296), + listOf(3u) to Rational(1265, 72), + listOf(4u) to Rational(-5011, 16), + listOf(0u, 1u) to Rational(47743, 1800), + listOf(1u, 1u) to Rational(619229, 32400), + listOf(2u, 1u) to Rational(-5978369, 58320), + listOf(3u, 1u) to Rational(-86081, 1620), + listOf(4u, 1u) to Rational(6325, 72), + listOf(0u, 2u) to Rational(110951, 3360), + listOf(1u, 2u) to Rational(-9550649, 302400), + listOf(2u, 2u) to Rational(6542933, 85050), + listOf(3u, 2u) to Rational(4708291, 38880), + listOf(4u, 2u) to Rational(-433327, 1296), + listOf(0u, 3u) to Rational(56143, 600), + listOf(1u, 3u) to Rational(94243, 720), + listOf(2u, 3u) to Rational(-46779139, 226800), + listOf(3u, 3u) to Rational(-6948253, 12960), + listOf(4u, 3u) to Rational(-260261, 486), + listOf(0u, 4u) to Rational(-3205317, 19600), + listOf(1u, 4u) to Rational(-201253, 1050), + listOf(2u, 4u) to Rational(332192677, 302400), + listOf(3u, 4u) to Rational(351511, 360), + listOf(4u, 4u) to Rational(-40547, 81), + listOf(0u, 5u) to Rational(-65421, 1960), + listOf(1u, 5u) to Rational(-10118, 35), + listOf(2u, 5u) to Rational(-4341709, 10080), + listOf(3u, 5u) to Rational(-91703, 360), + listOf(4u, 5u) to Rational(-85, 9), + listOf(0u, 6u) to Rational(-25965, 784), + listOf(1u, 6u) to Rational(3351, 16), + listOf(2u, 6u) to Rational(595159, 1344), + listOf(3u, 6u) to Rational(-1381, 12), + listOf(4u, 6u) to Rational(-155, 3) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(10, 2), + listOf(1u) to Rational(6, 7), + listOf(2u) to Rational(-16, 1), + listOf(0u, 1u) to Rational(13, 8), + listOf(1u, 1u) to Rational(-12, 1), + listOf(2u, 1u) to Rational(16, 8), + listOf(0u, 2u) to Rational(10, 4), + listOf(1u, 2u) to Rational(4, 1), + listOf(2u, 2u) to Rational(-11, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1, 4), + listOf(1u) to Rational(-17, 4), + listOf(2u) to Rational(-14, 8), + listOf(0u, 1u) to Rational(17, 9), + listOf(1u, 1u) to Rational(1, 3), + listOf(2u, 1u) to Rational(7, 6), + listOf(0u, 2u) to Rational(16, 3), + listOf(1u, 2u) to Rational(-17, 1), + listOf(2u, 2u) to Rational(-10, 8), + ) + ).substitute(RationalField, bufferOf( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-17, 5), + listOf(1u) to Rational(2, 6), + listOf(2u) to Rational(14, 1), + listOf(0u, 1u) to Rational(-6, 6), + listOf(1u, 1u) to Rational(-7, 3), + listOf(2u, 1u) to Rational(-2, 9), + listOf(0u, 2u) to Rational(-9, 6), + listOf(1u, 2u) to Rational(17, 4), + listOf(2u, 2u) to Rational(2, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(5, 4), + listOf(1u) to Rational(-5, 9), + listOf(2u) to Rational(-3, 6), + listOf(0u, 1u) to Rational(6, 5), + listOf(1u, 1u) to Rational(14, 5), + listOf(2u, 1u) to Rational(5, 2), + listOf(0u, 2u) to Rational(-18, 7), + listOf(1u, 2u) to Rational(-8, 2), + listOf(2u, 2u) to Rational(18, 9), + ) + ), + )), + "test 5" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(10, 2), + listOf(1u) to Rational(6, 7), + listOf(2u) to Rational(-16, 1), + listOf(0u, 1u) to Rational(13, 8), + listOf(1u, 1u) to Rational(-12, 1), + listOf(2u, 1u) to Rational(16, 8), + listOf(0u, 2u) to Rational(10, 4), + listOf(1u, 2u) to Rational(4, 1), + listOf(2u, 2u) to Rational(-11, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1, 4), + listOf(1u) to Rational(-17, 4), + listOf(2u) to Rational(-14, 8), + listOf(0u, 1u) to Rational(17, 9), + listOf(1u, 1u) to Rational(1, 3), + listOf(2u, 1u) to Rational(7, 6), + listOf(0u, 2u) to Rational(16, 3), + listOf(1u, 2u) to Rational(-17, 1), + listOf(2u, 2u) to Rational(-10, 8), + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(10, 2), + listOf(1u) to Rational(6, 7), + listOf(2u) to Rational(-16, 1), + listOf(0u, 1u) to Rational(13, 8), + listOf(1u, 1u) to Rational(-12, 1), + listOf(2u, 1u) to Rational(16, 8), + listOf(0u, 2u) to Rational(10, 4), + listOf(1u, 2u) to Rational(4, 1), + listOf(2u, 2u) to Rational(-11, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1, 4), + listOf(1u) to Rational(-17, 4), + listOf(2u) to Rational(-14, 8), + listOf(0u, 1u) to Rational(17, 9), + listOf(1u, 1u) to Rational(1, 3), + listOf(2u, 1u) to Rational(7, 6), + listOf(0u, 2u) to Rational(16, 3), + listOf(1u, 2u) to Rational(-17, 1), + listOf(2u, 2u) to Rational(-10, 8), + ) + ).substitute(RationalField, bufferOf>()), + "test 6" + ) } @Test - @Ignore fun test_Polynomial_substituteFully_Double_Buffer() { - // TODO + assertEquals( + 0.0, + NumberedPolynomialAsIs( + listOf() to 1.0, + listOf(1u) to -2.0, + listOf(2u) to 1.0, + ).substituteFully(bufferOf( + 1.0 + )), + 0.001, + "test 1" + ) + assertFailsWithTypeAndMessage( + fullSubstitutionExceptionMessage, + "test 2" + ) { + NumberedPolynomialAsIs( + listOf() to 0.8597048543814783, + listOf(1u) to 0.22997637465889875, + listOf(2u) to 0.32675302591924016, + listOf(0u, 1u) to 0.4561746111587508, + listOf(1u, 1u) to 0.5304946210170756, + listOf(2u, 1u) to 0.6244313712888998, + listOf(0u, 2u) to 0.2700930201481795, + listOf(1u, 2u) to -0.06962351375204712, + listOf(2u, 2u) to -0.015206988092131501, + ).substituteFully(bufferOf()) + } + assertFailsWithTypeAndMessage( + fullSubstitutionExceptionMessage, + "test 3" + ) { + NumberedPolynomialAsIs( + listOf() to 0.8597048543814783, + listOf(1u) to 0.22997637465889875, + listOf(2u) to 0.32675302591924016, + listOf(0u, 1u) to 0.4561746111587508, + listOf(1u, 1u) to 0.5304946210170756, + listOf(2u, 1u) to 0.6244313712888998, + listOf(0u, 2u) to 0.2700930201481795, + listOf(1u, 2u) to -0.06962351375204712, + listOf(2u, 2u) to -0.015206988092131501, + ).substituteFully(bufferOf( + 0.0, + )) + } + assertFailsWithTypeAndMessage( + fullSubstitutionExceptionMessage, + "test 4" + ) { + NumberedPolynomialAsIs( + listOf() to 0.8597048543814783, + listOf(1u) to 0.22997637465889875, + listOf(2u) to 0.32675302591924016, + listOf(0u, 1u) to 0.4561746111587508, + listOf(1u, 1u) to 0.5304946210170756, + listOf(2u, 1u) to 0.6244313712888998, + listOf(0u, 2u) to 0.2700930201481795, + listOf(1u, 2u) to -0.06962351375204712, + listOf(2u, 2u) to -0.015206988092131501, + ).substituteFully(bufferOf( + 0.4846192734143442, + )) + } + assertEquals( + 1.934530767358133, + NumberedPolynomialAsIs( + listOf() to 0.8597048543814783, + listOf(1u) to 0.22997637465889875, + listOf(2u) to 0.32675302591924016, + listOf(0u, 1u) to 0.4561746111587508, + listOf(1u, 1u) to 0.5304946210170756, + listOf(2u, 1u) to 0.6244313712888998, + listOf(0u, 2u) to 0.2700930201481795, + listOf(1u, 2u) to -0.06962351375204712, + listOf(2u, 2u) to -0.015206988092131501, + ).substituteFully(bufferOf( + 0.4846192734143442, + 0.8400458576651112, + )), + 0.001, + "test 5" + ) + assertEquals( + 1.934530767358133, + NumberedPolynomialAsIs( + listOf() to 0.8597048543814783, + listOf(1u) to 0.22997637465889875, + listOf(2u) to 0.32675302591924016, + listOf(0u, 1u) to 0.4561746111587508, + listOf(1u, 1u) to 0.5304946210170756, + listOf(2u, 1u) to 0.6244313712888998, + listOf(0u, 2u) to 0.2700930201481795, + listOf(1u, 2u) to -0.06962351375204712, + listOf(2u, 2u) to -0.015206988092131501, + ).substituteFully(bufferOf( + 0.4846192734143442, + 0.8400458576651112, + 0.9211194782050933 + )), + 0.001, + "test 6" + ) + assertEquals( + 1.934530767358133, + NumberedPolynomialAsIs( + listOf() to 0.8597048543814783, + listOf(1u) to 0.22997637465889875, + listOf(2u) to 0.32675302591924016, + listOf(0u, 1u) to 0.4561746111587508, + listOf(1u, 1u) to 0.5304946210170756, + listOf(2u, 1u) to 0.6244313712888998, + listOf(0u, 2u) to 0.2700930201481795, + listOf(1u, 2u) to -0.06962351375204712, + listOf(2u, 2u) to -0.015206988092131501, + ).substituteFully(bufferOf( + 0.4846192734143442, + 0.8400458576651112, + 0.9211194782050933, + 0.4752854632152105 + )), + 0.001, + "test 7" + ) } @Test - @Ignore fun test_Polynomial_substituteFully_Constant_Buffer() { - // TODO + assertEquals( + Rational(0), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1) + ).substituteFully(RationalField, bufferOf( + Rational(1) + )), + "test 1" + ) + assertFailsWithTypeAndMessage( + fullSubstitutionExceptionMessage, + "test 2" + ) { + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substituteFully(RationalField, bufferOf()) + } + assertFailsWithTypeAndMessage( + fullSubstitutionExceptionMessage, + "test 3" + ) { + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substituteFully( + RationalField, bufferOf( + Rational(-2, 5), + ) + ) + } + // https://www.wolframalpha.com/input?i=%28-3%2F2+%2B+8%2F6+x+%2B+14%2F6+x%5E2%29+%2B+%28-3%2F1+%2B+-19%2F2+x+%2B+9%2F4+x%5E2%29+y+%2B+%285%2F5+%2B+18%2F9+x+%2B+5%2F2+x%5E2%29+y%5E2+where+x+%3D+-2%2F5%2C+y+%3D+12%2F9 + assertEquals( + Rational(143, 150), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substituteFully(RationalField, bufferOf( + Rational(-2, 5), + Rational(12, 9), + )), + "test 4" + ) + assertEquals( + Rational(143, 150), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substituteFully(RationalField, bufferOf( + Rational(-2, 5), + Rational(12, 9), + Rational(57, 179), + )), + "test 5" + ) + // https://www.wolframalpha.com/input?i=%28%28-3%2F2+%2B+8%2F6+x+%2B+14%2F6+x%5E2%29+%2B+%28-3%2F1+%2B+-19%2F2+x+%2B+9%2F4+x%5E2%29+y+%2B+%285%2F5+%2B+18%2F9+x+%2B+5%2F2+x%5E2%29+y%5E2%29+p%5E8+where+x+%3D+q%2Fp%2C+y+%3D+x%5E3%2C+p+%3D+-2%2F5%2C+q+%3D+12%2F9 + assertEquals( + Rational(47639065216, 2562890625), + NumberedPolynomialAsIs( + listOf(8u) to Rational(-3, 2), + listOf(7u, 1u) to Rational(8, 6), + listOf(6u, 2u) to Rational(14, 6), + listOf(5u, 3u) to Rational(-3, 1), + listOf(4u, 4u) to Rational(-19, 2), + listOf(3u, 5u) to Rational(9, 4), + listOf(2u, 6u) to Rational(5, 5), + listOf(1u, 7u) to Rational(18, 9), + listOf(0u, 8u) to Rational(5, 2), + ).substituteFully(RationalField, bufferOf( + Rational(-2, 5), + Rational(12, 9), + )), + "test 6" + ) } @Test - @Ignore fun test_RationalFunction_substituteFully_Double_Buffer() { - // TODO + assertEquals( + 0.0, + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 1.0, + listOf(1u) to -2.0, + listOf(2u) to 1.0, + ), + NumberedPolynomialAsIs( + listOf() to 1.0, + ) + ).substituteFully(bufferOf( + 1.0 + )), + 0.001, + "test 1" + ) + assertFailsWithTypeAndMessage( + fullSubstitutionExceptionMessage, + "test 2" + ) { + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 6.593754860231304, + listOf(1u) to -7.853302571550634, + listOf(2u) to 1.2265042281530025, + listOf(0u, 1u) to 3.762648877294904, + listOf(1u, 1u) to -8.945144619305292, + listOf(2u, 1u) to -5.141384718042281, + listOf(0u, 2u) to 7.359794483988782, + listOf(1u, 2u) to -4.3526172680518815, + listOf(2u, 2u) to 0.907910924854372, + ), + NumberedPolynomialAsIs( + listOf() to 9.533292132172562, + listOf(1u) to -1.982814534018857, + listOf(2u) to -5.974248303415283, + listOf(0u, 1u) to 1.5876716499288879, + listOf(1u, 1u) to -7.535152566659664, + listOf(2u, 1u) to 0.7549300500153517, + listOf(0u, 2u) to -5.242030058021028, + listOf(1u, 2u) to -0.7265704289690582, + listOf(2u, 2u) to -7.139677818189821, + ) + ).substituteFully(bufferOf()) + } + assertFailsWithTypeAndMessage( + fullSubstitutionExceptionMessage, + "test 3" + ) { + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 6.593754860231304, + listOf(1u) to -7.853302571550634, + listOf(2u) to 1.2265042281530025, + listOf(0u, 1u) to 3.762648877294904, + listOf(1u, 1u) to -8.945144619305292, + listOf(2u, 1u) to -5.141384718042281, + listOf(0u, 2u) to 7.359794483988782, + listOf(1u, 2u) to -4.3526172680518815, + listOf(2u, 2u) to 0.907910924854372, + ), + NumberedPolynomialAsIs( + listOf() to 9.533292132172562, + listOf(1u) to -1.982814534018857, + listOf(2u) to -5.974248303415283, + listOf(0u, 1u) to 1.5876716499288879, + listOf(1u, 1u) to -7.535152566659664, + listOf(2u, 1u) to 0.7549300500153517, + listOf(0u, 2u) to -5.242030058021028, + listOf(1u, 2u) to -0.7265704289690582, + listOf(2u, 2u) to -7.139677818189821, + ) + ).substituteFully( + bufferOf( + -8.11707689492641, + ) + ) + } + assertEquals( + -0.012718636022899672, + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 6.593754860231304, + listOf(1u) to -7.853302571550634, + listOf(2u) to 1.2265042281530025, + listOf(0u, 1u) to 3.762648877294904, + listOf(1u, 1u) to -8.945144619305292, + listOf(2u, 1u) to -5.141384718042281, + listOf(0u, 2u) to 7.359794483988782, + listOf(1u, 2u) to -4.3526172680518815, + listOf(2u, 2u) to 0.907910924854372, + ), + NumberedPolynomialAsIs( + listOf() to 9.533292132172562, + listOf(1u) to -1.982814534018857, + listOf(2u) to -5.974248303415283, + listOf(0u, 1u) to 1.5876716499288879, + listOf(1u, 1u) to -7.535152566659664, + listOf(2u, 1u) to 0.7549300500153517, + listOf(0u, 2u) to -5.242030058021028, + listOf(1u, 2u) to -0.7265704289690582, + listOf(2u, 2u) to -7.139677818189821, + ) + ).substituteFully(bufferOf( + -8.11707689492641, + 0.795265651276015, + )), + 0.001, + "test 4" + ) + assertEquals( + -0.012718636022899672, + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 6.593754860231304, + listOf(1u) to -7.853302571550634, + listOf(2u) to 1.2265042281530025, + listOf(0u, 1u) to 3.762648877294904, + listOf(1u, 1u) to -8.945144619305292, + listOf(2u, 1u) to -5.141384718042281, + listOf(0u, 2u) to 7.359794483988782, + listOf(1u, 2u) to -4.3526172680518815, + listOf(2u, 2u) to 0.907910924854372, + ), + NumberedPolynomialAsIs( + listOf() to 9.533292132172562, + listOf(1u) to -1.982814534018857, + listOf(2u) to -5.974248303415283, + listOf(0u, 1u) to 1.5876716499288879, + listOf(1u, 1u) to -7.535152566659664, + listOf(2u, 1u) to 0.7549300500153517, + listOf(0u, 2u) to -5.242030058021028, + listOf(1u, 2u) to -0.7265704289690582, + listOf(2u, 2u) to -7.139677818189821, + ) + ).substituteFully(bufferOf( + -8.11707689492641, + 0.795265651276015, + 0.9211194782050933 + )), + 0.001, + "test 5" + ) } @Test - @Ignore fun test_RationalFunction_substituteFully_Constant_Buffer() { - // TODO + assertEquals( + Rational(0), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1) + ), + NumberedPolynomialAsIs( + listOf() to Rational(1) + ) + ).substituteFully(RationalField, bufferOf( + Rational(1) + )), + "test 1" + ) + assertEquals( + Rational(-1322820, 2204953), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 5), + listOf(1u) to Rational(-18, 4), + listOf(2u) to Rational(9, 8), + listOf(0u, 1u) to Rational(-11, 6), + listOf(1u, 1u) to Rational(-16, 3), + listOf(2u, 1u) to Rational(12, 2), + listOf(0u, 2u) to Rational(5, 3), + listOf(1u, 2u) to Rational(17, 8), + listOf(2u, 2u) to Rational(1, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(11, 1), + listOf(1u) to Rational(4, 1), + listOf(2u) to Rational(-18, 3), + listOf(0u, 1u) to Rational(12, 9), + listOf(1u, 1u) to Rational(14, 7), + listOf(2u, 1u) to Rational(-17, 5), + listOf(0u, 2u) to Rational(-4, 1), + listOf(1u, 2u) to Rational(-5, 5), + listOf(2u, 2u) to Rational(-7, 8), + ) + ).substituteFully(RationalField, bufferOf( + Rational(7, 5), + Rational(-13, 7), + Rational(-16, 4), + )), + "test 2" + ) + assertEquals( + Rational(-1322820, 2204953), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 5), + listOf(1u) to Rational(-18, 4), + listOf(2u) to Rational(9, 8), + listOf(0u, 1u) to Rational(-11, 6), + listOf(1u, 1u) to Rational(-16, 3), + listOf(2u, 1u) to Rational(12, 2), + listOf(0u, 2u) to Rational(5, 3), + listOf(1u, 2u) to Rational(17, 8), + listOf(2u, 2u) to Rational(1, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(11, 1), + listOf(1u) to Rational(4, 1), + listOf(2u) to Rational(-18, 3), + listOf(0u, 1u) to Rational(12, 9), + listOf(1u, 1u) to Rational(14, 7), + listOf(2u, 1u) to Rational(-17, 5), + listOf(0u, 2u) to Rational(-4, 1), + listOf(1u, 2u) to Rational(-5, 5), + listOf(2u, 2u) to Rational(-7, 8), + ) + ).substituteFully(RationalField, bufferOf( + Rational(7, 5), + Rational(-13, 7), + )), + "test 3" + ) + assertFailsWithTypeAndMessage( + fullSubstitutionExceptionMessage, + "test 4" + ) { + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 5), + listOf(1u) to Rational(-18, 4), + listOf(2u) to Rational(9, 8), + listOf(0u, 1u) to Rational(-11, 6), + listOf(1u, 1u) to Rational(-16, 3), + listOf(2u, 1u) to Rational(12, 2), + listOf(0u, 2u) to Rational(5, 3), + listOf(1u, 2u) to Rational(17, 8), + listOf(2u, 2u) to Rational(1, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(11, 1), + listOf(1u) to Rational(4, 1), + listOf(2u) to Rational(-18, 3), + listOf(0u, 1u) to Rational(12, 9), + listOf(1u, 1u) to Rational(14, 7), + listOf(2u, 1u) to Rational(-17, 5), + listOf(0u, 2u) to Rational(-4, 1), + listOf(1u, 2u) to Rational(-5, 5), + listOf(2u, 2u) to Rational(-7, 8), + ) + ).substituteFully( + RationalField, bufferOf( + Rational(7, 5), + ) + ) + } + assertFailsWithTypeAndMessage( + fullSubstitutionExceptionMessage, + "test 5" + ) { + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 5), + listOf(1u) to Rational(-18, 4), + listOf(2u) to Rational(9, 8), + listOf(0u, 1u) to Rational(-11, 6), + listOf(1u, 1u) to Rational(-16, 3), + listOf(2u, 1u) to Rational(12, 2), + listOf(0u, 2u) to Rational(5, 3), + listOf(1u, 2u) to Rational(17, 8), + listOf(2u, 2u) to Rational(1, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(11, 1), + listOf(1u) to Rational(4, 1), + listOf(2u) to Rational(-18, 3), + listOf(0u, 1u) to Rational(12, 9), + listOf(1u, 1u) to Rational(14, 7), + listOf(2u, 1u) to Rational(-17, 5), + listOf(0u, 2u) to Rational(-4, 1), + listOf(1u, 2u) to Rational(-5, 5), + listOf(2u, 2u) to Rational(-7, 8), + ) + ).substituteFully(RationalField, bufferOf()) + } } @Test @Ignore diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/assertion.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/assertion.kt index bf8675675..3ad482454 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/assertion.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/assertion.kt @@ -8,6 +8,7 @@ package space.kscience.kmath.test.misc import space.kscience.kmath.functions.NumberedPolynomial import space.kscience.kmath.functions.NumberedRationalFunction import kotlin.test.assertEquals +import kotlin.test.assertFailsWith fun assertContentEquals(expected: Map, actual: Map, absoluteTolerance: Double, message: String? = null) { @@ -45,4 +46,15 @@ fun assertEquals( absoluteTolerance, message ) -} \ No newline at end of file +} + +inline fun assertFailsWithTypeAndMessage( + expectedMessage: String? = null, + assertionMessage: String? = null, + block: () -> Unit +) = + assertEquals( + expectedMessage, + assertFailsWith(T::class, assertionMessage, block).message, + assertionMessage + ) \ No newline at end of file -- 2.34.1 From 39088ec36b3ab7635889fc5ca593f6684021bf54 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Mon, 4 Jul 2022 02:36:46 +0300 Subject: [PATCH 093/123] Replaced assertFailsWith with assertFailsWithTypeAndMessage. --- .../kmath/functions/ListPolynomialUtilTest.kt | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt index 9d4f4411b..685a2a506 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt @@ -8,16 +8,22 @@ package space.kscience.kmath.functions import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.test.misc.Rational import space.kscience.kmath.test.misc.RationalField +import space.kscience.kmath.test.misc.assertFailsWithTypeAndMessage import kotlin.test.Ignore import kotlin.test.Test import kotlin.test.assertEquals -import kotlin.test.assertFailsWith @OptIn(UnstableKMathAPI::class) class ListPolynomialUtilTest { @Test fun test_Polynomial_substitute_Double() { + assertEquals( + 0.0, + ListPolynomial(1.0, -2.0, 1.0).substitute(1.0), + 0.001, + "test 1" + ) assertEquals( 0.0, ListPolynomial(1.0, -2.0, 1.0).substitute(1.0), @@ -859,7 +865,10 @@ class ListPolynomialUtilTest { ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 1), "test 1" ) - assertFailsWith("test2") { + assertFailsWithTypeAndMessage( + "Order of derivative must be non-negative", + "test2" + ) { ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, -1) } assertEquals( @@ -928,7 +937,10 @@ class ListPolynomialUtilTest { ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 1), "test 1" ) - assertFailsWith("test2") { + assertFailsWithTypeAndMessage( + "Order of antiderivative must be non-negative", + "test2" + ) { ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, -1) } assertEquals( -- 2.34.1 From e89e4e19d35e61240e8cb7fb00d88c4e35087991 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Mon, 4 Jul 2022 03:54:28 +0300 Subject: [PATCH 094/123] Return suppresses. --- .../kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt | 2 ++ .../space/kscience/kmath/functions/LabeledRationalFunction.kt | 2 ++ .../kotlin/space/kscience/kmath/functions/ListPolynomial.kt | 2 ++ .../space/kscience/kmath/functions/ListRationalFunction.kt | 2 ++ .../kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt | 2 ++ .../space/kscience/kmath/functions/NumberedRationalFunction.kt | 2 ++ .../space/kscience/kmath/functions/labeledConstructors.kt | 2 +- .../space/kscience/kmath/functions/numberedConstructors.kt | 2 +- .../kotlin/space/kscience/kmath/test/misc/Rational.kt | 1 + 9 files changed, 15 insertions(+), 2 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt index f1859ac4b..6d9af631a 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt @@ -3,6 +3,8 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ +@file:Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress") + package space.kscience.kmath.functions import space.kscience.kmath.expressions.Symbol diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt index c34d1e46f..e4f2b6c37 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt @@ -3,6 +3,8 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ +@file:Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress") + package space.kscience.kmath.functions import space.kscience.kmath.expressions.Symbol diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt index 3f470d5e7..a83b3915a 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt @@ -3,6 +3,8 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ +@file:Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress") + package space.kscience.kmath.functions import space.kscience.kmath.operations.Ring diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt index 40c6745d9..b744afc51 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt @@ -3,6 +3,8 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ +@file:Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress") + package space.kscience.kmath.functions import space.kscience.kmath.operations.Ring diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt index 35d0c7448..ad421d7d3 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -3,6 +3,8 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ +@file:Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress") + package space.kscience.kmath.functions import space.kscience.kmath.operations.Ring diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt index 97dffebe1..0f3c1ced9 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt @@ -3,6 +3,8 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ +@file:Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress") + package space.kscience.kmath.functions import space.kscience.kmath.operations.Ring diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt index f3fa32334..7a8d961c0 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt @@ -3,7 +3,7 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -@file:Suppress("FunctionName") +@file:Suppress("FunctionName", "NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress") package space.kscience.kmath.functions diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt index d561e06ba..7f02ff1e3 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt @@ -3,7 +3,7 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -@file:Suppress("FunctionName") +@file:Suppress("FunctionName", "NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress") package space.kscience.kmath.functions 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 index 071701593..62b7dc3be 100644 --- 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 @@ -9,6 +9,7 @@ import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.Field import space.kscience.kmath.operations.NumbersAddOps +@Suppress("NAME_SHADOWING") class Rational { companion object { val ZERO: Rational = Rational(0L) -- 2.34.1 From e40977647ddf5637855fe9a3171d03895103ef02 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Mon, 4 Jul 2022 04:02:08 +0300 Subject: [PATCH 095/123] Added suppresses. --- .../kotlin/space/kscience/kmath/test/misc/IntModulo.kt | 2 ++ .../kotlin/space/kscience/kmath/test/misc/Rational.kt | 2 ++ 2 files changed, 4 insertions(+) diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt index b3bb4faf7..f6e8457bb 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt @@ -3,6 +3,8 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ +@file:Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress") + package space.kscience.kmath.test.misc import space.kscience.kmath.functions.ListPolynomial 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 index 62b7dc3be..731621658 100644 --- 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 @@ -3,6 +3,8 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ +@file:Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress") + package space.kscience.kmath.test.misc import space.kscience.kmath.misc.UnstableKMathAPI -- 2.34.1 From 45ed45bd137bb5e5f7547333ca72bf6b3d90b46d Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Tue, 5 Jul 2022 03:41:52 +0300 Subject: [PATCH 096/123] Finish tests generation for numbered utilities. Also: - Optimize a bit labeled and numbered differentiation. - Fixed bugs in numbered anti-differentiation. --- .../kscience/kmath/functions/labeledUtil.kt | 12 +- .../kscience/kmath/functions/numberedUtil.kt | 24 +- .../functions/NumberedPolynomialUtilTest.kt | 2816 ++++++++++++++++- 3 files changed, 2823 insertions(+), 29 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledUtil.kt index 4002eb25a..4e799cb43 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledUtil.kt @@ -148,7 +148,7 @@ public fun > LabeledPolynomial.derivativeWithRespectTo( variable: Symbol, ): LabeledPolynomial = algebra { LabeledPolynomial( - buildMap(coefficients.size) { + buildMap(coefficients.count { it.key.getOrElse(variable) { 0u } >= 1u }) { coefficients .forEach { (degs, c) -> if (variable !in degs) return@forEach @@ -179,7 +179,7 @@ public fun > LabeledPolynomial.nthDerivativeWithRespectTo( ): LabeledPolynomial = algebra { if (order == 0u) return this@nthDerivativeWithRespectTo LabeledPolynomial( - buildMap(coefficients.size) { + buildMap(coefficients.count { it.key.getOrElse(variable) { 0u } >= order }) { coefficients .forEach { (degs, c) -> if (degs.getOrElse(variable) { 0u } < order) return@forEach @@ -213,7 +213,13 @@ public fun > LabeledPolynomial.nthDerivativeWithRespectTo( val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u } if (filteredVariablesAndOrders.isEmpty()) return this@nthDerivativeWithRespectTo LabeledPolynomial( - buildMap(coefficients.size) { + buildMap( + coefficients.count { + variablesAndOrders.all { (variable, order) -> + it.key.getOrElse(variable) { 0u } >= order + } + } + ) { coefficients .forEach { (degs, c) -> if (filteredVariablesAndOrders.any { (variable, order) -> degs.getOrElse(variable) { 0u } < order }) return@forEach diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt index 9397c1956..9d88cd648 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt @@ -352,7 +352,7 @@ public fun > NumberedPolynomial.derivativeWithRespectTo( variable: Int, ): NumberedPolynomial = ring { NumberedPolynomial( - buildMap(coefficients.size) { + buildMap(coefficients.count { it.key.getOrElse(variable) { 0u } >= 1u }) { coefficients .forEach { (degs, c) -> if (degs.lastIndex < variable) return@forEach @@ -382,7 +382,7 @@ public fun > NumberedPolynomial.nthDerivativeWithRespectTo( ): NumberedPolynomial = ring { if (order == 0u) return this@nthDerivativeWithRespectTo NumberedPolynomial( - buildMap(coefficients.size) { + buildMap(coefficients.count { it.key.getOrElse(variable) { 0u } >= order }) { coefficients .forEach { (degs, c) -> if (degs.lastIndex < variable) return@forEach @@ -451,8 +451,8 @@ public fun > NumberedPolynomial.antiderivativeWithRespectTo( coefficients .forEach { (degs, c) -> put( - List(max(variable + 1, degs.size)) { if (it != variable) degs[it] else degs[it] + 1u }, - c / multiplyByDoubling(one, degs[variable]) + List(max(variable + 1, degs.size)) { degs.getOrElse(it) { 0u } + if (it != variable) 0u else 1u }, + c / multiplyByDoubling(one, degs.getOrElse(variable) { 0u } + 1u) ) } } @@ -474,9 +474,9 @@ public fun > NumberedPolynomial.nthAntiderivativeWithRespectT coefficients .forEach { (degs, c) -> put( - List(max(variable + 1, degs.size)) { if (it != variable) degs[it] else degs[it] + order }, - degs[variable].let { deg -> - (deg downTo deg - order + 1u) + List(max(variable + 1, degs.size)) { degs.getOrElse(it) { 0u } + if (it != variable) 0u else order }, + degs.getOrElse(variable) { 0u }.let { deg -> + (deg + 1u .. deg + order) .fold(c) { acc, ord -> acc / multiplyByDoubling(one, ord) } } ) @@ -501,11 +501,11 @@ public fun > NumberedPolynomial.nthAntiderivativeWithRespectT coefficients .forEach { (degs, c) -> put( - List(max(maxRespectedVariable + 1, degs.size)) { degs[it] + filteredVariablesAndOrders.getOrElse(it) { 0u } }, - filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> - degs[index].let { deg -> - (deg downTo deg - order + 1u) - .fold(acc1) { acc2, ord -> acc2 / multiplyByDoubling(one, ord) } + List(max(maxRespectedVariable + 1, degs.size)) { degs.getOrElse(it) { 0u } + filteredVariablesAndOrders.getOrElse(it) { 0u } }, + filteredVariablesAndOrders.entries.fold(c) { acc1, (variable, order) -> + degs.getOrElse(variable) { 0u }.let { deg -> + (deg + 1u .. deg + order) + .fold(acc1) { acc, ord -> acc / multiplyByDoubling(one, ord) } } } ) diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt index 9e49f1315..1b87d3fcf 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt @@ -5,6 +5,7 @@ package space.kscience.kmath.functions +import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.asBuffer import space.kscience.kmath.test.misc.Rational @@ -8832,7 +8833,7 @@ class NumberedPolynomialUtilTest { listOf(0u, 2u) to Rational(5, 5), listOf(1u, 2u) to Rational(18, 9), listOf(2u, 2u) to Rational(5, 2), - ).substituteFully(RationalField, bufferOf()) + ).substituteFully(RationalField, bufferOf()) } assertFailsWithTypeAndMessage( fullSubstitutionExceptionMessage, @@ -9200,37 +9201,2824 @@ class NumberedPolynomialUtilTest { listOf(1u, 2u) to Rational(-5, 5), listOf(2u, 2u) to Rational(-7, 8), ) - ).substituteFully(RationalField, bufferOf()) + ).substituteFully(RationalField, bufferOf()) } } @Test - @Ignore + @OptIn(UnstableKMathAPI::class) fun test_Polynomial_derivativeWithRespectTo_variable() { - // TODO + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(-2), + listOf(1u) to Rational(2), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).derivativeWithRespectTo(RationalField, 0), + "test 1" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(-2, 3), + listOf(1u) to Rational(1, 1), + listOf(2u) to Rational(-33, 8), + listOf(3u) to Rational(72, 1), + listOf(0u, 1u) to Rational(2, 3), + listOf(1u, 1u) to Rational(-22, 1), + listOf(2u, 1u) to Rational(-1, 1), + listOf(3u, 1u) to Rational(-36, 1), + listOf(0u, 2u) to Rational(-8, 5), + listOf(1u, 2u) to Rational(-1, 4), + listOf(2u, 2u) to Rational(12, 7), + listOf(3u, 2u) to Rational(-2, 1), + listOf(0u, 3u) to Rational(16, 8), + listOf(1u, 3u) to Rational(-4, 1), + listOf(2u, 3u) to Rational(9, 2), + listOf(3u, 3u) to Rational(20, 9), + listOf(0u, 4u) to Rational(-10, 1), + listOf(1u, 4u) to Rational(-14, 1), + listOf(2u, 4u) to Rational(3, 7), + listOf(3u, 4u) to Rational(20, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(-11, 8), + listOf(4u) to Rational(18, 1), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(-1, 3), + listOf(4u, 1u) to Rational(-18, 2), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(3, 7), + listOf(1u, 3u) to Rational(16, 8), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(-18, 8), + listOf(1u, 4u) to Rational(-10, 1), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).derivativeWithRespectTo(RationalField, 0), + "test 2a" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(-18, 3), + listOf(1u) to Rational(2, 3), + listOf(2u) to Rational(-11, 1), + listOf(3u) to Rational(-1, 3), + listOf(4u) to Rational(-18, 2), + listOf(0u, 1u) to Rational(-20, 3), + listOf(1u, 1u) to Rational(-16, 5), + listOf(2u, 1u) to Rational(-1, 4), + listOf(3u, 1u) to Rational(8, 7), + listOf(4u, 1u) to Rational(-1, 1), + listOf(0u, 2u) to Rational(9, 7), + listOf(1u, 2u) to Rational(6, 1), + listOf(2u, 2u) to Rational(-6, 1), + listOf(3u, 2u) to Rational(9, 2), + listOf(4u, 2u) to Rational(5, 3), + listOf(0u, 3u) to Rational(-9, 1), + listOf(1u, 3u) to Rational(-40, 1), + listOf(2u, 3u) to Rational(-28, 1), + listOf(3u, 3u) to Rational(4, 7), + listOf(4u, 3u) to Rational(20, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(-11, 8), + listOf(4u) to Rational(18, 1), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(-1, 3), + listOf(4u, 1u) to Rational(-18, 2), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(3, 7), + listOf(1u, 3u) to Rational(16, 8), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(-18, 8), + listOf(1u, 4u) to Rational(-10, 1), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).derivativeWithRespectTo(RationalField, 1), + "test 2b" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(0), + listOf(1u) to Rational(0), + listOf(2u) to Rational(0), + listOf(3u) to Rational(0), + listOf(0u, 1u) to Rational(0), + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(0), + listOf(3u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(-1, 4), + listOf(2u, 2u) to Rational(12, 7), + listOf(3u, 2u) to Rational(-2, 1), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(-4, 1), + listOf(2u, 3u) to Rational(9, 2), + listOf(3u, 3u) to Rational(20, 9), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(-14, 1), + listOf(2u, 4u) to Rational(3, 7), + listOf(3u, 4u) to Rational(20, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(0), + listOf(1u) to Rational(0), + listOf(2u) to Rational(0), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(0), + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(0), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).derivativeWithRespectTo(RationalField, 0), + "test 3a" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(0), + listOf(1u) to Rational(0), + listOf(2u) to Rational(0), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(0), + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(-1, 4), + listOf(3u, 1u) to Rational(8, 7), + listOf(4u, 1u) to Rational(-1, 1), + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(-6, 1), + listOf(3u, 2u) to Rational(9, 2), + listOf(4u, 2u) to Rational(5, 3), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(-28, 1), + listOf(3u, 3u) to Rational(4, 7), + listOf(4u, 3u) to Rational(20, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(0), + listOf(1u) to Rational(0), + listOf(2u) to Rational(0), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(0), + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(0), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).derivativeWithRespectTo(RationalField, 1), + "test 3b" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(-2, 3), + listOf(1u) to Rational(1, 1), + listOf(2u) to Rational(0), + listOf(3u) to Rational(0), + listOf(0u, 1u) to Rational(2, 3), + listOf(1u, 1u) to Rational(-22, 1), + listOf(2u, 1u) to Rational(0), + listOf(3u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(-8, 5), + listOf(1u, 2u) to Rational(-1, 4), + listOf(2u, 2u) to Rational(0), + listOf(3u, 2u) to Rational(0), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(0), + listOf(3u, 3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(0), + listOf(3u, 4u) to Rational(0), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(0), + listOf(4u, 2u) to Rational(0), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(0), + listOf(3u, 3u) to Rational(0), + listOf(4u, 3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(0), + listOf(3u, 4u) to Rational(0), + listOf(4u, 4u) to Rational(0), + ).derivativeWithRespectTo(RationalField, 0), + "test 4a" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(-18, 3), + listOf(1u) to Rational(2, 3), + listOf(2u) to Rational(-11, 1), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(-20, 3), + listOf(1u, 1u) to Rational(-16, 5), + listOf(2u, 1u) to Rational(-1, 4), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(0), + listOf(3u, 2u) to Rational(0), + listOf(4u, 2u) to Rational(0), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(0), + listOf(3u, 3u) to Rational(0), + listOf(4u, 3u) to Rational(0), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(0), + listOf(4u, 2u) to Rational(0), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(0), + listOf(3u, 3u) to Rational(0), + listOf(4u, 3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(0), + listOf(3u, 4u) to Rational(0), + listOf(4u, 4u) to Rational(0), + ).derivativeWithRespectTo(RationalField, 1), + "test 4b" + ) + assertEquals( + NumberedPolynomialAsIs(), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(-11, 8), + listOf(4u) to Rational(18, 1), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(-1, 3), + listOf(4u, 1u) to Rational(-18, 2), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(3, 7), + listOf(1u, 3u) to Rational(16, 8), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(-18, 8), + listOf(1u, 4u) to Rational(-10, 1), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).derivativeWithRespectTo(RationalField, 5), + "test 5" + ) } @Test - @Ignore + @OptIn(UnstableKMathAPI::class) fun test_Polynomial_nthDerivativeWithRespectTo_variable_order() { - // TODO + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(-2), + listOf(1u) to Rational(2), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, 0, 1u), + "test 1" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, 0, 0u), + "test 2" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(2), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, 0, 2u), + "test 3" + ) + assertEquals( + NumberedPolynomialAsIs(), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, 0, 3u), + "test 4" + ) + assertEquals( + NumberedPolynomialAsIs(), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, 0, 4u), + "test 5" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, 1, 0u), + "test 6" + ) + assertEquals( + NumberedPolynomialAsIs(), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, 1, 1u), + "test 7" + ) + assertEquals( + NumberedPolynomialAsIs(), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, 1, 2u), + "test 8" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(1, 1), + listOf(1u) to Rational(-33, 4), + listOf(2u) to Rational(216, 1), + listOf(0u, 1u) to Rational(-22, 1), + listOf(1u, 1u) to Rational(-2, 1), + listOf(2u, 1u) to Rational(-108, 1), + listOf(0u, 2u) to Rational(-1, 4), + listOf(1u, 2u) to Rational(24, 7), + listOf(2u, 2u) to Rational(-6, 1), + listOf(0u, 3u) to Rational(-4, 1), + listOf(1u, 3u) to Rational(9, 1), + listOf(2u, 3u) to Rational(20, 3), + listOf(0u, 4u) to Rational(-14, 1), + listOf(1u, 4u) to Rational(6, 7), + listOf(2u, 4u) to Rational(60, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(-11, 8), + listOf(4u) to Rational(18, 1), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(-1, 3), + listOf(4u, 1u) to Rational(-18, 2), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(3, 7), + listOf(1u, 3u) to Rational(16, 8), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(-18, 8), + listOf(1u, 4u) to Rational(-10, 1), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).nthDerivativeWithRespectTo(RationalField, 0, 2u), + "test 9a" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(-20, 3), + listOf(1u) to Rational(-16, 5), + listOf(2u) to Rational(-1, 4), + listOf(3u) to Rational(8, 7), + listOf(4u) to Rational(-1, 1), + listOf(0u, 1u) to Rational(18, 7), + listOf(1u, 1u) to Rational(12, 1), + listOf(2u, 1u) to Rational(-12, 1), + listOf(3u, 1u) to Rational(9, 1), + listOf(4u, 1u) to Rational(10, 3), + listOf(0u, 2u) to Rational(-27, 1), + listOf(1u, 2u) to Rational(-120, 1), + listOf(2u, 2u) to Rational(-84, 1), + listOf(3u, 2u) to Rational(12, 7), + listOf(4u, 2u) to Rational(60, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(-11, 8), + listOf(4u) to Rational(18, 1), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(-1, 3), + listOf(4u, 1u) to Rational(-18, 2), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(3, 7), + listOf(1u, 3u) to Rational(16, 8), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(-18, 8), + listOf(1u, 4u) to Rational(-10, 1), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).nthDerivativeWithRespectTo(RationalField, 1, 2u), + "test 9b" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(0), + listOf(1u) to Rational(0), + listOf(2u) to Rational(0), + listOf(0u, 1u) to Rational(0), + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(-1, 4), + listOf(1u, 2u) to Rational(24, 7), + listOf(2u, 2u) to Rational(-6, 1), + listOf(0u, 3u) to Rational(-4, 1), + listOf(1u, 3u) to Rational(9, 1), + listOf(2u, 3u) to Rational(20, 3), + listOf(0u, 4u) to Rational(-14, 1), + listOf(1u, 4u) to Rational(6, 7), + listOf(2u, 4u) to Rational(60, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(0), + listOf(1u) to Rational(0), + listOf(2u) to Rational(0), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(0), + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(0), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).nthDerivativeWithRespectTo(RationalField, 0, 2u), + "test 10a" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(0), + listOf(1u) to Rational(0), + listOf(2u) to Rational(-1, 4), + listOf(3u) to Rational(8, 7), + listOf(4u) to Rational(-1, 1), + listOf(0u, 1u) to Rational(0), + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(-12, 1), + listOf(3u, 1u) to Rational(9, 1), + listOf(4u, 1u) to Rational(10, 3), + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(-84, 1), + listOf(3u, 2u) to Rational(12, 7), + listOf(4u, 2u) to Rational(60, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(0), + listOf(1u) to Rational(0), + listOf(2u) to Rational(0), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(0), + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(0), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).nthDerivativeWithRespectTo(RationalField, 1, 2u), + "test 10b" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(1, 1), + listOf(1u) to Rational(0), + listOf(2u) to Rational(0), + listOf(0u, 1u) to Rational(-22, 1), + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(-1, 4), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(0), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(0), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(0), + listOf(4u, 2u) to Rational(0), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(0), + listOf(3u, 3u) to Rational(0), + listOf(4u, 3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(0), + listOf(3u, 4u) to Rational(0), + listOf(4u, 4u) to Rational(0), + ).nthDerivativeWithRespectTo(RationalField, 0, 2u), + "test 11a" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(-20, 3), + listOf(1u) to Rational(-16, 5), + listOf(2u) to Rational(-1, 4), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(0), + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(0), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(0), + listOf(3u, 2u) to Rational(0), + listOf(4u, 2u) to Rational(0), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(0), + listOf(4u, 2u) to Rational(0), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(0), + listOf(3u, 3u) to Rational(0), + listOf(4u, 3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(0), + listOf(3u, 4u) to Rational(0), + listOf(4u, 4u) to Rational(0), + ).nthDerivativeWithRespectTo(RationalField, 1, 2u), + "test 11b" + ) } @Test - @Ignore + @OptIn(UnstableKMathAPI::class) fun test_Polynomial_nthDerivativeWithRespectTo_variablesAndOrders() { - // TODO + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(-2), + listOf(1u) to Rational(2), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, mapOf(0 to 1u)), + "test 1" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, mapOf(0 to 0u)), + "test 2" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(2), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, mapOf(0 to 2u)), + "test 3" + ) + assertEquals( + NumberedPolynomialAsIs(), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, mapOf(0 to 3u)), + "test 4" + ) + assertEquals( + NumberedPolynomialAsIs(), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, mapOf(0 to 4u)), + "test 5" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, mapOf(1 to 0u)), + "test 6" + ) + assertEquals( + NumberedPolynomialAsIs(), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, mapOf(1 to 1u)), + "test 7" + ) + assertEquals( + NumberedPolynomialAsIs(), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, mapOf(1 to 2u)), + "test 8" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, mapOf()), + "test 9" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(-2), + listOf(1u) to Rational(2), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, mapOf( + 0 to 1u, + 1 to 0u + )), + "test 10" + ) + assertEquals( + NumberedPolynomialAsIs(), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, mapOf( + 0 to 0u, + 1 to 1u + )), + "test 11" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(1, 1), + listOf(1u) to Rational(-33, 4), + listOf(2u) to Rational(216, 1), + listOf(0u, 1u) to Rational(-22, 1), + listOf(1u, 1u) to Rational(-2, 1), + listOf(2u, 1u) to Rational(-108, 1), + listOf(0u, 2u) to Rational(-1, 4), + listOf(1u, 2u) to Rational(24, 7), + listOf(2u, 2u) to Rational(-6, 1), + listOf(0u, 3u) to Rational(-4, 1), + listOf(1u, 3u) to Rational(9, 1), + listOf(2u, 3u) to Rational(20, 3), + listOf(0u, 4u) to Rational(-14, 1), + listOf(1u, 4u) to Rational(6, 7), + listOf(2u, 4u) to Rational(60, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(-11, 8), + listOf(4u) to Rational(18, 1), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(-1, 3), + listOf(4u, 1u) to Rational(-18, 2), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(3, 7), + listOf(1u, 3u) to Rational(16, 8), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(-18, 8), + listOf(1u, 4u) to Rational(-10, 1), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).nthDerivativeWithRespectTo(RationalField, mapOf(0 to 2u)), + "test 12a" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(2, 3), + listOf(1u) to Rational(-22, 1), + listOf(2u) to Rational(-1, 1), + listOf(3u) to Rational(-36, 1), + listOf(0u, 1u) to Rational(-16, 5), + listOf(1u, 1u) to Rational(-1, 2), + listOf(2u, 1u) to Rational(24, 7), + listOf(3u, 1u) to Rational(-4, 1), + listOf(0u, 2u) to Rational(6, 1), + listOf(1u, 2u) to Rational(-12, 1), + listOf(2u, 2u) to Rational(27, 2), + listOf(3u, 2u) to Rational(20, 3), + listOf(0u, 3u) to Rational(-40, 1), + listOf(1u, 3u) to Rational(-56, 1), + listOf(2u, 3u) to Rational(12, 7), + listOf(3u, 3u) to Rational(80, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(-11, 8), + listOf(4u) to Rational(18, 1), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(-1, 3), + listOf(4u, 1u) to Rational(-18, 2), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(3, 7), + listOf(1u, 3u) to Rational(16, 8), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(-18, 8), + listOf(1u, 4u) to Rational(-10, 1), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).nthDerivativeWithRespectTo(RationalField, mapOf(0 to 1u, 1 to 1u)), + "test 12b" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(-20, 3), + listOf(1u) to Rational(-16, 5), + listOf(2u) to Rational(-1, 4), + listOf(3u) to Rational(8, 7), + listOf(4u) to Rational(-1, 1), + listOf(0u, 1u) to Rational(18, 7), + listOf(1u, 1u) to Rational(12, 1), + listOf(2u, 1u) to Rational(-12, 1), + listOf(3u, 1u) to Rational(9, 1), + listOf(4u, 1u) to Rational(10, 3), + listOf(0u, 2u) to Rational(-27, 1), + listOf(1u, 2u) to Rational(-120, 1), + listOf(2u, 2u) to Rational(-84, 1), + listOf(3u, 2u) to Rational(12, 7), + listOf(4u, 2u) to Rational(60, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(-11, 8), + listOf(4u) to Rational(18, 1), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(-1, 3), + listOf(4u, 1u) to Rational(-18, 2), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(3, 7), + listOf(1u, 3u) to Rational(16, 8), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(-18, 8), + listOf(1u, 4u) to Rational(-10, 1), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).nthDerivativeWithRespectTo(RationalField, mapOf(1 to 2u)), + "test 12c" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(0), + listOf(1u) to Rational(0), + listOf(2u) to Rational(0), + listOf(0u, 1u) to Rational(0), + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(-1, 4), + listOf(1u, 2u) to Rational(24, 7), + listOf(2u, 2u) to Rational(-6, 1), + listOf(0u, 3u) to Rational(-4, 1), + listOf(1u, 3u) to Rational(9, 1), + listOf(2u, 3u) to Rational(20, 3), + listOf(0u, 4u) to Rational(-14, 1), + listOf(1u, 4u) to Rational(6, 7), + listOf(2u, 4u) to Rational(60, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(0), + listOf(1u) to Rational(0), + listOf(2u) to Rational(0), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(0), + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(0), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).nthDerivativeWithRespectTo(RationalField, mapOf(0 to 2u)), + "test 13a" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(0), + listOf(1u) to Rational(0), + listOf(2u) to Rational(0), + listOf(3u) to Rational(0), + listOf(0u, 1u) to Rational(0), + listOf(1u, 1u) to Rational(-1, 2), + listOf(2u, 1u) to Rational(24, 7), + listOf(3u, 1u) to Rational(-4, 1), + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(-12, 1), + listOf(2u, 2u) to Rational(27, 2), + listOf(3u, 2u) to Rational(20, 3), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(-56, 1), + listOf(2u, 3u) to Rational(12, 7), + listOf(3u, 3u) to Rational(80, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(0), + listOf(1u) to Rational(0), + listOf(2u) to Rational(0), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(0), + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(0), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).nthDerivativeWithRespectTo(RationalField, mapOf(0 to 1u, 1 to 1u)), + "test 13b" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(0), + listOf(1u) to Rational(0), + listOf(2u) to Rational(-1, 4), + listOf(3u) to Rational(8, 7), + listOf(4u) to Rational(-1, 1), + listOf(0u, 1u) to Rational(0), + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(-12, 1), + listOf(3u, 1u) to Rational(9, 1), + listOf(4u, 1u) to Rational(10, 3), + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(-84, 1), + listOf(3u, 2u) to Rational(12, 7), + listOf(4u, 2u) to Rational(60, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(0), + listOf(1u) to Rational(0), + listOf(2u) to Rational(0), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(0), + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(0), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).nthDerivativeWithRespectTo(RationalField, mapOf(1 to 2u)), + "test 13c" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(1, 1), + listOf(1u) to Rational(0), + listOf(2u) to Rational(0), + listOf(0u, 1u) to Rational(-22, 1), + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(-1, 4), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(0), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(0), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(0), + listOf(4u, 2u) to Rational(0), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(0), + listOf(3u, 3u) to Rational(0), + listOf(4u, 3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(0), + listOf(3u, 4u) to Rational(0), + listOf(4u, 4u) to Rational(0), + ).nthDerivativeWithRespectTo(RationalField, mapOf(0 to 2u)), + "test 14a" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(2, 3), + listOf(1u) to Rational(-22, 1), + listOf(2u) to Rational(0), + listOf(3u) to Rational(0), + listOf(0u, 1u) to Rational(-16, 5), + listOf(1u, 1u) to Rational(-1, 2), + listOf(2u, 1u) to Rational(0), + listOf(3u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(0), + listOf(3u, 2u) to Rational(0), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(0), + listOf(3u, 3u) to Rational(0), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(0), + listOf(4u, 2u) to Rational(0), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(0), + listOf(3u, 3u) to Rational(0), + listOf(4u, 3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(0), + listOf(3u, 4u) to Rational(0), + listOf(4u, 4u) to Rational(0), + ).nthDerivativeWithRespectTo(RationalField, mapOf(0 to 1u, 1 to 1u)), + "test 14b" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(-20, 3), + listOf(1u) to Rational(-16, 5), + listOf(2u) to Rational(-1, 4), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(0), + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(0), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(0), + listOf(3u, 2u) to Rational(0), + listOf(4u, 2u) to Rational(0), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(0), + listOf(4u, 2u) to Rational(0), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(0), + listOf(3u, 3u) to Rational(0), + listOf(4u, 3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(0), + listOf(3u, 4u) to Rational(0), + listOf(4u, 4u) to Rational(0), + ).nthDerivativeWithRespectTo(RationalField, mapOf(1 to 2u)), + "test 14c" + ) } @Test - @Ignore + @OptIn(UnstableKMathAPI::class) fun test_Polynomial_antiderivativeWithRespectTo_variable() { - // TODO + assertEquals( + NumberedPolynomialAsIs( + listOf(1u) to Rational(1), + listOf(2u) to Rational(-1), + listOf(3u) to Rational(1, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).antiderivativeWithRespectTo(RationalField, 0), + "test 1" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(1u) to Rational(-6, 8), + listOf(2u) to Rational(-1, 3), + listOf(3u) to Rational(1, 6), + listOf(4u) to Rational(-11, 32), + listOf(5u) to Rational(18, 5), + listOf(1u, 1u) to Rational(-18, 3), + listOf(2u, 1u) to Rational(1, 3), + listOf(3u, 1u) to Rational(-11, 3), + listOf(4u, 1u) to Rational(-1, 12), + listOf(5u, 1u) to Rational(-18, 10), + listOf(1u, 2u) to Rational(-10, 3), + listOf(2u, 2u) to Rational(-4, 5), + listOf(3u, 2u) to Rational(-1, 24), + listOf(4u, 2u) to Rational(1, 7), + listOf(5u, 2u) to Rational(-1, 10), + listOf(1u, 3u) to Rational(3, 7), + listOf(2u, 3u) to Rational(1, 1), + listOf(3u, 3u) to Rational(-2, 3), + listOf(4u, 3u) to Rational(3, 8), + listOf(5u, 3u) to Rational(1, 9), + listOf(1u, 4u) to Rational(-18, 8), + listOf(2u, 4u) to Rational(-5, 1), + listOf(3u, 4u) to Rational(-7, 3), + listOf(4u, 4u) to Rational(1, 28), + listOf(5u, 4u) to Rational(1, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(-11, 8), + listOf(4u) to Rational(18, 1), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(-1, 3), + listOf(4u, 1u) to Rational(-18, 2), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(3, 7), + listOf(1u, 3u) to Rational(16, 8), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(-18, 8), + listOf(1u, 4u) to Rational(-10, 1), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).antiderivativeWithRespectTo(RationalField, 0), + "test 2a" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(0u, 1u) to Rational(-6, 8), + listOf(1u, 1u) to Rational(-2, 3), + listOf(2u, 1u) to Rational(1, 2), + listOf(3u, 1u) to Rational(-11, 8), + listOf(4u, 1u) to Rational(18, 1), + listOf(0u, 2u) to Rational(-9, 3), + listOf(1u, 2u) to Rational(1, 3), + listOf(2u, 2u) to Rational(-11, 2), + listOf(3u, 2u) to Rational(-1, 6), + listOf(4u, 2u) to Rational(-9, 2), + listOf(0u, 3u) to Rational(-10, 9), + listOf(1u, 3u) to Rational(-8, 15), + listOf(2u, 3u) to Rational(-1, 24), + listOf(3u, 3u) to Rational(4, 21), + listOf(4u, 3u) to Rational(-1, 6), + listOf(0u, 4u) to Rational(3, 28), + listOf(1u, 4u) to Rational(1, 2), + listOf(2u, 4u) to Rational(-1, 2), + listOf(3u, 4u) to Rational(3, 8), + listOf(4u, 4u) to Rational(5, 36), + listOf(0u, 5u) to Rational(-9, 20), + listOf(1u, 5u) to Rational(-2, 1), + listOf(2u, 5u) to Rational(-7, 5), + listOf(3u, 5u) to Rational(1, 35), + listOf(4u, 5u) to Rational(1, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(-11, 8), + listOf(4u) to Rational(18, 1), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(-1, 3), + listOf(4u, 1u) to Rational(-18, 2), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(3, 7), + listOf(1u, 3u) to Rational(16, 8), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(-18, 8), + listOf(1u, 4u) to Rational(-10, 1), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).antiderivativeWithRespectTo(RationalField, 1), + "test 2b" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(1u) to Rational(0), + listOf(2u) to Rational(0), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(5u) to Rational(0), + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(0), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(5u, 1u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(0), + listOf(3u, 2u) to Rational(-1, 24), + listOf(4u, 2u) to Rational(1, 7), + listOf(5u, 2u) to Rational(-1, 10), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(0), + listOf(3u, 3u) to Rational(-2, 3), + listOf(4u, 3u) to Rational(3, 8), + listOf(5u, 3u) to Rational(1, 9), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(0), + listOf(3u, 4u) to Rational(-7, 3), + listOf(4u, 4u) to Rational(1, 28), + listOf(5u, 4u) to Rational(1, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(0), + listOf(1u) to Rational(0), + listOf(2u) to Rational(0), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(0), + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(0), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).antiderivativeWithRespectTo(RationalField, 0), + "test 3a" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(0u, 1u) to Rational(0), + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(0), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(0), + listOf(3u, 2u) to Rational(0), + listOf(4u, 2u) to Rational(0), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(-1, 24), + listOf(3u, 3u) to Rational(4, 21), + listOf(4u, 3u) to Rational(-1, 6), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(-1, 2), + listOf(3u, 4u) to Rational(3, 8), + listOf(4u, 4u) to Rational(5, 36), + listOf(0u, 5u) to Rational(0), + listOf(1u, 5u) to Rational(0), + listOf(2u, 5u) to Rational(-7, 5), + listOf(3u, 5u) to Rational(1, 35), + listOf(4u, 5u) to Rational(1, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(0), + listOf(1u) to Rational(0), + listOf(2u) to Rational(0), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(0), + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(0), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).antiderivativeWithRespectTo(RationalField, 1), + "test 3b" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(1u) to Rational(-6, 8), + listOf(2u) to Rational(-1, 3), + listOf(3u) to Rational(1, 6), + listOf(4u) to Rational(0), + listOf(5u) to Rational(0), + listOf(1u, 1u) to Rational(-18, 3), + listOf(2u, 1u) to Rational(1, 3), + listOf(3u, 1u) to Rational(-11, 3), + listOf(4u, 1u) to Rational(0), + listOf(5u, 1u) to Rational(0), + listOf(1u, 2u) to Rational(-10, 3), + listOf(2u, 2u) to Rational(-4, 5), + listOf(3u, 2u) to Rational(-1, 24), + listOf(4u, 2u) to Rational(0), + listOf(5u, 2u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(0), + listOf(3u, 3u) to Rational(0), + listOf(4u, 3u) to Rational(0), + listOf(5u, 3u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(0), + listOf(3u, 4u) to Rational(0), + listOf(4u, 4u) to Rational(0), + listOf(5u, 4u) to Rational(0), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(0), + listOf(4u, 2u) to Rational(0), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(0), + listOf(3u, 3u) to Rational(0), + listOf(4u, 3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(0), + listOf(3u, 4u) to Rational(0), + listOf(4u, 4u) to Rational(0), + ).antiderivativeWithRespectTo(RationalField, 0), + "test 4a" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(0u, 1u) to Rational(-6, 8), + listOf(1u, 1u) to Rational(-2, 3), + listOf(2u, 1u) to Rational(1, 2), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(-9, 3), + listOf(1u, 2u) to Rational(1, 3), + listOf(2u, 2u) to Rational(-11, 2), + listOf(3u, 2u) to Rational(0), + listOf(4u, 2u) to Rational(0), + listOf(0u, 3u) to Rational(-10, 9), + listOf(1u, 3u) to Rational(-8, 15), + listOf(2u, 3u) to Rational(-1, 24), + listOf(3u, 3u) to Rational(0), + listOf(4u, 3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(0), + listOf(3u, 4u) to Rational(0), + listOf(4u, 4u) to Rational(0), + listOf(0u, 5u) to Rational(0), + listOf(1u, 5u) to Rational(0), + listOf(2u, 5u) to Rational(0), + listOf(3u, 5u) to Rational(0), + listOf(4u, 5u) to Rational(0), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(0), + listOf(4u, 2u) to Rational(0), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(0), + listOf(3u, 3u) to Rational(0), + listOf(4u, 3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(0), + listOf(3u, 4u) to Rational(0), + listOf(4u, 4u) to Rational(0), + ).antiderivativeWithRespectTo(RationalField, 1), + "test 4b" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(0u, 0u, 0u, 0u, 0u, 1u) to Rational(-6, 8), + listOf(1u, 0u, 0u, 0u, 0u, 1u) to Rational(-2, 3), + listOf(2u, 0u, 0u, 0u, 0u, 1u) to Rational(1, 2), + listOf(3u, 0u, 0u, 0u, 0u, 1u) to Rational(-11, 8), + listOf(4u, 0u, 0u, 0u, 0u, 1u) to Rational(18, 1), + listOf(0u, 1u, 0u, 0u, 0u, 1u) to Rational(-18, 3), + listOf(1u, 1u, 0u, 0u, 0u, 1u) to Rational(2, 3), + listOf(2u, 1u, 0u, 0u, 0u, 1u) to Rational(-11, 1), + listOf(3u, 1u, 0u, 0u, 0u, 1u) to Rational(-1, 3), + listOf(4u, 1u, 0u, 0u, 0u, 1u) to Rational(-18, 2), + listOf(0u, 2u, 0u, 0u, 0u, 1u) to Rational(-10, 3), + listOf(1u, 2u, 0u, 0u, 0u, 1u) to Rational(-8, 5), + listOf(2u, 2u, 0u, 0u, 0u, 1u) to Rational(-1, 8), + listOf(3u, 2u, 0u, 0u, 0u, 1u) to Rational(4, 7), + listOf(4u, 2u, 0u, 0u, 0u, 1u) to Rational(-4, 8), + listOf(0u, 3u, 0u, 0u, 0u, 1u) to Rational(3, 7), + listOf(1u, 3u, 0u, 0u, 0u, 1u) to Rational(16, 8), + listOf(2u, 3u, 0u, 0u, 0u, 1u) to Rational(-16, 8), + listOf(3u, 3u, 0u, 0u, 0u, 1u) to Rational(12, 8), + listOf(4u, 3u, 0u, 0u, 0u, 1u) to Rational(5, 9), + listOf(0u, 4u, 0u, 0u, 0u, 1u) to Rational(-18, 8), + listOf(1u, 4u, 0u, 0u, 0u, 1u) to Rational(-10, 1), + listOf(2u, 4u, 0u, 0u, 0u, 1u) to Rational(-14, 2), + listOf(3u, 4u, 0u, 0u, 0u, 1u) to Rational(1, 7), + listOf(4u, 4u, 0u, 0u, 0u, 1u) to Rational(15, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(-11, 8), + listOf(4u) to Rational(18, 1), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(-1, 3), + listOf(4u, 1u) to Rational(-18, 2), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(3, 7), + listOf(1u, 3u) to Rational(16, 8), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(-18, 8), + listOf(1u, 4u) to Rational(-10, 1), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).antiderivativeWithRespectTo(RationalField, 5), + "test 5" + ) } @Test - @Ignore + @OptIn(UnstableKMathAPI::class) fun test_Polynomial_nthAntiderivativeWithRespectTo_variable_order() { - // TODO + assertEquals( + NumberedPolynomialAsIs( + listOf(1u) to Rational(1), + listOf(2u) to Rational(-1), + listOf(3u) to Rational(1, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, 0, 1u), + "test 1" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, 0, 0u), + "test 2" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(-1, 3), + listOf(4u) to Rational(1, 12), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, 0, 2u), + "test 3" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(3u) to Rational(1, 6), + listOf(4u) to Rational(-1, 12), + listOf(5u) to Rational(1, 60), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, 0, 3u), + "test 4" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(4u) to Rational(1, 24), + listOf(5u) to Rational(-1, 60), + listOf(6u) to Rational(1, 360), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, 0, 4u), + "test 5" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, 1, 0u), + "test 6" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(0u, 1u) to Rational(1), + listOf(1u, 1u) to Rational(-2), + listOf(2u, 1u) to Rational(1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, 1, 1u), + "test 7" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(0u, 2u) to Rational(1, 2), + listOf(1u, 2u) to Rational(-1), + listOf(2u, 2u) to Rational(1, 2), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, 1, 2u), + "test 8" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(2u) to Rational(-3, 8), + listOf(3u) to Rational(-1, 9), + listOf(4u) to Rational(1, 24), + listOf(5u) to Rational(-11, 160), + listOf(6u) to Rational(3, 5), + listOf(2u, 1u) to Rational(-9, 3), + listOf(3u, 1u) to Rational(1, 9), + listOf(4u, 1u) to Rational(-11, 12), + listOf(5u, 1u) to Rational(-1, 60), + listOf(6u, 1u) to Rational(-3, 10), + listOf(2u, 2u) to Rational(-5, 3), + listOf(3u, 2u) to Rational(-4, 15), + listOf(4u, 2u) to Rational(-1, 96), + listOf(5u, 2u) to Rational(1, 35), + listOf(6u, 2u) to Rational(-1, 60), + listOf(2u, 3u) to Rational(3, 14), + listOf(3u, 3u) to Rational(1, 3), + listOf(4u, 3u) to Rational(-1, 6), + listOf(5u, 3u) to Rational(3, 40), + listOf(6u, 3u) to Rational(1, 54), + listOf(2u, 4u) to Rational(-9, 8), + listOf(3u, 4u) to Rational(-5, 3), + listOf(4u, 4u) to Rational(-7, 12), + listOf(5u, 4u) to Rational(1, 140), + listOf(6u, 4u) to Rational(1, 6), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(-11, 8), + listOf(4u) to Rational(18, 1), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(-1, 3), + listOf(4u, 1u) to Rational(-18, 2), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(3, 7), + listOf(1u, 3u) to Rational(16, 8), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(-18, 8), + listOf(1u, 4u) to Rational(-10, 1), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).nthAntiderivativeWithRespectTo(RationalField, 0, 2u), + "test 9a" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(0u, 2u) to Rational(-3, 8), + listOf(1u, 2u) to Rational(-1, 3), + listOf(2u, 2u) to Rational(1, 4), + listOf(3u, 2u) to Rational(-11, 16), + listOf(4u, 2u) to Rational(9, 1), + listOf(0u, 3u) to Rational(-1, 1), + listOf(1u, 3u) to Rational(1, 9), + listOf(2u, 3u) to Rational(-11, 6), + listOf(3u, 3u) to Rational(-1, 18), + listOf(4u, 3u) to Rational(-9, 6), + listOf(0u, 4u) to Rational(-5, 18), + listOf(1u, 4u) to Rational(-2, 15), + listOf(2u, 4u) to Rational(-1, 96), + listOf(3u, 4u) to Rational(1, 21), + listOf(4u, 4u) to Rational(-1, 24), + listOf(0u, 5u) to Rational(3, 140), + listOf(1u, 5u) to Rational(1, 10), + listOf(2u, 5u) to Rational(-1, 10), + listOf(3u, 5u) to Rational(3, 40), + listOf(4u, 5u) to Rational(1, 36), + listOf(0u, 6u) to Rational(-3, 40), + listOf(1u, 6u) to Rational(-1, 3), + listOf(2u, 6u) to Rational(-7, 30), + listOf(3u, 6u) to Rational(1, 210), + listOf(4u, 6u) to Rational(1, 6), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(-11, 8), + listOf(4u) to Rational(18, 1), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(-1, 3), + listOf(4u, 1u) to Rational(-18, 2), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(3, 7), + listOf(1u, 3u) to Rational(16, 8), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(-18, 8), + listOf(1u, 4u) to Rational(-10, 1), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).nthAntiderivativeWithRespectTo(RationalField, 1, 2u), + "test 9b" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(2u) to Rational(0), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(5u) to Rational(0), + listOf(6u) to Rational(0), + listOf(2u, 1u) to Rational(0), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(5u, 1u) to Rational(0), + listOf(6u, 1u) to Rational(0), + listOf(2u, 2u) to Rational(0), + listOf(3u, 2u) to Rational(0), + listOf(4u, 2u) to Rational(-1, 96), + listOf(5u, 2u) to Rational(1, 35), + listOf(6u, 2u) to Rational(-1, 60), + listOf(2u, 3u) to Rational(0), + listOf(3u, 3u) to Rational(0), + listOf(4u, 3u) to Rational(-1, 6), + listOf(5u, 3u) to Rational(3, 40), + listOf(6u, 3u) to Rational(1, 54), + listOf(2u, 4u) to Rational(0), + listOf(3u, 4u) to Rational(0), + listOf(4u, 4u) to Rational(-7, 12), + listOf(5u, 4u) to Rational(1, 140), + listOf(6u, 4u) to Rational(1, 6), + ), + NumberedPolynomialAsIs( + listOf() to Rational(0), + listOf(1u) to Rational(0), + listOf(2u) to Rational(0), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(0), + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(0), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).nthAntiderivativeWithRespectTo(RationalField, 0, 2u), + "test 10a" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(0), + listOf(3u, 2u) to Rational(0), + listOf(4u, 2u) to Rational(0), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(0), + listOf(3u, 3u) to Rational(0), + listOf(4u, 3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(-1, 96), + listOf(3u, 4u) to Rational(1, 21), + listOf(4u, 4u) to Rational(-1, 24), + listOf(0u, 5u) to Rational(0), + listOf(1u, 5u) to Rational(0), + listOf(2u, 5u) to Rational(-1, 10), + listOf(3u, 5u) to Rational(3, 40), + listOf(4u, 5u) to Rational(1, 36), + listOf(0u, 6u) to Rational(0), + listOf(1u, 6u) to Rational(0), + listOf(2u, 6u) to Rational(-7, 30), + listOf(3u, 6u) to Rational(1, 210), + listOf(4u, 6u) to Rational(1, 6), + ), + NumberedPolynomialAsIs( + listOf() to Rational(0), + listOf(1u) to Rational(0), + listOf(2u) to Rational(0), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(0), + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(0), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).nthAntiderivativeWithRespectTo(RationalField, 1, 2u), + "test 10b" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(2u) to Rational(-3, 8), + listOf(3u) to Rational(-1, 9), + listOf(4u) to Rational(1, 24), + listOf(5u) to Rational(0), + listOf(6u) to Rational(0), + listOf(2u, 1u) to Rational(-9, 3), + listOf(3u, 1u) to Rational(1, 9), + listOf(4u, 1u) to Rational(-11, 12), + listOf(5u, 1u) to Rational(0), + listOf(6u, 1u) to Rational(0), + listOf(2u, 2u) to Rational(-5, 3), + listOf(3u, 2u) to Rational(-4, 15), + listOf(4u, 2u) to Rational(-1, 96), + listOf(5u, 2u) to Rational(0), + listOf(6u, 2u) to Rational(0), + listOf(2u, 3u) to Rational(0), + listOf(3u, 3u) to Rational(0), + listOf(4u, 3u) to Rational(0), + listOf(5u, 3u) to Rational(0), + listOf(6u, 3u) to Rational(0), + listOf(2u, 4u) to Rational(0), + listOf(3u, 4u) to Rational(0), + listOf(4u, 4u) to Rational(0), + listOf(5u, 4u) to Rational(0), + listOf(6u, 4u) to Rational(0), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(0), + listOf(4u, 2u) to Rational(0), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(0), + listOf(3u, 3u) to Rational(0), + listOf(4u, 3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(0), + listOf(3u, 4u) to Rational(0), + listOf(4u, 4u) to Rational(0), + ).nthAntiderivativeWithRespectTo(RationalField, 0, 2u), + "test 11a" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(0u, 2u) to Rational(-3, 8), + listOf(1u, 2u) to Rational(-1, 3), + listOf(2u, 2u) to Rational(1, 4), + listOf(3u, 2u) to Rational(0), + listOf(4u, 2u) to Rational(0), + listOf(0u, 3u) to Rational(-1, 1), + listOf(1u, 3u) to Rational(1, 9), + listOf(2u, 3u) to Rational(-11, 6), + listOf(3u, 3u) to Rational(0), + listOf(4u, 3u) to Rational(0), + listOf(0u, 4u) to Rational(-5, 18), + listOf(1u, 4u) to Rational(-2, 15), + listOf(2u, 4u) to Rational(-1, 96), + listOf(3u, 4u) to Rational(0), + listOf(4u, 4u) to Rational(0), + listOf(0u, 5u) to Rational(0), + listOf(1u, 5u) to Rational(0), + listOf(2u, 5u) to Rational(0), + listOf(3u, 5u) to Rational(0), + listOf(4u, 5u) to Rational(0), + listOf(0u, 6u) to Rational(0), + listOf(1u, 6u) to Rational(0), + listOf(2u, 6u) to Rational(0), + listOf(3u, 6u) to Rational(0), + listOf(4u, 6u) to Rational(0), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(0), + listOf(4u, 2u) to Rational(0), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(0), + listOf(3u, 3u) to Rational(0), + listOf(4u, 3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(0), + listOf(3u, 4u) to Rational(0), + listOf(4u, 4u) to Rational(0), + ).nthAntiderivativeWithRespectTo(RationalField, 1, 2u), + "test 11b" + ) } @Test - @Ignore + @OptIn(UnstableKMathAPI::class) fun test_Polynomial_nthAntiderivativeWithRespectTo_variablesAndOrders() { - // TODO + assertEquals( + NumberedPolynomialAsIs( + listOf(1u) to Rational(1), + listOf(2u) to Rational(-1), + listOf(3u) to Rational(1, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, mapOf(0 to 1u)), + "test 1" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, 0, 0u), + "test 2" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(-1, 3), + listOf(4u) to Rational(1, 12), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, 0, 2u), + "test 3" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(3u) to Rational(1, 6), + listOf(4u) to Rational(-1, 12), + listOf(5u) to Rational(1, 60), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, 0, 3u), + "test 4" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(4u) to Rational(1, 24), + listOf(5u) to Rational(-1, 60), + listOf(6u) to Rational(1, 360), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, 0, 4u), + "test 5" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, 1, 0u), + "test 6" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(0u, 1u) to Rational(1), + listOf(1u, 1u) to Rational(-2), + listOf(2u, 1u) to Rational(1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, 1, 1u), + "test 7" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(0u, 2u) to Rational(1, 2), + listOf(1u, 2u) to Rational(-1), + listOf(2u, 2u) to Rational(1, 2), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, 1, 2u), + "test 8" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, mapOf()), + "test 9" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(1u) to Rational(1), + listOf(2u) to Rational(-1), + listOf(3u) to Rational(1, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, mapOf( + 0 to 1u, + 1 to 0u + )), + "test 10" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(0u, 1u) to Rational(1), + listOf(1u, 1u) to Rational(-2), + listOf(2u, 1u) to Rational(1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, mapOf( + 0 to 0u, + 1 to 1u + )), + "test 11" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(2u) to Rational(-3, 8), + listOf(3u) to Rational(-1, 9), + listOf(4u) to Rational(1, 24), + listOf(5u) to Rational(-11, 160), + listOf(6u) to Rational(3, 5), + listOf(2u, 1u) to Rational(-9, 3), + listOf(3u, 1u) to Rational(1, 9), + listOf(4u, 1u) to Rational(-11, 12), + listOf(5u, 1u) to Rational(-1, 60), + listOf(6u, 1u) to Rational(-3, 10), + listOf(2u, 2u) to Rational(-5, 3), + listOf(3u, 2u) to Rational(-4, 15), + listOf(4u, 2u) to Rational(-1, 96), + listOf(5u, 2u) to Rational(1, 35), + listOf(6u, 2u) to Rational(-1, 60), + listOf(2u, 3u) to Rational(3, 14), + listOf(3u, 3u) to Rational(1, 3), + listOf(4u, 3u) to Rational(-1, 6), + listOf(5u, 3u) to Rational(3, 40), + listOf(6u, 3u) to Rational(1, 54), + listOf(2u, 4u) to Rational(-9, 8), + listOf(3u, 4u) to Rational(-5, 3), + listOf(4u, 4u) to Rational(-7, 12), + listOf(5u, 4u) to Rational(1, 140), + listOf(6u, 4u) to Rational(1, 6), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(-11, 8), + listOf(4u) to Rational(18, 1), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(-1, 3), + listOf(4u, 1u) to Rational(-18, 2), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(3, 7), + listOf(1u, 3u) to Rational(16, 8), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(-18, 8), + listOf(1u, 4u) to Rational(-10, 1), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).nthAntiderivativeWithRespectTo(RationalField, mapOf(0 to 2u)), + "test 12a" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(1u, 1u) to Rational(-6, 8), + listOf(2u, 1u) to Rational(-1, 3), + listOf(3u, 1u) to Rational(1, 6), + listOf(4u, 1u) to Rational(-11, 32), + listOf(5u, 1u) to Rational(18, 5), + listOf(1u, 2u) to Rational(-9, 3), + listOf(2u, 2u) to Rational(1, 6), + listOf(3u, 2u) to Rational(-11, 6), + listOf(4u, 2u) to Rational(-1, 24), + listOf(5u, 2u) to Rational(-9, 10), + listOf(1u, 3u) to Rational(-10, 9), + listOf(2u, 3u) to Rational(-4, 15), + listOf(3u, 3u) to Rational(-1, 72), + listOf(4u, 3u) to Rational(1, 21), + listOf(5u, 3u) to Rational(-1, 30), + listOf(1u, 4u) to Rational(3, 28), + listOf(2u, 4u) to Rational(1, 4), + listOf(3u, 4u) to Rational(-1, 6), + listOf(4u, 4u) to Rational(3, 32), + listOf(5u, 4u) to Rational(1, 36), + listOf(1u, 5u) to Rational(-9, 20), + listOf(2u, 5u) to Rational(-1, 1), + listOf(3u, 5u) to Rational(-7, 15), + listOf(4u, 5u) to Rational(1, 140), + listOf(5u, 5u) to Rational(1, 5), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(-11, 8), + listOf(4u) to Rational(18, 1), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(-1, 3), + listOf(4u, 1u) to Rational(-18, 2), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(3, 7), + listOf(1u, 3u) to Rational(16, 8), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(-18, 8), + listOf(1u, 4u) to Rational(-10, 1), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).nthAntiderivativeWithRespectTo(RationalField, mapOf(0 to 1u, 1 to 1u)), + "test 12b" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(0u, 2u) to Rational(-3, 8), + listOf(1u, 2u) to Rational(-1, 3), + listOf(2u, 2u) to Rational(1, 4), + listOf(3u, 2u) to Rational(-11, 16), + listOf(4u, 2u) to Rational(9, 1), + listOf(0u, 3u) to Rational(-1, 1), + listOf(1u, 3u) to Rational(1, 9), + listOf(2u, 3u) to Rational(-11, 6), + listOf(3u, 3u) to Rational(-1, 18), + listOf(4u, 3u) to Rational(-9, 6), + listOf(0u, 4u) to Rational(-5, 18), + listOf(1u, 4u) to Rational(-2, 15), + listOf(2u, 4u) to Rational(-1, 96), + listOf(3u, 4u) to Rational(1, 21), + listOf(4u, 4u) to Rational(-1, 24), + listOf(0u, 5u) to Rational(3, 140), + listOf(1u, 5u) to Rational(1, 10), + listOf(2u, 5u) to Rational(-1, 10), + listOf(3u, 5u) to Rational(3, 40), + listOf(4u, 5u) to Rational(1, 36), + listOf(0u, 6u) to Rational(-3, 40), + listOf(1u, 6u) to Rational(-1, 3), + listOf(2u, 6u) to Rational(-7, 30), + listOf(3u, 6u) to Rational(1, 210), + listOf(4u, 6u) to Rational(1, 6), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(-11, 8), + listOf(4u) to Rational(18, 1), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(-1, 3), + listOf(4u, 1u) to Rational(-18, 2), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(3, 7), + listOf(1u, 3u) to Rational(16, 8), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(-18, 8), + listOf(1u, 4u) to Rational(-10, 1), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).nthAntiderivativeWithRespectTo(RationalField, mapOf(1 to 2u)), + "test 12c" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(2u) to Rational(0), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(5u) to Rational(0), + listOf(6u) to Rational(0), + listOf(2u, 1u) to Rational(0), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(5u, 1u) to Rational(0), + listOf(6u, 1u) to Rational(0), + listOf(2u, 2u) to Rational(0), + listOf(3u, 2u) to Rational(0), + listOf(4u, 2u) to Rational(-1, 96), + listOf(5u, 2u) to Rational(1, 35), + listOf(6u, 2u) to Rational(-1, 60), + listOf(2u, 3u) to Rational(0), + listOf(3u, 3u) to Rational(0), + listOf(4u, 3u) to Rational(-1, 6), + listOf(5u, 3u) to Rational(3, 40), + listOf(6u, 3u) to Rational(1, 54), + listOf(2u, 4u) to Rational(0), + listOf(3u, 4u) to Rational(0), + listOf(4u, 4u) to Rational(-7, 12), + listOf(5u, 4u) to Rational(1, 140), + listOf(6u, 4u) to Rational(1, 6), + ), + NumberedPolynomialAsIs( + listOf() to Rational(0), + listOf(1u) to Rational(0), + listOf(2u) to Rational(0), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(0), + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(0), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).nthAntiderivativeWithRespectTo(RationalField, mapOf(0 to 2u)), + "test 13a" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(0), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(5u, 1u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(0), + listOf(3u, 2u) to Rational(0), + listOf(4u, 2u) to Rational(0), + listOf(5u, 2u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(0), + listOf(3u, 3u) to Rational(-1, 72), + listOf(4u, 3u) to Rational(1, 21), + listOf(5u, 3u) to Rational(-1, 30), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(0), + listOf(3u, 4u) to Rational(-1, 6), + listOf(4u, 4u) to Rational(3, 32), + listOf(5u, 4u) to Rational(1, 36), + listOf(1u, 5u) to Rational(0), + listOf(2u, 5u) to Rational(0), + listOf(3u, 5u) to Rational(-7, 15), + listOf(4u, 5u) to Rational(1, 140), + listOf(5u, 5u) to Rational(1, 5), + ), + NumberedPolynomialAsIs( + listOf() to Rational(0), + listOf(1u) to Rational(0), + listOf(2u) to Rational(0), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(0), + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(0), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).nthAntiderivativeWithRespectTo(RationalField, mapOf(0 to 1u, 1 to 1u)), + "test 13b" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(0), + listOf(3u, 2u) to Rational(0), + listOf(4u, 2u) to Rational(0), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(0), + listOf(3u, 3u) to Rational(0), + listOf(4u, 3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(-1, 96), + listOf(3u, 4u) to Rational(1, 21), + listOf(4u, 4u) to Rational(-1, 24), + listOf(0u, 5u) to Rational(0), + listOf(1u, 5u) to Rational(0), + listOf(2u, 5u) to Rational(-1, 10), + listOf(3u, 5u) to Rational(3, 40), + listOf(4u, 5u) to Rational(1, 36), + listOf(0u, 6u) to Rational(0), + listOf(1u, 6u) to Rational(0), + listOf(2u, 6u) to Rational(-7, 30), + listOf(3u, 6u) to Rational(1, 210), + listOf(4u, 6u) to Rational(1, 6), + ), + NumberedPolynomialAsIs( + listOf() to Rational(0), + listOf(1u) to Rational(0), + listOf(2u) to Rational(0), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(0), + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(0), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).nthAntiderivativeWithRespectTo(RationalField, mapOf(1 to 2u)), + "test 13c" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(2u) to Rational(-3, 8), + listOf(3u) to Rational(-1, 9), + listOf(4u) to Rational(1, 24), + listOf(5u) to Rational(0), + listOf(6u) to Rational(0), + listOf(2u, 1u) to Rational(-9, 3), + listOf(3u, 1u) to Rational(1, 9), + listOf(4u, 1u) to Rational(-11, 12), + listOf(5u, 1u) to Rational(0), + listOf(6u, 1u) to Rational(0), + listOf(2u, 2u) to Rational(-5, 3), + listOf(3u, 2u) to Rational(-4, 15), + listOf(4u, 2u) to Rational(-1, 96), + listOf(5u, 2u) to Rational(0), + listOf(6u, 2u) to Rational(0), + listOf(2u, 3u) to Rational(0), + listOf(3u, 3u) to Rational(0), + listOf(4u, 3u) to Rational(0), + listOf(5u, 3u) to Rational(0), + listOf(6u, 3u) to Rational(0), + listOf(2u, 4u) to Rational(0), + listOf(3u, 4u) to Rational(0), + listOf(4u, 4u) to Rational(0), + listOf(5u, 4u) to Rational(0), + listOf(6u, 4u) to Rational(0), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(0), + listOf(4u, 2u) to Rational(0), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(0), + listOf(3u, 3u) to Rational(0), + listOf(4u, 3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(0), + listOf(3u, 4u) to Rational(0), + listOf(4u, 4u) to Rational(0), + ).nthAntiderivativeWithRespectTo(RationalField, mapOf(0 to 2u)), + "test 14a" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(1u, 1u) to Rational(-6, 8), + listOf(2u, 1u) to Rational(-1, 3), + listOf(3u, 1u) to Rational(1, 6), + listOf(4u, 1u) to Rational(0), + listOf(5u, 1u) to Rational(0), + listOf(1u, 2u) to Rational(-9, 3), + listOf(2u, 2u) to Rational(1, 6), + listOf(3u, 2u) to Rational(-11, 6), + listOf(4u, 2u) to Rational(0), + listOf(5u, 2u) to Rational(0), + listOf(1u, 3u) to Rational(-10, 9), + listOf(2u, 3u) to Rational(-4, 15), + listOf(3u, 3u) to Rational(-1, 72), + listOf(4u, 3u) to Rational(0), + listOf(5u, 3u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(0), + listOf(3u, 4u) to Rational(0), + listOf(4u, 4u) to Rational(0), + listOf(5u, 4u) to Rational(0), + listOf(1u, 5u) to Rational(0), + listOf(2u, 5u) to Rational(0), + listOf(3u, 5u) to Rational(0), + listOf(4u, 5u) to Rational(0), + listOf(5u, 5u) to Rational(0), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(0), + listOf(4u, 2u) to Rational(0), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(0), + listOf(3u, 3u) to Rational(0), + listOf(4u, 3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(0), + listOf(3u, 4u) to Rational(0), + listOf(4u, 4u) to Rational(0), + ).nthAntiderivativeWithRespectTo(RationalField, mapOf(0 to 1u, 1 to 1u)), + "test 14b" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(0u, 2u) to Rational(-3, 8), + listOf(1u, 2u) to Rational(-1, 3), + listOf(2u, 2u) to Rational(1, 4), + listOf(3u, 2u) to Rational(0), + listOf(4u, 2u) to Rational(0), + listOf(0u, 3u) to Rational(-1, 1), + listOf(1u, 3u) to Rational(1, 9), + listOf(2u, 3u) to Rational(-11, 6), + listOf(3u, 3u) to Rational(0), + listOf(4u, 3u) to Rational(0), + listOf(0u, 4u) to Rational(-5, 18), + listOf(1u, 4u) to Rational(-2, 15), + listOf(2u, 4u) to Rational(-1, 96), + listOf(3u, 4u) to Rational(0), + listOf(4u, 4u) to Rational(0), + listOf(0u, 5u) to Rational(0), + listOf(1u, 5u) to Rational(0), + listOf(2u, 5u) to Rational(0), + listOf(3u, 5u) to Rational(0), + listOf(4u, 5u) to Rational(0), + listOf(0u, 6u) to Rational(0), + listOf(1u, 6u) to Rational(0), + listOf(2u, 6u) to Rational(0), + listOf(3u, 6u) to Rational(0), + listOf(4u, 6u) to Rational(0), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(0), + listOf(4u, 2u) to Rational(0), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(0), + listOf(3u, 3u) to Rational(0), + listOf(4u, 3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(0), + listOf(3u, 4u) to Rational(0), + listOf(4u, 4u) to Rational(0), + ).nthAntiderivativeWithRespectTo(RationalField, mapOf(1 to 2u)), + "test 14c" + ) } } \ No newline at end of file -- 2.34.1 From 5834fad938a973976eff3d0f1cea83df2198ba73 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Wed, 6 Jul 2022 00:37:46 +0300 Subject: [PATCH 097/123] Renamed constructing DSLs components. Fixed rejected NumberedPolynomial tests. --- .../kscience/kmath/functions/polynomials.kt | 205 +- .../kmath/functions/labeledConstructors.kt | 23 +- .../kmath/functions/numberedConstructors.kt | 22 +- .../functions/NumberedConstructorsTest.kt | 10 +- .../kmath/functions/NumberedPolynomialTest.kt | 2287 ++++++++--------- 5 files changed, 1270 insertions(+), 1277 deletions(-) diff --git a/examples/src/main/kotlin/space/kscience/kmath/functions/polynomials.kt b/examples/src/main/kotlin/space/kscience/kmath/functions/polynomials.kt index 273fe5cb9..7843a0210 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/functions/polynomials.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/functions/polynomials.kt @@ -8,6 +8,7 @@ package space.kscience.kmath.functions import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.expressions.symbol import space.kscience.kmath.operations.algebra +import space.kscience.kmath.operations.invoke /** @@ -102,7 +103,7 @@ fun numberedPolynomialsExample() { numberedPolynomialSpace { // Also there is DSL for constructing NumberedPolynomials: - val polynomial5: NumberedPolynomial = NumberedPolynomial { + val polynomial5: NumberedPolynomial = NumberedPolynomialDSL1 { 3 {} 5 { 2 inPowerOf 1u } -7 with { 1 pow 2u; 3 pow 1u } @@ -116,7 +117,7 @@ fun numberedPolynomialsExample() { } } - val polynomial6: NumberedPolynomial = with(Int.algebra) { + val polynomial6: NumberedPolynomial = Int.algebra { NumberedPolynomial( listOf() to 7, listOf(0u, 1u) to -5, @@ -127,28 +128,28 @@ fun numberedPolynomialsExample() { // For every ring there can be provided a polynomial ring: Int.algebra.numberedPolynomialSpace { println( - -polynomial6 == NumberedPolynomial { - (-7) {} - 5 { 2 pow 1u } - 0 { 1 pow 2u; 3 pow 1u } - (-4) { 4 pow 4u } - } + -polynomial6 == NumberedPolynomial( + listOf() to -7, + listOf(0u, 1u) to 5, + listOf(2u, 0u, 1u) to 0, + listOf(0u, 0u, 0u, 4u) to (-4), + ) ) // true println( - polynomial1 + polynomial6 == NumberedPolynomial { - 10 {} - 0 { 2 pow 1u } - (-7) { 1 pow 2u; 3 pow 1u } - 4 { 4 pow 4u } - } + polynomial1 + polynomial6 == NumberedPolynomial( + listOf() to 10, + listOf(0u, 1u) to 0, + listOf(2u, 0u, 1u) to -7, + listOf(0u, 0u, 0u, 4u) to 4, + ) ) // true println( - polynomial1 - polynomial6 == NumberedPolynomial { - (-4) {} - 10 { 2 pow 1u } - (-7) { 1 pow 2u; 3 pow 1u } - (-4) { 4 pow 4u } - } + polynomial1 - polynomial6 == NumberedPolynomial( + listOf() to -4, + listOf(0u, 1u) to 10, + listOf(2u, 0u, 1u) to -7, + listOf(0u, 0u, 0u, 4u) to -4, + ) ) // true polynomial1 * polynomial6 // Multiplication works too @@ -156,14 +157,14 @@ fun numberedPolynomialsExample() { Double.algebra.numberedPolynomialSpace { // You can even write - val x_1: NumberedPolynomial = NumberedPolynomial { 1.0 { 1 pow 1u } } - val x_2: NumberedPolynomial = NumberedPolynomial { 1.0 { 2 pow 1u } } - val x_3: NumberedPolynomial = NumberedPolynomial { 1.0 { 3 pow 1u } } - val polynomial7: NumberedPolynomial = NumberedPolynomial { - 3.0 {} - 5.0 { 2 pow 1u } - (-7.0) { 1 pow 2u; 3 pow 1u } - } + val x_1: NumberedPolynomial = NumberedPolynomial(listOf(1u) to 1.0) + val x_2: NumberedPolynomial = NumberedPolynomial(listOf(0u, 1u) to 1.0) + val x_3: NumberedPolynomial = NumberedPolynomial(listOf(0u, 0u, 1u) to 1.0) + val polynomial7: NumberedPolynomial = NumberedPolynomial( + listOf() to 3.0, + listOf(0u, 1u) to 5.0, + listOf(2u, 0u, 1u) to -7.0, + ) Double.algebra.listPolynomialSpace { println(3 + 5 * x_2 - 7 * x_1 * x_1 * x_3 == polynomial7) println(3.0 + 5.0 * x_2 - 7.0 * x_1 * x_1 * x_3 == polynomial7) @@ -171,49 +172,49 @@ fun numberedPolynomialsExample() { } Int.algebra.numberedPolynomialSpace { - val x_4: NumberedPolynomial = NumberedPolynomial { 1 { 4 pow 1u } } + val x_4: NumberedPolynomial = NumberedPolynomial(listOf(0u, 0u, 0u, 4u) to 1) // Also there are some utilities for polynomials: println(polynomial1.substitute(mapOf(0 to 1, 1 to -2, 2 to -1)) == 0.asNumberedPolynomial()) // true, // because it's substitution x_1 -> 1, x_2 -> -2, x_3 -> -1, // so 3 + 5 x_2 - 7 x_1^2 x_3 = 3 + 5 * (-2) - 7 * 1^2 * (-1) = 3 - 10 + 7 = 0 println( - polynomial1.substitute(mapOf(1 to x_4)) == NumberedPolynomial { - 3 {} - 5 { 4 pow 1u } - (-7) { 1 pow 2u; 3 pow 1u } - } + polynomial1.substitute(mapOf(1 to x_4)) == NumberedPolynomial( + listOf() to 3, + listOf(0u, 1u) to 5, + listOf(2u, 0u, 1u) to -7, + ) ) // true, because it's substitution x_2 -> x_4, so result is 3 + 5 x_4 - 7 x_1^2 x_3 println( polynomial1.derivativeWithRespectTo(Int.algebra, 1) == - NumberedPolynomial { 5 {} } + NumberedPolynomial(listOf() to 5) ) // true, d/dx_2 (3 + 5 x_2 - 7 x_1^2 x_3) = 5 } // Lastly, there are rational functions and some other utilities: Double.algebra.numberedRationalFunctionSpace { val rationalFunction1: NumberedRationalFunction = NumberedRationalFunction( - NumberedPolynomial { - 2.0 {} - (-3.0) { 1 pow 1u } - 1.0 { 1 pow 2u } - }, - NumberedPolynomial { - 3.0 {} - (-1.0) { 1 pow 1u } - } + NumberedPolynomial( + listOf() to 2.0, + listOf(1u) to -3.0, + listOf(2u) to 1.0, + ), + NumberedPolynomial( + listOf() to 3.0, + listOf(1u) to -1.0, + ) ) // It's just (2 - 3x + x^2)/(3 - x) where x = x_1 val rationalFunction2: NumberedRationalFunction = NumberedRationalFunction( - NumberedPolynomial { - 5.0 {} - (-4.0) { 1 pow 1u } - 1.0 { 1 pow 2u } - }, - NumberedPolynomial { - 3.0 {} - (-1.0) { 1 pow 1u } - } + NumberedPolynomial( + listOf() to 5.0, + listOf(1u) to -4.0, + listOf(2u) to 1.0, + ), + NumberedPolynomial( + listOf() to 3.0, + listOf(1u) to -1.0, + ) ) // It's just (5 - 4x + x^2)/(3 - x) where x = x_1 @@ -267,7 +268,7 @@ fun labeledPolynomialsExample() { labeledPolynomialSpace { // Also there is DSL for constructing NumberedPolynomials: - val polynomial5: LabeledPolynomial = LabeledPolynomial { + val polynomial5: LabeledPolynomial = LabeledPolynomialDSL1 { 3 {} 5 { y inPowerOf 1u } -7 with { x pow 2u; z pow 1u } @@ -281,7 +282,7 @@ fun labeledPolynomialsExample() { } } - val polynomial6: LabeledPolynomial = with(Int.algebra) { + val polynomial6: LabeledPolynomial = Int.algebra { LabeledPolynomial( mapOf() to 7, mapOf(y to 1u) to -5, @@ -292,28 +293,28 @@ fun labeledPolynomialsExample() { // For every ring there can be provided a polynomial ring: Int.algebra.labeledPolynomialSpace { println( - -polynomial6 == LabeledPolynomial { - (-7) {} - 5 { y pow 1u } - 0 { x pow 2u; z pow 1u } - (-4) { t pow 4u } - } + -polynomial6 == LabeledPolynomial( + mapOf() to -7, + mapOf(y to 1u) to 5, + mapOf(x to 2u, z to 1u) to 0, + mapOf(t to 4u) to -4, + ) ) // true println( - polynomial1 + polynomial6 == LabeledPolynomial { - 10 {} - 0 { y pow 1u } - (-7) { x pow 2u; z pow 1u } - 4 { t pow 4u } - } + polynomial1 + polynomial6 == LabeledPolynomial( + mapOf() to 10, + mapOf(y to 1u) to 0, + mapOf(x to 2u, z to 1u) to -7, + mapOf(t to 4u) to 4, + ) ) // true println( - polynomial1 - polynomial6 == LabeledPolynomial { - (-4) {} - 10 { y pow 1u } - (-7) { x pow 2u; z pow 1u } - (-4) { t pow 4u } - } + polynomial1 - polynomial6 == LabeledPolynomial( + mapOf() to -4, + mapOf(y to 1u) to 10, + mapOf(x to 2u, z to 1u) to -7, + mapOf(t to 4u) to -4, + ) ) // true polynomial1 * polynomial6 // Multiplication works too @@ -321,11 +322,11 @@ fun labeledPolynomialsExample() { Double.algebra.labeledPolynomialSpace { // You can even write - val polynomial7: LabeledPolynomial = LabeledPolynomial { - 3.0 {} - 5.0 { y pow 1u } - (-7.0) { x pow 2u; z pow 1u } - } + val polynomial7: LabeledPolynomial = LabeledPolynomial( + mapOf() to 3.0, + mapOf(y to 1u) to 5.0, + mapOf(x to 2u, z to 1u) to -7.0, + ) Double.algebra.listPolynomialSpace { println(3 + 5 * y - 7 * x * x * z == polynomial7) println(3.0 + 5.0 * y - 7.0 * x * x * z == polynomial7) @@ -338,42 +339,42 @@ fun labeledPolynomialsExample() { // because it's substitution x -> 1, y -> -2, z -> -1, // so 3 + 5 y - 7 x^2 z = 3 + 5 * (-2) - 7 * 1^2 * (-1) = 3 - 10 + 7 = 0 println( - polynomial1.substitute(mapOf(y to t.asPolynomial())) == LabeledPolynomial { - 3 {} - 5 { t pow 1u } - (-7) { x pow 2u; z pow 1u } - } + polynomial1.substitute(mapOf(y to t.asPolynomial())) == LabeledPolynomial( + mapOf() to 3, + mapOf(t to 1u) to 5, + mapOf(x to 2u, z to 1u) to -7, + ) ) // true, because it's substitution y -> t, so result is 3 + 5 t - 7 x^2 z println( - polynomial1.derivativeWithRespectTo(Int.algebra, y) == LabeledPolynomial { 5 {} } + polynomial1.derivativeWithRespectTo(Int.algebra, y) == LabeledPolynomial(mapOf() to 5) ) // true, d/dy (3 + 5 y - 7 x^2 z) = 5 } // Lastly, there are rational functions and some other utilities: Double.algebra.labeledRationalFunctionSpace { val rationalFunction1: LabeledRationalFunction = LabeledRationalFunction( - LabeledPolynomial { - 2.0 {} - (-3.0) { x pow 1u } - 1.0 { x pow 2u } - }, - LabeledPolynomial { - 3.0 {} - (-1.0) { x pow 1u } - } + LabeledPolynomial( + mapOf() to 2.0, + mapOf(x to 1u) to -3.0, + mapOf(x to 2u) to 1.0, + ), + LabeledPolynomial( + mapOf() to 3.0, + mapOf(x to 1u) to -1.0, + ) ) // It's just (2 - 3x + x^2)/(3 - x) val rationalFunction2: LabeledRationalFunction = LabeledRationalFunction( - LabeledPolynomial { - 5.0 {} - (-4.0) { x pow 1u } - 1.0 { x pow 2u } - }, - LabeledPolynomial { - 3.0 {} - (-1.0) { x pow 1u } - } + LabeledPolynomial( + mapOf() to 5.0, + mapOf(x to 1u) to -4.0, + mapOf(x to 2u) to 1.0, + ), + LabeledPolynomial( + mapOf() to 3.0, + mapOf(x to 1u) to -1.0, + ) ) // It's just (5 - 4x + x^2)/(3 - x) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt index 7a8d961c0..8442d3f91 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt @@ -274,14 +274,14 @@ public inline fun C.asLabeledPolynomial() : LabeledPolynomial = LabeledPo */ @DslMarker @UnstableKMathAPI -internal annotation class LabeledPolynomialConstructorDSL +internal annotation class LabeledPolynomialConstructorDSL1 /** * Builder of [LabeledPolynomial] signature. It should be used as an implicit context for lambdas that describe term signature. */ @UnstableKMathAPI -@LabeledPolynomialConstructorDSL -public class LabeledPolynomialTermSignatureBuilder { +@LabeledPolynomialConstructorDSL1 +public class DSL1LabeledPolynomialTermSignatureBuilder { /** * Signature storage. Any declaration of any variable's power updates the storage by increasing corresponding value. * Afterward the storage will be used as a resulting signature. @@ -302,7 +302,7 @@ public class LabeledPolynomialTermSignatureBuilder { * Declaring another power of the same variable will increase its degree by received degree. */ public infix fun Symbol.inPowerOf(deg: UInt) { - signature[this] = deg + signature[this] = signature.getOrElse(this) { 0u } + deg } /** * Declares power of [this] variable of degree [deg]. @@ -328,7 +328,8 @@ public class LabeledPolynomialTermSignatureBuilder { * Builder of [LabeledPolynomial]. It should be used as an implicit context for lambdas that describe [LabeledPolynomial]. */ @UnstableKMathAPI -public class LabeledPolynomialBuilder( +@LabeledPolynomialConstructorDSL1 +public class DSL1LabeledPolynomialBuilder( /** * Summation operation that will be used to sum coefficients of monomials of same signatures. */ @@ -367,15 +368,15 @@ public class LabeledPolynomialBuilder( * Declaring another monomial with the same signature will add [this] coefficient to existing one. If the sum of such * coefficients is zero at any moment the monomial won't be removed but will be left as it is. */ - public inline infix fun C.with(noinline block: LabeledPolynomialTermSignatureBuilder.() -> Unit): Unit = this.invoke(block) + public inline infix fun C.with(noinline block: DSL1LabeledPolynomialTermSignatureBuilder.() -> Unit): Unit = this.invoke(block) /** * Declares monomial with [this] coefficient and signature constructed by [block]. * * Declaring another monomial with the same signature will add [this] coefficient to existing one. If the sum of such * coefficients is zero at any moment the monomial won't be removed but will be left as it is. */ - public inline operator fun C.invoke(block: LabeledPolynomialTermSignatureBuilder.() -> Unit): Unit = - this with LabeledPolynomialTermSignatureBuilder().apply(block).build() + public inline operator fun C.invoke(block: DSL1LabeledPolynomialTermSignatureBuilder.() -> Unit): Unit = + this with DSL1LabeledPolynomialTermSignatureBuilder().apply(block).build() } // Waiting for context receivers :( FIXME: Replace with context receivers when they will be available @@ -398,7 +399,7 @@ public class LabeledPolynomialBuilder( // 2. Union types are implemented. Then all three functions should be rewritten // as one with single union type as a (context) receiver. //@UnstableKMathAPI -//public inline fun > A.LabeledPolynomial(initialCapacity: Int = 0, block: LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = LabeledPolynomialBuilder(::add, initialCapacity).apply(block).build() +//public inline fun > A.LabeledPolynomialDSL1(initialCapacity: Int = 0, block: LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = LabeledPolynomialBuilder(::add, initialCapacity).apply(block).build() /** * Creates [LabeledPolynomial] with lambda [block] in context of [this] ring of [LabeledPolynomial]s. * @@ -413,7 +414,7 @@ public class LabeledPolynomialBuilder( * ``` */ @UnstableKMathAPI -public inline fun > LabeledPolynomialSpace.LabeledPolynomial(initialCapacity: Int = 0, block: LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = LabeledPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() +public inline fun > LabeledPolynomialSpace.LabeledPolynomialDSL1(initialCapacity: Int = 0, block: DSL1LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = DSL1LabeledPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() /** * Creates [LabeledPolynomial] with lambda [block] in context of [this] field of [LabeledRationalFunction]s. * @@ -428,7 +429,7 @@ public inline fun > LabeledPolynomialSpace.LabeledPolynomial * ``` */ @UnstableKMathAPI -public inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(initialCapacity: Int = 0, block: LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = LabeledPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() +public inline fun > LabeledRationalFunctionSpace.LabeledPolynomialDSL1(initialCapacity: Int = 0, block: DSL1LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = DSL1LabeledPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() // Waiting for context receivers :( FIXME: Replace with context receivers when they will be available diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt index 7f02ff1e3..8d2c9e617 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt @@ -255,14 +255,14 @@ public inline fun C.asNumberedPolynomial() : NumberedPolynomial = Numbere */ @DslMarker @UnstableKMathAPI -internal annotation class NumberedPolynomialConstructorDSL +internal annotation class NumberedPolynomialConstructorDSL1 /** * Builder of [NumberedPolynomial] signature. It should be used as an implicit context for lambdas that describe term signature. */ @UnstableKMathAPI -@NumberedPolynomialConstructorDSL -public class NumberedPolynomialTermSignatureBuilder { +@NumberedPolynomialConstructorDSL1 +public class DSL1NumberedPolynomialTermSignatureBuilder { /** * Signature storage. Any declaration of any variable's power updates the storage by increasing corresponding value. * Afterward the storage will be used as a resulting signature. @@ -316,8 +316,8 @@ public class NumberedPolynomialTermSignatureBuilder { * Builder of [NumberedPolynomial]. It should be used as an implicit context for lambdas that describe [NumberedPolynomial]. */ @UnstableKMathAPI -@NumberedPolynomialConstructorDSL -public class NumberedPolynomialBuilder( +@NumberedPolynomialConstructorDSL1 +public class DSL1NumberedPolynomialBuilder( /** * Summation operation that will be used to sum coefficients of monomials of same signatures. */ @@ -356,15 +356,15 @@ public class NumberedPolynomialBuilder( * Declaring another monomial with the same signature will add [this] coefficient to existing one. If the sum of such * coefficients is zero at any moment the monomial won't be removed but will be left as it is. */ - public inline infix fun C.with(noinline block: NumberedPolynomialTermSignatureBuilder.() -> Unit): Unit = this.invoke(block) + public inline infix fun C.with(noinline block: DSL1NumberedPolynomialTermSignatureBuilder.() -> Unit): Unit = this.invoke(block) /** * Declares monomial with [this] coefficient and signature constructed by [block]. * * Declaring another monomial with the same signature will add [this] coefficient to existing one. If the sum of such * coefficients is zero at any moment the monomial won't be removed but will be left as it is. */ - public inline operator fun C.invoke(block: NumberedPolynomialTermSignatureBuilder.() -> Unit): Unit = - this with NumberedPolynomialTermSignatureBuilder().apply(block).build() + public inline operator fun C.invoke(block: DSL1NumberedPolynomialTermSignatureBuilder.() -> Unit): Unit = + this with DSL1NumberedPolynomialTermSignatureBuilder().apply(block).build() } // Waiting for context receivers :( FIXME: Replace with context receivers when they will be available @@ -387,7 +387,7 @@ public class NumberedPolynomialBuilder( // 2. Union types are implemented. Then all three functions should be rewritten // as one with single union type as a (context) receiver. //@UnstableKMathAPI -//public inline fun > A.NumberedPolynomial(initialCapacity: Int = 0, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder(::add, initialCapacity).apply(block).build() +//public inline fun > A.NumberedPolynomialDSL1(initialCapacity: Int = 0, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder(::add, initialCapacity).apply(block).build() /** * Creates [NumberedPolynomial] with lambda [block] in context of [this] ring of [NumberedPolynomial]s. * @@ -402,7 +402,7 @@ public class NumberedPolynomialBuilder( * ``` */ @UnstableKMathAPI -public inline fun > NumberedPolynomialSpace.NumberedPolynomial(initialCapacity: Int = 0, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() +public inline fun > NumberedPolynomialSpace.NumberedPolynomialDSL1(initialCapacity: Int = 0, block: DSL1NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = DSL1NumberedPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() /** * Creates [NumberedPolynomial] with lambda [block] in context of [this] field of [NumberedRationalFunction]s. * @@ -417,7 +417,7 @@ public inline fun > NumberedPolynomialSpace.NumberedPolynomi * ``` */ @UnstableKMathAPI -public inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(initialCapacity: Int = 0, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() +public inline fun > NumberedRationalFunctionSpace.NumberedPolynomialDSL1(initialCapacity: Int = 0, block: DSL1NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = DSL1NumberedPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() // Waiting for context receivers :( FIXME: Replace with context receivers when they will be available diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt index 8d1b128cf..f9a5a041b 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt @@ -15,14 +15,14 @@ import kotlin.test.assertEquals class NumberedConstructorsTest { @Test @UnstableKMathAPI - fun testBuilder() { + fun testDSL1() { assertEquals( NumberedPolynomialAsIs( listOf(2u, 0u, 3u) to 5, listOf(0u, 1u) to -6, ), Int.algebra.numberedPolynomialSpace { - NumberedPolynomial { + NumberedPolynomialDSL1 { 5 { 1 pow 2u; 3 pow 3u } (-6) { 2 pow 1u } } @@ -34,7 +34,7 @@ class NumberedConstructorsTest { listOf() to -1, ), Int.algebra.numberedPolynomialSpace { - NumberedPolynomial { + NumberedPolynomialDSL1 { 5 { } (-6) { } } @@ -46,7 +46,7 @@ class NumberedConstructorsTest { listOf(2u) to -1, ), Int.algebra.numberedPolynomialSpace { - NumberedPolynomial { + NumberedPolynomialDSL1 { 5 { 1 pow 1u; 1 pow 1u } (-6) { 1 pow 2u } } @@ -58,7 +58,7 @@ class NumberedConstructorsTest { listOf(2u) to -1, ), Int.algebra.numberedPolynomialSpace { - NumberedPolynomial { + NumberedPolynomialDSL1 { 5 { 1 pow 1u; 1 pow 1u } (-6) { 1 pow 2u; 3 pow 0u } } diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt index dac7c1a62..f0a1128b4 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt @@ -14,84 +14,85 @@ import kotlin.test.* @UnstableKMathAPI class NumberedPolynomialTest { + private val o = Rational(0) @Test fun test_Polynomial_Int_plus() { RationalField.numberedPolynomialSpace { assertEquals( - NumberedPolynomial { - Rational(-22, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - NumberedPolynomial { - Rational(5, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } + -3, + NumberedPolynomial( + listOf() to Rational(-22, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), + NumberedPolynomial( + listOf() to Rational(5, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ) + -3, "test 1" ) assertEquals( - NumberedPolynomial { - Rational(-3, 1) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - NumberedPolynomial { - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } + -3, + NumberedPolynomial( + listOf() to Rational(-3, 1), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), + NumberedPolynomial( + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ) + -3, "test 2" ) assertEquals( - NumberedPolynomial { - Rational(0, 1) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - NumberedPolynomial { - Rational(27, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } + -3, + NumberedPolynomial( + listOf() to Rational(0, 1), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), + NumberedPolynomial( + listOf() to Rational(27, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ) + -3, "test 3" ) assertEquals( - NumberedPolynomial { - Rational(0, 1) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - NumberedPolynomial { - Rational(27, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } + -3, + NumberedPolynomial( + listOf() to Rational(0), + listOf(3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + ), + NumberedPolynomial( + listOf() to Rational(27, 9), + listOf(3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + ) + -3, "test 4" ) - val polynomial_5 = NumberedPolynomial { - Rational(-22, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } + val polynomial_5 = NumberedPolynomial( + listOf() to Rational(-22, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ) assertSame( polynomial_5, polynomial_5 + 0, "test 5" ) - val polynomial_6 = NumberedPolynomial { - Rational(0, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } + val polynomial_6 = NumberedPolynomial( + listOf() to Rational(0, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ) assertSame( polynomial_6, polynomial_6 + 0, "test 6" ) - val polynomial_7 = NumberedPolynomial { - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } + val polynomial_7 = NumberedPolynomial( + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ) assertSame( polynomial_7, polynomial_7 + 0, @@ -103,80 +104,80 @@ class NumberedPolynomialTest { fun test_Polynomial_Int_minus() { RationalField.numberedPolynomialSpace { assertEquals( - NumberedPolynomial { - Rational(-22, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - NumberedPolynomial { - Rational(5, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } - 3, + NumberedPolynomial( + listOf() to Rational(-22, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), + NumberedPolynomial( + listOf() to Rational(5, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ) - 3, "test 1" ) assertEquals( - NumberedPolynomial { - Rational(-3, 1) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - NumberedPolynomial { - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } - 3, + NumberedPolynomial( + listOf() to Rational(-3, 1), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), + NumberedPolynomial( + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ) - 3, "test 2" ) assertEquals( - NumberedPolynomial { - Rational(0, 1) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - NumberedPolynomial { - Rational(27, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } - 3, + NumberedPolynomial( + listOf() to Rational(0, 1), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), + NumberedPolynomial( + listOf() to Rational(27, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ) - 3, "test 3" ) assertEquals( - NumberedPolynomial { - Rational(0, 1) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - NumberedPolynomial { - Rational(27, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } - 3, + NumberedPolynomial( + listOf() to Rational(0), + listOf(3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + ), + NumberedPolynomial( + listOf() to Rational(27, 9), + listOf(3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + ) - 3, "test 4" ) - val polynomial_5 = NumberedPolynomial { - Rational(-22, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } + val polynomial_5 = NumberedPolynomial( + listOf() to Rational(-22, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ) assertSame( polynomial_5, polynomial_5 - 0, "test 5" ) - val polynomial_6 = NumberedPolynomial { - Rational(0, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } + val polynomial_6 = NumberedPolynomial( + listOf() to Rational(0, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ) assertSame( polynomial_6, polynomial_6 - 0, "test 6" ) - val polynomial_7 = NumberedPolynomial { - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } + val polynomial_7 = NumberedPolynomial( + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ) assertSame( polynomial_7, polynomial_7 - 0, @@ -188,46 +189,46 @@ class NumberedPolynomialTest { fun test_Polynomial_Int_times() { IntModuloRing(35).numberedPolynomialSpace { assertEquals( - NumberedPolynomial { - m(34) with {} - m(2) with { 1 pow 3u } - m(1) with { 2 pow 1u } - m(20) with { 1 pow 1u } - m(2) with { 3 pow 2u } - }, - NumberedPolynomial { - m(22) with {} - m(26) with { 1 pow 3u } - m(13) with { 2 pow 1u } - m(15) with { 1 pow 1u } - m(26) with { 3 pow 2u } - } * 27, + NumberedPolynomial( + listOf() to m(34), + listOf(3u) to m(2), + listOf(0u, 1u) to m(1), + listOf(1u) to m(20), + listOf(0u, 0u, 2u) to m(2), + ), + NumberedPolynomial( + listOf() to m(22), + listOf(3u) to m(26), + listOf(0u, 1u) to m(13), + listOf(1u) to m(15), + listOf(0u, 0u, 2u) to m(26), + ) * 27, "test 1" ) assertEquals( - NumberedPolynomial { - m(0) with {} - m(0) with { 1 pow 3u } - m(0) with { 2 pow 1u } - m(0) with { 1 pow 1u } - m(0) with { 3 pow 2u } - }, - NumberedPolynomial { - m(7) with {} - m(0) with { 1 pow 3u } - m(49) with { 2 pow 1u } - m(21) with { 1 pow 1u } - m(14) with { 3 pow 2u } - } * 15, + NumberedPolynomial( + listOf() to m(0), + listOf(3u) to m(0), + listOf(0u, 1u) to m(0), + listOf(1u) to m(0), + listOf(0u, 0u, 2u) to m(0), + ), + NumberedPolynomial( + listOf() to m(7), + listOf(3u) to m(0), + listOf(0u, 1u) to m(49), + listOf(1u) to m(21), + listOf(0u, 0u, 2u) to m(14), + ) * 15, "test 2" ) - val polynomial = NumberedPolynomial { - m(22) with {} - m(26) with { 1 pow 3u } - m(13) with { 2 pow 1u } - m(15) with { 1 pow 1u } - m(26) with { 3 pow 2u } - } + val polynomial = NumberedPolynomial( + listOf() to m(22), + listOf(3u) to m(26), + listOf(0u, 1u) to m(13), + listOf(1u) to m(15), + listOf(0u, 0u, 2u) to m(26), + ) assertSame( zero, polynomial * 0, @@ -244,80 +245,80 @@ class NumberedPolynomialTest { fun test_Int_Polynomial_plus() { RationalField.numberedPolynomialSpace { assertEquals( - NumberedPolynomial { - Rational(-22, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - -3 + NumberedPolynomial { - Rational(5, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, + NumberedPolynomial( + listOf() to Rational(-22, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), + -3 + NumberedPolynomial( + listOf() to Rational(5, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), "test 1" ) assertEquals( - NumberedPolynomial { - Rational(-3, 1) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - -3 + NumberedPolynomial { - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, + NumberedPolynomial( + listOf() to Rational(-3, 1), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), + -3 + NumberedPolynomial( + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), "test 2" ) assertEquals( - NumberedPolynomial { - Rational(0, 1) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - -3 + NumberedPolynomial { - Rational(27, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, + NumberedPolynomial( + listOf() to Rational(0), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), + -3 + NumberedPolynomial( + listOf() to Rational(27, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), "test 3" ) assertEquals( - NumberedPolynomial { - Rational(0, 1) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - -3 + NumberedPolynomial { - Rational(27, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, + NumberedPolynomial( + listOf() to Rational(0), + listOf(3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + ), + -3 + NumberedPolynomial( + listOf() to Rational(27, 9), + listOf(3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + ), "test 4" ) - val polynomial_5 = NumberedPolynomial { - Rational(-22, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } + val polynomial_5 = NumberedPolynomial( + listOf() to Rational(-22, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ) assertSame( polynomial_5, 0 + polynomial_5, "test 5" ) - val polynomial_6 = NumberedPolynomial { - Rational(0, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } + val polynomial_6 = NumberedPolynomial( + listOf() to Rational(0, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ) assertSame( polynomial_6, 0 + polynomial_6, "test 6" ) - val polynomial_7 = NumberedPolynomial { - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } + val polynomial_7 = NumberedPolynomial( + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ) assertSame( polynomial_7, 0 + polynomial_7, @@ -329,91 +330,91 @@ class NumberedPolynomialTest { fun test_Int_Polynomial_minus() { RationalField.numberedPolynomialSpace { assertEquals( - NumberedPolynomial { - Rational(22, 9) with {} - Rational(8, 9) with { 1 pow 3u } - Rational(8, 7) with { 2 pow 4u } - }, - 3 - NumberedPolynomial { - Rational(5, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, + NumberedPolynomial( + listOf() to Rational(22, 9), + listOf(3u) to Rational(8, 9), + listOf(0u, 4u) to Rational(8, 7), + ), + 3 - NumberedPolynomial( + listOf() to Rational(5, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), "test 1" ) assertEquals( - NumberedPolynomial { - Rational(3, 1) with {} - Rational(8, 9) with { 1 pow 3u } - Rational(8, 7) with { 2 pow 4u } - }, - 3 - NumberedPolynomial { - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, + NumberedPolynomial( + listOf() to Rational(3, 1), + listOf(3u) to Rational(8, 9), + listOf(0u, 4u) to Rational(8, 7), + ), + 3 - NumberedPolynomial( + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), "test 2" ) assertEquals( - NumberedPolynomial { - Rational(0, 1) with {} - Rational(8, 9) with { 1 pow 3u } - Rational(8, 7) with { 2 pow 4u } - }, - 3 - NumberedPolynomial { - Rational(27, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, + NumberedPolynomial( + listOf() to Rational(0, 1), + listOf(3u) to Rational(8, 9), + listOf(0u, 4u) to Rational(8, 7), + ), + 3 - NumberedPolynomial( + listOf() to Rational(27, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), "test 3" ) assertEquals( - NumberedPolynomial { - Rational(0, 1) with {} - Rational(8, 9) with { 1 pow 3u } - Rational(8, 7) with { 2 pow 4u } - }, - 3 - NumberedPolynomial { - Rational(27, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, + NumberedPolynomial( + listOf() to Rational(0), + listOf(3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + ), + 3 - NumberedPolynomial( + listOf() to Rational(27, 9), + listOf(3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + ), "test 4" ) assertEquals( - NumberedPolynomial { - Rational(22, 9) with {} - Rational(8, 9) with { 1 pow 3u } - Rational(8, 7) with { 2 pow 4u } - }, - 0 - NumberedPolynomial { - Rational(-22, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, + NumberedPolynomial( + listOf() to Rational(22, 9), + listOf(3u) to Rational(8, 9), + listOf(0u, 4u) to Rational(8, 7), + ), + 0 - NumberedPolynomial( + listOf() to Rational(-22, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), "test 5" ) assertEquals( - NumberedPolynomial { - Rational(0, 9) with {} - Rational(8, 9) with { 1 pow 3u } - Rational(8, 7) with { 2 pow 4u } - }, - 0 - NumberedPolynomial { - Rational(0, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, + NumberedPolynomial( + listOf() to Rational(0, 9), + listOf(3u) to Rational(8, 9), + listOf(0u, 4u) to Rational(8, 7), + ), + 0 - NumberedPolynomial( + listOf() to Rational(0, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), "test 6" ) assertEquals( - NumberedPolynomial { - Rational(8, 9) with { 1 pow 3u } - Rational(8, 7) with { 2 pow 4u } - }, - 0 - NumberedPolynomial { - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, + NumberedPolynomial( + listOf(3u) to Rational(8, 9), + listOf(0u, 4u) to Rational(8, 7), + ), + 0 - NumberedPolynomial( + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), "test 7" ) } @@ -422,46 +423,46 @@ class NumberedPolynomialTest { fun test_Int_Polynomial_times() { IntModuloRing(35).numberedPolynomialSpace { assertEquals( - NumberedPolynomial { - m(34) with {} - m(2) with { 1 pow 3u } - m(1) with { 2 pow 1u } - m(20) with { 1 pow 1u } - m(2) with { 3 pow 2u } - }, - 27 * NumberedPolynomial { - m(22) with {} - m(26) with { 1 pow 3u } - m(13) with { 2 pow 1u } - m(15) with { 1 pow 1u } - m(26) with { 3 pow 2u } - }, + NumberedPolynomial( + listOf() to m(34), + listOf(3u) to m(2), + listOf(0u, 1u) to m(1), + listOf(1u) to m(20), + listOf(0u, 0u, 2u) to m(2), + ), + 27 * NumberedPolynomial( + listOf() to m(22), + listOf(3u) to m(26), + listOf(0u, 1u) to m(13), + listOf(1u) to m(15), + listOf(0u, 0u, 2u) to m(26), + ), "test 1" ) assertEquals( - NumberedPolynomial { - m(0) with {} - m(0) with { 1 pow 3u } - m(0) with { 2 pow 1u } - m(0) with { 1 pow 1u } - m(0) with { 3 pow 2u } - }, - 15 * NumberedPolynomial { - m(7) with {} - m(0) with { 1 pow 3u } - m(49) with { 2 pow 1u } - m(21) with { 1 pow 1u } - m(14) with { 3 pow 2u } - }, + NumberedPolynomial( + listOf() to m(0), + listOf(3u) to m(0), + listOf(0u, 1u) to m(0), + listOf(1u) to m(0), + listOf(0u, 0u, 2u) to m(0), + ), + 15 * NumberedPolynomial( + listOf() to m(7), + listOf(3u) to m(0), + listOf(0u, 1u) to m(49), + listOf(1u) to m(21), + listOf(0u, 0u, 2u) to m(14), + ), "test 2" ) - val polynomial = NumberedPolynomial { - m(22) with {} - m(26) with { 1 pow 3u } - m(13) with { 2 pow 1u } - m(15) with { 1 pow 1u } - m(26) with { 3 pow 2u } - } + val polynomial = NumberedPolynomial( + listOf() to m(22), + listOf(3u) to m(26), + listOf(0u, 1u) to m(13), + listOf(1u) to m(15), + listOf(0u, 0u, 2u) to m(26), + ) assertSame( zero, 0 * polynomial, @@ -478,92 +479,91 @@ class NumberedPolynomialTest { fun test_Polynomial_Constant_plus() { RationalField.numberedPolynomialSpace { assertEquals( - NumberedPolynomial { - Rational(-22, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - NumberedPolynomial { - Rational(5, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } + Rational(-3), + NumberedPolynomial( + listOf() to Rational(-22, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), + NumberedPolynomial( + listOf() to Rational(5, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ) + Rational(-3), "test 1" ) assertEquals( - NumberedPolynomial { - Rational(-3, 1) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - NumberedPolynomial { - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } + Rational(-3), + NumberedPolynomial( + listOf() to Rational(-3, 1), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), + NumberedPolynomial( + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ) + Rational(-3), "test 2" ) assertEquals( - NumberedPolynomial { - Rational(0, 1) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - NumberedPolynomial { - Rational(27, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } + Rational(-3), + NumberedPolynomial( + listOf() to Rational(0, 1), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), + NumberedPolynomial( + listOf() to Rational(27, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ) + Rational(-3), "test 3" ) assertEquals( - NumberedPolynomial { - Rational(0, 1) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - NumberedPolynomial { - Rational(27, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } + Rational(-3), + NumberedPolynomial( + listOf() to Rational(0), + listOf(3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + ), + NumberedPolynomial( + listOf() to Rational(27, 9), + listOf(3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + ) + Rational(-3), "test 4" ) assertEquals( - NumberedPolynomial { - Rational(-22, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - NumberedPolynomial { - Rational(-22, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } + Rational(0), + NumberedPolynomial( + listOf() to Rational(-22, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), + NumberedPolynomial( + listOf() to Rational(-22, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ) + Rational(0), "test 5" ) assertEquals( - NumberedPolynomial { - Rational(0, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - NumberedPolynomial { - Rational(0, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } + Rational(0), + NumberedPolynomial( + listOf() to Rational(0, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), + NumberedPolynomial( + listOf() to Rational(0, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ) + Rational(0), "test 6" ) assertEquals( - NumberedPolynomial { - Rational(0) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - NumberedPolynomial { - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } + Rational(0), + NumberedPolynomial( + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), + NumberedPolynomial( + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ) + Rational(0), "test 7" ) } @@ -572,92 +572,91 @@ class NumberedPolynomialTest { fun test_Polynomial_Constant_minus() { RationalField.numberedPolynomialSpace { assertEquals( - NumberedPolynomial { - Rational(-22, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - NumberedPolynomial { - Rational(5, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } - Rational(3), + NumberedPolynomial( + listOf() to Rational(-22, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), + NumberedPolynomial( + listOf() to Rational(5, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ) - Rational(3), "test 1" ) assertEquals( - NumberedPolynomial { - Rational(-3, 1) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - NumberedPolynomial { - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } - Rational(3), + NumberedPolynomial( + listOf() to Rational(-3, 1), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), + NumberedPolynomial( + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ) - Rational(3), "test 2" ) assertEquals( - NumberedPolynomial { - Rational(0, 1) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - NumberedPolynomial { - Rational(27, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } - Rational(3), + NumberedPolynomial( + listOf() to Rational(0, 1), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), + NumberedPolynomial( + listOf() to Rational(27, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ) - Rational(3), "test 3" ) assertEquals( - NumberedPolynomial { - Rational(0, 1) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - NumberedPolynomial { - Rational(27, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } - Rational(3), + NumberedPolynomial( + listOf() to Rational(0), + listOf(3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + ), + NumberedPolynomial( + listOf() to Rational(27, 9), + listOf(3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + ) - Rational(3), "test 4" ) assertEquals( - NumberedPolynomial { - Rational(-22, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - NumberedPolynomial { - Rational(-22, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } - Rational(0), + NumberedPolynomial( + listOf() to Rational(-22, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), + NumberedPolynomial( + listOf() to Rational(-22, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ) - Rational(0), "test 5" ) assertEquals( - NumberedPolynomial { - Rational(0, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - NumberedPolynomial { - Rational(0, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } - Rational(0), + NumberedPolynomial( + listOf() to Rational(0, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), + NumberedPolynomial( + listOf() to Rational(0, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ) - Rational(0), "test 6" ) assertEquals( - NumberedPolynomial { - Rational(0) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - NumberedPolynomial { - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } - Rational(0), + NumberedPolynomial( + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), + NumberedPolynomial( + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ) - Rational(0), "test 7" ) } @@ -666,71 +665,71 @@ class NumberedPolynomialTest { fun test_Polynomial_Constant_times() { IntModuloRing(35).numberedPolynomialSpace { assertEquals( - NumberedPolynomial { - m(34) with {} - m(2) with { 1 pow 3u } - m(1) with { 2 pow 1u } - m(20) with { 1 pow 1u } - m(2) with { 3 pow 2u } - }, - NumberedPolynomial { - m(22) with {} - m(26) with { 1 pow 3u } - m(13) with { 2 pow 1u } - m(15) with { 1 pow 1u } - m(26) with { 3 pow 2u } - } * m(27), + NumberedPolynomial( + listOf() to m(34), + listOf(3u) to m(2), + listOf(0u, 1u) to m(1), + listOf(1u) to m(20), + listOf(0u, 0u, 2u) to m(2), + ), + NumberedPolynomial( + listOf() to m(22), + listOf(3u) to m(26), + listOf(0u, 1u) to m(13), + listOf(1u) to m(15), + listOf(0u, 0u, 2u) to m(26), + ) * m(27), "test 1" ) assertEquals( - NumberedPolynomial { - m(0) with {} - m(0) with { 1 pow 3u } - m(0) with { 2 pow 1u } - m(0) with { 1 pow 1u } - m(0) with { 3 pow 2u } - }, - NumberedPolynomial { - m(7) with {} - m(0) with { 1 pow 3u } - m(49) with { 2 pow 1u } - m(21) with { 1 pow 1u } - m(14) with { 3 pow 2u } - } * m(15), + NumberedPolynomial( + listOf() to m(0), + listOf(3u) to m(0), + listOf(0u, 1u) to m(0), + listOf(1u) to m(0), + listOf(0u, 0u, 2u) to m(0), + ), + NumberedPolynomial( + listOf() to m(7), + listOf(3u) to m(0), + listOf(0u, 1u) to m(49), + listOf(1u) to m(21), + listOf(0u, 0u, 2u) to m(14), + ) * m(15), "test 2" ) assertEquals( - NumberedPolynomial { - m(0) with {} - m(0) with { 1 pow 3u } - m(0) with { 2 pow 1u } - m(0) with { 1 pow 1u } - m(0) with { 3 pow 2u } - }, - NumberedPolynomial { - m(22) with {} - m(26) with { 1 pow 3u } - m(13) with { 2 pow 1u } - m(15) with { 1 pow 1u } - m(26) with { 3 pow 2u } - } * m(0), + NumberedPolynomial( + listOf() to m(0), + listOf(3u) to m(0), + listOf(0u, 1u) to m(0), + listOf(1u) to m(0), + listOf(0u, 0u, 2u) to m(0), + ), + NumberedPolynomial( + listOf() to m(22), + listOf(3u) to m(26), + listOf(0u, 1u) to m(13), + listOf(1u) to m(15), + listOf(0u, 0u, 2u) to m(26), + ) * m(0), "test 3" ) assertEquals( - NumberedPolynomial { - m(22) with {} - m(26) with { 1 pow 3u } - m(13) with { 2 pow 1u } - m(15) with { 1 pow 1u } - m(26) with { 3 pow 2u } - }, - NumberedPolynomial { - m(22) with {} - m(26) with { 1 pow 3u } - m(13) with { 2 pow 1u } - m(15) with { 1 pow 1u } - m(26) with { 3 pow 2u } - } * m(1), + NumberedPolynomial( + listOf() to m(22), + listOf(3u) to m(26), + listOf(0u, 1u) to m(13), + listOf(1u) to m(15), + listOf(0u, 0u, 2u) to m(26), + ), + NumberedPolynomial( + listOf() to m(22), + listOf(3u) to m(26), + listOf(0u, 1u) to m(13), + listOf(1u) to m(15), + listOf(0u, 0u, 2u) to m(26), + ) * m(1), "test 4" ) } @@ -739,92 +738,91 @@ class NumberedPolynomialTest { fun test_Constant_Polynomial_plus() { RationalField.numberedPolynomialSpace { assertEquals( - NumberedPolynomial { - Rational(-22, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - Rational(-3) + NumberedPolynomial { - Rational(5, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, + NumberedPolynomial( + listOf() to Rational(-22, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), + Rational(-3) + NumberedPolynomial( + listOf() to Rational(5, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), "test 1" ) assertEquals( - NumberedPolynomial { - Rational(-3, 1) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - Rational(-3) + NumberedPolynomial { - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, + NumberedPolynomial( + listOf() to Rational(-3, 1), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), + Rational(-3) + NumberedPolynomial( + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), "test 2" ) assertEquals( - NumberedPolynomial { - Rational(0, 1) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - Rational(-3) + NumberedPolynomial { - Rational(27, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, + NumberedPolynomial( + listOf() to Rational(0, 1), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), + Rational(-3) + NumberedPolynomial( + listOf() to Rational(27, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), "test 3" ) assertEquals( - NumberedPolynomial { - Rational(0, 1) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - Rational(-3) + NumberedPolynomial { - Rational(27, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, + NumberedPolynomial( + listOf() to Rational(0), + listOf(3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + ), + Rational(-3) + NumberedPolynomial( + listOf() to Rational(27, 9), + listOf(3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + ), "test 4" ) assertEquals( - NumberedPolynomial { - Rational(-22, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - Rational(0) + NumberedPolynomial { - Rational(-22, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, + NumberedPolynomial( + listOf() to Rational(-22, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), + Rational(0) + NumberedPolynomial( + listOf() to Rational(-22, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), "test 5" ) assertEquals( - NumberedPolynomial { - Rational(0, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - Rational(0) + NumberedPolynomial { - Rational(0, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, + NumberedPolynomial( + listOf() to Rational(0, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), + Rational(0) + NumberedPolynomial( + listOf() to Rational(0, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), "test 6" ) assertEquals( - NumberedPolynomial { - Rational(0) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - Rational(0) + NumberedPolynomial { - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, + NumberedPolynomial( + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), + Rational(0) + NumberedPolynomial( + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), "test 7" ) } @@ -833,92 +831,92 @@ class NumberedPolynomialTest { fun test_Constant_Polynomial_minus() { RationalField.numberedPolynomialSpace { assertEquals( - NumberedPolynomial { - Rational(22, 9) with {} - Rational(8, 9) with { 1 pow 3u } - Rational(8, 7) with { 2 pow 4u } - }, - Rational(3) - NumberedPolynomial { - Rational(5, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, + NumberedPolynomial( + listOf() to Rational(22, 9), + listOf(3u) to Rational(8, 9), + listOf(0u, 4u) to Rational(8, 7), + ), + Rational(3) - NumberedPolynomial( + listOf() to Rational(5, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), "test 1" ) assertEquals( - NumberedPolynomial { - Rational(3, 1) with {} - Rational(8, 9) with { 1 pow 3u } - Rational(8, 7) with { 2 pow 4u } - }, - Rational(3) - NumberedPolynomial { - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, + NumberedPolynomial( + listOf() to Rational(3, 1), + listOf(3u) to Rational(8, 9), + listOf(0u, 4u) to Rational(8, 7), + ), + Rational(3) - NumberedPolynomial( + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), "test 2" ) assertEquals( - NumberedPolynomial { - Rational(0, 1) with {} - Rational(8, 9) with { 1 pow 3u } - Rational(8, 7) with { 2 pow 4u } - }, - Rational(3) - NumberedPolynomial { - Rational(27, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, + NumberedPolynomial( + listOf() to Rational(0, 1), + listOf(3u) to Rational(8, 9), + listOf(0u, 4u) to Rational(8, 7), + ), + Rational(3) - NumberedPolynomial( + listOf() to Rational(27, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), "test 3" ) assertEquals( - NumberedPolynomial { - Rational(0, 1) with {} - Rational(8, 9) with { 1 pow 3u } - Rational(8, 7) with { 2 pow 4u } - }, - Rational(3) - NumberedPolynomial { - Rational(27, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, + NumberedPolynomial( + listOf() to Rational(0), + listOf(3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + ), + Rational(3) - NumberedPolynomial( + listOf() to Rational(27, 9), + listOf(3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + ), "test 4" ) assertEquals( - NumberedPolynomial { - Rational(22, 9) with {} - Rational(8, 9) with { 1 pow 3u } - Rational(8, 7) with { 2 pow 4u } - }, - Rational(0) - NumberedPolynomial { - Rational(-22, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, + NumberedPolynomial( + listOf() to Rational(22, 9), + listOf(3u) to Rational(8, 9), + listOf(0u, 4u) to Rational(8, 7), + ), + Rational(0) - NumberedPolynomial( + listOf() to Rational(-22, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), "test 5" ) assertEquals( - NumberedPolynomial { - Rational(0, 9) with {} - Rational(8, 9) with { 1 pow 3u } - Rational(8, 7) with { 2 pow 4u } - }, - Rational(0) - NumberedPolynomial { - Rational(0, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, + NumberedPolynomial( + listOf() to Rational(0, 9), + listOf(3u) to Rational(8, 9), + listOf(0u, 4u) to Rational(8, 7), + ), + Rational(0) - NumberedPolynomial( + listOf() to Rational(0, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), "test 6" ) assertEquals( - NumberedPolynomial { - Rational(0) with {} - Rational(8, 9) with { 1 pow 3u } - Rational(8, 7) with { 2 pow 4u } - }, - Rational(0) - NumberedPolynomial { - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, + NumberedPolynomial( + listOf() to Rational(0), + listOf(3u) to Rational(8, 9), + listOf(0u, 4u) to Rational(8, 7), + ), + Rational(0) - NumberedPolynomial( + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), "test 7" ) } @@ -927,71 +925,71 @@ class NumberedPolynomialTest { fun test_Constant_Polynomial_times() { IntModuloRing(35).numberedPolynomialSpace { assertEquals( - NumberedPolynomial { - m(34) with {} - m(2) with { 1 pow 3u } - m(1) with { 2 pow 1u } - m(20) with { 1 pow 1u } - m(2) with { 3 pow 2u } - }, - m(27) * NumberedPolynomial { - m(22) with {} - m(26) with { 1 pow 3u } - m(13) with { 2 pow 1u } - m(15) with { 1 pow 1u } - m(26) with { 3 pow 2u } - }, + NumberedPolynomial( + listOf() to m(34), + listOf(3u) to m(2), + listOf(0u, 1u) to m(1), + listOf(1u) to m(20), + listOf(0u, 0u, 2u) to m(2), + ), + m(27) * NumberedPolynomial( + listOf() to m(22), + listOf(3u) to m(26), + listOf(0u, 1u) to m(13), + listOf(1u) to m(15), + listOf(0u, 0u, 2u) to m(26), + ), "test 1" ) assertEquals( - NumberedPolynomial { - m(0) with {} - m(0) with { 1 pow 3u } - m(0) with { 2 pow 1u } - m(0) with { 1 pow 1u } - m(0) with { 3 pow 2u } - }, - m(15) * NumberedPolynomial { - m(7) with {} - m(0) with { 1 pow 3u } - m(49) with { 2 pow 1u } - m(21) with { 1 pow 1u } - m(14) with { 3 pow 2u } - }, + NumberedPolynomial( + listOf() to m(0), + listOf(3u) to m(0), + listOf(0u, 1u) to m(0), + listOf(1u) to m(0), + listOf(0u, 0u, 2u) to m(0), + ), + m(15) * NumberedPolynomial( + listOf() to m(7), + listOf(3u) to m(0), + listOf(0u, 1u) to m(49), + listOf(1u) to m(21), + listOf(0u, 0u, 2u) to m(14), + ), "test 2" ) assertEquals( - NumberedPolynomial { - m(0) with {} - m(0) with { 1 pow 3u } - m(0) with { 2 pow 1u } - m(0) with { 1 pow 1u } - m(0) with { 3 pow 2u } - }, - m(0) * NumberedPolynomial { - m(22) with {} - m(26) with { 1 pow 3u } - m(13) with { 2 pow 1u } - m(15) with { 1 pow 1u } - m(26) with { 3 pow 2u } - }, + NumberedPolynomial( + listOf() to m(0), + listOf(3u) to m(0), + listOf(0u, 1u) to m(0), + listOf(1u) to m(0), + listOf(0u, 0u, 2u) to m(0), + ), + m(0) * NumberedPolynomial( + listOf() to m(22), + listOf(3u) to m(26), + listOf(0u, 1u) to m(13), + listOf(1u) to m(15), + listOf(0u, 0u, 2u) to m(26), + ), "test 3" ) assertEquals( - NumberedPolynomial { - m(22) with {} - m(26) with { 1 pow 3u } - m(13) with { 2 pow 1u } - m(15) with { 1 pow 1u } - m(26) with { 3 pow 2u } - }, - m(1) * NumberedPolynomial { - m(22) with {} - m(26) with { 1 pow 3u } - m(13) with { 2 pow 1u } - m(15) with { 1 pow 1u } - m(26) with { 3 pow 2u } - }, + NumberedPolynomial( + listOf() to m(22), + listOf(3u) to m(26), + listOf(0u, 1u) to m(13), + listOf(1u) to m(15), + listOf(0u, 0u, 2u) to m(26), + ), + m(1) * NumberedPolynomial( + listOf() to m(22), + listOf(3u) to m(26), + listOf(0u, 1u) to m(13), + listOf(1u) to m(15), + listOf(0u, 0u, 2u) to m(26), + ), "test 4" ) } @@ -1000,33 +998,33 @@ class NumberedPolynomialTest { fun test_Polynomial_unaryMinus() { RationalField.numberedPolynomialSpace { assertEquals( - NumberedPolynomial { - Rational(-5, 9) with { 1 pow 5u } - Rational(8, 9) with {} - Rational(8, 7) with { 7 pow 13u } - }, - -NumberedPolynomial { - Rational(5, 9) with { 1 pow 5u } - Rational(-8, 9) with {} - Rational(-8, 7) with { 7 pow 13u } - }, + NumberedPolynomial( + listOf(5u) to Rational(-5, 9), + listOf() to Rational(8, 9), + listOf(0u, 0u, 0u, 0u, 0u, 0u, 13u) to Rational(8, 7), + ), + -NumberedPolynomial( + listOf(5u) to Rational(5, 9), + listOf() to Rational(-8, 9), + listOf(0u, 0u, 0u, 0u, 0u, 0u, 13u) to Rational(-8, 7), + ), "test 1" ) assertEquals( - NumberedPolynomial { - Rational(-5, 9) with { 3 pow 7u } - Rational(8, 9) with {} - Rational(8, 7) with { 1 pow 3u } - Rational(0) with { 2 pow 4u } - Rational(0) with { 1 pow 5u } - }, - -NumberedPolynomial { - Rational(5, 9) with { 3 pow 7u } - Rational(-8, 9) with {} - Rational(-8, 7) with { 1 pow 3u } - Rational(0) with { 2 pow 4u } - Rational(0) with { 1 pow 5u } - }, + NumberedPolynomial( + listOf(5u) to Rational(-5, 9), + listOf() to Rational(8, 9), + listOf(0u, 0u, 0u, 0u, 0u, 0u, 13u) to Rational(8, 7), + listOf(0u, 4u) to Rational(0), + listOf(5u) to Rational(0), + ), + -NumberedPolynomial( + listOf(5u) to Rational(5, 9), + listOf() to Rational(-8, 9), + listOf(0u, 0u, 0u, 0u, 0u, 0u, 13u) to Rational(-8, 7), + listOf(0u, 4u) to Rational(0), + listOf(5u) to Rational(0), + ), "test 2" ) } @@ -1035,137 +1033,137 @@ class NumberedPolynomialTest { fun test_Polynomial_Polynomial_plus() { RationalField.numberedPolynomialSpace { assertEquals( - NumberedPolynomial { - Rational(-17, 2) with {} - Rational(-1, 3) with { 1 pow 1u } - Rational(-25, 21) with { 1 pow 2u } - Rational(146, 63) with { 2 pow 1u } - Rational(-3, 5) with { 1 pow 1u; 2 pow 1u } - Rational(61, 15) with { 1 pow 2u; 2 pow 1u } - Rational(157, 63) with { 2 pow 2u } - Rational(-55, 21) with { 1 pow 1u; 2 pow 2u } - Rational(11, 24) with { 1 pow 2u; 2 pow 2u } - }, - NumberedPolynomial { - Rational(6, 4) with {} - Rational(-2, 6) with { 1 pow 1u } - Rational(10, 6) with { 1 pow 2u } - Rational(17, 7) with { 2 pow 1u } - Rational(-7, 7) with { 1 pow 1u; 2 pow 1u } - Rational(12, 5) with { 1 pow 2u; 2 pow 1u } - Rational(12, 7) with { 2 pow 2u } - Rational(-10, 3) with { 1 pow 1u; 2 pow 2u } - Rational(9, 8) with { 1 pow 2u; 2 pow 2u } - } + NumberedPolynomial { - Rational(-20, 2) with {} - Rational(0, 9) with { 1 pow 1u } - Rational(-20, 7) with { 1 pow 2u } - Rational(-1, 9) with { 2 pow 1u } - Rational(2, 5) with { 1 pow 1u; 2 pow 1u } - Rational(10, 6) with { 1 pow 2u; 2 pow 1u } - Rational(7, 9) with { 2 pow 2u } - Rational(5, 7) with { 1 pow 1u; 2 pow 2u } - Rational(-2, 3) with { 1 pow 2u; 2 pow 2u } - }, + NumberedPolynomial( + listOf() to Rational(-17, 2), + listOf(1u) to Rational(-1, 3), + listOf(2u) to Rational(-25, 21), + listOf(0u, 1u) to Rational(146, 63), + listOf(1u, 1u) to Rational(-3, 5), + listOf(2u, 1u) to Rational(61, 15), + listOf(0u, 2u) to Rational(157, 63), + listOf(1u, 2u) to Rational(-55, 21), + listOf(2u, 2u) to Rational(11, 24), + ), + NumberedPolynomial( + listOf() to Rational(6, 4), + listOf(1u) to Rational(-2, 6), + listOf(2u) to Rational(10, 6), + listOf(0u, 1u) to Rational(17, 7), + listOf(1u, 1u) to Rational(-7, 7), + listOf(2u, 1u) to Rational(12, 5), + listOf(0u, 2u) to Rational(12, 7), + listOf(1u, 2u) to Rational(-10, 3), + listOf(2u, 2u) to Rational(9, 8), + ) + NumberedPolynomial( + listOf() to Rational(-20, 2), + listOf(1u) to Rational(0, 9), + listOf(2u) to Rational(-20, 7), + listOf(0u, 1u) to Rational(-1, 9), + listOf(1u, 1u) to Rational(2, 5), + listOf(2u, 1u) to Rational(10, 6), + listOf(0u, 2u) to Rational(7, 9), + listOf(1u, 2u) to Rational(5, 7), + listOf(2u, 2u) to Rational(-2, 3), + ), "test 1" ) assertEquals( - NumberedPolynomial { - Rational(-17, 2) with {} - Rational(-1, 3) with { 1 pow 1u } - Rational(-25, 21) with { 1 pow 2u } - Rational(-1, 9) with { 2 pow 1u } - Rational(2, 5) with { 1 pow 1u; 2 pow 1u } - Rational(10, 6) with { 1 pow 2u; 2 pow 1u } - Rational(157, 63) with { 2 pow 2u } - Rational(-55, 21) with { 1 pow 1u; 2 pow 2u } - Rational(11, 24) with { 1 pow 2u; 2 pow 2u } - }, - NumberedPolynomial { - Rational(6, 4) with {} - Rational(-2, 6) with { 1 pow 1u } - Rational(10, 6) with { 1 pow 2u } - Rational(12, 7) with { 2 pow 2u } - Rational(-10, 3) with { 1 pow 1u; 2 pow 2u } - Rational(9, 8) with { 1 pow 2u; 2 pow 2u } - } + NumberedPolynomial { - Rational(-20, 2) with {} - Rational(0, 9) with { 1 pow 1u } - Rational(-20, 7) with { 1 pow 2u } - Rational(-1, 9) with { 2 pow 1u } - Rational(2, 5) with { 1 pow 1u; 2 pow 1u } - Rational(10, 6) with { 1 pow 2u; 2 pow 1u } - Rational(7, 9) with { 2 pow 2u } - Rational(5, 7) with { 1 pow 1u; 2 pow 2u } - Rational(-2, 3) with { 1 pow 2u; 2 pow 2u } - }, + NumberedPolynomial( + listOf() to Rational(-17, 2), + listOf(1u) to Rational(-1, 3), + listOf(2u) to Rational(-25, 21), + listOf(0u, 1u) to Rational(-1, 9), + listOf(1u, 1u) to Rational(2, 5), + listOf(2u, 1u) to Rational(10, 6), + listOf(0u, 2u) to Rational(157, 63), + listOf(1u, 2u) to Rational(-55, 21), + listOf(2u, 2u) to Rational(11, 24), + ), + NumberedPolynomial( + listOf() to Rational(6, 4), + listOf(1u) to Rational(-2, 6), + listOf(2u) to Rational(10, 6), + listOf(0u, 2u) to Rational(12, 7), + listOf(1u, 2u) to Rational(-10, 3), + listOf(2u, 2u) to Rational(9, 8), + ) + NumberedPolynomial( + listOf() to Rational(-20, 2), + listOf(1u) to Rational(0, 9), + listOf(2u) to Rational(-20, 7), + listOf(0u, 1u) to Rational(-1, 9), + listOf(1u, 1u) to Rational(2, 5), + listOf(2u, 1u) to Rational(10, 6), + listOf(0u, 2u) to Rational(7, 9), + listOf(1u, 2u) to Rational(5, 7), + listOf(2u, 2u) to Rational(-2, 3), + ), "test 2" ) assertEquals( - NumberedPolynomial { - Rational(-17, 2) with {} - Rational(-1, 3) with { 1 pow 1u } - Rational(-25, 21) with { 1 pow 2u } - Rational(-1, 9) with { 2 pow 1u } - Rational(2, 5) with { 1 pow 1u; 2 pow 1u } - Rational(10, 6) with { 1 pow 2u; 2 pow 1u } - Rational(12, 7) with { 2 pow 2u } - Rational(-10, 3) with { 1 pow 1u; 2 pow 2u } - Rational(9, 8) with { 1 pow 2u; 2 pow 2u } - }, - NumberedPolynomial { - Rational(6, 4) with {} - Rational(-2, 6) with { 1 pow 1u } - Rational(10, 6) with { 1 pow 2u } - Rational(12, 7) with { 2 pow 2u } - Rational(-10, 3) with { 1 pow 1u; 2 pow 2u } - Rational(9, 8) with { 1 pow 2u; 2 pow 2u } - } + NumberedPolynomial { - Rational(-20, 2) with {} - Rational(0, 9) with { 1 pow 1u } - Rational(-20, 7) with { 1 pow 2u } - Rational(-1, 9) with { 2 pow 1u } - Rational(2, 5) with { 1 pow 1u; 2 pow 1u } - Rational(10, 6) with { 1 pow 2u; 2 pow 1u } - Rational(0) with { 2 pow 2u } - Rational(0) with { 1 pow 1u; 2 pow 2u } - Rational(0) with { 1 pow 2u; 2 pow 2u } - }, + NumberedPolynomial( + listOf() to Rational(-17, 2), + listOf(1u) to Rational(-1, 3), + listOf(2u) to Rational(-25, 21), + listOf(0u, 1u) to Rational(-1, 9), + listOf(1u, 1u) to Rational(2, 5), + listOf(2u, 1u) to Rational(10, 6), + listOf(0u, 2u) to Rational(12, 7), + listOf(1u, 2u) to Rational(-10, 3), + listOf(2u, 2u) to Rational(9, 8), + ), + NumberedPolynomial( + listOf() to Rational(6, 4), + listOf(1u) to Rational(-2, 6), + listOf(2u) to Rational(10, 6), + listOf(0u, 2u) to Rational(12, 7), + listOf(1u, 2u) to Rational(-10, 3), + listOf(2u, 2u) to Rational(9, 8), + ) + NumberedPolynomial( + listOf() to Rational(-20, 2), + listOf(1u) to Rational(0, 9), + listOf(2u) to Rational(-20, 7), + listOf(0u, 1u) to Rational(-1, 9), + listOf(1u, 1u) to Rational(2, 5), + listOf(2u, 1u) to Rational(10, 6), + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(0), + ), "test 3" ) assertEquals( - NumberedPolynomial { - Rational(0) with {} - Rational(0) with { 1 pow 1u } - Rational(0) with { 1 pow 2u } - Rational(0) with { 2 pow 1u } - Rational(0) with { 1 pow 1u; 2 pow 1u } - Rational(0) with { 1 pow 2u; 2 pow 1u } - Rational(0) with { 2 pow 2u } - Rational(0) with { 1 pow 1u; 2 pow 2u } - Rational(0) with { 1 pow 2u; 2 pow 2u } - }, - NumberedPolynomial { - Rational(6, 4) with {} - Rational(-2, 6) with { 1 pow 1u } - Rational(10, 6) with { 1 pow 2u } - Rational(17, 7) with { 2 pow 1u } - Rational(-7, 7) with { 1 pow 1u; 2 pow 1u } - Rational(12, 5) with { 1 pow 2u; 2 pow 1u } - Rational(12, 7) with { 2 pow 2u } - Rational(-10, 3) with { 1 pow 1u; 2 pow 2u } - Rational(9, 8) with { 1 pow 2u; 2 pow 2u } - } + NumberedPolynomial { - Rational(-6, 4) with {} - Rational(2, 6) with { 1 pow 1u } - Rational(-10, 6) with { 1 pow 2u } - Rational(-17, 7) with { 2 pow 1u } - Rational(7, 7) with { 1 pow 1u; 2 pow 1u } - Rational(-12, 5) with { 1 pow 2u; 2 pow 1u } - Rational(-12, 7) with { 2 pow 2u } - Rational(10, 3) with { 1 pow 1u; 2 pow 2u } - Rational(-9, 8) with { 1 pow 2u; 2 pow 2u } - }, + NumberedPolynomial( + listOf() to Rational(0), + listOf(1u) to Rational(0), + listOf(2u) to Rational(0), + listOf(0u, 1u) to Rational(0), + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(0), + ), + NumberedPolynomial( + listOf() to Rational(6, 4), + listOf(1u) to Rational(-2, 6), + listOf(2u) to Rational(10, 6), + listOf(0u, 1u) to Rational(17, 7), + listOf(1u, 1u) to Rational(-7, 7), + listOf(2u, 1u) to Rational(12, 5), + listOf(0u, 2u) to Rational(12, 7), + listOf(1u, 2u) to Rational(-10, 3), + listOf(2u, 2u) to Rational(9, 8), + ) + NumberedPolynomial( + listOf() to Rational(-6, 4), + listOf(1u) to Rational(2, 6), + listOf(2u) to Rational(-10, 6), + listOf(0u, 1u) to Rational(-17, 7), + listOf(1u, 1u) to Rational(7, 7), + listOf(2u, 1u) to Rational(-12, 5), + listOf(0u, 2u) to Rational(-12, 7), + listOf(1u, 2u) to Rational(10, 3), + listOf(2u, 2u) to Rational(-9, 8), + ), "test 4" ) } @@ -1174,137 +1172,137 @@ class NumberedPolynomialTest { fun test_Polynomial_Polynomial_minus() { RationalField.numberedPolynomialSpace { assertEquals( - NumberedPolynomial { - Rational(-17, 2) with {} - Rational(-1, 3) with { 1 pow 1u } - Rational(-25, 21) with { 1 pow 2u } - Rational(146, 63) with { 2 pow 1u } - Rational(-3, 5) with { 1 pow 1u; 2 pow 1u } - Rational(61, 15) with { 1 pow 2u; 2 pow 1u } - Rational(157, 63) with { 2 pow 2u } - Rational(-55, 21) with { 1 pow 1u; 2 pow 2u } - Rational(11, 24) with { 1 pow 2u; 2 pow 2u } - }, - NumberedPolynomial { - Rational(6, 4) with {} - Rational(-2, 6) with { 1 pow 1u } - Rational(10, 6) with { 1 pow 2u } - Rational(17, 7) with { 2 pow 1u } - Rational(-7, 7) with { 1 pow 1u; 2 pow 1u } - Rational(12, 5) with { 1 pow 2u; 2 pow 1u } - Rational(12, 7) with { 2 pow 2u } - Rational(-10, 3) with { 1 pow 1u; 2 pow 2u } - Rational(9, 8) with { 1 pow 2u; 2 pow 2u } - } - NumberedPolynomial { - Rational(20, 2) with {} - Rational(0, 9) with { 1 pow 1u } - Rational(20, 7) with { 1 pow 2u } - Rational(1, 9) with { 2 pow 1u } - Rational(-2, 5) with { 1 pow 1u; 2 pow 1u } - Rational(-10, 6) with { 1 pow 2u; 2 pow 1u } - Rational(-7, 9) with { 2 pow 2u } - Rational(-5, 7) with { 1 pow 1u; 2 pow 2u } - Rational(2, 3) with { 1 pow 2u; 2 pow 2u } - }, + NumberedPolynomial( + listOf() to Rational(-17, 2), + listOf(1u) to Rational(-1, 3), + listOf(2u) to Rational(-25, 21), + listOf(0u, 1u) to Rational(146, 63), + listOf(1u, 1u) to Rational(-3, 5), + listOf(2u, 1u) to Rational(61, 15), + listOf(0u, 2u) to Rational(157, 63), + listOf(1u, 2u) to Rational(-55, 21), + listOf(2u, 2u) to Rational(11, 24), + ), + NumberedPolynomial( + listOf() to Rational(6, 4), + listOf(1u) to Rational(-2, 6), + listOf(2u) to Rational(10, 6), + listOf(0u, 1u) to Rational(17, 7), + listOf(1u, 1u) to Rational(-7, 7), + listOf(2u, 1u) to Rational(12, 5), + listOf(0u, 2u) to Rational(12, 7), + listOf(1u, 2u) to Rational(-10, 3), + listOf(2u, 2u) to Rational(9, 8), + ) - NumberedPolynomial( + listOf() to Rational(20, 2), + listOf(1u) to Rational(0, 9), + listOf(2u) to Rational(20, 7), + listOf(0u, 1u) to Rational(1, 9), + listOf(1u, 1u) to Rational(-2, 5), + listOf(2u, 1u) to Rational(-10, 6), + listOf(0u, 2u) to Rational(-7, 9), + listOf(1u, 2u) to Rational(-5, 7), + listOf(2u, 2u) to Rational(2, 3), + ), "test 1" ) assertEquals( - NumberedPolynomial { - Rational(-17, 2) with {} - Rational(-1, 3) with { 1 pow 1u } - Rational(-25, 21) with { 1 pow 2u } - Rational(-1, 9) with { 2 pow 1u } - Rational(2, 5) with { 1 pow 1u; 2 pow 1u } - Rational(10, 6) with { 1 pow 2u; 2 pow 1u } - Rational(157, 63) with { 2 pow 2u } - Rational(-55, 21) with { 1 pow 1u; 2 pow 2u } - Rational(11, 24) with { 1 pow 2u; 2 pow 2u } - }, - NumberedPolynomial { - Rational(6, 4) with {} - Rational(-2, 6) with { 1 pow 1u } - Rational(10, 6) with { 1 pow 2u } - Rational(12, 7) with { 2 pow 2u } - Rational(-10, 3) with { 1 pow 1u; 2 pow 2u } - Rational(9, 8) with { 1 pow 2u; 2 pow 2u } - } - NumberedPolynomial { - Rational(20, 2) with {} - Rational(0, 9) with { 1 pow 1u } - Rational(20, 7) with { 1 pow 2u } - Rational(1, 9) with { 2 pow 1u } - Rational(-2, 5) with { 1 pow 1u; 2 pow 1u } - Rational(-10, 6) with { 1 pow 2u; 2 pow 1u } - Rational(-7, 9) with { 2 pow 2u } - Rational(-5, 7) with { 1 pow 1u; 2 pow 2u } - Rational(2, 3) with { 1 pow 2u; 2 pow 2u } - }, + NumberedPolynomial( + listOf() to Rational(-17, 2), + listOf(1u) to Rational(-1, 3), + listOf(2u) to Rational(-25, 21), + listOf(0u, 1u) to Rational(-1, 9), + listOf(1u, 1u) to Rational(2, 5), + listOf(2u, 1u) to Rational(10, 6), + listOf(0u, 2u) to Rational(157, 63), + listOf(1u, 2u) to Rational(-55, 21), + listOf(2u, 2u) to Rational(11, 24), + ), + NumberedPolynomial( + listOf() to Rational(6, 4), + listOf(1u) to Rational(-2, 6), + listOf(2u) to Rational(10, 6), + listOf(0u, 2u) to Rational(12, 7), + listOf(1u, 2u) to Rational(-10, 3), + listOf(2u, 2u) to Rational(9, 8), + ) - NumberedPolynomial( + listOf() to Rational(20, 2), + listOf(1u) to Rational(0, 9), + listOf(2u) to Rational(20, 7), + listOf(0u, 1u) to Rational(1, 9), + listOf(1u, 1u) to Rational(-2, 5), + listOf(2u, 1u) to Rational(-10, 6), + listOf(0u, 2u) to Rational(-7, 9), + listOf(1u, 2u) to Rational(-5, 7), + listOf(2u, 2u) to Rational(2, 3), + ), "test 2" ) assertEquals( - NumberedPolynomial { - Rational(-17, 2) with {} - Rational(-1, 3) with { 1 pow 1u } - Rational(-25, 21) with { 1 pow 2u } - Rational(-1, 9) with { 2 pow 1u } - Rational(2, 5) with { 1 pow 1u; 2 pow 1u } - Rational(10, 6) with { 1 pow 2u; 2 pow 1u } - Rational(12, 7) with { 2 pow 2u } - Rational(-10, 3) with { 1 pow 1u; 2 pow 2u } - Rational(9, 8) with { 1 pow 2u; 2 pow 2u } - }, - NumberedPolynomial { - Rational(6, 4) with {} - Rational(-2, 6) with { 1 pow 1u } - Rational(10, 6) with { 1 pow 2u } - Rational(12, 7) with { 2 pow 2u } - Rational(-10, 3) with { 1 pow 1u; 2 pow 2u } - Rational(9, 8) with { 1 pow 2u; 2 pow 2u } - } - NumberedPolynomial { - Rational(20, 2) with {} - Rational(0, 9) with { 1 pow 1u } - Rational(20, 7) with { 1 pow 2u } - Rational(1, 9) with { 2 pow 1u } - Rational(-2, 5) with { 1 pow 1u; 2 pow 1u } - Rational(-10, 6) with { 1 pow 2u; 2 pow 1u } - Rational(0) with { 2 pow 2u } - Rational(0) with { 1 pow 1u; 2 pow 2u } - Rational(0) with { 1 pow 2u; 2 pow 2u } - }, + NumberedPolynomial( + listOf() to Rational(-17, 2), + listOf(1u) to Rational(-1, 3), + listOf(2u) to Rational(-25, 21), + listOf(0u, 1u) to Rational(-1, 9), + listOf(1u, 1u) to Rational(2, 5), + listOf(2u, 1u) to Rational(10, 6), + listOf(0u, 2u) to Rational(12, 7), + listOf(1u, 2u) to Rational(-10, 3), + listOf(2u, 2u) to Rational(9, 8), + ), + NumberedPolynomial( + listOf() to Rational(6, 4), + listOf(1u) to Rational(-2, 6), + listOf(2u) to Rational(10, 6), + listOf(0u, 2u) to Rational(12, 7), + listOf(1u, 2u) to Rational(-10, 3), + listOf(2u, 2u) to Rational(9, 8), + ) - NumberedPolynomial( + listOf() to Rational(20, 2), + listOf(1u) to Rational(0, 9), + listOf(2u) to Rational(20, 7), + listOf(0u, 1u) to Rational(1, 9), + listOf(1u, 1u) to Rational(-2, 5), + listOf(2u, 1u) to Rational(-10, 6), + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(0), + ), "test 3" ) assertEquals( - NumberedPolynomial { - Rational(0) with {} - Rational(0) with { 1 pow 1u } - Rational(0) with { 1 pow 2u } - Rational(0) with { 2 pow 1u } - Rational(0) with { 1 pow 1u; 2 pow 1u } - Rational(0) with { 1 pow 2u; 2 pow 1u } - Rational(0) with { 2 pow 2u } - Rational(0) with { 1 pow 1u; 2 pow 2u } - Rational(0) with { 1 pow 2u; 2 pow 2u } - }, - NumberedPolynomial { - Rational(6, 4) with {} - Rational(-2, 6) with { 1 pow 1u } - Rational(10, 6) with { 1 pow 2u } - Rational(17, 7) with { 2 pow 1u } - Rational(-7, 7) with { 1 pow 1u; 2 pow 1u } - Rational(12, 5) with { 1 pow 2u; 2 pow 1u } - Rational(12, 7) with { 2 pow 2u } - Rational(-10, 3) with { 1 pow 1u; 2 pow 2u } - Rational(9, 8) with { 1 pow 2u; 2 pow 2u } - } - NumberedPolynomial { - Rational(6, 4) with {} - Rational(-2, 6) with { 1 pow 1u } - Rational(10, 6) with { 1 pow 2u } - Rational(17, 7) with { 2 pow 1u } - Rational(-7, 7) with { 1 pow 1u; 2 pow 1u } - Rational(12, 5) with { 1 pow 2u; 2 pow 1u } - Rational(12, 7) with { 2 pow 2u } - Rational(-10, 3) with { 1 pow 1u; 2 pow 2u } - Rational(9, 8) with { 1 pow 2u; 2 pow 2u } - }, + NumberedPolynomial( + listOf() to Rational(0), + listOf(1u) to Rational(0), + listOf(2u) to Rational(0), + listOf(0u, 1u) to Rational(0), + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(0), + ), + NumberedPolynomial( + listOf() to Rational(6, 4), + listOf(1u) to Rational(-2, 6), + listOf(2u) to Rational(10, 6), + listOf(0u, 1u) to Rational(17, 7), + listOf(1u, 1u) to Rational(-7, 7), + listOf(2u, 1u) to Rational(12, 5), + listOf(0u, 2u) to Rational(12, 7), + listOf(1u, 2u) to Rational(-10, 3), + listOf(2u, 2u) to Rational(9, 8), + ) - NumberedPolynomial( + listOf() to Rational(6, 4), + listOf(1u) to Rational(-2, 6), + listOf(2u) to Rational(10, 6), + listOf(0u, 1u) to Rational(17, 7), + listOf(1u, 1u) to Rational(-7, 7), + listOf(2u, 1u) to Rational(12, 5), + listOf(0u, 2u) to Rational(12, 7), + listOf(1u, 2u) to Rational(-10, 3), + listOf(2u, 2u) to Rational(9, 8), + ), "test 4" ) } @@ -1314,255 +1312,250 @@ class NumberedPolynomialTest { IntModuloRing(35).numberedPolynomialSpace { // (p + q + r) * (p^2 + q^2 + r^2 - pq - pr - qr) = p^3 + q^3 + r^3 - 3pqr assertEquals( - NumberedPolynomial { - m(1) with { 1 pow 3u } - m(1) with { 2 pow 3u } - m(1) with { 3 pow 3u } - m(0) with { 1 pow 1u; 2 pow 2u } - m(0) with { 2 pow 1u; 3 pow 2u } - m(0) with { 3 pow 1u; 1 pow 2u } - m(0) with { 1 pow 1u; 3 pow 2u } - m(0) with { 2 pow 1u; 1 pow 2u } - m(0) with { 3 pow 1u; 2 pow 2u } - m(-3) with { 1 pow 1u; 2 pow 1u; 3 pow 1u } - }, - NumberedPolynomial { - m(1) with { 1 pow 1u } - m(1) with { 2 pow 1u } - m(1) with { 3 pow 1u } - } * NumberedPolynomial { - m(1) with { 1 pow 2u } - m(1) with { 2 pow 2u } - m(1) with { 3 pow 2u } - m(-1) with { 1 pow 1u; 2 pow 1u } - m(-1) with { 2 pow 1u; 3 pow 1u } - m(-1) with { 3 pow 1u; 1 pow 1u } - }, + NumberedPolynomial( + listOf(3u) to m(1), + listOf(0u, 3u) to m(1), + listOf(0u, 0u, 3u) to m(1), + listOf(1u, 2u) to m(0), + listOf(0u, 1u, 2u) to m(0), + listOf(2u, 0u, 1u) to m(0), + listOf(1u, 0u, 2u) to m(0), + listOf(2u, 1u) to m(0), + listOf(0u, 2u, 1u) to m(0), + listOf(1u, 1u, 1u) to m(-3), + ), + NumberedPolynomial( + listOf(1u) to m(1), + listOf(0u, 1u) to m(1), + listOf(0u, 0u, 1u) to m(1), + ) * NumberedPolynomial( + listOf(2u) to m(1), + listOf(0u, 2u) to m(1), + listOf(0u, 0u, 2u) to m(1), + listOf(1u, 1u) to m(-1), + listOf(0u, 1u, 1u) to m(-1), + listOf(1u, 0u, 1u) to m(-1), + ), "test 1" ) // Spoiler: 5 * 7 = 0 assertEquals( - NumberedPolynomial { - m(0) with { 1 pow 2u } - m(0) with { 2 pow 2u } - m(0) with { 3 pow 2u } - m(0) with { 1 pow 1u; 2 pow 1u } - m(0) with { 2 pow 1u; 3 pow 1u } - m(0) with { 3 pow 1u; 1 pow 1u } - }, - NumberedPolynomial { - m(5) with { 1 pow 1u } - m(-25) with { 2 pow 1u } - m(10) with { 3 pow 1u } - } * NumberedPolynomial { - m(21) with { 1 pow 1u } - m(14) with { 2 pow 1u } - m(-7) with { 3 pow 1u } - }, + NumberedPolynomial( + listOf(2u) to m(0), + listOf(0u, 2u) to m(0), + listOf(0u, 0u, 2u) to m(0), + listOf(1u, 1u) to m(0), + listOf(0u, 1u, 1u) to m(0), + listOf(1u, 0u, 1u) to m(0), + ), + NumberedPolynomial( + listOf(1u) to m(5), + listOf(0u, 1u) to m(-25), + listOf(0u, 0u, 1u) to m(10), + ) * NumberedPolynomial( + listOf(1u) to m(21), + listOf(0u, 1u) to m(14), + listOf(0u, 0u, 1u) to m(-7), + ), "test 2" ) } } @Test fun test_lastVariable() { - val o = Rational(0) RationalField.numberedPolynomialSpace { assertEquals( -1, - NumberedPolynomial {}.lastVariable, + NumberedPolynomial().lastVariable, "test 1" ) assertEquals( -1, - NumberedPolynomial { - o {} - }.lastVariable, + NumberedPolynomial( + listOf() to o + ).lastVariable, "test 2" ) assertEquals( 2, - NumberedPolynomial { - o { 1 pow 1u; 2 pow 2u; 3 pow 3u } - }.lastVariable, + NumberedPolynomial( + listOf(1u, 2u, 3u) to o + ).lastVariable, "test 3" ) assertEquals( 3, - NumberedPolynomial { - o { 1 pow 0u; 2 pow 1u; 3 pow 2u; 4 pow 1u; 5 pow 0u } - }.also { println(it) }.lastVariable, + NumberedPolynomial( + listOf(0u, 1u, 2u, 1u, 0u) to o + ).also { println(it) }.lastVariable, "test 4" ) assertEquals( 2, - NumberedPolynomial { - o {} - o { 2 pow 1u } - o { 1 pow 2u; 3 pow 1u } - }.lastVariable, + NumberedPolynomial( + listOf() to o, + listOf(0u, 1u) to o, + listOf(2u, 0u, 1u) to o, + ).lastVariable, "test 5" ) } } @Test fun test_degree() { - val o = Rational(0) RationalField.numberedPolynomialSpace { assertEquals( -1, - NumberedPolynomial {}.degree, + NumberedPolynomial().degree, "test 1" ) assertEquals( 0, - NumberedPolynomial { - o {} - }.degree, + NumberedPolynomial( + listOf() to o + ).degree, "test 2" ) assertEquals( 6, - NumberedPolynomial { - o { 1 pow 1u; 2 pow 2u; 3 pow 3u } - }.degree, + NumberedPolynomial( + listOf(1u, 2u, 3u) to o + ).degree, "test 3" ) assertEquals( 4, - NumberedPolynomial { - o { 1 pow 0u; 2 pow 1u; 3 pow 2u; 4 pow 1u; 5 pow 0u } - }.degree, + NumberedPolynomial( + listOf(0u, 1u, 2u, 1u, 0u) to o + ).degree, "test 4" ) assertEquals( 3, - NumberedPolynomial { - o {} - o { 2 pow 1u } - o { 1 pow 2u; 3 pow 1u } - }.degree, + NumberedPolynomial( + listOf() to o, + listOf(0u, 1u) to o, + listOf(2u, 0u, 1u) to o, + ).degree, "test 5" ) assertEquals( 4, - NumberedPolynomial { - o {} - o { 2 pow 1u } - o { 1 pow 2u; 3 pow 1u } - o { 4 pow 4u } - }.degree, + NumberedPolynomial( + listOf() to o, + listOf(0u, 1u) to o, + listOf(2u, 0u, 1u) to o, + listOf(0u, 0u, 0u, 4u) to o, + ).degree, "test 6" ) } } @Test fun test_degrees() { - val o = Rational(0) RationalField.numberedPolynomialSpace { assertEquals( listOf(), - NumberedPolynomial {}.degrees, + NumberedPolynomial().degrees, "test 1" ) assertEquals( listOf(), - NumberedPolynomial { - o {} - }.degrees, + NumberedPolynomial( + listOf() to o + ).degrees, "test 2" ) assertEquals( listOf(1u, 2u, 3u), - NumberedPolynomial { - o { 1 pow 1u; 2 pow 2u; 3 pow 3u } - }.degrees, + NumberedPolynomial( + listOf(1u, 2u, 3u) to o + ).degrees, "test 3" ) assertEquals( listOf(0u, 1u, 2u, 1u), - NumberedPolynomial { - o { 1 pow 0u; 2 pow 1u; 3 pow 2u; 4 pow 1u; 5 pow 0u } - }.degrees, + NumberedPolynomial( + listOf(0u, 1u, 2u, 1u, 0u) to o + ).degrees, "test 4" ) assertEquals( listOf(2u, 1u, 1u), - NumberedPolynomial { - o {} - o { 2 pow 1u } - o { 1 pow 2u; 3 pow 1u } - }.degrees, + NumberedPolynomial( + listOf() to o, + listOf(0u, 1u) to o, + listOf(2u, 0u, 1u) to o, + ).degrees, "test 5" ) assertEquals( listOf(2u, 2u, 2u, 4u), - NumberedPolynomial { - o {} - o { 1 pow 1u; 2 pow 2u } - o { 2 pow 1u; 3 pow 2u } - o { 1 pow 2u; 3 pow 1u } - o { 4 pow 4u } - }.degrees, + NumberedPolynomial( + listOf() to o, + listOf(1u, 2u) to o, + listOf(0u, 1u, 2u) to o, + listOf(2u, 0u, 1u) to o, + listOf(0u, 0u, 0u, 4u) to o, + ).degrees, "test 6" ) } } @Test fun test_degreeBy() { - val o = Rational(0) RationalField.numberedPolynomialSpace { fun NumberedPolynomial.collectDegrees(limit: Int = lastVariable + 2): List = List(limit) { degreeBy(it) } assertEquals( listOf(0u), - NumberedPolynomial {}.collectDegrees(), + NumberedPolynomial().collectDegrees(), "test 1" ) assertEquals( listOf(0u), - NumberedPolynomial { - o {} - }.collectDegrees(), + NumberedPolynomial( + listOf() to o + ).collectDegrees(), "test 2" ) assertEquals( listOf(1u, 2u, 3u, 0u), - NumberedPolynomial { - o { 1 pow 1u; 2 pow 2u; 3 pow 3u } - }.collectDegrees(), + NumberedPolynomial( + listOf(1u, 2u, 3u) to o + ).collectDegrees(), "test 3" ) assertEquals( listOf(0u, 1u, 2u, 1u, 0u), - NumberedPolynomial { - o { 1 pow 0u; 2 pow 1u; 3 pow 2u; 4 pow 1u; 5 pow 0u } - }.collectDegrees(), + NumberedPolynomial( + listOf(0u, 1u, 2u, 1u, 0u) to o + ).collectDegrees(), "test 4" ) assertEquals( listOf(2u, 1u, 1u, 0u), - NumberedPolynomial { - o {} - o { 2 pow 1u } - o { 1 pow 2u; 3 pow 1u } - }.collectDegrees(), + NumberedPolynomial( + listOf() to o, + listOf(0u, 1u) to o, + listOf(2u, 0u, 1u) to o, + ).collectDegrees(), "test 5" ) assertEquals( listOf(2u, 2u, 2u, 4u, 0u), - NumberedPolynomial { - o {} - o { 1 pow 1u; 2 pow 2u } - o { 2 pow 1u; 3 pow 2u } - o { 1 pow 2u; 3 pow 1u } - o { 4 pow 4u } - }.collectDegrees(), + NumberedPolynomial( + listOf() to o, + listOf(1u, 2u) to o, + listOf(0u, 1u, 2u) to o, + listOf(2u, 0u, 1u) to o, + listOf(0u, 0u, 0u, 4u) to o, + ).collectDegrees(), "test 6" ) } } @Test fun test_degreeBy_Collection() { - val o = Rational(0) RationalField.numberedPolynomialSpace { fun NumberedPolynomial.checkDegreeBy(message: String? = null) { val lastVariable = lastVariable @@ -1587,153 +1580,151 @@ class NumberedPolynomialTest { fail("${message ?: ""} Incorrect answer for variable collection $indexCollection: expected $expected, actual $actual") } } - NumberedPolynomial {}.checkDegreeBy("test 1") - NumberedPolynomial { - o {} - }.checkDegreeBy("test 2") - NumberedPolynomial { - o { 1 pow 1u; 2 pow 2u; 3 pow 3u } - }.checkDegreeBy("test 3") - NumberedPolynomial { - o { 1 pow 0u; 2 pow 1u; 3 pow 2u; 4 pow 1u; 5 pow 0u } - }.checkDegreeBy("test 4") - NumberedPolynomial { - o {} - o { 2 pow 1u } - o { 1 pow 2u; 3 pow 1u } - }.checkDegreeBy("test 5") - NumberedPolynomial { - o {} - o { 1 pow 1u; 2 pow 2u } - o { 2 pow 1u; 3 pow 2u } - o { 1 pow 2u; 3 pow 1u } - o { 4 pow 4u } - }.checkDegreeBy("test 6") + NumberedPolynomial().checkDegreeBy("test 1") + NumberedPolynomial( + listOf() to o + ).checkDegreeBy("test 2") + NumberedPolynomial( + listOf(1u, 2u, 3u) to o + ).checkDegreeBy("test 3") + NumberedPolynomial( + listOf(0u, 1u, 2u, 1u, 0u) to o + ).checkDegreeBy("test 4") + NumberedPolynomial( + listOf() to o, + listOf(0u, 1u) to o, + listOf(2u, 0u, 1u) to o, + ).checkDegreeBy("test 5") + NumberedPolynomial( + listOf() to o, + listOf(1u, 2u) to o, + listOf(0u, 1u, 2u) to o, + listOf(2u, 0u, 1u) to o, + listOf(0u, 0u, 0u, 4u) to o, + ).checkDegreeBy("test 6") } } @Test fun test_countOfVariables() { - val o = Rational(0) RationalField.numberedPolynomialSpace { assertEquals( 0, - NumberedPolynomial {}.countOfVariables, + NumberedPolynomial().countOfVariables, "test 1" ) assertEquals( 0, - NumberedPolynomial { - o {} - }.countOfVariables, + NumberedPolynomial( + listOf() to o + ).countOfVariables, "test 2" ) assertEquals( 3, - NumberedPolynomial { - o { 1 pow 1u; 2 pow 2u; 3 pow 3u } - }.countOfVariables, + NumberedPolynomial( + listOf(1u, 2u, 3u) to o + ).countOfVariables, "test 3" ) assertEquals( 3, - NumberedPolynomial { - o { 1 pow 0u; 2 pow 1u; 3 pow 2u; 4 pow 1u; 5 pow 0u } - }.countOfVariables, + NumberedPolynomial( + listOf(0u, 1u, 2u, 1u, 0u) to o + ).countOfVariables, "test 4" ) assertEquals( 3, - NumberedPolynomial { - o {} - o { 2 pow 1u } - o { 1 pow 2u; 3 pow 1u } - }.countOfVariables, + NumberedPolynomial( + listOf() to o, + listOf(0u, 1u) to o, + listOf(2u, 0u, 1u) to o, + ).countOfVariables, "test 5" ) assertEquals( 4, - NumberedPolynomial { - o {} - o { 1 pow 1u; 2 pow 2u } - o { 2 pow 1u; 3 pow 2u } - o { 1 pow 2u; 3 pow 1u } - o { 4 pow 4u } - }.countOfVariables, + NumberedPolynomial( + listOf() to o, + listOf(1u, 2u) to o, + listOf(0u, 1u, 2u) to o, + listOf(2u, 0u, 1u) to o, + listOf(0u, 0u, 0u, 4u) to o, + ).countOfVariables, "test 6" ) } } @Test fun test_RF_countOfVariables() { - val o = Rational(0) RationalField.numberedRationalFunctionSpace { assertEquals( 0, NumberedRationalFunction( - NumberedPolynomial {} + NumberedPolynomial() ).countOfVariables, "test 1" ) assertEquals( 0, NumberedRationalFunction( - NumberedPolynomial {}, - NumberedPolynomial {} + NumberedPolynomial(), + NumberedPolynomial() ).countOfVariables, "test 2" ) assertEquals( 0, NumberedRationalFunction( - NumberedPolynomial { - o {} - } + NumberedPolynomial( + listOf() to o + ) ).countOfVariables, "test 3" ) assertEquals( 3, NumberedRationalFunction( - NumberedPolynomial { - o { 1 pow 1u; 2 pow 2u; 3 pow 3u } - } + NumberedPolynomial( + listOf(1u, 2u, 3u) to o + ) ).countOfVariables, "test 4" ) assertEquals( 3, NumberedRationalFunction( - NumberedPolynomial { - o { 2 pow 1u; 4 pow 1u } - }, - NumberedPolynomial { - o { 1 pow 0u; 3 pow 2u; 5 pow 0u } - } + NumberedPolynomial( + listOf(0u, 1u, 0u, 1u) to o + ), + NumberedPolynomial( + listOf(0u, 0u, 2u) to o + ) ).countOfVariables, "test 5" ) assertEquals( 3, NumberedRationalFunction( - NumberedPolynomial { - o {} - o { 2 pow 1u } - o { 1 pow 2u; 3 pow 1u } - } + NumberedPolynomial( + listOf() to o, + listOf(0u, 1u) to o, + listOf(2u, 0u, 1u) to o, + ) ).countOfVariables, "test 6" ) assertEquals( 4, NumberedRationalFunction( - NumberedPolynomial { - o {} - o { 1 pow 1u; 2 pow 2u } - o { 1 pow 2u; 3 pow 1u } - }, NumberedPolynomial { - o { 2 pow 1u; 3 pow 2u } - o { 4 pow 4u } - } + NumberedPolynomial( + listOf() to o, + listOf(1u, 2u) to o, + listOf(2u, 0u, 1u) to o, + ), NumberedPolynomial( + listOf(0u, 1u, 2u) to o, + listOf(0u, 0u, 0u, 4u) to o, + ) ).countOfVariables, "test 7" ) -- 2.34.1 From 923c52737d4f5ca4e1153757b7079ebc2e19718b Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Wed, 6 Jul 2022 17:13:50 +0300 Subject: [PATCH 098/123] Adapt NumberedPolynomial tests to LabeledPolynomial tests. --- .../kmath/functions/LabeledPolynomial.kt | 42 +- .../kmath/functions/labeledConstructors.kt | 1 + .../functions/LabeledConstructorsTest.kt | 129 + .../kmath/functions/LabeledPolynomialTest.kt | 1872 ++++ .../functions/LabeledPolynomialUtilTest.kt | 8224 +++++++++++++++++ .../kmath/functions/NumberedPolynomialTest.kt | 18 +- .../kscience/kmath/test/misc/assertion.kt | 34 + 7 files changed, 10296 insertions(+), 24 deletions(-) create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledConstructorsTest.kt create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialTest.kt create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialUtilTest.kt diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt index 6d9af631a..1477796ea 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt @@ -177,14 +177,17 @@ public class LabeledPolynomialSpace>( * The operation is equivalent to sum of [other] copies of [this]. */ public override operator fun LabeledPolynomial.times(other: Int): LabeledPolynomial = - if (other == 0) zero - else LabeledPolynomial( - coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this[degs]!! * other - } - ) + when(other) { + 0 -> zero + 1 -> this + else -> LabeledPolynomial( + coefficients + .toMutableMap() + .apply { + for (degs in keys) this[degs] = this[degs]!! * other + } + ) + } /** * Returns sum of the integer represented as a polynomial and the polynomial. @@ -210,7 +213,7 @@ public class LabeledPolynomialSpace>( * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. */ public override operator fun Int.minus(other: LabeledPolynomial): LabeledPolynomial = - if (this == 0) other + if (this == 0) -other else with(other.coefficients) { if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap() to this@minus.asConstant())) else LabeledPolynomialAsIs( @@ -230,14 +233,17 @@ public class LabeledPolynomialSpace>( * The operation is equivalent to sum of [this] copies of [other]. */ public override operator fun Int.times(other: LabeledPolynomial): LabeledPolynomial = - if (this == 0) zero - else LabeledPolynomial( - other.coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this@times * this[degs]!! - } - ) + when(this) { + 0 -> zero + 1 -> other + else -> LabeledPolynomial( + other.coefficients + .toMutableMap() + .apply { + for (degs in keys) this[degs] = this@times * this[degs]!! + } + ) + } /** * Converts the integer [value] to polynomial. @@ -360,8 +366,6 @@ public class LabeledPolynomialSpace>( else LabeledPolynomialAsIs( toMutableMap() .apply { - forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } - val degs = emptyMap() this[degs] = getOrElse(degs) { constantZero } - other diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt index 8442d3f91..819a36449 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt @@ -302,6 +302,7 @@ public class DSL1LabeledPolynomialTermSignatureBuilder { * Declaring another power of the same variable will increase its degree by received degree. */ public infix fun Symbol.inPowerOf(deg: UInt) { + if (deg == 0u) return signature[this] = signature.getOrElse(this) { 0u } + deg } /** diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledConstructorsTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledConstructorsTest.kt new file mode 100644 index 000000000..edeaef6a7 --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledConstructorsTest.kt @@ -0,0 +1,129 @@ +/* + * 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.functions + +import space.kscience.kmath.expressions.Symbol +import space.kscience.kmath.expressions.symbol +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.algebra +import space.kscience.kmath.operations.invoke +import kotlin.test.Test +import kotlin.test.assertEquals + +class LabeledConstructorsTest { + val x by symbol + val y by symbol + val z by symbol + val t by symbol + + @Test + @UnstableKMathAPI + fun testDSL1() { + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 2u, z to 3u) to 5, + mapOf(y to 1u) to -6, + ), + Int.algebra.labeledPolynomialSpace { + LabeledPolynomialDSL1 { + 5 { x pow 2u; z pow 3u } + (-6) { y pow 1u } + } + }, + "test 1" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to -1, + ), + Int.algebra.labeledPolynomialSpace { + LabeledPolynomialDSL1 { + 5 { } + (-6) { } + } + }, + "test 2" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 2u) to -1, + ), + Int.algebra.labeledPolynomialSpace { + LabeledPolynomialDSL1 { + 5 { x pow 1u; x pow 1u } + (-6) { x pow 2u } + } + }, + "test 3" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 2u) to -1, + ), + Int.algebra.labeledPolynomialSpace { + LabeledPolynomialDSL1 { + 5 { x pow 1u; x pow 1u } + (-6) { x pow 2u; z pow 0u } + } + }, + "test 3" + ) + } + @Test + @UnstableKMathAPI + fun testFabric() { + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 2u, z to 3u) to 5, + mapOf(y to 1u) to -6, + ), + Int.algebra { + LabeledPolynomial( + mapOf(x to 2u, z to 3u) to 5, + mapOf(y to 1u) to -6, + ) + }, + "test 1" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 2u, z to 3u) to 5, + mapOf(y to 1u) to -6, + ), + Int.algebra { + LabeledPolynomial( + mapOf(x to 2u, y to 0u, z to 3u, t to 0u) to 5, + mapOf(x to 0u, y to 1u, z to 0u, t to 0u) to -6, + ) + }, + "test 2" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to -1, + ), + Int.algebra { + LabeledPolynomial( + mapOf(x to 0u) to 5, + mapOf(y to 0u, z to 0u) to -6, + ) + }, + "test 3" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to 0, + ), + Int.algebra { + LabeledPolynomial( + mapOf(x to 0u) to 5, + mapOf(z to 0u, t to 0u) to -5, + ) + }, + "test 4" + ) + } +} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialTest.kt new file mode 100644 index 000000000..15c4c3656 --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialTest.kt @@ -0,0 +1,1872 @@ +/* + * 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.functions + +import space.kscience.kmath.expressions.Symbol +import space.kscience.kmath.expressions.symbol +import space.kscience.kmath.test.misc.IntModuloRing +import space.kscience.kmath.test.misc.Rational +import space.kscience.kmath.test.misc.RationalField +import space.kscience.kmath.test.misc.m +import kotlin.test.* + + +// TODO: Тесты на конвертацию. +class LabeledPolynomialTest { + val x by symbol + val y by symbol + val z by symbol + val t by symbol + val s by symbol + val iota by symbol + + val o = Rational(0) + + @Test + @Ignore + fun test_Variable_Int_plus() { + // TODO + } + @Test + @Ignore + fun test_Variable_Int_minus() { + // TODO + } + @Test + @Ignore + fun test_Variable_Int_times() { + // TODO + } + @Test + @Ignore + fun test_Int_Variable_plus() { + // TODO + } + @Test + @Ignore + fun test_Int_Variable_minus() { + // TODO + } + @Test + @Ignore + fun test_Int_Variable_times() { + // TODO + } + @Test + fun test_Polynomial_Int_plus() { + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomial( + mapOf() to Rational(-22, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + LabeledPolynomial( + mapOf() to Rational(5, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ) + -3, + "test 1" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(-3, 1), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + LabeledPolynomial( + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ) + -3, + "test 2" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(0, 1), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + LabeledPolynomial( + mapOf() to Rational(27, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ) + -3, + "test 3" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(x to 0u, y to 4u) to Rational(0), + ), + LabeledPolynomial( + mapOf() to Rational(27, 9), + mapOf(x to 3u) to Rational(0), + mapOf(x to 0u, y to 4u) to Rational(0), + ) + -3, + "test 4" + ) + val polynomial_5 = LabeledPolynomial( + mapOf() to Rational(-22, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ) + assertSame( + polynomial_5, + polynomial_5 + 0, + "test 5" + ) + val polynomial_6 = LabeledPolynomial( + mapOf() to Rational(0, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ) + assertSame( + polynomial_6, + polynomial_6 + 0, + "test 6" + ) + val polynomial_7 = LabeledPolynomial( + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ) + assertSame( + polynomial_7, + polynomial_7 + 0, + "test 7" + ) + } + } + @Test + fun test_Polynomial_Int_minus() { + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomial( + mapOf() to Rational(-22, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + LabeledPolynomial( + mapOf() to Rational(5, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ) - 3, + "test 1" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(-3, 1), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + LabeledPolynomial( + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ) - 3, + "test 2" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(0, 1), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + LabeledPolynomial( + mapOf() to Rational(27, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ) - 3, + "test 3" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(x to 0u, y to 4u) to Rational(0), + ), + LabeledPolynomial( + mapOf() to Rational(27, 9), + mapOf(x to 3u) to Rational(0), + mapOf(x to 0u, y to 4u) to Rational(0), + ) - 3, + "test 4" + ) + val polynomial_5 = LabeledPolynomial( + mapOf() to Rational(-22, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ) + assertSame( + polynomial_5, + polynomial_5 - 0, + "test 5" + ) + val polynomial_6 = LabeledPolynomial( + mapOf() to Rational(0, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ) + assertSame( + polynomial_6, + polynomial_6 - 0, + "test 6" + ) + val polynomial_7 = LabeledPolynomial( + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ) + assertSame( + polynomial_7, + polynomial_7 - 0, + "test 7" + ) + } + } + @Test + fun test_Polynomial_Int_times() { + IntModuloRing(35).labeledPolynomialSpace { + assertEquals( + LabeledPolynomial( + mapOf() to m(34), + mapOf(x to 3u) to m(2), + mapOf(x to 0u, y to 1u) to m(1), + mapOf(x to 1u) to m(20), + mapOf(x to 0u, y to 0u, z to 2u) to m(2), + ), + LabeledPolynomial( + mapOf() to m(22), + mapOf(x to 3u) to m(26), + mapOf(x to 0u, y to 1u) to m(13), + mapOf(x to 1u) to m(15), + mapOf(x to 0u, y to 0u, z to 2u) to m(26), + ) * 27, + "test 1" + ) + assertEquals( + LabeledPolynomial( + mapOf() to m(0), + mapOf(x to 3u) to m(0), + mapOf(x to 0u, y to 1u) to m(0), + mapOf(x to 1u) to m(0), + mapOf(x to 0u, y to 0u, z to 2u) to m(0), + ), + LabeledPolynomial( + mapOf() to m(7), + mapOf(x to 3u) to m(0), + mapOf(x to 0u, y to 1u) to m(49), + mapOf(x to 1u) to m(21), + mapOf(x to 0u, y to 0u, z to 2u) to m(14), + ) * 15, + "test 2" + ) + val polynomial = LabeledPolynomial( + mapOf() to m(22), + mapOf(x to 3u) to m(26), + mapOf(x to 0u, y to 1u) to m(13), + mapOf(x to 1u) to m(15), + mapOf(x to 0u, y to 0u, z to 2u) to m(26), + ) + assertSame( + zero, + polynomial * 0, + "test 3" + ) + assertSame( + polynomial, + polynomial * 1, + "test 4" + ) + } + } + @Test + fun test_Int_Polynomial_plus() { + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomial( + mapOf() to Rational(-22, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + -3 + LabeledPolynomial( + mapOf() to Rational(5, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + "test 1" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(-3, 1), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + -3 + LabeledPolynomial( + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + "test 2" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(0), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + -3 + LabeledPolynomial( + mapOf() to Rational(27, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + "test 3" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(x to 0u, y to 4u) to Rational(0), + ), + -3 + LabeledPolynomial( + mapOf() to Rational(27, 9), + mapOf(x to 3u) to Rational(0), + mapOf(x to 0u, y to 4u) to Rational(0), + ), + "test 4" + ) + val polynomial_5 = LabeledPolynomial( + mapOf() to Rational(-22, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ) + assertSame( + polynomial_5, + 0 + polynomial_5, + "test 5" + ) + val polynomial_6 = LabeledPolynomial( + mapOf() to Rational(0, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ) + assertSame( + polynomial_6, + 0 + polynomial_6, + "test 6" + ) + val polynomial_7 = LabeledPolynomial( + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ) + assertSame( + polynomial_7, + 0 + polynomial_7, + "test 7" + ) + } + } + @Test + fun test_Int_Polynomial_minus() { + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomial( + mapOf() to Rational(22, 9), + mapOf(x to 3u) to Rational(8, 9), + mapOf(x to 0u, y to 4u) to Rational(8, 7), + ), + 3 - LabeledPolynomial( + mapOf() to Rational(5, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + "test 1" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(3, 1), + mapOf(x to 3u) to Rational(8, 9), + mapOf(x to 0u, y to 4u) to Rational(8, 7), + ), + 3 - LabeledPolynomial( + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + "test 2" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(0, 1), + mapOf(x to 3u) to Rational(8, 9), + mapOf(x to 0u, y to 4u) to Rational(8, 7), + ), + 3 - LabeledPolynomial( + mapOf() to Rational(27, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + "test 3" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(x to 0u, y to 4u) to Rational(0), + ), + 3 - LabeledPolynomial( + mapOf() to Rational(27, 9), + mapOf(x to 3u) to Rational(0), + mapOf(x to 0u, y to 4u) to Rational(0), + ), + "test 4" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(22, 9), + mapOf(x to 3u) to Rational(8, 9), + mapOf(x to 0u, y to 4u) to Rational(8, 7), + ), + 0 - LabeledPolynomial( + mapOf() to Rational(-22, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + "test 5" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(0, 9), + mapOf(x to 3u) to Rational(8, 9), + mapOf(x to 0u, y to 4u) to Rational(8, 7), + ), + 0 - LabeledPolynomial( + mapOf() to Rational(0, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + "test 6" + ) + assertEquals( + LabeledPolynomial( + mapOf(x to 3u) to Rational(8, 9), + mapOf(x to 0u, y to 4u) to Rational(8, 7), + ), + 0 - LabeledPolynomial( + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + "test 7" + ) + } + } + @Test + fun test_Int_Polynomial_times() { + IntModuloRing(35).labeledPolynomialSpace { + assertEquals( + LabeledPolynomial( + mapOf() to m(34), + mapOf(x to 3u) to m(2), + mapOf(x to 0u, y to 1u) to m(1), + mapOf(x to 1u) to m(20), + mapOf(x to 0u, y to 0u, z to 2u) to m(2), + ), + 27 * LabeledPolynomial( + mapOf() to m(22), + mapOf(x to 3u) to m(26), + mapOf(x to 0u, y to 1u) to m(13), + mapOf(x to 1u) to m(15), + mapOf(x to 0u, y to 0u, z to 2u) to m(26), + ), + "test 1" + ) + assertEquals( + LabeledPolynomial( + mapOf() to m(0), + mapOf(x to 3u) to m(0), + mapOf(x to 0u, y to 1u) to m(0), + mapOf(x to 1u) to m(0), + mapOf(x to 0u, y to 0u, z to 2u) to m(0), + ), + 15 * LabeledPolynomial( + mapOf() to m(7), + mapOf(x to 3u) to m(0), + mapOf(x to 0u, y to 1u) to m(49), + mapOf(x to 1u) to m(21), + mapOf(x to 0u, y to 0u, z to 2u) to m(14), + ), + "test 2" + ) + val polynomial = LabeledPolynomial( + mapOf() to m(22), + mapOf(x to 3u) to m(26), + mapOf(x to 0u, y to 1u) to m(13), + mapOf(x to 1u) to m(15), + mapOf(x to 0u, y to 0u, z to 2u) to m(26), + ) + assertSame( + zero, + 0 * polynomial, + "test 3" + ) + assertSame( + polynomial, + 1 * polynomial, + "test 4" + ) + } + } + @Test + @Ignore + fun test_Variable_Constant_plus() { + // TODO + } + @Test + @Ignore + fun test_Variable_Constant_minus() { + // TODO + } + @Test + @Ignore + fun test_Variable_Constant_times() { + // TODO + } + @Test + @Ignore + fun test_Constant_Variable_plus() { + // TODO + } + @Test + @Ignore + fun test_Constant_Variable_minus() { + // TODO + } + @Test + @Ignore + fun test_Constant_Variable_times() { + // TODO + } + @Test + fun test_Polynomial_Constant_plus() { + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomial( + mapOf() to Rational(-22, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + LabeledPolynomial( + mapOf() to Rational(5, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ) + Rational(-3), + "test 1" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(-3, 1), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + LabeledPolynomial( + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ) + Rational(-3), + "test 2" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(0, 1), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + LabeledPolynomial( + mapOf() to Rational(27, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ) + Rational(-3), + "test 3" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(x to 0u, y to 4u) to Rational(0), + ), + LabeledPolynomial( + mapOf() to Rational(27, 9), + mapOf(x to 3u) to Rational(0), + mapOf(x to 0u, y to 4u) to Rational(0), + ) + Rational(-3), + "test 4" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(-22, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + LabeledPolynomial( + mapOf() to Rational(-22, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ) + Rational(0), + "test 5" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(0, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + LabeledPolynomial( + mapOf() to Rational(0, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ) + Rational(0), + "test 6" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(0), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + LabeledPolynomial( + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ) + Rational(0), + "test 7" + ) + } + } + @Test + fun test_Polynomial_Constant_minus() { + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomial( + mapOf() to Rational(-22, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + LabeledPolynomial( + mapOf() to Rational(5, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ) - Rational(3), + "test 1" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(-3, 1), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + LabeledPolynomial( + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ) - Rational(3), + "test 2" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(0, 1), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + LabeledPolynomial( + mapOf() to Rational(27, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ) - Rational(3), + "test 3" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(x to 0u, y to 4u) to Rational(0), + ), + LabeledPolynomial( + mapOf() to Rational(27, 9), + mapOf(x to 3u) to Rational(0), + mapOf(x to 0u, y to 4u) to Rational(0), + ) - Rational(3), + "test 4" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(-22, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + LabeledPolynomial( + mapOf() to Rational(-22, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ) - Rational(0), + "test 5" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(0, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + LabeledPolynomial( + mapOf() to Rational(0, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ) - Rational(0), + "test 6" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(0), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + LabeledPolynomial( + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ) - Rational(0), + "test 7" + ) + } + } + @Test + fun test_Polynomial_Constant_times() { + IntModuloRing(35).labeledPolynomialSpace { + assertEquals( + LabeledPolynomial( + mapOf() to m(34), + mapOf(x to 3u) to m(2), + mapOf(x to 0u, y to 1u) to m(1), + mapOf(x to 1u) to m(20), + mapOf(x to 0u, y to 0u, z to 2u) to m(2), + ), + LabeledPolynomial( + mapOf() to m(22), + mapOf(x to 3u) to m(26), + mapOf(x to 0u, y to 1u) to m(13), + mapOf(x to 1u) to m(15), + mapOf(x to 0u, y to 0u, z to 2u) to m(26), + ) * m(27), + "test 1" + ) + assertEquals( + LabeledPolynomial( + mapOf() to m(0), + mapOf(x to 3u) to m(0), + mapOf(x to 0u, y to 1u) to m(0), + mapOf(x to 1u) to m(0), + mapOf(x to 0u, y to 0u, z to 2u) to m(0), + ), + LabeledPolynomial( + mapOf() to m(7), + mapOf(x to 3u) to m(0), + mapOf(x to 0u, y to 1u) to m(49), + mapOf(x to 1u) to m(21), + mapOf(x to 0u, y to 0u, z to 2u) to m(14), + ) * m(15), + "test 2" + ) + assertEquals( + LabeledPolynomial( + mapOf() to m(0), + mapOf(x to 3u) to m(0), + mapOf(x to 0u, y to 1u) to m(0), + mapOf(x to 1u) to m(0), + mapOf(x to 0u, y to 0u, z to 2u) to m(0), + ), + LabeledPolynomial( + mapOf() to m(22), + mapOf(x to 3u) to m(26), + mapOf(x to 0u, y to 1u) to m(13), + mapOf(x to 1u) to m(15), + mapOf(x to 0u, y to 0u, z to 2u) to m(26), + ) * m(0), + "test 3" + ) + assertEquals( + LabeledPolynomial( + mapOf() to m(22), + mapOf(x to 3u) to m(26), + mapOf(x to 0u, y to 1u) to m(13), + mapOf(x to 1u) to m(15), + mapOf(x to 0u, y to 0u, z to 2u) to m(26), + ), + LabeledPolynomial( + mapOf() to m(22), + mapOf(x to 3u) to m(26), + mapOf(x to 0u, y to 1u) to m(13), + mapOf(x to 1u) to m(15), + mapOf(x to 0u, y to 0u, z to 2u) to m(26), + ) * m(1), + "test 4" + ) + } + } + @Test + fun test_Constant_Polynomial_plus() { + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomial( + mapOf() to Rational(-22, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + Rational(-3) + LabeledPolynomial( + mapOf() to Rational(5, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + "test 1" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(-3, 1), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + Rational(-3) + LabeledPolynomial( + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + "test 2" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(0, 1), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + Rational(-3) + LabeledPolynomial( + mapOf() to Rational(27, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + "test 3" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(x to 0u, y to 4u) to Rational(0), + ), + Rational(-3) + LabeledPolynomial( + mapOf() to Rational(27, 9), + mapOf(x to 3u) to Rational(0), + mapOf(x to 0u, y to 4u) to Rational(0), + ), + "test 4" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(-22, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + Rational(0) + LabeledPolynomial( + mapOf() to Rational(-22, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + "test 5" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(0, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + Rational(0) + LabeledPolynomial( + mapOf() to Rational(0, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + "test 6" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(0), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + Rational(0) + LabeledPolynomial( + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + "test 7" + ) + } + } + @Test + fun test_Constant_Polynomial_minus() { + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomial( + mapOf() to Rational(22, 9), + mapOf(x to 3u) to Rational(8, 9), + mapOf(x to 0u, y to 4u) to Rational(8, 7), + ), + Rational(3) - LabeledPolynomial( + mapOf() to Rational(5, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + "test 1" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(3, 1), + mapOf(x to 3u) to Rational(8, 9), + mapOf(x to 0u, y to 4u) to Rational(8, 7), + ), + Rational(3) - LabeledPolynomial( + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + "test 2" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(0, 1), + mapOf(x to 3u) to Rational(8, 9), + mapOf(x to 0u, y to 4u) to Rational(8, 7), + ), + Rational(3) - LabeledPolynomial( + mapOf() to Rational(27, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + "test 3" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(x to 0u, y to 4u) to Rational(0), + ), + Rational(3) - LabeledPolynomial( + mapOf() to Rational(27, 9), + mapOf(x to 3u) to Rational(0), + mapOf(x to 0u, y to 4u) to Rational(0), + ), + "test 4" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(22, 9), + mapOf(x to 3u) to Rational(8, 9), + mapOf(x to 0u, y to 4u) to Rational(8, 7), + ), + Rational(0) - LabeledPolynomial( + mapOf() to Rational(-22, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + "test 5" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(0, 9), + mapOf(x to 3u) to Rational(8, 9), + mapOf(x to 0u, y to 4u) to Rational(8, 7), + ), + Rational(0) - LabeledPolynomial( + mapOf() to Rational(0, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + "test 6" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(0), + mapOf(x to 3u) to Rational(8, 9), + mapOf(x to 0u, y to 4u) to Rational(8, 7), + ), + Rational(0) - LabeledPolynomial( + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + "test 7" + ) + } + } + @Test + fun test_Constant_Polynomial_times() { + IntModuloRing(35).labeledPolynomialSpace { + assertEquals( + LabeledPolynomial( + mapOf() to m(34), + mapOf(x to 3u) to m(2), + mapOf(x to 0u, y to 1u) to m(1), + mapOf(x to 1u) to m(20), + mapOf(x to 0u, y to 0u, z to 2u) to m(2), + ), + m(27) * LabeledPolynomial( + mapOf() to m(22), + mapOf(x to 3u) to m(26), + mapOf(x to 0u, y to 1u) to m(13), + mapOf(x to 1u) to m(15), + mapOf(x to 0u, y to 0u, z to 2u) to m(26), + ), + "test 1" + ) + assertEquals( + LabeledPolynomial( + mapOf() to m(0), + mapOf(x to 3u) to m(0), + mapOf(x to 0u, y to 1u) to m(0), + mapOf(x to 1u) to m(0), + mapOf(x to 0u, y to 0u, z to 2u) to m(0), + ), + m(15) * LabeledPolynomial( + mapOf() to m(7), + mapOf(x to 3u) to m(0), + mapOf(x to 0u, y to 1u) to m(49), + mapOf(x to 1u) to m(21), + mapOf(x to 0u, y to 0u, z to 2u) to m(14), + ), + "test 2" + ) + assertEquals( + LabeledPolynomial( + mapOf() to m(0), + mapOf(x to 3u) to m(0), + mapOf(x to 0u, y to 1u) to m(0), + mapOf(x to 1u) to m(0), + mapOf(x to 0u, y to 0u, z to 2u) to m(0), + ), + m(0) * LabeledPolynomial( + mapOf() to m(22), + mapOf(x to 3u) to m(26), + mapOf(x to 0u, y to 1u) to m(13), + mapOf(x to 1u) to m(15), + mapOf(x to 0u, y to 0u, z to 2u) to m(26), + ), + "test 3" + ) + assertEquals( + LabeledPolynomial( + mapOf() to m(22), + mapOf(x to 3u) to m(26), + mapOf(x to 0u, y to 1u) to m(13), + mapOf(x to 1u) to m(15), + mapOf(x to 0u, y to 0u, z to 2u) to m(26), + ), + m(1) * LabeledPolynomial( + mapOf() to m(22), + mapOf(x to 3u) to m(26), + mapOf(x to 0u, y to 1u) to m(13), + mapOf(x to 1u) to m(15), + mapOf(x to 0u, y to 0u, z to 2u) to m(26), + ), + "test 4" + ) + } + } + @Test + @Ignore + fun test_Variable_unaryPlus(){ + // TODO + } + @Test + @Ignore + fun test_Variable_unaryMinus(){ + // TODO + } + @Test + @Ignore + fun test_Variable_Variable_plus(){ + // TODO + } + @Test + @Ignore + fun test_Variable_Variable_minus(){ + // TODO + } + @Test + @Ignore + fun test_Variable_Variable_times(){ + // TODO + } + @Test + @Ignore + fun test_Variable_Polynomial_plus(){ + // TODO + } + @Test + @Ignore + fun test_Variable_Polynomial_minus(){ + // TODO + } + @Test + @Ignore + fun test_Variable_Polynomial_times(){ + // TODO + } + @Test + @Ignore + fun test_Polynomial_Variable_plus(){ + // TODO + } + @Test + @Ignore + fun test_Polynomial_Variable_minus(){ + // TODO + } + @Test + @Ignore + fun test_Polynomial_Variable_times(){ + // TODO + } + @Test + fun test_Polynomial_unaryMinus() { + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomial( + mapOf(x to 5u) to Rational(-5, 9), + mapOf() to Rational(8, 9), + mapOf(iota to 13u) to Rational(8, 7), + ), + -LabeledPolynomial( + mapOf(x to 5u) to Rational(5, 9), + mapOf() to Rational(-8, 9), + mapOf(iota to 13u) to Rational(-8, 7), + ), + "test 1" + ) + assertEquals( + LabeledPolynomial( + mapOf(x to 5u) to Rational(-5, 9), + mapOf() to Rational(8, 9), + mapOf(iota to 13u) to Rational(8, 7), + mapOf(x to 0u, y to 4u) to Rational(0), + mapOf(x to 5u) to Rational(0), + ), + -LabeledPolynomial( + mapOf(x to 5u) to Rational(5, 9), + mapOf() to Rational(-8, 9), + mapOf(iota to 13u) to Rational(-8, 7), + mapOf(x to 0u, y to 4u) to Rational(0), + mapOf(x to 5u) to Rational(0), + ), + "test 2" + ) + } + } + @Test + fun test_Polynomial_Polynomial_plus() { + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomial( + mapOf() to Rational(-17, 2), + mapOf(x to 1u) to Rational(-1, 3), + mapOf(x to 2u) to Rational(-25, 21), + mapOf(x to 0u, y to 1u) to Rational(146, 63), + mapOf(x to 1u, y to 1u) to Rational(-3, 5), + mapOf(x to 2u, y to 1u) to Rational(61, 15), + mapOf(x to 0u, y to 2u) to Rational(157, 63), + mapOf(x to 1u, y to 2u) to Rational(-55, 21), + mapOf(x to 2u, y to 2u) to Rational(11, 24), + ), + LabeledPolynomial( + mapOf() to Rational(6, 4), + mapOf(x to 1u) to Rational(-2, 6), + mapOf(x to 2u) to Rational(10, 6), + mapOf(x to 0u, y to 1u) to Rational(17, 7), + mapOf(x to 1u, y to 1u) to Rational(-7, 7), + mapOf(x to 2u, y to 1u) to Rational(12, 5), + mapOf(x to 0u, y to 2u) to Rational(12, 7), + mapOf(x to 1u, y to 2u) to Rational(-10, 3), + mapOf(x to 2u, y to 2u) to Rational(9, 8), + ) + LabeledPolynomial( + mapOf() to Rational(-20, 2), + mapOf(x to 1u) to Rational(0, 9), + mapOf(x to 2u) to Rational(-20, 7), + mapOf(x to 0u, y to 1u) to Rational(-1, 9), + mapOf(x to 1u, y to 1u) to Rational(2, 5), + mapOf(x to 2u, y to 1u) to Rational(10, 6), + mapOf(x to 0u, y to 2u) to Rational(7, 9), + mapOf(x to 1u, y to 2u) to Rational(5, 7), + mapOf(x to 2u, y to 2u) to Rational(-2, 3), + ), + "test 1" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(-17, 2), + mapOf(x to 1u) to Rational(-1, 3), + mapOf(x to 2u) to Rational(-25, 21), + mapOf(x to 0u, y to 1u) to Rational(-1, 9), + mapOf(x to 1u, y to 1u) to Rational(2, 5), + mapOf(x to 2u, y to 1u) to Rational(10, 6), + mapOf(x to 0u, y to 2u) to Rational(157, 63), + mapOf(x to 1u, y to 2u) to Rational(-55, 21), + mapOf(x to 2u, y to 2u) to Rational(11, 24), + ), + LabeledPolynomial( + mapOf() to Rational(6, 4), + mapOf(x to 1u) to Rational(-2, 6), + mapOf(x to 2u) to Rational(10, 6), + mapOf(x to 0u, y to 2u) to Rational(12, 7), + mapOf(x to 1u, y to 2u) to Rational(-10, 3), + mapOf(x to 2u, y to 2u) to Rational(9, 8), + ) + LabeledPolynomial( + mapOf() to Rational(-20, 2), + mapOf(x to 1u) to Rational(0, 9), + mapOf(x to 2u) to Rational(-20, 7), + mapOf(x to 0u, y to 1u) to Rational(-1, 9), + mapOf(x to 1u, y to 1u) to Rational(2, 5), + mapOf(x to 2u, y to 1u) to Rational(10, 6), + mapOf(x to 0u, y to 2u) to Rational(7, 9), + mapOf(x to 1u, y to 2u) to Rational(5, 7), + mapOf(x to 2u, y to 2u) to Rational(-2, 3), + ), + "test 2" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(-17, 2), + mapOf(x to 1u) to Rational(-1, 3), + mapOf(x to 2u) to Rational(-25, 21), + mapOf(x to 0u, y to 1u) to Rational(-1, 9), + mapOf(x to 1u, y to 1u) to Rational(2, 5), + mapOf(x to 2u, y to 1u) to Rational(10, 6), + mapOf(x to 0u, y to 2u) to Rational(12, 7), + mapOf(x to 1u, y to 2u) to Rational(-10, 3), + mapOf(x to 2u, y to 2u) to Rational(9, 8), + ), + LabeledPolynomial( + mapOf() to Rational(6, 4), + mapOf(x to 1u) to Rational(-2, 6), + mapOf(x to 2u) to Rational(10, 6), + mapOf(x to 0u, y to 2u) to Rational(12, 7), + mapOf(x to 1u, y to 2u) to Rational(-10, 3), + mapOf(x to 2u, y to 2u) to Rational(9, 8), + ) + LabeledPolynomial( + mapOf() to Rational(-20, 2), + mapOf(x to 1u) to Rational(0, 9), + mapOf(x to 2u) to Rational(-20, 7), + mapOf(x to 0u, y to 1u) to Rational(-1, 9), + mapOf(x to 1u, y to 1u) to Rational(2, 5), + mapOf(x to 2u, y to 1u) to Rational(10, 6), + mapOf(x to 0u, y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(0), + ), + "test 3" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(0), + mapOf(x to 1u) to Rational(0), + mapOf(x to 2u) to Rational(0), + mapOf(x to 0u, y to 1u) to Rational(0), + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(x to 0u, y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(0), + ), + LabeledPolynomial( + mapOf() to Rational(6, 4), + mapOf(x to 1u) to Rational(-2, 6), + mapOf(x to 2u) to Rational(10, 6), + mapOf(x to 0u, y to 1u) to Rational(17, 7), + mapOf(x to 1u, y to 1u) to Rational(-7, 7), + mapOf(x to 2u, y to 1u) to Rational(12, 5), + mapOf(x to 0u, y to 2u) to Rational(12, 7), + mapOf(x to 1u, y to 2u) to Rational(-10, 3), + mapOf(x to 2u, y to 2u) to Rational(9, 8), + ) + LabeledPolynomial( + mapOf() to Rational(-6, 4), + mapOf(x to 1u) to Rational(2, 6), + mapOf(x to 2u) to Rational(-10, 6), + mapOf(x to 0u, y to 1u) to Rational(-17, 7), + mapOf(x to 1u, y to 1u) to Rational(7, 7), + mapOf(x to 2u, y to 1u) to Rational(-12, 5), + mapOf(x to 0u, y to 2u) to Rational(-12, 7), + mapOf(x to 1u, y to 2u) to Rational(10, 3), + mapOf(x to 2u, y to 2u) to Rational(-9, 8), + ), + "test 4" + ) + } + } + @Test + fun test_Polynomial_Polynomial_minus() { + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomial( + mapOf() to Rational(-17, 2), + mapOf(x to 1u) to Rational(-1, 3), + mapOf(x to 2u) to Rational(-25, 21), + mapOf(x to 0u, y to 1u) to Rational(146, 63), + mapOf(x to 1u, y to 1u) to Rational(-3, 5), + mapOf(x to 2u, y to 1u) to Rational(61, 15), + mapOf(x to 0u, y to 2u) to Rational(157, 63), + mapOf(x to 1u, y to 2u) to Rational(-55, 21), + mapOf(x to 2u, y to 2u) to Rational(11, 24), + ), + LabeledPolynomial( + mapOf() to Rational(6, 4), + mapOf(x to 1u) to Rational(-2, 6), + mapOf(x to 2u) to Rational(10, 6), + mapOf(x to 0u, y to 1u) to Rational(17, 7), + mapOf(x to 1u, y to 1u) to Rational(-7, 7), + mapOf(x to 2u, y to 1u) to Rational(12, 5), + mapOf(x to 0u, y to 2u) to Rational(12, 7), + mapOf(x to 1u, y to 2u) to Rational(-10, 3), + mapOf(x to 2u, y to 2u) to Rational(9, 8), + ) - LabeledPolynomial( + mapOf() to Rational(20, 2), + mapOf(x to 1u) to Rational(0, 9), + mapOf(x to 2u) to Rational(20, 7), + mapOf(x to 0u, y to 1u) to Rational(1, 9), + mapOf(x to 1u, y to 1u) to Rational(-2, 5), + mapOf(x to 2u, y to 1u) to Rational(-10, 6), + mapOf(x to 0u, y to 2u) to Rational(-7, 9), + mapOf(x to 1u, y to 2u) to Rational(-5, 7), + mapOf(x to 2u, y to 2u) to Rational(2, 3), + ), + "test 1" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(-17, 2), + mapOf(x to 1u) to Rational(-1, 3), + mapOf(x to 2u) to Rational(-25, 21), + mapOf(x to 0u, y to 1u) to Rational(-1, 9), + mapOf(x to 1u, y to 1u) to Rational(2, 5), + mapOf(x to 2u, y to 1u) to Rational(10, 6), + mapOf(x to 0u, y to 2u) to Rational(157, 63), + mapOf(x to 1u, y to 2u) to Rational(-55, 21), + mapOf(x to 2u, y to 2u) to Rational(11, 24), + ), + LabeledPolynomial( + mapOf() to Rational(6, 4), + mapOf(x to 1u) to Rational(-2, 6), + mapOf(x to 2u) to Rational(10, 6), + mapOf(x to 0u, y to 2u) to Rational(12, 7), + mapOf(x to 1u, y to 2u) to Rational(-10, 3), + mapOf(x to 2u, y to 2u) to Rational(9, 8), + ) - LabeledPolynomial( + mapOf() to Rational(20, 2), + mapOf(x to 1u) to Rational(0, 9), + mapOf(x to 2u) to Rational(20, 7), + mapOf(x to 0u, y to 1u) to Rational(1, 9), + mapOf(x to 1u, y to 1u) to Rational(-2, 5), + mapOf(x to 2u, y to 1u) to Rational(-10, 6), + mapOf(x to 0u, y to 2u) to Rational(-7, 9), + mapOf(x to 1u, y to 2u) to Rational(-5, 7), + mapOf(x to 2u, y to 2u) to Rational(2, 3), + ), + "test 2" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(-17, 2), + mapOf(x to 1u) to Rational(-1, 3), + mapOf(x to 2u) to Rational(-25, 21), + mapOf(x to 0u, y to 1u) to Rational(-1, 9), + mapOf(x to 1u, y to 1u) to Rational(2, 5), + mapOf(x to 2u, y to 1u) to Rational(10, 6), + mapOf(x to 0u, y to 2u) to Rational(12, 7), + mapOf(x to 1u, y to 2u) to Rational(-10, 3), + mapOf(x to 2u, y to 2u) to Rational(9, 8), + ), + LabeledPolynomial( + mapOf() to Rational(6, 4), + mapOf(x to 1u) to Rational(-2, 6), + mapOf(x to 2u) to Rational(10, 6), + mapOf(x to 0u, y to 2u) to Rational(12, 7), + mapOf(x to 1u, y to 2u) to Rational(-10, 3), + mapOf(x to 2u, y to 2u) to Rational(9, 8), + ) - LabeledPolynomial( + mapOf() to Rational(20, 2), + mapOf(x to 1u) to Rational(0, 9), + mapOf(x to 2u) to Rational(20, 7), + mapOf(x to 0u, y to 1u) to Rational(1, 9), + mapOf(x to 1u, y to 1u) to Rational(-2, 5), + mapOf(x to 2u, y to 1u) to Rational(-10, 6), + mapOf(x to 0u, y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(0), + ), + "test 3" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(0), + mapOf(x to 1u) to Rational(0), + mapOf(x to 2u) to Rational(0), + mapOf(x to 0u, y to 1u) to Rational(0), + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(x to 0u, y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(0), + ), + LabeledPolynomial( + mapOf() to Rational(6, 4), + mapOf(x to 1u) to Rational(-2, 6), + mapOf(x to 2u) to Rational(10, 6), + mapOf(x to 0u, y to 1u) to Rational(17, 7), + mapOf(x to 1u, y to 1u) to Rational(-7, 7), + mapOf(x to 2u, y to 1u) to Rational(12, 5), + mapOf(x to 0u, y to 2u) to Rational(12, 7), + mapOf(x to 1u, y to 2u) to Rational(-10, 3), + mapOf(x to 2u, y to 2u) to Rational(9, 8), + ) - LabeledPolynomial( + mapOf() to Rational(6, 4), + mapOf(x to 1u) to Rational(-2, 6), + mapOf(x to 2u) to Rational(10, 6), + mapOf(x to 0u, y to 1u) to Rational(17, 7), + mapOf(x to 1u, y to 1u) to Rational(-7, 7), + mapOf(x to 2u, y to 1u) to Rational(12, 5), + mapOf(x to 0u, y to 2u) to Rational(12, 7), + mapOf(x to 1u, y to 2u) to Rational(-10, 3), + mapOf(x to 2u, y to 2u) to Rational(9, 8), + ), + "test 4" + ) + } + } + @Test + fun test_Polynomial_Polynomial_times() { + IntModuloRing(35).labeledPolynomialSpace { + // (p + q + r) * (p^2 + q^2 + r^2 - pq - pr - qr) = p^3 + q^3 + r^3 - 3pqr + assertEquals( + LabeledPolynomial( + mapOf(x to 3u) to m(1), + mapOf(x to 0u, y to 3u) to m(1), + mapOf(x to 0u, y to 0u, z to 3u) to m(1), + mapOf(x to 1u, y to 2u) to m(0), + mapOf(x to 0u, y to 1u, z to 2u) to m(0), + mapOf(x to 2u, y to 0u, z to 1u) to m(0), + mapOf(x to 1u, y to 0u, z to 2u) to m(0), + mapOf(x to 2u, y to 1u) to m(0), + mapOf(x to 0u, y to 2u, z to 1u) to m(0), + mapOf(x to 1u, y to 1u, z to 1u) to m(-3), + ), + LabeledPolynomial( + mapOf(x to 1u) to m(1), + mapOf(x to 0u, y to 1u) to m(1), + mapOf(x to 0u, y to 0u, z to 1u) to m(1), + ) * LabeledPolynomial( + mapOf(x to 2u) to m(1), + mapOf(x to 0u, y to 2u) to m(1), + mapOf(x to 0u, y to 0u, z to 2u) to m(1), + mapOf(x to 1u, y to 1u) to m(-1), + mapOf(x to 0u, y to 1u, z to 1u) to m(-1), + mapOf(x to 1u, y to 0u, z to 1u) to m(-1), + ), + "test 1" + ) + // Spoiler: 5 * 7 = 0 + assertEquals( + LabeledPolynomial( + mapOf(x to 2u) to m(0), + mapOf(x to 0u, y to 2u) to m(0), + mapOf(x to 0u, y to 0u, z to 2u) to m(0), + mapOf(x to 1u, y to 1u) to m(0), + mapOf(x to 0u, y to 1u, z to 1u) to m(0), + mapOf(x to 1u, y to 0u, z to 1u) to m(0), + ), + LabeledPolynomial( + mapOf(x to 1u) to m(5), + mapOf(x to 0u, y to 1u) to m(-25), + mapOf(x to 0u, y to 0u, z to 1u) to m(10), + ) * LabeledPolynomial( + mapOf(x to 1u) to m(21), + mapOf(x to 0u, y to 1u) to m(14), + mapOf(x to 0u, y to 0u, z to 1u) to m(-7), + ), + "test 2" + ) + } + } + @Test + fun test_degree() { + RationalField.labeledPolynomialSpace { + assertEquals( + -1, + LabeledPolynomial().degree, + "test 1" + ) + assertEquals( + 0, + LabeledPolynomial( + mapOf() to o + ).degree, + "test 2" + ) + assertEquals( + 6, + LabeledPolynomial( + mapOf(x to 1u, y to 2u, z to 3u) to o + ).degree, + "test 3" + ) + assertEquals( + 4, + LabeledPolynomial( + mapOf(x to 0u, y to 1u, z to 2u, t to 1u, s to 0u) to o + ).degree, + "test 4" + ) + assertEquals( + 3, + LabeledPolynomial( + mapOf() to o, + mapOf(x to 0u, y to 1u) to o, + mapOf(x to 2u, y to 0u, z to 1u) to o, + ).degree, + "test 5" + ) + assertEquals( + 4, + LabeledPolynomial( + mapOf() to o, + mapOf(x to 0u, y to 1u) to o, + mapOf(x to 2u, y to 0u, z to 1u) to o, + mapOf(x to 0u, y to 0u, z to 0u, t to 4u) to o, + ).degree, + "test 6" + ) + } + } + @Test + fun test_degrees() { + RationalField.labeledPolynomialSpace { + assertEquals( + mapOf(), + LabeledPolynomial().degrees, + "test 1" + ) + assertEquals( + mapOf(), + LabeledPolynomial( + mapOf() to o + ).degrees, + "test 2" + ) + assertEquals( + mapOf(x to 1u, y to 2u, z to 3u), + LabeledPolynomial( + mapOf(x to 1u, y to 2u, z to 3u) to o + ).degrees, + "test 3" + ) + assertEquals( + mapOf(y to 1u, z to 2u, t to 1u), + LabeledPolynomial( + mapOf(x to 0u, y to 1u, z to 2u, t to 1u, s to 0u) to o + ).degrees, + "test 4" + ) + assertEquals( + mapOf(x to 2u, y to 1u, z to 1u), + LabeledPolynomial( + mapOf() to o, + mapOf(x to 0u, y to 1u) to o, + mapOf(x to 2u, y to 0u, z to 1u) to o, + ).degrees, + "test 5" + ) + assertEquals( + mapOf(x to 2u, y to 2u, z to 2u, t to 4u), + LabeledPolynomial( + mapOf() to o, + mapOf(x to 1u, y to 2u) to o, + mapOf(x to 0u, y to 1u, z to 2u) to o, + mapOf(x to 2u, y to 0u, z to 1u) to o, + mapOf(x to 0u, y to 0u, z to 0u, t to 4u) to o, + ).degrees, + "test 6" + ) + } + } + @Test + fun test_degreeBy() { + RationalField.labeledPolynomialSpace { + fun LabeledPolynomial.collectDegrees(variables: Set = this.variables + iota): Map = variables.associateWith { degreeBy(it) } + assertEquals( + mapOf(iota to 0u), + LabeledPolynomial().collectDegrees(), + "test 1" + ) + assertEquals( + mapOf(iota to 0u), + LabeledPolynomial( + mapOf() to o + ).collectDegrees(), + "test 2" + ) + assertEquals( + mapOf(x to 1u, y to 2u, z to 3u, iota to 0u), + LabeledPolynomial( + mapOf(x to 1u, y to 2u, z to 3u) to o + ).collectDegrees(), + "test 3" + ) + assertEquals( + mapOf(y to 1u, z to 2u, t to 1u, iota to 0u), + LabeledPolynomial( + mapOf(x to 0u, y to 1u, z to 2u, t to 1u, s to 0u) to o + ).collectDegrees(), + "test 4" + ) + assertEquals( + mapOf(x to 2u, y to 1u, z to 1u, iota to 0u), + LabeledPolynomial( + mapOf() to o, + mapOf(x to 0u, y to 1u) to o, + mapOf(x to 2u, y to 0u, z to 1u) to o, + ).collectDegrees(), + "test 5" + ) + assertEquals( + mapOf(x to 2u, y to 2u, z to 2u, t to 4u, iota to 0u), + LabeledPolynomial( + mapOf() to o, + mapOf(x to 1u, y to 2u) to o, + mapOf(x to 0u, y to 1u, z to 2u) to o, + mapOf(x to 2u, y to 0u, z to 1u) to o, + mapOf(x to 0u, y to 0u, z to 0u, t to 4u) to o, + ).collectDegrees(), + "test 6" + ) + } + } + @Test + fun test_degreeBy_Collection() { + RationalField.labeledPolynomialSpace { + fun LabeledPolynomial.checkDegreeBy(message: String? = null) { + val variables = variables.toList() + iota + val variablesCollectionSequence: Sequence> = sequence { + val appearances = MutableList(variables.size) { 0 } + while (true) { + yield( + buildList { + for ((variableIndex, count) in appearances.withIndex()) repeat(count) { add(variables[variableIndex]) } + } + ) + val indexChange = appearances.indexOfFirst { it < 4 } + if (indexChange == -1) break + appearances[indexChange] += 1 + for (index in 0 until indexChange) appearances[index] = 0 + } + } + for (variablesCollection in variablesCollectionSequence) { + val expected = coefficients.keys.maxOfOrNull { degs -> degs.filterKeys { it in variablesCollection }.values.sum() } ?: 0u + val actual = degreeBy(variablesCollection) + if (actual != expected) + fail("${message ?: ""} Incorrect answer for variable collection $variablesCollection: expected $expected, actual $actual") + } + } + LabeledPolynomial().checkDegreeBy("test 1") + LabeledPolynomial( + mapOf() to o + ).checkDegreeBy("test 2") + LabeledPolynomial( + mapOf(x to 1u, y to 2u, z to 3u) to o + ).checkDegreeBy("test 3") + LabeledPolynomial( + mapOf(x to 0u, y to 1u, z to 2u, t to 1u, s to 0u) to o + ).checkDegreeBy("test 4") + LabeledPolynomial( + mapOf() to o, + mapOf(x to 0u, y to 1u) to o, + mapOf(x to 2u, y to 0u, z to 1u) to o, + ).checkDegreeBy("test 5") + LabeledPolynomial( + mapOf() to o, + mapOf(x to 1u, y to 2u) to o, + mapOf(x to 0u, y to 1u, z to 2u) to o, + mapOf(x to 2u, y to 0u, z to 1u) to o, + mapOf(x to 0u, y to 0u, z to 0u, t to 4u) to o, + ).checkDegreeBy("test 6") + } + } + @Test + fun test_variables() { + RationalField.labeledPolynomialSpace { + assertEquals( + setOf(), + LabeledPolynomial().variables, + "test 1" + ) + assertEquals( + setOf(), + LabeledPolynomial( + mapOf() to o + ).variables, + "test 2" + ) + assertEquals( + setOf(x, y, z), + LabeledPolynomial( + mapOf(x to 1u, y to 2u, z to 3u) to o + ).variables, + "test 3" + ) + assertEquals( + setOf(y, z, t), + LabeledPolynomial( + mapOf(x to 0u, y to 1u, z to 2u, t to 1u, s to 0u) to o + ).variables, + "test 4" + ) + assertEquals( + setOf(x, y, z), + LabeledPolynomial( + mapOf() to o, + mapOf(x to 0u, y to 1u) to o, + mapOf(x to 2u, y to 0u, z to 1u) to o, + ).variables, + "test 5" + ) + assertEquals( + setOf(x, y, z, t), + LabeledPolynomial( + mapOf() to o, + mapOf(x to 1u, y to 2u) to o, + mapOf(x to 0u, y to 1u, z to 2u) to o, + mapOf(x to 2u, y to 0u, z to 1u) to o, + mapOf(x to 0u, y to 0u, z to 0u, t to 4u) to o, + ).variables, + "test 6" + ) + } + } + @Test + fun test_countOfVariables() { + RationalField.labeledPolynomialSpace { + assertEquals( + 0, + LabeledPolynomial().countOfVariables, + "test 1" + ) + assertEquals( + 0, + LabeledPolynomial( + mapOf() to o + ).countOfVariables, + "test 2" + ) + assertEquals( + 3, + LabeledPolynomial( + mapOf(x to 1u, y to 2u, z to 3u) to o + ).countOfVariables, + "test 3" + ) + assertEquals( + 3, + LabeledPolynomial( + mapOf(x to 0u, y to 1u, z to 2u, t to 1u, s to 0u) to o + ).countOfVariables, + "test 4" + ) + assertEquals( + 3, + LabeledPolynomial( + mapOf() to o, + mapOf(x to 0u, y to 1u) to o, + mapOf(x to 2u, y to 0u, z to 1u) to o, + ).countOfVariables, + "test 5" + ) + assertEquals( + 4, + LabeledPolynomial( + mapOf() to o, + mapOf(x to 1u, y to 2u) to o, + mapOf(x to 0u, y to 1u, z to 2u) to o, + mapOf(x to 2u, y to 0u, z to 1u) to o, + mapOf(x to 0u, y to 0u, z to 0u, t to 4u) to o, + ).countOfVariables, + "test 6" + ) + } + } + @Test + fun test_RF_countOfVariables() { + RationalField.labeledRationalFunctionSpace { + assertEquals( + 0, + LabeledRationalFunction( + LabeledPolynomial() + ).countOfVariables, + "test 1" + ) + assertEquals( + 0, + LabeledRationalFunction( + LabeledPolynomial(), + LabeledPolynomial() + ).countOfVariables, + "test 2" + ) + assertEquals( + 0, + LabeledRationalFunction( + LabeledPolynomial( + mapOf() to o + ) + ).countOfVariables, + "test 3" + ) + assertEquals( + 3, + LabeledRationalFunction( + LabeledPolynomial( + mapOf(x to 1u, y to 2u, z to 3u) to o + ) + ).countOfVariables, + "test 4" + ) + assertEquals( + 3, + LabeledRationalFunction( + LabeledPolynomial( + mapOf(x to 0u, y to 1u, z to 0u, t to 1u) to o + ), + LabeledPolynomial( + mapOf(x to 0u, y to 0u, z to 2u) to o + ) + ).countOfVariables, + "test 5" + ) + assertEquals( + 3, + LabeledRationalFunction( + LabeledPolynomial( + mapOf() to o, + mapOf(x to 0u, y to 1u) to o, + mapOf(x to 2u, y to 0u, z to 1u) to o, + ) + ).countOfVariables, + "test 6" + ) + assertEquals( + 4, + LabeledRationalFunction( + LabeledPolynomial( + mapOf() to o, + mapOf(x to 1u, y to 2u) to o, + mapOf(x to 2u, y to 0u, z to 1u) to o, + ), LabeledPolynomial( + mapOf(x to 0u, y to 1u, z to 2u) to o, + mapOf(x to 0u, y to 0u, z to 0u, t to 4u) to o, + ) + ).countOfVariables, + "test 7" + ) + } + } +} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialUtilTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialUtilTest.kt new file mode 100644 index 000000000..cdfe309f9 --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialUtilTest.kt @@ -0,0 +1,8224 @@ +/* + * 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.functions + +import space.kscience.kmath.expressions.Symbol +import space.kscience.kmath.expressions.symbol +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.test.misc.Rational +import space.kscience.kmath.test.misc.RationalField +import space.kscience.kmath.test.misc.assertEquals +import kotlin.test.Ignore +import kotlin.test.Test +import kotlin.test.assertEquals + +class LabeledPolynomialUtilTest { + val x by symbol + val y by symbol + val iota by symbol + + @Test + fun test_Polynomial_substitute_Double() { + assertEquals( + LabeledPolynomialAsIs(emptyMap() to 0.0), + LabeledPolynomialAsIs( + mapOf() to 1.0, + mapOf(x to 1u) to -2.0, + mapOf(x to 2u) to 1.0, + ).substitute(mapOf( + x to 1.0 + )), + 0.001, + "test 1" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to 0.8597048543814783, + mapOf(x to 1u) to 0.22997637465889875, + mapOf(x to 2u) to 0.32675302591924016, + mapOf(y to 1u) to 0.4561746111587508, + mapOf(x to 1u, y to 1u) to 0.5304946210170756, + mapOf(x to 2u, y to 1u) to 0.6244313712888998, + mapOf(y to 2u) to 0.2700930201481795, + mapOf(x to 1u, y to 2u) to -0.06962351375204712, + mapOf(x to 2u, y to 2u) to -0.015206988092131501, + ), + LabeledPolynomialAsIs( + mapOf() to 0.8597048543814783, + mapOf(x to 1u) to 0.22997637465889875, + mapOf(x to 2u) to 0.32675302591924016, + mapOf(y to 1u) to 0.4561746111587508, + mapOf(x to 1u, y to 1u) to 0.5304946210170756, + mapOf(x to 2u, y to 1u) to 0.6244313712888998, + mapOf(y to 2u) to 0.2700930201481795, + mapOf(x to 1u, y to 2u) to -0.06962351375204712, + mapOf(x to 2u, y to 2u) to -0.015206988092131501, + ).substitute(mapOf()), + 0.001, + "test 2" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to 0.8597048543814783, + mapOf(x to 1u) to 0.22997637465889875, + mapOf(x to 2u) to 0.32675302591924016, + mapOf(y to 1u) to 0.4561746111587508, + mapOf(x to 1u, y to 1u) to 0.5304946210170756, + mapOf(x to 2u, y to 1u) to 0.6244313712888998, + mapOf(y to 2u) to 0.2700930201481795, + mapOf(x to 1u, y to 2u) to -0.06962351375204712, + mapOf(x to 2u, y to 2u) to -0.015206988092131501, + ), + LabeledPolynomialAsIs( + mapOf() to 0.8597048543814783, + mapOf(x to 1u) to 0.22997637465889875, + mapOf(x to 2u) to 0.32675302591924016, + mapOf(y to 1u) to 0.4561746111587508, + mapOf(x to 1u, y to 1u) to 0.5304946210170756, + mapOf(x to 2u, y to 1u) to 0.6244313712888998, + mapOf(y to 2u) to 0.2700930201481795, + mapOf(x to 1u, y to 2u) to -0.06962351375204712, + mapOf(x to 2u, y to 2u) to -0.015206988092131501, + ).substitute(mapOf( + iota to 0.9211194782050933 + )), + 0.001, + "test 2'" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to 0.8597048543814783, + mapOf(y to 1u) to 0.4561746111587508, + mapOf(y to 2u) to 0.2700930201481795, + ), + LabeledPolynomialAsIs( + mapOf() to 0.8597048543814783, + mapOf(x to 1u) to 0.22997637465889875, + mapOf(x to 2u) to 0.32675302591924016, + mapOf(y to 1u) to 0.4561746111587508, + mapOf(x to 1u, y to 1u) to 0.5304946210170756, + mapOf(x to 2u, y to 1u) to 0.6244313712888998, + mapOf(y to 2u) to 0.2700930201481795, + mapOf(x to 1u, y to 2u) to -0.06962351375204712, + mapOf(x to 2u, y to 2u) to -0.015206988092131501, + ).substitute(mapOf( + x to 0.0 + )), + 0.001, + "test 3" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to 0.8597048543814783, + mapOf(y to 1u) to 0.4561746111587508, + mapOf(y to 2u) to 0.2700930201481795, + ), + LabeledPolynomialAsIs( + mapOf() to 0.8597048543814783, + mapOf(x to 1u) to 0.22997637465889875, + mapOf(x to 2u) to 0.32675302591924016, + mapOf(y to 1u) to 0.4561746111587508, + mapOf(x to 1u, y to 1u) to 0.5304946210170756, + mapOf(x to 2u, y to 1u) to 0.6244313712888998, + mapOf(y to 2u) to 0.2700930201481795, + mapOf(x to 1u, y to 2u) to -0.06962351375204712, + mapOf(x to 2u, y to 2u) to -0.015206988092131501, + ).substitute(mapOf( + x to 0.0, + iota to 0.9211194782050933 + )), + 0.001, + "test 3'" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to 1.433510890645169, + mapOf(x to 1u) to 0.6264844682514724, + mapOf(x to 2u) to 0.8405727903771333, + ), + LabeledPolynomialAsIs( + mapOf() to 0.8597048543814783, + mapOf(x to 1u) to 0.22997637465889875, + mapOf(x to 2u) to 0.32675302591924016, + mapOf(y to 1u) to 0.4561746111587508, + mapOf(x to 1u, y to 1u) to 0.5304946210170756, + mapOf(x to 2u, y to 1u) to 0.6244313712888998, + mapOf(y to 2u) to 0.2700930201481795, + mapOf(x to 1u, y to 2u) to -0.06962351375204712, + mapOf(x to 2u, y to 2u) to -0.015206988092131501, + ).substitute(mapOf( + y to 0.8400458576651112 + )), + 0.001, + "test 4" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to 1.433510890645169, + mapOf(x to 1u) to 0.6264844682514724, + mapOf(x to 2u) to 0.8405727903771333, + ), + LabeledPolynomialAsIs( + mapOf() to 0.8597048543814783, + mapOf(x to 1u) to 0.22997637465889875, + mapOf(x to 2u) to 0.32675302591924016, + mapOf(y to 1u) to 0.4561746111587508, + mapOf(x to 1u, y to 1u) to 0.5304946210170756, + mapOf(x to 2u, y to 1u) to 0.6244313712888998, + mapOf(y to 2u) to 0.2700930201481795, + mapOf(x to 1u, y to 2u) to -0.06962351375204712, + mapOf(x to 2u, y to 2u) to -0.015206988092131501, + ).substitute(mapOf( + y to 0.8400458576651112, + iota to 0.9211194782050933 + )), + 0.001, + "test 4'" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to 1.934530767358133, + ), + LabeledPolynomialAsIs( + mapOf() to 0.8597048543814783, + mapOf(x to 1u) to 0.22997637465889875, + mapOf(x to 2u) to 0.32675302591924016, + mapOf(y to 1u) to 0.4561746111587508, + mapOf(x to 1u, y to 1u) to 0.5304946210170756, + mapOf(x to 2u, y to 1u) to 0.6244313712888998, + mapOf(y to 2u) to 0.2700930201481795, + mapOf(x to 1u, y to 2u) to -0.06962351375204712, + mapOf(x to 2u, y to 2u) to -0.015206988092131501, + ).substitute(mapOf( + x to 0.4846192734143442, + y to 0.8400458576651112, + )), + 0.001, + "test 5" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to 1.934530767358133, + ), + LabeledPolynomialAsIs( + mapOf() to 0.8597048543814783, + mapOf(x to 1u) to 0.22997637465889875, + mapOf(x to 2u) to 0.32675302591924016, + mapOf(y to 1u) to 0.4561746111587508, + mapOf(x to 1u, y to 1u) to 0.5304946210170756, + mapOf(x to 2u, y to 1u) to 0.6244313712888998, + mapOf(y to 2u) to 0.2700930201481795, + mapOf(x to 1u, y to 2u) to -0.06962351375204712, + mapOf(x to 2u, y to 2u) to -0.015206988092131501, + ).substitute(mapOf( + x to 0.4846192734143442, + y to 0.8400458576651112, + iota to 0.9211194782050933 + )), + 0.001, + "test 5'" + ) + } + @Test + fun test_Polynomial_substitute_Constant_Map() { + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(0) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1) + ).substitute(RationalField, mapOf( + x to Rational(1) + )), + "test 1" + ) + // https://www.wolframalpha.com/input?i=%28-3%2F2+%2B+8%2F6+x+%2B+14%2F6+x%5E2%29+%2B+%28-3%2F1+%2B+-19%2F2+x+%2B+9%2F4+x%5E2%29+y+%2B+%285%2F5+%2B+18%2F9+x+%2B+5%2F2+x%5E2%29+y%5E2+where+x+%3D+-2%2F5%2C+y+%3D+12%2F9 + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(143, 150) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 2), + mapOf(x to 1u) to Rational(8, 6), + mapOf(x to 2u) to Rational(14, 6), + mapOf(y to 1u) to Rational(-3, 1), + mapOf(x to 1u, y to 1u) to Rational(-19, 2), + mapOf(x to 2u, y to 1u) to Rational(9, 4), + mapOf(y to 2u) to Rational(5, 5), + mapOf(x to 1u, y to 2u) to Rational(18, 9), + mapOf(x to 2u, y to 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + x to Rational(-2, 5), + y to Rational(12, 9), + )), + "test 2" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(143, 150) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 2), + mapOf(x to 1u) to Rational(8, 6), + mapOf(x to 2u) to Rational(14, 6), + mapOf(y to 1u) to Rational(-3, 1), + mapOf(x to 1u, y to 1u) to Rational(-19, 2), + mapOf(x to 2u, y to 1u) to Rational(9, 4), + mapOf(y to 2u) to Rational(5, 5), + mapOf(x to 1u, y to 2u) to Rational(18, 9), + mapOf(x to 2u, y to 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + x to Rational(-2, 5), + y to Rational(12, 9), + iota to Rational(57, 179), + )), + "test 2'" + ) + // https://www.wolframalpha.com/input?i=%28-3%2F2+%2B+8%2F6+x+%2B+14%2F6+x%5E2%29+%2B+%28-3%2F1+%2B+-19%2F2+x+%2B+9%2F4+x%5E2%29+y+%2B+%285%2F5+%2B+18%2F9+x+%2B+5%2F2+x%5E2%29+y%5E2+where+y+%3D+12%2F9 + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-67, 18), + mapOf(x to 1u) to Rational(-70, 9), + mapOf(x to 2u) to Rational(88, 9), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 2), + mapOf(x to 1u) to Rational(8, 6), + mapOf(x to 2u) to Rational(14, 6), + mapOf(y to 1u) to Rational(-3, 1), + mapOf(x to 1u, y to 1u) to Rational(-19, 2), + mapOf(x to 2u, y to 1u) to Rational(9, 4), + mapOf(y to 2u) to Rational(5, 5), + mapOf(x to 1u, y to 2u) to Rational(18, 9), + mapOf(x to 2u, y to 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + y to Rational(12, 9), + )), + "test 3" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-67, 18), + mapOf(x to 1u) to Rational(-70, 9), + mapOf(x to 2u) to Rational(88, 9), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 2), + mapOf(x to 1u) to Rational(8, 6), + mapOf(x to 2u) to Rational(14, 6), + mapOf(y to 1u) to Rational(-3, 1), + mapOf(x to 1u, y to 1u) to Rational(-19, 2), + mapOf(x to 2u, y to 1u) to Rational(9, 4), + mapOf(y to 2u) to Rational(5, 5), + mapOf(x to 1u, y to 2u) to Rational(18, 9), + mapOf(x to 2u, y to 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + y to Rational(12, 9), + iota to Rational(57, 179), + )), + "test 3'" + ) + // https://www.wolframalpha.com/input?i=%28-3%2F2+%2B+8%2F6+x+%2B+14%2F6+x%5E2%29+%2B+%28-3%2F1+%2B+-19%2F2+x+%2B+9%2F4+x%5E2%29+y+%2B+%285%2F5+%2B+18%2F9+x+%2B+5%2F2+x%5E2%29+y%5E2+where+x+%3D+-2%2F5 + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-83, 50), + mapOf(y to 1u) to Rational(29, 25), + mapOf(y to 2u) to Rational(3, 5), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 2), + mapOf(x to 1u) to Rational(8, 6), + mapOf(x to 2u) to Rational(14, 6), + mapOf(y to 1u) to Rational(-3, 1), + mapOf(x to 1u, y to 1u) to Rational(-19, 2), + mapOf(x to 2u, y to 1u) to Rational(9, 4), + mapOf(y to 2u) to Rational(5, 5), + mapOf(x to 1u, y to 2u) to Rational(18, 9), + mapOf(x to 2u, y to 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + x to Rational(-2, 5), + )), + "test 4" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-83, 50), + mapOf(y to 1u) to Rational(29, 25), + mapOf(y to 2u) to Rational(3, 5), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 2), + mapOf(x to 1u) to Rational(8, 6), + mapOf(x to 2u) to Rational(14, 6), + mapOf(y to 1u) to Rational(-3, 1), + mapOf(x to 1u, y to 1u) to Rational(-19, 2), + mapOf(x to 2u, y to 1u) to Rational(9, 4), + mapOf(y to 2u) to Rational(5, 5), + mapOf(x to 1u, y to 2u) to Rational(18, 9), + mapOf(x to 2u, y to 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + x to Rational(-2, 5), + iota to Rational(57, 179), + )), + "test 4'" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 2), + mapOf(x to 1u) to Rational(8, 6), + mapOf(x to 2u) to Rational(14, 6), + mapOf(y to 1u) to Rational(-3, 1), + mapOf(x to 1u, y to 1u) to Rational(-19, 2), + mapOf(x to 2u, y to 1u) to Rational(9, 4), + mapOf(y to 2u) to Rational(5, 5), + mapOf(x to 1u, y to 2u) to Rational(18, 9), + mapOf(x to 2u, y to 2u) to Rational(5, 2), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 2), + mapOf(x to 1u) to Rational(8, 6), + mapOf(x to 2u) to Rational(14, 6), + mapOf(y to 1u) to Rational(-3, 1), + mapOf(x to 1u, y to 1u) to Rational(-19, 2), + mapOf(x to 2u, y to 1u) to Rational(9, 4), + mapOf(y to 2u) to Rational(5, 5), + mapOf(x to 1u, y to 2u) to Rational(18, 9), + mapOf(x to 2u, y to 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf()), + "test 5" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 2), + mapOf(x to 1u) to Rational(8, 6), + mapOf(x to 2u) to Rational(14, 6), + mapOf(y to 1u) to Rational(-3, 1), + mapOf(x to 1u, y to 1u) to Rational(-19, 2), + mapOf(x to 2u, y to 1u) to Rational(9, 4), + mapOf(y to 2u) to Rational(5, 5), + mapOf(x to 1u, y to 2u) to Rational(18, 9), + mapOf(x to 2u, y to 2u) to Rational(5, 2), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 2), + mapOf(x to 1u) to Rational(8, 6), + mapOf(x to 2u) to Rational(14, 6), + mapOf(y to 1u) to Rational(-3, 1), + mapOf(x to 1u, y to 1u) to Rational(-19, 2), + mapOf(x to 2u, y to 1u) to Rational(9, 4), + mapOf(y to 2u) to Rational(5, 5), + mapOf(x to 1u, y to 2u) to Rational(18, 9), + mapOf(x to 2u, y to 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + iota to Rational(57, 179), + )), + "test 5'" + ) + // https://www.wolframalpha.com/input?i=%28%28-3%2F2+%2B+8%2F6+x+%2B+14%2F6+x%5E2%29+%2B+%28-3%2F1+%2B+-19%2F2+x+%2B+9%2F4+x%5E2%29+y+%2B+%285%2F5+%2B+18%2F9+x+%2B+5%2F2+x%5E2%29+y%5E2%29+p%5E8+where+x+%3D+q%2Fp%2C+y+%3D+x%5E3%2C+p+%3D+-2%2F5%2C+q+%3D+12%2F9 + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(47639065216, 2562890625) + ), + LabeledPolynomialAsIs( + mapOf(x to 8u) to Rational(-3, 2), + mapOf(x to 7u, y to 1u) to Rational(8, 6), + mapOf(x to 6u, y to 2u) to Rational(14, 6), + mapOf(x to 5u, y to 3u) to Rational(-3, 1), + mapOf(x to 4u, y to 4u) to Rational(-19, 2), + mapOf(x to 3u, y to 5u) to Rational(9, 4), + mapOf(x to 2u, y to 6u) to Rational(5, 5), + mapOf(x to 1u, y to 7u) to Rational(18, 9), + mapOf(y to 8u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + x to Rational(-2, 5), + y to Rational(12, 9), + )), + "test 6" + ) + } + @Test + fun test_Polynomial_substitute_Polynomial_Map() { + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(0) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1) + ).substitute(RationalField, mapOf( + x to LabeledPolynomialAsIs( + mapOf() to Rational(1) + ) + )), + "test 1" + ) + // https://www.wolframalpha.com/input?i=%28-3%2F2+%2B+8%2F6+x+%2B+14%2F6+x%5E2%29+%2B+%28-3%2F1+%2B+-19%2F2+x+%2B+9%2F4+x%5E2%29+y+%2B+%285%2F5+%2B+18%2F9+x+%2B+5%2F2+x%5E2%29+y%5E2+where+x+%3D+-5%2F1+s+%2B+2%2F8+t%2C+y+%3D+11%2F7+t + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 2), + mapOf(y to 1u) to Rational(-92, 21), + mapOf(y to 2u) to Rational(-2627, 2352), + mapOf(y to 3u) to Rational(4565, 3136), + mapOf(y to 4u) to Rational(605, 1568), + mapOf(x to 1u) to Rational(-20, 3), + mapOf(x to 1u, y to 1u) to Rational(1445, 21), + mapOf(x to 1u, y to 2u) to Rational(-13145, 392), + mapOf(x to 1u, y to 3u) to Rational(-3025, 196), + mapOf(x to 2u) to Rational(175, 3), + mapOf(x to 2u, y to 1u) to Rational(2475, 28), + mapOf(x to 2u, y to 2u) to Rational(15125, 98), + mapOf(x to 3u) to Rational(0), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u) to Rational(0), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 2), + mapOf(x to 1u) to Rational(8, 6), + mapOf(x to 2u) to Rational(14, 6), + mapOf(y to 1u) to Rational(-3, 1), + mapOf(x to 1u, y to 1u) to Rational(-19, 2), + mapOf(x to 2u, y to 1u) to Rational(9, 4), + mapOf(y to 2u) to Rational(5, 5), + mapOf(x to 1u, y to 2u) to Rational(18, 9), + mapOf(x to 2u, y to 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + x to LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(-5, 1), + mapOf(y to 1u) to Rational(2, 8), + ), + y to LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(0, 5), + mapOf(y to 1u) to Rational(11, 7), + ), + )), + "test 2" + ) + // (-3/2 + 8/6 x + 14/6 x^2) + (-3/1 + -19/2 x + 9/4 x^2) y + (5/5 + 18/9 x + 5/2 x^2) y^2 where x = (0/6 + 14/8 s + -14/2 s^2) + (-3/5 + 11/1 s + 3/7 s^2) t + (-3/7 + -18/5 s + -9/1 s^2) t^2, y = (-9/2 + 2/7 s + 9/1 s^2) + (13/1 + -1/8 s + 2/8 s^2) t + (19/4 + 15/7 s + -19/4 s^2) t^2 + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(129, 4), + mapOf(x to 1u) to Rational(48583, 336), + mapOf(x to 2u) to Rational(-913477, 1568), + mapOf(x to 3u) to Rational(-967567, 672), + mapOf(x to 4u) to Rational(4722043, 1344), + mapOf(x to 5u) to Rational(8855, 2), + mapOf(x to 6u) to Rational(-311971, 32), + mapOf(x to 7u) to Rational(-17325, 4), + mapOf(x to 8u) to Rational(19845, 2), + mapOf(y to 1u) to Rational(-827, 4), + mapOf(x to 1u, y to 1u) to Rational(191927, 840), + mapOf(x to 2u, y to 1u) to Rational(9592627, 2352), + mapOf(x to 3u, y to 1u) to Rational(-105400711, 53760), + mapOf(x to 4u, y to 1u) to Rational(-10054101459, 439040), + mapOf(x to 5u, y to 1u) to Rational(2127351, 128), + mapOf(x to 6u, y to 1u) to Rational(116680973, 3136), + mapOf(x to 7u, y to 1u) to Rational(-220445, 7), + mapOf(x to 8u, y to 1u) to Rational(-2655, 4), + mapOf(y to 2u) to Rational(30567, 100), + mapOf(x to 1u, y to 2u) to Rational(-156284953, 39200), + mapOf(x to 2u, y to 2u) to Rational(-57661541711, 6585600), + mapOf(x to 3u, y to 2u) to Rational(131931579, 3136), + mapOf(x to 4u, y to 2u) to Rational(98818124791, 3512320), + mapOf(x to 5u, y to 2u) to Rational(-94458855053, 878080), + mapOf(x to 6u, y to 2u) to Rational(13937705305, 1229312), + mapOf(x to 7u, y to 2u) to Rational(335706887, 21952), + mapOf(x to 8u, y to 2u) to Rational(23549165, 1568), + mapOf(y to 3u) to Rational(111367, 1400), + mapOf(x to 1u, y to 3u) to Rational(4937369, 700), + mapOf(x to 2u, y to 3u) to Rational(-4449423711, 274400), + mapOf(x to 3u, y to 3u) to Rational(-351873325703, 4390400), + mapOf(x to 4u, y to 3u) to Rational(23495875029, 307328), + mapOf(x to 5u, y to 3u) to Rational(17576300919, 878080), + mapOf(x to 6u, y to 3u) to Rational(230316993, 12544), + mapOf(x to 7u, y to 3u) to Rational(-191130515, 21952), + mapOf(x to 8u, y to 3u) to Rational(332435, 392), + mapOf(y to 4u) to Rational(-275084, 1225), + mapOf(x to 1u, y to 4u) to Rational(-266774603, 137200), + mapOf(x to 2u, y to 4u) to Rational(2176279167121, 30732800), + mapOf(x to 3u, y to 4u) to Rational(10904913303, 2195200), + mapOf(x to 4u, y to 4u) to Rational(-10769286147, 2195200), + mapOf(x to 5u, y to 4u) to Rational(-26277119793, 439040), + mapOf(x to 6u, y to 4u) to Rational(25859735869, 6146560), + mapOf(x to 7u, y to 4u) to Rational(38906289, 2744), + mapOf(x to 8u, y to 4u) to Rational(-3072025, 392), + mapOf(y to 5u) to Rational(9573, 98), + mapOf(x to 1u, y to 5u) to Rational(-4154651399, 548800), + mapOf(x to 2u, y to 5u) to Rational(3446069019, 548800), + mapOf(x to 3u, y to 5u) to Rational(-7851500623, 137200), + mapOf(x to 4u, y to 5u) to Rational(-53205142903, 1920800), + mapOf(x to 5u, y to 5u) to Rational(-31953611, 3430), + mapOf(x to 6u, y to 5u) to Rational(1447380313, 109760), + mapOf(x to 7u, y to 5u) to Rational(764158625, 21952), + mapOf(x to 8u, y to 5u) to Rational(1153515, 784), + mapOf(y to 6u) to Rational(1722351, 7840), + mapOf(x to 1u, y to 6u) to Rational(-164554821, 109760), + mapOf(x to 2u, y to 6u) to Rational(-79096147243, 7683200), + mapOf(x to 3u, y to 6u) to Rational(-624721089, 15680), + mapOf(x to 4u, y to 6u) to Rational(11147305567, 548800), + mapOf(x to 5u, y to 6u) to Rational(8318333679, 109760), + mapOf(x to 6u, y to 6u) to Rational(32981871553, 1536640), + mapOf(x to 7u, y to 6u) to Rational(-225359619, 21952), + mapOf(x to 8u, y to 6u) to Rational(-3973995, 392), + mapOf(y to 7u) to Rational(67203, 784), + mapOf(x to 1u, y to 7u) to Rational(39281469, 54880), + mapOf(x to 2u, y to 7u) to Rational(70162551, 27440), + mapOf(x to 3u, y to 7u) to Rational(413630709, 54880), + mapOf(x to 4u, y to 7u) to Rational(4640410269, 192080), + mapOf(x to 5u, y to 7u) to Rational(802712247, 54880), + mapOf(x to 6u, y to 7u) to Rational(-473517603, 27440), + mapOf(x to 7u, y to 7u) to Rational(-17055459, 1568), + mapOf(x to 8u, y to 7u) to Rational(-12825, 14), + mapOf(y to 8u) to Rational(16245, 1568), + mapOf(x to 1u, y to 8u) to Rational(503253, 2744), + mapOf(x to 2u, y to 8u) to Rational(125292591, 96040), + mapOf(x to 3u, y to 8u) to Rational(12033171, 2744), + mapOf(x to 4u, y to 8u) to Rational(154352673, 27440), + mapOf(x to 5u, y to 8u) to Rational(-1302291, 392), + mapOf(x to 6u, y to 8u) to Rational(-20265741, 1960), + mapOf(x to 7u, y to 8u) to Rational(-26163, 56), + mapOf(x to 8u, y to 8u) to Rational(146205, 32), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 2), + mapOf(x to 1u) to Rational(8, 6), + mapOf(x to 2u) to Rational(14, 6), + mapOf(y to 1u) to Rational(-3, 1), + mapOf(x to 1u, y to 1u) to Rational(-19, 2), + mapOf(x to 2u, y to 1u) to Rational(9, 4), + mapOf(y to 2u) to Rational(5, 5), + mapOf(x to 1u, y to 2u) to Rational(18, 9), + mapOf(x to 2u, y to 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + x to LabeledPolynomialAsIs( + mapOf() to Rational(0, 6), + mapOf(x to 1u) to Rational(14, 8), + mapOf(x to 2u) to Rational(-14, 2), + mapOf(y to 1u) to Rational(-3, 5), + mapOf(x to 1u, y to 1u) to Rational(11, 1), + mapOf(x to 2u, y to 1u) to Rational(3, 7), + mapOf(y to 2u) to Rational(-3, 7), + mapOf(x to 1u, y to 2u) to Rational(-18, 5), + mapOf(x to 2u, y to 2u) to Rational(-9, 1), + ), + y to LabeledPolynomialAsIs( + mapOf() to Rational(-9, 2), + mapOf(x to 1u) to Rational(2, 7), + mapOf(x to 2u) to Rational(9, 1), + mapOf(y to 1u) to Rational(13, 1), + mapOf(x to 1u, y to 1u) to Rational(-1, 8), + mapOf(x to 2u, y to 1u) to Rational(2, 8), + mapOf(y to 2u) to Rational(19, 4), + mapOf(x to 1u, y to 2u) to Rational(15, 7), + mapOf(x to 2u, y to 2u) to Rational(-19, 4), + ), + )), + "test 3" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(129, 4), + mapOf(x to 1u) to Rational(48583, 336), + mapOf(x to 2u) to Rational(-913477, 1568), + mapOf(x to 3u) to Rational(-967567, 672), + mapOf(x to 4u) to Rational(4722043, 1344), + mapOf(x to 5u) to Rational(8855, 2), + mapOf(x to 6u) to Rational(-311971, 32), + mapOf(x to 7u) to Rational(-17325, 4), + mapOf(x to 8u) to Rational(19845, 2), + mapOf(y to 1u) to Rational(-827, 4), + mapOf(x to 1u, y to 1u) to Rational(191927, 840), + mapOf(x to 2u, y to 1u) to Rational(9592627, 2352), + mapOf(x to 3u, y to 1u) to Rational(-105400711, 53760), + mapOf(x to 4u, y to 1u) to Rational(-10054101459, 439040), + mapOf(x to 5u, y to 1u) to Rational(2127351, 128), + mapOf(x to 6u, y to 1u) to Rational(116680973, 3136), + mapOf(x to 7u, y to 1u) to Rational(-220445, 7), + mapOf(x to 8u, y to 1u) to Rational(-2655, 4), + mapOf(y to 2u) to Rational(30567, 100), + mapOf(x to 1u, y to 2u) to Rational(-156284953, 39200), + mapOf(x to 2u, y to 2u) to Rational(-57661541711, 6585600), + mapOf(x to 3u, y to 2u) to Rational(131931579, 3136), + mapOf(x to 4u, y to 2u) to Rational(98818124791, 3512320), + mapOf(x to 5u, y to 2u) to Rational(-94458855053, 878080), + mapOf(x to 6u, y to 2u) to Rational(13937705305, 1229312), + mapOf(x to 7u, y to 2u) to Rational(335706887, 21952), + mapOf(x to 8u, y to 2u) to Rational(23549165, 1568), + mapOf(y to 3u) to Rational(111367, 1400), + mapOf(x to 1u, y to 3u) to Rational(4937369, 700), + mapOf(x to 2u, y to 3u) to Rational(-4449423711, 274400), + mapOf(x to 3u, y to 3u) to Rational(-351873325703, 4390400), + mapOf(x to 4u, y to 3u) to Rational(23495875029, 307328), + mapOf(x to 5u, y to 3u) to Rational(17576300919, 878080), + mapOf(x to 6u, y to 3u) to Rational(230316993, 12544), + mapOf(x to 7u, y to 3u) to Rational(-191130515, 21952), + mapOf(x to 8u, y to 3u) to Rational(332435, 392), + mapOf(y to 4u) to Rational(-275084, 1225), + mapOf(x to 1u, y to 4u) to Rational(-266774603, 137200), + mapOf(x to 2u, y to 4u) to Rational(2176279167121, 30732800), + mapOf(x to 3u, y to 4u) to Rational(10904913303, 2195200), + mapOf(x to 4u, y to 4u) to Rational(-10769286147, 2195200), + mapOf(x to 5u, y to 4u) to Rational(-26277119793, 439040), + mapOf(x to 6u, y to 4u) to Rational(25859735869, 6146560), + mapOf(x to 7u, y to 4u) to Rational(38906289, 2744), + mapOf(x to 8u, y to 4u) to Rational(-3072025, 392), + mapOf(y to 5u) to Rational(9573, 98), + mapOf(x to 1u, y to 5u) to Rational(-4154651399, 548800), + mapOf(x to 2u, y to 5u) to Rational(3446069019, 548800), + mapOf(x to 3u, y to 5u) to Rational(-7851500623, 137200), + mapOf(x to 4u, y to 5u) to Rational(-53205142903, 1920800), + mapOf(x to 5u, y to 5u) to Rational(-31953611, 3430), + mapOf(x to 6u, y to 5u) to Rational(1447380313, 109760), + mapOf(x to 7u, y to 5u) to Rational(764158625, 21952), + mapOf(x to 8u, y to 5u) to Rational(1153515, 784), + mapOf(y to 6u) to Rational(1722351, 7840), + mapOf(x to 1u, y to 6u) to Rational(-164554821, 109760), + mapOf(x to 2u, y to 6u) to Rational(-79096147243, 7683200), + mapOf(x to 3u, y to 6u) to Rational(-624721089, 15680), + mapOf(x to 4u, y to 6u) to Rational(11147305567, 548800), + mapOf(x to 5u, y to 6u) to Rational(8318333679, 109760), + mapOf(x to 6u, y to 6u) to Rational(32981871553, 1536640), + mapOf(x to 7u, y to 6u) to Rational(-225359619, 21952), + mapOf(x to 8u, y to 6u) to Rational(-3973995, 392), + mapOf(y to 7u) to Rational(67203, 784), + mapOf(x to 1u, y to 7u) to Rational(39281469, 54880), + mapOf(x to 2u, y to 7u) to Rational(70162551, 27440), + mapOf(x to 3u, y to 7u) to Rational(413630709, 54880), + mapOf(x to 4u, y to 7u) to Rational(4640410269, 192080), + mapOf(x to 5u, y to 7u) to Rational(802712247, 54880), + mapOf(x to 6u, y to 7u) to Rational(-473517603, 27440), + mapOf(x to 7u, y to 7u) to Rational(-17055459, 1568), + mapOf(x to 8u, y to 7u) to Rational(-12825, 14), + mapOf(y to 8u) to Rational(16245, 1568), + mapOf(x to 1u, y to 8u) to Rational(503253, 2744), + mapOf(x to 2u, y to 8u) to Rational(125292591, 96040), + mapOf(x to 3u, y to 8u) to Rational(12033171, 2744), + mapOf(x to 4u, y to 8u) to Rational(154352673, 27440), + mapOf(x to 5u, y to 8u) to Rational(-1302291, 392), + mapOf(x to 6u, y to 8u) to Rational(-20265741, 1960), + mapOf(x to 7u, y to 8u) to Rational(-26163, 56), + mapOf(x to 8u, y to 8u) to Rational(146205, 32), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 2), + mapOf(x to 1u) to Rational(8, 6), + mapOf(x to 2u) to Rational(14, 6), + mapOf(y to 1u) to Rational(-3, 1), + mapOf(x to 1u, y to 1u) to Rational(-19, 2), + mapOf(x to 2u, y to 1u) to Rational(9, 4), + mapOf(y to 2u) to Rational(5, 5), + mapOf(x to 1u, y to 2u) to Rational(18, 9), + mapOf(x to 2u, y to 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + x to LabeledPolynomialAsIs( + mapOf() to Rational(0, 6), + mapOf(x to 1u) to Rational(14, 8), + mapOf(x to 2u) to Rational(-14, 2), + mapOf(y to 1u) to Rational(-3, 5), + mapOf(x to 1u, y to 1u) to Rational(11, 1), + mapOf(x to 2u, y to 1u) to Rational(3, 7), + mapOf(y to 2u) to Rational(-3, 7), + mapOf(x to 1u, y to 2u) to Rational(-18, 5), + mapOf(x to 2u, y to 2u) to Rational(-9, 1), + ), + y to LabeledPolynomialAsIs( + mapOf() to Rational(-9, 2), + mapOf(x to 1u) to Rational(2, 7), + mapOf(x to 2u) to Rational(9, 1), + mapOf(y to 1u) to Rational(13, 1), + mapOf(x to 1u, y to 1u) to Rational(-1, 8), + mapOf(x to 2u, y to 1u) to Rational(2, 8), + mapOf(y to 2u) to Rational(19, 4), + mapOf(x to 1u, y to 2u) to Rational(15, 7), + mapOf(x to 2u, y to 2u) to Rational(-19, 4), + ), + iota to LabeledPolynomialAsIs( + mapOf() to Rational(-11, 3), + mapOf(x to 1u) to Rational(5, 2), + mapOf(x to 2u) to Rational(13, 7), + mapOf(y to 1u) to Rational(16, 9), + mapOf(x to 1u, y to 1u) to Rational(14, 7), + mapOf(x to 2u, y to 1u) to Rational(6, 1), + mapOf(y to 2u) to Rational(-14, 3), + mapOf(x to 1u, y to 2u) to Rational(-2, 7), + mapOf(x to 2u, y to 2u) to Rational(-10, 8), + ) + )), + "test 3'" + ) + // (-3/2 + 8/6 x + 14/6 x^2) + (-3/1 + -19/2 x + 9/4 x^2) y + (5/5 + 18/9 x + 5/2 x^2) y^2 where x = s, y = (-9/2 + 2/7 s + 9/1 s^2) + (13/1 + -1/8 s + 2/8 s^2) t + (19/4 + 15/7 s + -19/4 s^2) t^2 + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(129, 4), + mapOf(x to 1u) to Rational(6817, 84), + mapOf(x to 2u) to Rational(-21445, 294), + mapOf(x to 3u) to Rational(-12151, 49), + mapOf(x to 4u) to Rational(-17789, 196), + mapOf(x to 5u) to Rational(1224, 7), + mapOf(x to 6u) to Rational(405, 2), + mapOf(y to 1u) to Rational(-156), + mapOf(x to 1u, y to 1u) to Rational(-2440, 7), + mapOf(x to 2u, y to 1u) to Rational(-1571, 112), + mapOf(x to 3u, y to 1u) to Rational(107515, 224), + mapOf(x to 4u, y to 1u) to Rational(64965, 112), + mapOf(x to 5u, y to 1u) to Rational(209, 56), + mapOf(x to 6u, y to 1u) to Rational(45, 4), + mapOf(y to 2u) to Rational(112), + mapOf(x to 1u, y to 2u) to Rational(1449, 8), + mapOf(x to 2u, y to 2u) to Rational(1306309, 3136), + mapOf(x to 3u, y to 2u) to Rational(483207, 1568), + mapOf(x to 4u, y to 2u) to Rational(1978437, 6272), + mapOf(x to 5u, y to 2u) to Rational(-18231, 224), + mapOf(x to 6u, y to 2u) to Rational(-6835, 32), + mapOf(y to 3u) to Rational(247, 2), + mapOf(x to 1u, y to 3u) to Rational(33771, 112), + mapOf(x to 2u, y to 3u) to Rational(2073, 7), + mapOf(x to 3u, y to 3u) to Rational(-23463, 224), + mapOf(x to 4u, y to 3u) to Rational(-33825, 112), + mapOf(x to 5u, y to 3u) to Rational(201, 224), + mapOf(x to 6u, y to 3u) to Rational(-95, 16), + mapOf(y to 4u) to Rational(361, 16), + mapOf(x to 1u, y to 4u) to Rational(3667, 56), + mapOf(x to 2u, y to 4u) to Rational(88729, 1568), + mapOf(x to 3u, y to 4u) to Rational(-2476, 49), + mapOf(x to 4u, y to 4u) to Rational(-23419, 196), + mapOf(x to 5u, y to 4u) to Rational(-323, 56), + mapOf(x to 6u, y to 4u) to Rational(1805, 32), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 2), + mapOf(x to 1u) to Rational(8, 6), + mapOf(x to 2u) to Rational(14, 6), + mapOf(y to 1u) to Rational(-3, 1), + mapOf(x to 1u, y to 1u) to Rational(-19, 2), + mapOf(x to 2u, y to 1u) to Rational(9, 4), + mapOf(y to 2u) to Rational(5, 5), + mapOf(x to 1u, y to 2u) to Rational(18, 9), + mapOf(x to 2u, y to 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + y to LabeledPolynomialAsIs( + mapOf() to Rational(-9, 2), + mapOf(x to 1u) to Rational(2, 7), + mapOf(x to 2u) to Rational(9, 1), + mapOf(y to 1u) to Rational(13, 1), + mapOf(x to 1u, y to 1u) to Rational(-1, 8), + mapOf(x to 2u, y to 1u) to Rational(2, 8), + mapOf(y to 2u) to Rational(19, 4), + mapOf(x to 1u, y to 2u) to Rational(15, 7), + mapOf(x to 2u, y to 2u) to Rational(-19, 4), + ), + )), + "test 4" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(129, 4), + mapOf(x to 1u) to Rational(6817, 84), + mapOf(x to 2u) to Rational(-21445, 294), + mapOf(x to 3u) to Rational(-12151, 49), + mapOf(x to 4u) to Rational(-17789, 196), + mapOf(x to 5u) to Rational(1224, 7), + mapOf(x to 6u) to Rational(405, 2), + mapOf(y to 1u) to Rational(-156), + mapOf(x to 1u, y to 1u) to Rational(-2440, 7), + mapOf(x to 2u, y to 1u) to Rational(-1571, 112), + mapOf(x to 3u, y to 1u) to Rational(107515, 224), + mapOf(x to 4u, y to 1u) to Rational(64965, 112), + mapOf(x to 5u, y to 1u) to Rational(209, 56), + mapOf(x to 6u, y to 1u) to Rational(45, 4), + mapOf(y to 2u) to Rational(112), + mapOf(x to 1u, y to 2u) to Rational(1449, 8), + mapOf(x to 2u, y to 2u) to Rational(1306309, 3136), + mapOf(x to 3u, y to 2u) to Rational(483207, 1568), + mapOf(x to 4u, y to 2u) to Rational(1978437, 6272), + mapOf(x to 5u, y to 2u) to Rational(-18231, 224), + mapOf(x to 6u, y to 2u) to Rational(-6835, 32), + mapOf(y to 3u) to Rational(247, 2), + mapOf(x to 1u, y to 3u) to Rational(33771, 112), + mapOf(x to 2u, y to 3u) to Rational(2073, 7), + mapOf(x to 3u, y to 3u) to Rational(-23463, 224), + mapOf(x to 4u, y to 3u) to Rational(-33825, 112), + mapOf(x to 5u, y to 3u) to Rational(201, 224), + mapOf(x to 6u, y to 3u) to Rational(-95, 16), + mapOf(y to 4u) to Rational(361, 16), + mapOf(x to 1u, y to 4u) to Rational(3667, 56), + mapOf(x to 2u, y to 4u) to Rational(88729, 1568), + mapOf(x to 3u, y to 4u) to Rational(-2476, 49), + mapOf(x to 4u, y to 4u) to Rational(-23419, 196), + mapOf(x to 5u, y to 4u) to Rational(-323, 56), + mapOf(x to 6u, y to 4u) to Rational(1805, 32), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 2), + mapOf(x to 1u) to Rational(8, 6), + mapOf(x to 2u) to Rational(14, 6), + mapOf(y to 1u) to Rational(-3, 1), + mapOf(x to 1u, y to 1u) to Rational(-19, 2), + mapOf(x to 2u, y to 1u) to Rational(9, 4), + mapOf(y to 2u) to Rational(5, 5), + mapOf(x to 1u, y to 2u) to Rational(18, 9), + mapOf(x to 2u, y to 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + y to LabeledPolynomialAsIs( + mapOf() to Rational(-9, 2), + mapOf(x to 1u) to Rational(2, 7), + mapOf(x to 2u) to Rational(9, 1), + mapOf(y to 1u) to Rational(13, 1), + mapOf(x to 1u, y to 1u) to Rational(-1, 8), + mapOf(x to 2u, y to 1u) to Rational(2, 8), + mapOf(y to 2u) to Rational(19, 4), + mapOf(x to 1u, y to 2u) to Rational(15, 7), + mapOf(x to 2u, y to 2u) to Rational(-19, 4), + ), + iota to LabeledPolynomialAsIs( + mapOf() to Rational(-11, 3), + mapOf(x to 1u) to Rational(5, 2), + mapOf(x to 2u) to Rational(13, 7), + mapOf(y to 1u) to Rational(16, 9), + mapOf(x to 1u, y to 1u) to Rational(14, 7), + mapOf(x to 2u, y to 1u) to Rational(6, 1), + mapOf(y to 2u) to Rational(-14, 3), + mapOf(x to 1u, y to 2u) to Rational(-2, 7), + mapOf(x to 2u, y to 2u) to Rational(-10, 8), + ) + )), + "test 4'" + ) + // (-3/2 + 8/6 x + 14/6 x^2) + (-3/1 + -19/2 x + 9/4 x^2) y + (5/5 + 18/9 x + 5/2 x^2) y^2 where x = (0/6 + 14/8 s + -14/2 s^2) + (-3/5 + 11/1 s + 3/7 s^2) t + (-3/7 + -18/5 s + -9/1 s^2) t^2, y = t + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 2), + mapOf(x to 1u) to Rational(7, 3), + mapOf(x to 2u) to Rational(-35, 16), + mapOf(x to 3u) to Rational(-343, 6), + mapOf(x to 4u) to Rational(343, 3), + mapOf(y to 1u) to Rational(-19, 5), + mapOf(x to 1u, y to 1u) to Rational(-823, 120), + mapOf(x to 2u, y to 1u) to Rational(1232417, 6720), + mapOf(x to 3u, y to 1u) to Rational(-9863, 24), + mapOf(x to 4u, y to 1u) to Rational(385, 4), + mapOf(y to 2u) to Rational(2439, 350), + mapOf(x to 1u, y to 2u) to Rational(-5793, 40), + mapOf(x to 2u, y to 2u) to Rational(1172113, 3360), + mapOf(x to 3u, y to 2u) to Rational(-13531, 40), + mapOf(x to 4u, y to 2u) to Rational(2824, 7), + mapOf(y to 3u) to Rational(3417, 700), + mapOf(x to 1u, y to 3u) to Rational(1191, 200), + mapOf(x to 2u, y to 3u) to Rational(8383, 28), + mapOf(x to 3u, y to 3u) to Rational(-220279, 280), + mapOf(x to 4u, y to 3u) to Rational(49179, 196), + mapOf(y to 4u) to Rational(57, 35), + mapOf(x to 1u, y to 4u) to Rational(-33771, 700), + mapOf(x to 2u, y to 4u) to Rational(196279, 1225), + mapOf(x to 3u, y to 4u) to Rational(-32259, 140), + mapOf(x to 4u, y to 4u) to Rational(23868, 49), + mapOf(y to 5u) to Rational(333, 196), + mapOf(x to 1u, y to 5u) to Rational(-204, 35), + mapOf(x to 2u, y to 5u) to Rational(-307233, 2450), + mapOf(x to 3u, y to 5u) to Rational(-12492, 35), + mapOf(x to 4u, y to 5u) to Rational(4563, 28), + mapOf(y to 6u) to Rational(45, 98), + mapOf(x to 1u, y to 6u) to Rational(54, 7), + mapOf(x to 2u, y to 6u) to Rational(1809, 35), + mapOf(x to 3u, y to 6u) to Rational(162), + mapOf(x to 4u, y to 6u) to Rational(405, 2), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 2), + mapOf(x to 1u) to Rational(8, 6), + mapOf(x to 2u) to Rational(14, 6), + mapOf(y to 1u) to Rational(-3, 1), + mapOf(x to 1u, y to 1u) to Rational(-19, 2), + mapOf(x to 2u, y to 1u) to Rational(9, 4), + mapOf(y to 2u) to Rational(5, 5), + mapOf(x to 1u, y to 2u) to Rational(18, 9), + mapOf(x to 2u, y to 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + x to LabeledPolynomialAsIs( + mapOf() to Rational(0, 6), + mapOf(x to 1u) to Rational(14, 8), + mapOf(x to 2u) to Rational(-14, 2), + mapOf(y to 1u) to Rational(-3, 5), + mapOf(x to 1u, y to 1u) to Rational(11, 1), + mapOf(x to 2u, y to 1u) to Rational(3, 7), + mapOf(y to 2u) to Rational(-3, 7), + mapOf(x to 1u, y to 2u) to Rational(-18, 5), + mapOf(x to 2u, y to 2u) to Rational(-9, 1), + ), + )), + "test 5" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 2), + mapOf(x to 1u) to Rational(7, 3), + mapOf(x to 2u) to Rational(-35, 16), + mapOf(x to 3u) to Rational(-343, 6), + mapOf(x to 4u) to Rational(343, 3), + mapOf(y to 1u) to Rational(-19, 5), + mapOf(x to 1u, y to 1u) to Rational(-823, 120), + mapOf(x to 2u, y to 1u) to Rational(1232417, 6720), + mapOf(x to 3u, y to 1u) to Rational(-9863, 24), + mapOf(x to 4u, y to 1u) to Rational(385, 4), + mapOf(y to 2u) to Rational(2439, 350), + mapOf(x to 1u, y to 2u) to Rational(-5793, 40), + mapOf(x to 2u, y to 2u) to Rational(1172113, 3360), + mapOf(x to 3u, y to 2u) to Rational(-13531, 40), + mapOf(x to 4u, y to 2u) to Rational(2824, 7), + mapOf(y to 3u) to Rational(3417, 700), + mapOf(x to 1u, y to 3u) to Rational(1191, 200), + mapOf(x to 2u, y to 3u) to Rational(8383, 28), + mapOf(x to 3u, y to 3u) to Rational(-220279, 280), + mapOf(x to 4u, y to 3u) to Rational(49179, 196), + mapOf(y to 4u) to Rational(57, 35), + mapOf(x to 1u, y to 4u) to Rational(-33771, 700), + mapOf(x to 2u, y to 4u) to Rational(196279, 1225), + mapOf(x to 3u, y to 4u) to Rational(-32259, 140), + mapOf(x to 4u, y to 4u) to Rational(23868, 49), + mapOf(y to 5u) to Rational(333, 196), + mapOf(x to 1u, y to 5u) to Rational(-204, 35), + mapOf(x to 2u, y to 5u) to Rational(-307233, 2450), + mapOf(x to 3u, y to 5u) to Rational(-12492, 35), + mapOf(x to 4u, y to 5u) to Rational(4563, 28), + mapOf(y to 6u) to Rational(45, 98), + mapOf(x to 1u, y to 6u) to Rational(54, 7), + mapOf(x to 2u, y to 6u) to Rational(1809, 35), + mapOf(x to 3u, y to 6u) to Rational(162), + mapOf(x to 4u, y to 6u) to Rational(405, 2), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 2), + mapOf(x to 1u) to Rational(8, 6), + mapOf(x to 2u) to Rational(14, 6), + mapOf(y to 1u) to Rational(-3, 1), + mapOf(x to 1u, y to 1u) to Rational(-19, 2), + mapOf(x to 2u, y to 1u) to Rational(9, 4), + mapOf(y to 2u) to Rational(5, 5), + mapOf(x to 1u, y to 2u) to Rational(18, 9), + mapOf(x to 2u, y to 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + x to LabeledPolynomialAsIs( + mapOf() to Rational(0, 6), + mapOf(x to 1u) to Rational(14, 8), + mapOf(x to 2u) to Rational(-14, 2), + mapOf(y to 1u) to Rational(-3, 5), + mapOf(x to 1u, y to 1u) to Rational(11, 1), + mapOf(x to 2u, y to 1u) to Rational(3, 7), + mapOf(y to 2u) to Rational(-3, 7), + mapOf(x to 1u, y to 2u) to Rational(-18, 5), + mapOf(x to 2u, y to 2u) to Rational(-9, 1), + ), + iota to LabeledPolynomialAsIs( + mapOf() to Rational(-11, 3), + mapOf(x to 1u) to Rational(5, 2), + mapOf(x to 2u) to Rational(13, 7), + mapOf(y to 1u) to Rational(16, 9), + mapOf(x to 1u, y to 1u) to Rational(14, 7), + mapOf(x to 2u, y to 1u) to Rational(6, 1), + mapOf(y to 2u) to Rational(-14, 3), + mapOf(x to 1u, y to 2u) to Rational(-2, 7), + mapOf(x to 2u, y to 2u) to Rational(-10, 8), + ) + )), + "test 5'" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 2), + mapOf(x to 1u) to Rational(8, 6), + mapOf(x to 2u) to Rational(14, 6), + mapOf(y to 1u) to Rational(-3, 1), + mapOf(x to 1u, y to 1u) to Rational(-19, 2), + mapOf(x to 2u, y to 1u) to Rational(9, 4), + mapOf(y to 2u) to Rational(5, 5), + mapOf(x to 1u, y to 2u) to Rational(18, 9), + mapOf(x to 2u, y to 2u) to Rational(5, 2), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 2), + mapOf(x to 1u) to Rational(8, 6), + mapOf(x to 2u) to Rational(14, 6), + mapOf(y to 1u) to Rational(-3, 1), + mapOf(x to 1u, y to 1u) to Rational(-19, 2), + mapOf(x to 2u, y to 1u) to Rational(9, 4), + mapOf(y to 2u) to Rational(5, 5), + mapOf(x to 1u, y to 2u) to Rational(18, 9), + mapOf(x to 2u, y to 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf>()), + "test 6" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 2), + mapOf(x to 1u) to Rational(8, 6), + mapOf(x to 2u) to Rational(14, 6), + mapOf(y to 1u) to Rational(-3, 1), + mapOf(x to 1u, y to 1u) to Rational(-19, 2), + mapOf(x to 2u, y to 1u) to Rational(9, 4), + mapOf(y to 2u) to Rational(5, 5), + mapOf(x to 1u, y to 2u) to Rational(18, 9), + mapOf(x to 2u, y to 2u) to Rational(5, 2), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 2), + mapOf(x to 1u) to Rational(8, 6), + mapOf(x to 2u) to Rational(14, 6), + mapOf(y to 1u) to Rational(-3, 1), + mapOf(x to 1u, y to 1u) to Rational(-19, 2), + mapOf(x to 2u, y to 1u) to Rational(9, 4), + mapOf(y to 2u) to Rational(5, 5), + mapOf(x to 1u, y to 2u) to Rational(18, 9), + mapOf(x to 2u, y to 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + iota to LabeledPolynomialAsIs( + mapOf() to Rational(-11, 3), + mapOf(x to 1u) to Rational(5, 2), + mapOf(x to 2u) to Rational(13, 7), + mapOf(y to 1u) to Rational(16, 9), + mapOf(x to 1u, y to 1u) to Rational(14, 7), + mapOf(x to 2u, y to 1u) to Rational(6, 1), + mapOf(y to 2u) to Rational(-14, 3), + mapOf(x to 1u, y to 2u) to Rational(-2, 7), + mapOf(x to 2u, y to 2u) to Rational(-10, 8), + ) + )), + "test 6'" + ) + } + @Test + @Ignore // FIXME: This tests work only for sane realisations of the substitutions. Currently, it is not. + // Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should return denominator r^deg(p), + // not r^(deg(p)(deg(p)+1)/2) as it is now. + fun test_Polynomial_substitute_RationalFunction_Map() { + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(0) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1) + ) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1) + ).substitute(RationalField, mapOf( + x to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(1) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1) + ) + ) + )), + "test 1" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf(x to 4u) to Rational(-194071, 4900), + mapOf(x to 3u, y to 1u) to Rational(394811, 225), + mapOf(x to 2u, y to 2u) to Rational(-444183161, 66150), + mapOf(x to 1u, y to 3u) to Rational(70537618, 59535), + mapOf(y to 4u) to Rational(9655504, 2835), + ), + LabeledPolynomialAsIs( + mapOf(x to 4u) to Rational(9, 1), + mapOf(x to 3u, y to 1u) to Rational(61, 1), + mapOf(x to 2u, y to 2u) to Rational(2137, 36), + mapOf(x to 1u, y to 3u) to Rational(-1342, 9), + mapOf(y to 4u) to Rational(484, 9), + ) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(15, 7), + mapOf(x to 1u) to Rational(1, 5), + mapOf(x to 2u) to Rational(-7, 4), + mapOf(y to 1u) to Rational(-1, 9), + mapOf(x to 1u, y to 1u) to Rational(-2, 7), + mapOf(x to 2u, y to 1u) to Rational(17, 3), + mapOf(y to 2u) to Rational(2, 6), + mapOf(x to 1u, y to 2u) to Rational(-17, 6), + mapOf(x to 2u, y to 2u) to Rational(-6, 2), + ).substitute(RationalField, mapOf( + x to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(17, 7), + mapOf(y to 1u) to Rational(-13, 1), + ), + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(-18, 6), + mapOf(y to 1u) to Rational(11, 6), + ) + ), + y to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(18, 5), + mapOf(y to 1u) to Rational(-16, 3), + ), + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(-1, 1), + mapOf(y to 1u) to Rational(-4, 1), + ) + ), + )), + "test 2" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-6443599, 10000), + mapOf(x to 1u) to Rational(166251223, 210000), + mapOf(x to 2u) to Rational(-4606805099, 3528000), + mapOf(x to 3u) to Rational(51204379, 19600), + mapOf(x to 4u) to Rational(-529045460659, 277830000), + mapOf(x to 5u) to Rational(2630836709, 1488375), + mapOf(x to 6u) to Rational(-42675691369, 25004700), + mapOf(x to 7u) to Rational(495825223, 1250235), + mapOf(x to 8u) to Rational(-22531756, 1750329), + mapOf(y to 1u) to Rational(-2526552797, 420000), + mapOf(x to 1u, y to 1u) to Rational(31108840471, 2520000), + mapOf(x to 2u, y to 1u) to Rational(-4789740847, 1102500), + mapOf(x to 3u, y to 1u) to Rational(186594307807, 11340000), + mapOf(x to 4u, y to 1u) to Rational(-11677815943, 1488375), + mapOf(x to 5u, y to 1u) to Rational(-181118486447, 27783000), + mapOf(x to 6u, y to 1u) to Rational(-16123292162, 14586075), + mapOf(x to 7u, y to 1u) to Rational(-140339343808, 26254935), + mapOf(x to 8u, y to 1u) to Rational(4570171616, 5250987), + mapOf(y to 2u) to Rational(-181436530573, 10080000), + mapOf(x to 1u, y to 2u) to Rational(6700437957491, 105840000), + mapOf(x to 2u, y to 2u) to Rational(-3527267461, 1417500), + mapOf(x to 3u, y to 2u) to Rational(-38084563451, 5556600), + mapOf(x to 4u, y to 2u) to Rational(-565662040631, 13891500), + mapOf(x to 5u, y to 2u) to Rational(-35479071126397, 583443000), + mapOf(x to 6u, y to 2u) to Rational(-11717559078469, 525098700), + mapOf(x to 7u, y to 2u) to Rational(-2043385293517, 225042300), + mapOf(x to 8u, y to 2u) to Rational(-3644439630451, 551353635), + mapOf(y to 3u) to Rational(-1760423269, 126000), + mapOf(x to 1u, y to 3u) to Rational(310176758299, 2352000), + mapOf(x to 2u, y to 3u) to Rational(-907229584837, 21168000), + mapOf(x to 3u, y to 3u) to Rational(-16717135885963, 95256000), + mapOf(x to 4u, y to 3u) to Rational(-43762928025353, 333396000), + mapOf(x to 5u, y to 3u) to Rational(-328427480571607, 3000564000), + mapOf(x to 6u, y to 3u) to Rational(-7722675917197, 210039480), + mapOf(x to 7u, y to 3u) to Rational(1713350137019, 1225230300), + mapOf(x to 8u, y to 3u) to Rational(156695935643, 31505922), + mapOf(y to 4u) to Rational(18362364269, 1008000), + mapOf(x to 1u, y to 4u) to Rational(955674858553, 10584000), + mapOf(x to 2u, y to 4u) to Rational(-71937470607371, 444528000), + mapOf(x to 3u, y to 4u) to Rational(-34097985615163, 95256000), + mapOf(x to 4u, y to 4u) to Rational(-340736178775883, 2000376000), + mapOf(x to 5u, y to 4u) to Rational(-511324523441897, 10501974000), + mapOf(x to 6u, y to 4u) to Rational(-125375649409151, 8821658160), + mapOf(x to 7u, y to 4u) to Rational(-2813518533421, 1575296100), + mapOf(x to 8u, y to 4u) to Rational(-17044089109, 5250987), + mapOf(y to 5u) to Rational(600086461, 20160), + mapOf(x to 1u, y to 5u) to Rational(-18959931367, 423360), + mapOf(x to 2u, y to 5u) to Rational(-9178804929607, 44452800), + mapOf(x to 3u, y to 5u) to Rational(-1460114275979, 5334336), + mapOf(x to 4u, y to 5u) to Rational(-342533479090169, 4200789600), + mapOf(x to 5u, y to 5u) to Rational(20335453022963, 4200789600), + mapOf(x to 6u, y to 5u) to Rational(-21649775090197, 6301184400), + mapOf(x to 7u, y to 5u) to Rational(-197301716069, 131274675), + mapOf(x to 8u, y to 5u) to Rational(18711357470, 15752961), + mapOf(y to 6u) to Rational(621417991, 100800), + mapOf(x to 1u, y to 6u) to Rational(-159236792977, 2116800), + mapOf(x to 2u, y to 6u) to Rational(-6602528890883, 66679200), + mapOf(x to 3u, y to 6u) to Rational(-1086091664047, 19051200), + mapOf(x to 4u, y to 6u) to Rational(3769375009003, 1680315840), + mapOf(x to 5u, y to 6u) to Rational(-12920385574769, 1050197400), + mapOf(x to 6u, y to 6u) to Rational(-90219591809287, 6301184400), + mapOf(x to 7u, y to 6u) to Rational(656361553391, 1575296100), + mapOf(x to 8u, y to 6u) to Rational(757900793, 2250423), + mapOf(y to 7u) to Rational(-100770017, 15120), + mapOf(x to 1u, y to 7u) to Rational(-316364851, 17640), + mapOf(x to 2u, y to 7u) to Rational(-85118560057, 6667920), + mapOf(x to 3u, y to 7u) to Rational(6286563719, 416745), + mapOf(x to 4u, y to 7u) to Rational(26803885301, 1714608), + mapOf(x to 5u, y to 7u) to Rational(-13767154393, 4286520), + mapOf(x to 6u, y to 7u) to Rational(-3875138933, 1224720), + mapOf(x to 7u, y to 7u) to Rational(65193755, 333396), + mapOf(x to 8u, y to 7u) to Rational(90974351, 2500470), + mapOf(y to 8u) to Rational(-3182197, 1260), + mapOf(x to 1u, y to 8u) to Rational(24899923, 8820), + mapOf(x to 2u, y to 8u) to Rational(-19999556, 19845), + mapOf(x to 3u, y to 8u) to Rational(3276587, 3969), + mapOf(x to 4u, y to 8u) to Rational(13719549239, 5000940), + mapOf(x to 5u, y to 8u) to Rational(-961839938, 1250235), + mapOf(x to 6u, y to 8u) to Rational(-198184871, 833490), + mapOf(x to 7u, y to 8u) to Rational(230659711, 5000940), + mapOf(x to 8u, y to 8u) to Rational(292447, 35721) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(9, 100), + mapOf(x to 1u) to Rational(-21, 50), + mapOf(x to 2u) to Rational(293, 700), + mapOf(x to 3u) to Rational(29, 210), + mapOf(x to 4u) to Rational(3233, 8820), + mapOf(x to 5u) to Rational(-289, 441), + mapOf(x to 6u) to Rational(-1, 9), + mapOf(x to 7u) to Rational(-20, 441), + mapOf(x to 8u) to Rational(100, 441), + mapOf(y to 1u) to Rational(-57, 80), + mapOf(x to 1u, y to 1u) to Rational(-121, 400), + mapOf(x to 2u, y to 1u) to Rational(37117, 8400), + mapOf(x to 3u, y to 1u) to Rational(-4853, 3150), + mapOf(x to 4u, y to 1u) to Rational(1166203, 132300), + mapOf(x to 5u, y to 1u) to Rational(-2708, 567), + mapOf(x to 6u, y to 1u) to Rational(-287159, 416745), + mapOf(x to 7u, y to 1u) to Rational(-478204, 83349), + mapOf(x to 8u, y to 1u) to Rational(176320, 83349), + mapOf(y to 2u) to Rational(-6239, 6400), + mapOf(x to 1u, y to 2u) to Rational(264211, 11200), + mapOf(x to 2u, y to 2u) to Rational(-1591999, 100800), + mapOf(x to 3u, y to 2u) to Rational(12450091, 529200), + mapOf(x to 4u, y to 2u) to Rational(9230759, 226800), + mapOf(x to 5u, y to 2u) to Rational(18995554, 2083725), + mapOf(x to 6u, y to 2u) to Rational(136706258, 6251175), + mapOf(x to 7u, y to 2u) to Rational(-120907496, 3750705), + mapOf(x to 8u, y to 2u) to Rational(117200176, 15752961), + mapOf(y to 3u) to Rational(5653, 320), + mapOf(x to 1u, y to 3u) to Rational(-130853, 8400), + mapOf(x to 2u, y to 3u) to Rational(-20939327, 151200), + mapOf(x to 3u, y to 3u) to Rational(2566691, 25200), + mapOf(x to 4u, y to 3u) to Rational(-68441519, 476280), + mapOf(x to 5u, y to 3u) to Rational(2462904247, 12502350), + mapOf(x to 6u, y to 3u) to Rational(353667161, 18753525), + mapOf(x to 7u, y to 3u) to Rational(-1689134372, 26254935), + mapOf(x to 8u, y to 3u) to Rational(35084104, 2250423), + mapOf(y to 4u) to Rational(-3587, 300), + mapOf(x to 1u, y to 4u) to Rational(-10513243, 33600), + mapOf(x to 2u, y to 4u) to Rational(30766733, 176400), + mapOf(x to 3u, y to 4u) to Rational(-65680021, 198450), + mapOf(x to 4u, y to 4u) to Rational(-8108910547, 20003760), + mapOf(x to 5u, y to 4u) to Rational(2922125159, 6251175), + mapOf(x to 6u, y to 4u) to Rational(-4245279943, 131274675), + mapOf(x to 7u, y to 4u) to Rational(-371946872, 3750705), + mapOf(x to 8u, y to 4u) to Rational(61286752, 2250423), + mapOf(y to 5u) to Rational(-20477, 160), + mapOf(x to 1u, y to 5u) to Rational(215741, 1120), + mapOf(x to 2u, y to 5u) to Rational(30785843, 31752), + mapOf(x to 3u, y to 5u) to Rational(-357495959, 317520), + mapOf(x to 4u, y to 5u) to Rational(-1611242993, 10001880), + mapOf(x to 5u, y to 5u) to Rational(345925495, 500094), + mapOf(x to 6u, y to 5u) to Rational(-755948411, 3750705), + mapOf(x to 7u, y to 5u) to Rational(-108643496, 1250235), + mapOf(x to 8u, y to 5u) to Rational(1122512, 35721), + mapOf(y to 6u) to Rational(358037, 2880), + mapOf(x to 1u, y to 6u) to Rational(3895837, 3360), + mapOf(x to 2u, y to 6u) to Rational(359419201, 1270080), + mapOf(x to 3u, y to 6u) to Rational(-158522587, 105840), + mapOf(x to 4u, y to 6u) to Rational(10909002599, 20003760), + mapOf(x to 5u, y to 6u) to Rational(76846972, 138915), + mapOf(x to 6u, y to 6u) to Rational(-327696553, 1250235), + mapOf(x to 7u, y to 6u) to Rational(-1687328, 35721), + mapOf(x to 8u, y to 6u) to Rational(1016836, 35721), + mapOf(y to 7u) to Rational(658, 3), + mapOf(x to 1u, y to 7u) to Rational(48035, 168), + mapOf(x to 2u, y to 7u) to Rational(-5777875, 5292), + mapOf(x to 3u, y to 7u) to Rational(-7893899, 10584), + mapOf(x to 4u, y to 7u) to Rational(10191652, 11907), + mapOf(x to 5u, y to 7u) to Rational(2920121, 23814), + mapOf(x to 6u, y to 7u) to Rational(-2699780, 11907), + mapOf(x to 7u, y to 7u) to Rational(4556, 441), + mapOf(x to 8u, y to 7u) to Rational(3440, 189), + mapOf(y to 8u) to Rational(64, 1), + mapOf(x to 1u, y to 8u) to Rational(-808, 7), + mapOf(x to 2u, y to 8u) to Rational(-360895, 1764), + mapOf(x to 3u, y to 8u) to Rational(257657, 882), + mapOf(x to 4u, y to 8u) to Rational(3779917, 15876), + mapOf(x to 5u, y to 8u) to Rational(-610279, 3969), + mapOf(x to 6u, y to 8u) to Rational(-25091, 441), + mapOf(x to 7u, y to 8u) to Rational(9560, 567), + mapOf(x to 8u, y to 8u) to Rational(400, 81) + ) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(15, 7), + mapOf(x to 1u) to Rational(1, 5), + mapOf(x to 2u) to Rational(-7, 4), + mapOf(y to 1u) to Rational(-1, 9), + mapOf(x to 1u, y to 1u) to Rational(-2, 7), + mapOf(x to 2u, y to 1u) to Rational(17, 3), + mapOf(y to 2u) to Rational(2, 6), + mapOf(x to 1u, y to 2u) to Rational(-17, 6), + mapOf(x to 2u, y to 2u) to Rational(-6, 2), + ).substitute(RationalField, mapOf( + x to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(17, 5), + mapOf(x to 1u) to Rational(11, 6), + mapOf(x to 2u) to Rational(14, 3), + mapOf(y to 1u) to Rational(17, 1), + mapOf(x to 1u, y to 1u) to Rational(12, 3), + mapOf(x to 2u, y to 1u) to Rational(-6, 2), + mapOf(y to 2u) to Rational(17, 1), + mapOf(x to 1u, y to 2u) to Rational(-4, 3), + mapOf(x to 2u, y to 2u) to Rational(2, 6), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(3, 5), + mapOf(x to 1u) to Rational(3, 5), + mapOf(x to 2u) to Rational(3, 7), + mapOf(y to 1u) to Rational(-3, 8), + mapOf(x to 1u, y to 1u) to Rational(-1, 1), + mapOf(x to 2u, y to 1u) to Rational(17, 9), + mapOf(y to 2u) to Rational(-8, 1), + mapOf(x to 1u, y to 2u) to Rational(6, 4), + mapOf(x to 2u, y to 2u) to Rational(10, 9), + ) + ), + y to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(18, 5), + mapOf(x to 1u) to Rational(-17, 5), + mapOf(x to 2u) to Rational(-2, 7), + mapOf(y to 1u) to Rational(6, 5), + mapOf(x to 1u, y to 1u) to Rational(-5, 1), + mapOf(x to 2u, y to 1u) to Rational(-9, 1), + mapOf(y to 2u) to Rational(-8, 8), + mapOf(x to 1u, y to 2u) to Rational(2, 7), + mapOf(x to 2u, y to 2u) to Rational(-13, 7), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-4, 8), + mapOf(x to 1u) to Rational(15, 9), + mapOf(x to 2u) to Rational(-10, 9), + mapOf(y to 1u) to Rational(5, 3), + mapOf(x to 1u, y to 1u) to Rational(4, 1), + mapOf(x to 2u, y to 1u) to Rational(-2, 7), + mapOf(y to 2u) to Rational(2, 2), + mapOf(x to 1u, y to 2u) to Rational(-5, 7), + mapOf(x to 2u, y to 2u) to Rational(-18, 9), + ) + ), + )), + "test 3" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-6443599, 10000), + mapOf(x to 1u) to Rational(166251223, 210000), + mapOf(x to 2u) to Rational(-4606805099, 3528000), + mapOf(x to 3u) to Rational(51204379, 19600), + mapOf(x to 4u) to Rational(-529045460659, 277830000), + mapOf(x to 5u) to Rational(2630836709, 1488375), + mapOf(x to 6u) to Rational(-42675691369, 25004700), + mapOf(x to 7u) to Rational(495825223, 1250235), + mapOf(x to 8u) to Rational(-22531756, 1750329), + mapOf(y to 1u) to Rational(-2526552797, 420000), + mapOf(x to 1u, y to 1u) to Rational(31108840471, 2520000), + mapOf(x to 2u, y to 1u) to Rational(-4789740847, 1102500), + mapOf(x to 3u, y to 1u) to Rational(186594307807, 11340000), + mapOf(x to 4u, y to 1u) to Rational(-11677815943, 1488375), + mapOf(x to 5u, y to 1u) to Rational(-181118486447, 27783000), + mapOf(x to 6u, y to 1u) to Rational(-16123292162, 14586075), + mapOf(x to 7u, y to 1u) to Rational(-140339343808, 26254935), + mapOf(x to 8u, y to 1u) to Rational(4570171616, 5250987), + mapOf(y to 2u) to Rational(-181436530573, 10080000), + mapOf(x to 1u, y to 2u) to Rational(6700437957491, 105840000), + mapOf(x to 2u, y to 2u) to Rational(-3527267461, 1417500), + mapOf(x to 3u, y to 2u) to Rational(-38084563451, 5556600), + mapOf(x to 4u, y to 2u) to Rational(-565662040631, 13891500), + mapOf(x to 5u, y to 2u) to Rational(-35479071126397, 583443000), + mapOf(x to 6u, y to 2u) to Rational(-11717559078469, 525098700), + mapOf(x to 7u, y to 2u) to Rational(-2043385293517, 225042300), + mapOf(x to 8u, y to 2u) to Rational(-3644439630451, 551353635), + mapOf(y to 3u) to Rational(-1760423269, 126000), + mapOf(x to 1u, y to 3u) to Rational(310176758299, 2352000), + mapOf(x to 2u, y to 3u) to Rational(-907229584837, 21168000), + mapOf(x to 3u, y to 3u) to Rational(-16717135885963, 95256000), + mapOf(x to 4u, y to 3u) to Rational(-43762928025353, 333396000), + mapOf(x to 5u, y to 3u) to Rational(-328427480571607, 3000564000), + mapOf(x to 6u, y to 3u) to Rational(-7722675917197, 210039480), + mapOf(x to 7u, y to 3u) to Rational(1713350137019, 1225230300), + mapOf(x to 8u, y to 3u) to Rational(156695935643, 31505922), + mapOf(y to 4u) to Rational(18362364269, 1008000), + mapOf(x to 1u, y to 4u) to Rational(955674858553, 10584000), + mapOf(x to 2u, y to 4u) to Rational(-71937470607371, 444528000), + mapOf(x to 3u, y to 4u) to Rational(-34097985615163, 95256000), + mapOf(x to 4u, y to 4u) to Rational(-340736178775883, 2000376000), + mapOf(x to 5u, y to 4u) to Rational(-511324523441897, 10501974000), + mapOf(x to 6u, y to 4u) to Rational(-125375649409151, 8821658160), + mapOf(x to 7u, y to 4u) to Rational(-2813518533421, 1575296100), + mapOf(x to 8u, y to 4u) to Rational(-17044089109, 5250987), + mapOf(y to 5u) to Rational(600086461, 20160), + mapOf(x to 1u, y to 5u) to Rational(-18959931367, 423360), + mapOf(x to 2u, y to 5u) to Rational(-9178804929607, 44452800), + mapOf(x to 3u, y to 5u) to Rational(-1460114275979, 5334336), + mapOf(x to 4u, y to 5u) to Rational(-342533479090169, 4200789600), + mapOf(x to 5u, y to 5u) to Rational(20335453022963, 4200789600), + mapOf(x to 6u, y to 5u) to Rational(-21649775090197, 6301184400), + mapOf(x to 7u, y to 5u) to Rational(-197301716069, 131274675), + mapOf(x to 8u, y to 5u) to Rational(18711357470, 15752961), + mapOf(y to 6u) to Rational(621417991, 100800), + mapOf(x to 1u, y to 6u) to Rational(-159236792977, 2116800), + mapOf(x to 2u, y to 6u) to Rational(-6602528890883, 66679200), + mapOf(x to 3u, y to 6u) to Rational(-1086091664047, 19051200), + mapOf(x to 4u, y to 6u) to Rational(3769375009003, 1680315840), + mapOf(x to 5u, y to 6u) to Rational(-12920385574769, 1050197400), + mapOf(x to 6u, y to 6u) to Rational(-90219591809287, 6301184400), + mapOf(x to 7u, y to 6u) to Rational(656361553391, 1575296100), + mapOf(x to 8u, y to 6u) to Rational(757900793, 2250423), + mapOf(y to 7u) to Rational(-100770017, 15120), + mapOf(x to 1u, y to 7u) to Rational(-316364851, 17640), + mapOf(x to 2u, y to 7u) to Rational(-85118560057, 6667920), + mapOf(x to 3u, y to 7u) to Rational(6286563719, 416745), + mapOf(x to 4u, y to 7u) to Rational(26803885301, 1714608), + mapOf(x to 5u, y to 7u) to Rational(-13767154393, 4286520), + mapOf(x to 6u, y to 7u) to Rational(-3875138933, 1224720), + mapOf(x to 7u, y to 7u) to Rational(65193755, 333396), + mapOf(x to 8u, y to 7u) to Rational(90974351, 2500470), + mapOf(y to 8u) to Rational(-3182197, 1260), + mapOf(x to 1u, y to 8u) to Rational(24899923, 8820), + mapOf(x to 2u, y to 8u) to Rational(-19999556, 19845), + mapOf(x to 3u, y to 8u) to Rational(3276587, 3969), + mapOf(x to 4u, y to 8u) to Rational(13719549239, 5000940), + mapOf(x to 5u, y to 8u) to Rational(-961839938, 1250235), + mapOf(x to 6u, y to 8u) to Rational(-198184871, 833490), + mapOf(x to 7u, y to 8u) to Rational(230659711, 5000940), + mapOf(x to 8u, y to 8u) to Rational(292447, 35721) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(9, 100), + mapOf(x to 1u) to Rational(-21, 50), + mapOf(x to 2u) to Rational(293, 700), + mapOf(x to 3u) to Rational(29, 210), + mapOf(x to 4u) to Rational(3233, 8820), + mapOf(x to 5u) to Rational(-289, 441), + mapOf(x to 6u) to Rational(-1, 9), + mapOf(x to 7u) to Rational(-20, 441), + mapOf(x to 8u) to Rational(100, 441), + mapOf(y to 1u) to Rational(-57, 80), + mapOf(x to 1u, y to 1u) to Rational(-121, 400), + mapOf(x to 2u, y to 1u) to Rational(37117, 8400), + mapOf(x to 3u, y to 1u) to Rational(-4853, 3150), + mapOf(x to 4u, y to 1u) to Rational(1166203, 132300), + mapOf(x to 5u, y to 1u) to Rational(-2708, 567), + mapOf(x to 6u, y to 1u) to Rational(-287159, 416745), + mapOf(x to 7u, y to 1u) to Rational(-478204, 83349), + mapOf(x to 8u, y to 1u) to Rational(176320, 83349), + mapOf(y to 2u) to Rational(-6239, 6400), + mapOf(x to 1u, y to 2u) to Rational(264211, 11200), + mapOf(x to 2u, y to 2u) to Rational(-1591999, 100800), + mapOf(x to 3u, y to 2u) to Rational(12450091, 529200), + mapOf(x to 4u, y to 2u) to Rational(9230759, 226800), + mapOf(x to 5u, y to 2u) to Rational(18995554, 2083725), + mapOf(x to 6u, y to 2u) to Rational(136706258, 6251175), + mapOf(x to 7u, y to 2u) to Rational(-120907496, 3750705), + mapOf(x to 8u, y to 2u) to Rational(117200176, 15752961), + mapOf(y to 3u) to Rational(5653, 320), + mapOf(x to 1u, y to 3u) to Rational(-130853, 8400), + mapOf(x to 2u, y to 3u) to Rational(-20939327, 151200), + mapOf(x to 3u, y to 3u) to Rational(2566691, 25200), + mapOf(x to 4u, y to 3u) to Rational(-68441519, 476280), + mapOf(x to 5u, y to 3u) to Rational(2462904247, 12502350), + mapOf(x to 6u, y to 3u) to Rational(353667161, 18753525), + mapOf(x to 7u, y to 3u) to Rational(-1689134372, 26254935), + mapOf(x to 8u, y to 3u) to Rational(35084104, 2250423), + mapOf(y to 4u) to Rational(-3587, 300), + mapOf(x to 1u, y to 4u) to Rational(-10513243, 33600), + mapOf(x to 2u, y to 4u) to Rational(30766733, 176400), + mapOf(x to 3u, y to 4u) to Rational(-65680021, 198450), + mapOf(x to 4u, y to 4u) to Rational(-8108910547, 20003760), + mapOf(x to 5u, y to 4u) to Rational(2922125159, 6251175), + mapOf(x to 6u, y to 4u) to Rational(-4245279943, 131274675), + mapOf(x to 7u, y to 4u) to Rational(-371946872, 3750705), + mapOf(x to 8u, y to 4u) to Rational(61286752, 2250423), + mapOf(y to 5u) to Rational(-20477, 160), + mapOf(x to 1u, y to 5u) to Rational(215741, 1120), + mapOf(x to 2u, y to 5u) to Rational(30785843, 31752), + mapOf(x to 3u, y to 5u) to Rational(-357495959, 317520), + mapOf(x to 4u, y to 5u) to Rational(-1611242993, 10001880), + mapOf(x to 5u, y to 5u) to Rational(345925495, 500094), + mapOf(x to 6u, y to 5u) to Rational(-755948411, 3750705), + mapOf(x to 7u, y to 5u) to Rational(-108643496, 1250235), + mapOf(x to 8u, y to 5u) to Rational(1122512, 35721), + mapOf(y to 6u) to Rational(358037, 2880), + mapOf(x to 1u, y to 6u) to Rational(3895837, 3360), + mapOf(x to 2u, y to 6u) to Rational(359419201, 1270080), + mapOf(x to 3u, y to 6u) to Rational(-158522587, 105840), + mapOf(x to 4u, y to 6u) to Rational(10909002599, 20003760), + mapOf(x to 5u, y to 6u) to Rational(76846972, 138915), + mapOf(x to 6u, y to 6u) to Rational(-327696553, 1250235), + mapOf(x to 7u, y to 6u) to Rational(-1687328, 35721), + mapOf(x to 8u, y to 6u) to Rational(1016836, 35721), + mapOf(y to 7u) to Rational(658, 3), + mapOf(x to 1u, y to 7u) to Rational(48035, 168), + mapOf(x to 2u, y to 7u) to Rational(-5777875, 5292), + mapOf(x to 3u, y to 7u) to Rational(-7893899, 10584), + mapOf(x to 4u, y to 7u) to Rational(10191652, 11907), + mapOf(x to 5u, y to 7u) to Rational(2920121, 23814), + mapOf(x to 6u, y to 7u) to Rational(-2699780, 11907), + mapOf(x to 7u, y to 7u) to Rational(4556, 441), + mapOf(x to 8u, y to 7u) to Rational(3440, 189), + mapOf(y to 8u) to Rational(64, 1), + mapOf(x to 1u, y to 8u) to Rational(-808, 7), + mapOf(x to 2u, y to 8u) to Rational(-360895, 1764), + mapOf(x to 3u, y to 8u) to Rational(257657, 882), + mapOf(x to 4u, y to 8u) to Rational(3779917, 15876), + mapOf(x to 5u, y to 8u) to Rational(-610279, 3969), + mapOf(x to 6u, y to 8u) to Rational(-25091, 441), + mapOf(x to 7u, y to 8u) to Rational(9560, 567), + mapOf(x to 8u, y to 8u) to Rational(400, 81) + ) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(15, 7), + mapOf(x to 1u) to Rational(1, 5), + mapOf(x to 2u) to Rational(-7, 4), + mapOf(y to 1u) to Rational(-1, 9), + mapOf(x to 1u, y to 1u) to Rational(-2, 7), + mapOf(x to 2u, y to 1u) to Rational(17, 3), + mapOf(y to 2u) to Rational(2, 6), + mapOf(x to 1u, y to 2u) to Rational(-17, 6), + mapOf(x to 2u, y to 2u) to Rational(-6, 2), + ).substitute(RationalField, mapOf( + x to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(17, 5), + mapOf(x to 1u) to Rational(11, 6), + mapOf(x to 2u) to Rational(14, 3), + mapOf(y to 1u) to Rational(17, 1), + mapOf(x to 1u, y to 1u) to Rational(12, 3), + mapOf(x to 2u, y to 1u) to Rational(-6, 2), + mapOf(y to 2u) to Rational(17, 1), + mapOf(x to 1u, y to 2u) to Rational(-4, 3), + mapOf(x to 2u, y to 2u) to Rational(2, 6), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(3, 5), + mapOf(x to 1u) to Rational(3, 5), + mapOf(x to 2u) to Rational(3, 7), + mapOf(y to 1u) to Rational(-3, 8), + mapOf(x to 1u, y to 1u) to Rational(-1, 1), + mapOf(x to 2u, y to 1u) to Rational(17, 9), + mapOf(y to 2u) to Rational(-8, 1), + mapOf(x to 1u, y to 2u) to Rational(6, 4), + mapOf(x to 2u, y to 2u) to Rational(10, 9), + ) + ), + y to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(18, 5), + mapOf(x to 1u) to Rational(-17, 5), + mapOf(x to 2u) to Rational(-2, 7), + mapOf(y to 1u) to Rational(6, 5), + mapOf(x to 1u, y to 1u) to Rational(-5, 1), + mapOf(x to 2u, y to 1u) to Rational(-9, 1), + mapOf(y to 2u) to Rational(-8, 8), + mapOf(x to 1u, y to 2u) to Rational(2, 7), + mapOf(x to 2u, y to 2u) to Rational(-13, 7), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-4, 8), + mapOf(x to 1u) to Rational(15, 9), + mapOf(x to 2u) to Rational(-10, 9), + mapOf(y to 1u) to Rational(5, 3), + mapOf(x to 1u, y to 1u) to Rational(4, 1), + mapOf(x to 2u, y to 1u) to Rational(-2, 7), + mapOf(y to 2u) to Rational(2, 2), + mapOf(x to 1u, y to 2u) to Rational(-5, 7), + mapOf(x to 2u, y to 2u) to Rational(-18, 9), + ) + ), + iota to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-2, 9), + mapOf(x to 1u) to Rational(-6, 3), + mapOf(x to 2u) to Rational(10, 9), + mapOf(y to 1u) to Rational(13, 3), + mapOf(x to 1u, y to 1u) to Rational(-12, 4), + mapOf(x to 2u, y to 1u) to Rational(3, 6), + mapOf(y to 2u) to Rational(2, 9), + mapOf(x to 1u, y to 2u) to Rational(7, 3), + mapOf(x to 2u, y to 2u) to Rational(16, 5), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 2), + mapOf(x to 1u) to Rational(6, 2), + mapOf(x to 2u) to Rational(2, 7), + mapOf(y to 1u) to Rational(-18, 1), + mapOf(x to 1u, y to 1u) to Rational(-11, 3), + mapOf(x to 2u, y to 1u) to Rational(7, 5), + mapOf(y to 2u) to Rational(8, 1), + mapOf(x to 1u, y to 2u) to Rational(6, 7), + mapOf(x to 2u, y to 2u) to Rational(17, 4), + ) + ) + )), + "test 3'" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-66677, 3500), + mapOf(x to 1u) to Rational(-206281, 10500), + mapOf(x to 2u) to Rational(-412567, 7056), + mapOf(x to 3u) to Rational(-310081, 11025), + mapOf(x to 4u) to Rational(-575996, 15435), + mapOf(y to 1u) to Rational(-573701, 4200), + mapOf(x to 1u, y to 1u) to Rational(-2239001, 25200), + mapOf(x to 2u, y to 1u) to Rational(-8817889, 132300), + mapOf(x to 3u, y to 1u) to Rational(2317919, 44100), + mapOf(x to 4u, y to 1u) to Rational(1169471, 6615), + mapOf(y to 2u) to Rational(-4057819, 33600), + mapOf(x to 1u, y to 2u) to Rational(1373311, 12600), + mapOf(x to 2u, y to 2u) to Rational(32433493, 52920), + mapOf(x to 3u, y to 2u) to Rational(4998053, 33075), + mapOf(x to 4u, y to 2u) to Rational(-2147779, 8820), + mapOf(y to 3u) to Rational(2018481, 2240), + mapOf(x to 1u, y to 3u) to Rational(941713, 1440), + mapOf(x to 2u, y to 3u) to Rational(183749, 6615), + mapOf(x to 3u, y to 3u) to Rational(-4631023, 15876), + mapOf(x to 4u, y to 3u) to Rational(25609336, 178605), + mapOf(y to 4u) to Rational(11886431, 6720), + mapOf(x to 1u, y to 4u) to Rational(18433, 504), + mapOf(x to 2u, y to 4u) to Rational(-39613331, 45360), + mapOf(x to 3u, y to 4u) to Rational(681619, 5670), + mapOf(x to 4u, y to 4u) to Rational(-864841, 20412), + mapOf(y to 5u) to Rational(343535, 1008), + mapOf(x to 1u, y to 5u) to Rational(-33583, 72), + mapOf(x to 2u, y to 5u) to Rational(1194625, 9072), + mapOf(x to 3u, y to 5u) to Rational(-62917, 2268), + mapOf(x to 4u, y to 5u) to Rational(157645, 10206), + mapOf(y to 6u) to Rational(-1381, 3), + mapOf(x to 1u, y to 6u) to Rational(919, 36), + mapOf(x to 2u, y to 6u) to Rational(-3053, 36), + mapOf(x to 3u, y to 6u) to Rational(2125, 324), + mapOf(x to 4u, y to 6u) to Rational(-236, 243) + ), + LabeledPolynomialAsIs(mapOf() to Rational(0, 1), + mapOf() to Rational(1, 4), + mapOf(x to 1u) to Rational(-5, 3), + mapOf(x to 2u) to Rational(35, 9), + mapOf(x to 3u) to Rational(-100, 27), + mapOf(x to 4u) to Rational(100, 81), + mapOf(y to 1u) to Rational(-5, 3), + mapOf(x to 1u, y to 1u) to Rational(14, 9), + mapOf(x to 2u, y to 1u) to Rational(1874, 189), + mapOf(x to 3u, y to 1u) to Rational(-620, 63), + mapOf(x to 4u, y to 1u) to Rational(40, 63), + mapOf(y to 2u) to Rational(16, 9), + mapOf(x to 1u, y to 2u) to Rational(365, 21), + mapOf(x to 2u, y to 2u) to Rational(112, 9), + mapOf(x to 3u, y to 2u) to Rational(-464, 63), + mapOf(x to 4u, y to 2u) to Rational(1996, 441), + mapOf(y to 3u) to Rational(10, 3), + mapOf(x to 1u, y to 3u) to Rational(118, 21), + mapOf(x to 2u, y to 3u) to Rational(-272, 21), + mapOf(x to 3u, y to 3u) to Rational(-764, 49), + mapOf(x to 4u, y to 3u) to Rational(8, 7), + mapOf(y to 4u) to Rational(1, 1), + mapOf(x to 1u, y to 4u) to Rational(-10, 7), + mapOf(x to 2u, y to 4u) to Rational(-171, 49), + mapOf(x to 3u, y to 4u) to Rational(20, 7), + mapOf(x to 4u, y to 4u) to Rational(4, 1) + ) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(15, 7), + mapOf(x to 1u) to Rational(1, 5), + mapOf(x to 2u) to Rational(-7, 4), + mapOf(y to 1u) to Rational(-1, 9), + mapOf(x to 1u, y to 1u) to Rational(-2, 7), + mapOf(x to 2u, y to 1u) to Rational(17, 3), + mapOf(y to 2u) to Rational(2, 6), + mapOf(x to 1u, y to 2u) to Rational(-17, 6), + mapOf(x to 2u, y to 2u) to Rational(-6, 2), + ).substitute(RationalField, mapOf( + x to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(17, 5), + mapOf(x to 1u) to Rational(11, 6), + mapOf(x to 2u) to Rational(14, 3), + mapOf(y to 1u) to Rational(17, 1), + mapOf(x to 1u, y to 1u) to Rational(12, 3), + mapOf(x to 2u, y to 1u) to Rational(-6, 2), + mapOf(y to 2u) to Rational(17, 1), + mapOf(x to 1u, y to 2u) to Rational(-4, 3), + mapOf(x to 2u, y to 2u) to Rational(2, 6), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(3, 5), + mapOf(x to 1u) to Rational(3, 5), + mapOf(x to 2u) to Rational(3, 7), + mapOf(y to 1u) to Rational(-3, 8), + mapOf(x to 1u, y to 1u) to Rational(-1, 1), + mapOf(x to 2u, y to 1u) to Rational(17, 9), + mapOf(y to 2u) to Rational(-8, 1), + mapOf(x to 1u, y to 2u) to Rational(6, 4), + mapOf(x to 2u, y to 2u) to Rational(10, 9), + ) + ), + )), + "test 4" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-66677, 3500), + mapOf(x to 1u) to Rational(-206281, 10500), + mapOf(x to 2u) to Rational(-412567, 7056), + mapOf(x to 3u) to Rational(-310081, 11025), + mapOf(x to 4u) to Rational(-575996, 15435), + mapOf(y to 1u) to Rational(-573701, 4200), + mapOf(x to 1u, y to 1u) to Rational(-2239001, 25200), + mapOf(x to 2u, y to 1u) to Rational(-8817889, 132300), + mapOf(x to 3u, y to 1u) to Rational(2317919, 44100), + mapOf(x to 4u, y to 1u) to Rational(1169471, 6615), + mapOf(y to 2u) to Rational(-4057819, 33600), + mapOf(x to 1u, y to 2u) to Rational(1373311, 12600), + mapOf(x to 2u, y to 2u) to Rational(32433493, 52920), + mapOf(x to 3u, y to 2u) to Rational(4998053, 33075), + mapOf(x to 4u, y to 2u) to Rational(-2147779, 8820), + mapOf(y to 3u) to Rational(2018481, 2240), + mapOf(x to 1u, y to 3u) to Rational(941713, 1440), + mapOf(x to 2u, y to 3u) to Rational(183749, 6615), + mapOf(x to 3u, y to 3u) to Rational(-4631023, 15876), + mapOf(x to 4u, y to 3u) to Rational(25609336, 178605), + mapOf(y to 4u) to Rational(11886431, 6720), + mapOf(x to 1u, y to 4u) to Rational(18433, 504), + mapOf(x to 2u, y to 4u) to Rational(-39613331, 45360), + mapOf(x to 3u, y to 4u) to Rational(681619, 5670), + mapOf(x to 4u, y to 4u) to Rational(-864841, 20412), + mapOf(y to 5u) to Rational(343535, 1008), + mapOf(x to 1u, y to 5u) to Rational(-33583, 72), + mapOf(x to 2u, y to 5u) to Rational(1194625, 9072), + mapOf(x to 3u, y to 5u) to Rational(-62917, 2268), + mapOf(x to 4u, y to 5u) to Rational(157645, 10206), + mapOf(y to 6u) to Rational(-1381, 3), + mapOf(x to 1u, y to 6u) to Rational(919, 36), + mapOf(x to 2u, y to 6u) to Rational(-3053, 36), + mapOf(x to 3u, y to 6u) to Rational(2125, 324), + mapOf(x to 4u, y to 6u) to Rational(-236, 243) + ), + LabeledPolynomialAsIs(mapOf() to Rational(0, 1), + mapOf() to Rational(1, 4), + mapOf(x to 1u) to Rational(-5, 3), + mapOf(x to 2u) to Rational(35, 9), + mapOf(x to 3u) to Rational(-100, 27), + mapOf(x to 4u) to Rational(100, 81), + mapOf(y to 1u) to Rational(-5, 3), + mapOf(x to 1u, y to 1u) to Rational(14, 9), + mapOf(x to 2u, y to 1u) to Rational(1874, 189), + mapOf(x to 3u, y to 1u) to Rational(-620, 63), + mapOf(x to 4u, y to 1u) to Rational(40, 63), + mapOf(y to 2u) to Rational(16, 9), + mapOf(x to 1u, y to 2u) to Rational(365, 21), + mapOf(x to 2u, y to 2u) to Rational(112, 9), + mapOf(x to 3u, y to 2u) to Rational(-464, 63), + mapOf(x to 4u, y to 2u) to Rational(1996, 441), + mapOf(y to 3u) to Rational(10, 3), + mapOf(x to 1u, y to 3u) to Rational(118, 21), + mapOf(x to 2u, y to 3u) to Rational(-272, 21), + mapOf(x to 3u, y to 3u) to Rational(-764, 49), + mapOf(x to 4u, y to 3u) to Rational(8, 7), + mapOf(y to 4u) to Rational(1, 1), + mapOf(x to 1u, y to 4u) to Rational(-10, 7), + mapOf(x to 2u, y to 4u) to Rational(-171, 49), + mapOf(x to 3u, y to 4u) to Rational(20, 7), + mapOf(x to 4u, y to 4u) to Rational(4, 1) + ) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(15, 7), + mapOf(x to 1u) to Rational(1, 5), + mapOf(x to 2u) to Rational(-7, 4), + mapOf(y to 1u) to Rational(-1, 9), + mapOf(x to 1u, y to 1u) to Rational(-2, 7), + mapOf(x to 2u, y to 1u) to Rational(17, 3), + mapOf(y to 2u) to Rational(2, 6), + mapOf(x to 1u, y to 2u) to Rational(-17, 6), + mapOf(x to 2u, y to 2u) to Rational(-6, 2), + ).substitute(RationalField, mapOf( + x to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(17, 5), + mapOf(x to 1u) to Rational(11, 6), + mapOf(x to 2u) to Rational(14, 3), + mapOf(y to 1u) to Rational(17, 1), + mapOf(x to 1u, y to 1u) to Rational(12, 3), + mapOf(x to 2u, y to 1u) to Rational(-6, 2), + mapOf(y to 2u) to Rational(17, 1), + mapOf(x to 1u, y to 2u) to Rational(-4, 3), + mapOf(x to 2u, y to 2u) to Rational(2, 6), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(3, 5), + mapOf(x to 1u) to Rational(3, 5), + mapOf(x to 2u) to Rational(3, 7), + mapOf(y to 1u) to Rational(-3, 8), + mapOf(x to 1u, y to 1u) to Rational(-1, 1), + mapOf(x to 2u, y to 1u) to Rational(17, 9), + mapOf(y to 2u) to Rational(-8, 1), + mapOf(x to 1u, y to 2u) to Rational(6, 4), + mapOf(x to 2u, y to 2u) to Rational(10, 9), + ) + ), + iota to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-2, 9), + mapOf(x to 1u) to Rational(-6, 3), + mapOf(x to 2u) to Rational(10, 9), + mapOf(y to 1u) to Rational(13, 3), + mapOf(x to 1u, y to 1u) to Rational(-12, 4), + mapOf(x to 2u, y to 1u) to Rational(3, 6), + mapOf(y to 2u) to Rational(2, 9), + mapOf(x to 1u, y to 2u) to Rational(7, 3), + mapOf(x to 2u, y to 2u) to Rational(16, 5), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 2), + mapOf(x to 1u) to Rational(6, 2), + mapOf(x to 2u) to Rational(2, 7), + mapOf(y to 1u) to Rational(-18, 1), + mapOf(x to 1u, y to 1u) to Rational(-11, 3), + mapOf(x to 2u, y to 1u) to Rational(7, 5), + mapOf(y to 2u) to Rational(8, 1), + mapOf(x to 1u, y to 2u) to Rational(6, 7), + mapOf(x to 2u, y to 2u) to Rational(17, 4), + ) + ) + )), + "test 4'" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(3539, 700), + mapOf(x to 1u) to Rational(-307079, 6300), + mapOf(x to 2u) to Rational(451609, 15120), + mapOf(x to 3u) to Rational(35287733, 396900), + mapOf(x to 4u) to Rational(-37242617, 396900), + mapOf(x to 5u) to Rational(382747, 19845), + mapOf(x to 6u) to Rational(-2407, 3969), + mapOf(y to 1u) to Rational(-226, 175), + mapOf(x to 1u, y to 1u) to Rational(-74113, 1890), + mapOf(x to 2u, y to 1u) to Rational(250931, 1764), + mapOf(x to 3u, y to 1u) to Rational(30071473, 99225), + mapOf(x to 4u, y to 1u) to Rational(-286466, 1323), + mapOf(x to 5u, y to 1u) to Rational(-2285282, 9261), + mapOf(x to 6u, y to 1u) to Rational(17900, 441), + mapOf(y to 2u) to Rational(3817, 3150), + mapOf(x to 1u, y to 2u) to Rational(577568, 11025), + mapOf(x to 2u, y to 2u) to Rational(9073553, 99225), + mapOf(x to 3u, y to 2u) to Rational(-1415849, 79380), + mapOf(x to 4u, y to 2u) to Rational(-124715629, 277830), + mapOf(x to 5u, y to 2u) to Rational(-1328953, 1890), + mapOf(x to 6u, y to 2u) to Rational(-297148, 1323), + mapOf(y to 3u) to Rational(6043, 945), + mapOf(x to 1u, y to 3u) to Rational(160381, 6615), + mapOf(x to 2u, y to 3u) to Rational(-673249, 13230), + mapOf(x to 3u, y to 3u) to Rational(-319255, 2058), + mapOf(x to 4u, y to 3u) to Rational(-98144, 1029), + mapOf(x to 5u, y to 3u) to Rational(-320239, 5145), + mapOf(x to 6u, y to 3u) to Rational(400, 147), + mapOf(y to 4u) to Rational(163, 63), + mapOf(x to 1u, y to 4u) to Rational(-25183, 4410), + mapOf(x to 2u, y to 4u) to Rational(-21369, 1372), + mapOf(x to 3u, y to 4u) to Rational(127499, 30870), + mapOf(x to 4u, y to 4u) to Rational(86971, 12348), + mapOf(x to 5u, y to 4u) to Rational(-11129, 1470), + mapOf(x to 6u, y to 4u) to Rational(544, 147) + ), + LabeledPolynomialAsIs(mapOf() to Rational(0, 1), + mapOf() to Rational(1, 4), + mapOf(x to 1u) to Rational(-5, 3), + mapOf(x to 2u) to Rational(35, 9), + mapOf(x to 3u) to Rational(-100, 27), + mapOf(x to 4u) to Rational(100, 81), + mapOf(y to 1u) to Rational(-5, 3), + mapOf(x to 1u, y to 1u) to Rational(14, 9), + mapOf(x to 2u, y to 1u) to Rational(1874, 189), + mapOf(x to 3u, y to 1u) to Rational(-620, 63), + mapOf(x to 4u, y to 1u) to Rational(40, 63), + mapOf(y to 2u) to Rational(16, 9), + mapOf(x to 1u, y to 2u) to Rational(365, 21), + mapOf(x to 2u, y to 2u) to Rational(112, 9), + mapOf(x to 3u, y to 2u) to Rational(-464, 63), + mapOf(x to 4u, y to 2u) to Rational(1996, 441), + mapOf(y to 3u) to Rational(10, 3), + mapOf(x to 1u, y to 3u) to Rational(118, 21), + mapOf(x to 2u, y to 3u) to Rational(-272, 21), + mapOf(x to 3u, y to 3u) to Rational(-764, 49), + mapOf(x to 4u, y to 3u) to Rational(8, 7), + mapOf(y to 4u) to Rational(1, 1), + mapOf(x to 1u, y to 4u) to Rational(-10, 7), + mapOf(x to 2u, y to 4u) to Rational(-171, 49), + mapOf(x to 3u, y to 4u) to Rational(20, 7), + mapOf(x to 4u, y to 4u) to Rational(4, 1) + ) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(15, 7), + mapOf(x to 1u) to Rational(1, 5), + mapOf(x to 2u) to Rational(-7, 4), + mapOf(y to 1u) to Rational(-1, 9), + mapOf(x to 1u, y to 1u) to Rational(-2, 7), + mapOf(x to 2u, y to 1u) to Rational(17, 3), + mapOf(y to 2u) to Rational(2, 6), + mapOf(x to 1u, y to 2u) to Rational(-17, 6), + mapOf(x to 2u, y to 2u) to Rational(-6, 2), + ).substitute(RationalField, mapOf( + y to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(18, 5), + mapOf(x to 1u) to Rational(-17, 5), + mapOf(x to 2u) to Rational(-2, 7), + mapOf(y to 1u) to Rational(6, 5), + mapOf(x to 1u, y to 1u) to Rational(-5, 1), + mapOf(x to 2u, y to 1u) to Rational(-9, 1), + mapOf(y to 2u) to Rational(-8, 8), + mapOf(x to 1u, y to 2u) to Rational(2, 7), + mapOf(x to 2u, y to 2u) to Rational(-13, 7), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-4, 8), + mapOf(x to 1u) to Rational(15, 9), + mapOf(x to 2u) to Rational(-10, 9), + mapOf(y to 1u) to Rational(5, 3), + mapOf(x to 1u, y to 1u) to Rational(4, 1), + mapOf(x to 2u, y to 1u) to Rational(-2, 7), + mapOf(y to 2u) to Rational(2, 2), + mapOf(x to 1u, y to 2u) to Rational(-5, 7), + mapOf(x to 2u, y to 2u) to Rational(-18, 9), + ) + ), + )), + "test 5" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(3539, 700), + mapOf(x to 1u) to Rational(-307079, 6300), + mapOf(x to 2u) to Rational(451609, 15120), + mapOf(x to 3u) to Rational(35287733, 396900), + mapOf(x to 4u) to Rational(-37242617, 396900), + mapOf(x to 5u) to Rational(382747, 19845), + mapOf(x to 6u) to Rational(-2407, 3969), + mapOf(y to 1u) to Rational(-226, 175), + mapOf(x to 1u, y to 1u) to Rational(-74113, 1890), + mapOf(x to 2u, y to 1u) to Rational(250931, 1764), + mapOf(x to 3u, y to 1u) to Rational(30071473, 99225), + mapOf(x to 4u, y to 1u) to Rational(-286466, 1323), + mapOf(x to 5u, y to 1u) to Rational(-2285282, 9261), + mapOf(x to 6u, y to 1u) to Rational(17900, 441), + mapOf(y to 2u) to Rational(3817, 3150), + mapOf(x to 1u, y to 2u) to Rational(577568, 11025), + mapOf(x to 2u, y to 2u) to Rational(9073553, 99225), + mapOf(x to 3u, y to 2u) to Rational(-1415849, 79380), + mapOf(x to 4u, y to 2u) to Rational(-124715629, 277830), + mapOf(x to 5u, y to 2u) to Rational(-1328953, 1890), + mapOf(x to 6u, y to 2u) to Rational(-297148, 1323), + mapOf(y to 3u) to Rational(6043, 945), + mapOf(x to 1u, y to 3u) to Rational(160381, 6615), + mapOf(x to 2u, y to 3u) to Rational(-673249, 13230), + mapOf(x to 3u, y to 3u) to Rational(-319255, 2058), + mapOf(x to 4u, y to 3u) to Rational(-98144, 1029), + mapOf(x to 5u, y to 3u) to Rational(-320239, 5145), + mapOf(x to 6u, y to 3u) to Rational(400, 147), + mapOf(y to 4u) to Rational(163, 63), + mapOf(x to 1u, y to 4u) to Rational(-25183, 4410), + mapOf(x to 2u, y to 4u) to Rational(-21369, 1372), + mapOf(x to 3u, y to 4u) to Rational(127499, 30870), + mapOf(x to 4u, y to 4u) to Rational(86971, 12348), + mapOf(x to 5u, y to 4u) to Rational(-11129, 1470), + mapOf(x to 6u, y to 4u) to Rational(544, 147) + ), + LabeledPolynomialAsIs(mapOf() to Rational(0, 1), + mapOf() to Rational(1, 4), + mapOf(x to 1u) to Rational(-5, 3), + mapOf(x to 2u) to Rational(35, 9), + mapOf(x to 3u) to Rational(-100, 27), + mapOf(x to 4u) to Rational(100, 81), + mapOf(y to 1u) to Rational(-5, 3), + mapOf(x to 1u, y to 1u) to Rational(14, 9), + mapOf(x to 2u, y to 1u) to Rational(1874, 189), + mapOf(x to 3u, y to 1u) to Rational(-620, 63), + mapOf(x to 4u, y to 1u) to Rational(40, 63), + mapOf(y to 2u) to Rational(16, 9), + mapOf(x to 1u, y to 2u) to Rational(365, 21), + mapOf(x to 2u, y to 2u) to Rational(112, 9), + mapOf(x to 3u, y to 2u) to Rational(-464, 63), + mapOf(x to 4u, y to 2u) to Rational(1996, 441), + mapOf(y to 3u) to Rational(10, 3), + mapOf(x to 1u, y to 3u) to Rational(118, 21), + mapOf(x to 2u, y to 3u) to Rational(-272, 21), + mapOf(x to 3u, y to 3u) to Rational(-764, 49), + mapOf(x to 4u, y to 3u) to Rational(8, 7), + mapOf(y to 4u) to Rational(1, 1), + mapOf(x to 1u, y to 4u) to Rational(-10, 7), + mapOf(x to 2u, y to 4u) to Rational(-171, 49), + mapOf(x to 3u, y to 4u) to Rational(20, 7), + mapOf(x to 4u, y to 4u) to Rational(4, 1) + ) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(15, 7), + mapOf(x to 1u) to Rational(1, 5), + mapOf(x to 2u) to Rational(-7, 4), + mapOf(y to 1u) to Rational(-1, 9), + mapOf(x to 1u, y to 1u) to Rational(-2, 7), + mapOf(x to 2u, y to 1u) to Rational(17, 3), + mapOf(y to 2u) to Rational(2, 6), + mapOf(x to 1u, y to 2u) to Rational(-17, 6), + mapOf(x to 2u, y to 2u) to Rational(-6, 2), + ).substitute(RationalField, mapOf( + y to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(18, 5), + mapOf(x to 1u) to Rational(-17, 5), + mapOf(x to 2u) to Rational(-2, 7), + mapOf(y to 1u) to Rational(6, 5), + mapOf(x to 1u, y to 1u) to Rational(-5, 1), + mapOf(x to 2u, y to 1u) to Rational(-9, 1), + mapOf(y to 2u) to Rational(-8, 8), + mapOf(x to 1u, y to 2u) to Rational(2, 7), + mapOf(x to 2u, y to 2u) to Rational(-13, 7), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-4, 8), + mapOf(x to 1u) to Rational(15, 9), + mapOf(x to 2u) to Rational(-10, 9), + mapOf(y to 1u) to Rational(5, 3), + mapOf(x to 1u, y to 1u) to Rational(4, 1), + mapOf(x to 2u, y to 1u) to Rational(-2, 7), + mapOf(y to 2u) to Rational(2, 2), + mapOf(x to 1u, y to 2u) to Rational(-5, 7), + mapOf(x to 2u, y to 2u) to Rational(-18, 9), + ) + ), + iota to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-2, 9), + mapOf(x to 1u) to Rational(-6, 3), + mapOf(x to 2u) to Rational(10, 9), + mapOf(y to 1u) to Rational(13, 3), + mapOf(x to 1u, y to 1u) to Rational(-12, 4), + mapOf(x to 2u, y to 1u) to Rational(3, 6), + mapOf(y to 2u) to Rational(2, 9), + mapOf(x to 1u, y to 2u) to Rational(7, 3), + mapOf(x to 2u, y to 2u) to Rational(16, 5), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 2), + mapOf(x to 1u) to Rational(6, 2), + mapOf(x to 2u) to Rational(2, 7), + mapOf(y to 1u) to Rational(-18, 1), + mapOf(x to 1u, y to 1u) to Rational(-11, 3), + mapOf(x to 2u, y to 1u) to Rational(7, 5), + mapOf(y to 2u) to Rational(8, 1), + mapOf(x to 1u, y to 2u) to Rational(6, 7), + mapOf(x to 2u, y to 2u) to Rational(17, 4), + ) + ) + )), + "test 5'" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(15, 7), + mapOf(x to 1u) to Rational(1, 5), + mapOf(x to 2u) to Rational(-7, 4), + mapOf(y to 1u) to Rational(-1, 9), + mapOf(x to 1u, y to 1u) to Rational(-2, 7), + mapOf(x to 2u, y to 1u) to Rational(17, 3), + mapOf(y to 2u) to Rational(2, 6), + mapOf(x to 1u, y to 2u) to Rational(-17, 6), + mapOf(x to 2u, y to 2u) to Rational(-6, 2), + ), + LabeledPolynomialAsIs(mapOf() to Rational(0, 1), + mapOf() to Rational(0, 1) + ) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(15, 7), + mapOf(x to 1u) to Rational(1, 5), + mapOf(x to 2u) to Rational(-7, 4), + mapOf(y to 1u) to Rational(-1, 9), + mapOf(x to 1u, y to 1u) to Rational(-2, 7), + mapOf(x to 2u, y to 1u) to Rational(17, 3), + mapOf(y to 2u) to Rational(2, 6), + mapOf(x to 1u, y to 2u) to Rational(-17, 6), + mapOf(x to 2u, y to 2u) to Rational(-6, 2), + ).substitute(RationalField, mapOf>()), + "test 6" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(15, 7), + mapOf(x to 1u) to Rational(1, 5), + mapOf(x to 2u) to Rational(-7, 4), + mapOf(y to 1u) to Rational(-1, 9), + mapOf(x to 1u, y to 1u) to Rational(-2, 7), + mapOf(x to 2u, y to 1u) to Rational(17, 3), + mapOf(y to 2u) to Rational(2, 6), + mapOf(x to 1u, y to 2u) to Rational(-17, 6), + mapOf(x to 2u, y to 2u) to Rational(-6, 2), + ), + LabeledPolynomialAsIs(mapOf() to Rational(0, 1), + mapOf() to Rational(0, 1) + ) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(15, 7), + mapOf(x to 1u) to Rational(1, 5), + mapOf(x to 2u) to Rational(-7, 4), + mapOf(y to 1u) to Rational(-1, 9), + mapOf(x to 1u, y to 1u) to Rational(-2, 7), + mapOf(x to 2u, y to 1u) to Rational(17, 3), + mapOf(y to 2u) to Rational(2, 6), + mapOf(x to 1u, y to 2u) to Rational(-17, 6), + mapOf(x to 2u, y to 2u) to Rational(-6, 2), + ).substitute(RationalField, mapOf( + iota to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-2, 9), + mapOf(x to 1u) to Rational(-6, 3), + mapOf(x to 2u) to Rational(10, 9), + mapOf(y to 1u) to Rational(13, 3), + mapOf(x to 1u, y to 1u) to Rational(-12, 4), + mapOf(x to 2u, y to 1u) to Rational(3, 6), + mapOf(y to 2u) to Rational(2, 9), + mapOf(x to 1u, y to 2u) to Rational(7, 3), + mapOf(x to 2u, y to 2u) to Rational(16, 5), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 2), + mapOf(x to 1u) to Rational(6, 2), + mapOf(x to 2u) to Rational(2, 7), + mapOf(y to 1u) to Rational(-18, 1), + mapOf(x to 1u, y to 1u) to Rational(-11, 3), + mapOf(x to 2u, y to 1u) to Rational(7, 5), + mapOf(y to 2u) to Rational(8, 1), + mapOf(x to 1u, y to 2u) to Rational(6, 7), + mapOf(x to 2u, y to 2u) to Rational(17, 4), + ) + ) + )), + "test 6'" + ) + } + @Test + fun test_RationalFunction_substitute_Double_Map() { + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs(emptyMap() to 0.0), + LabeledPolynomialAsIs(emptyMap() to 1.0), + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to 1.0, + mapOf(x to 1u) to -2.0, + mapOf(x to 2u) to 1.0, + ), + LabeledPolynomialAsIs( + mapOf() to 1.0, + ) + ).substitute(mapOf( + x to 1.0 + )), + 0.001, + "test 1" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to 6.593754860231304, + mapOf(x to 1u) to -7.853302571550634, + mapOf(x to 2u) to 1.2265042281530025, + mapOf(y to 1u) to 3.762648877294904, + mapOf(x to 1u, y to 1u) to -8.945144619305292, + mapOf(x to 2u, y to 1u) to -5.141384718042281, + mapOf(y to 2u) to 7.359794483988782, + mapOf(x to 1u, y to 2u) to -4.3526172680518815, + mapOf(x to 2u, y to 2u) to 0.907910924854372, + ), + LabeledPolynomialAsIs( + mapOf() to 9.533292132172562, + mapOf(x to 1u) to -1.982814534018857, + mapOf(x to 2u) to -5.974248303415283, + mapOf(y to 1u) to 1.5876716499288879, + mapOf(x to 1u, y to 1u) to -7.535152566659664, + mapOf(x to 2u, y to 1u) to 0.7549300500153517, + mapOf(y to 2u) to -5.242030058021028, + mapOf(x to 1u, y to 2u) to -0.7265704289690582, + mapOf(x to 2u, y to 2u) to -7.139677818189821, + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to 6.593754860231304, + mapOf(x to 1u) to -7.853302571550634, + mapOf(x to 2u) to 1.2265042281530025, + mapOf(y to 1u) to 3.762648877294904, + mapOf(x to 1u, y to 1u) to -8.945144619305292, + mapOf(x to 2u, y to 1u) to -5.141384718042281, + mapOf(y to 2u) to 7.359794483988782, + mapOf(x to 1u, y to 2u) to -4.3526172680518815, + mapOf(x to 2u, y to 2u) to 0.907910924854372, + ), + LabeledPolynomialAsIs( + mapOf() to 9.533292132172562, + mapOf(x to 1u) to -1.982814534018857, + mapOf(x to 2u) to -5.974248303415283, + mapOf(y to 1u) to 1.5876716499288879, + mapOf(x to 1u, y to 1u) to -7.535152566659664, + mapOf(x to 2u, y to 1u) to 0.7549300500153517, + mapOf(y to 2u) to -5.242030058021028, + mapOf(x to 1u, y to 2u) to -0.7265704289690582, + mapOf(x to 2u, y to 2u) to -7.139677818189821, + ) + ).substitute(mapOf()), + 0.001, + "test 2" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to 6.593754860231304, + mapOf(x to 1u) to -7.853302571550634, + mapOf(x to 2u) to 1.2265042281530025, + mapOf(y to 1u) to 3.762648877294904, + mapOf(x to 1u, y to 1u) to -8.945144619305292, + mapOf(x to 2u, y to 1u) to -5.141384718042281, + mapOf(y to 2u) to 7.359794483988782, + mapOf(x to 1u, y to 2u) to -4.3526172680518815, + mapOf(x to 2u, y to 2u) to 0.907910924854372, + ), + LabeledPolynomialAsIs( + mapOf() to 9.533292132172562, + mapOf(x to 1u) to -1.982814534018857, + mapOf(x to 2u) to -5.974248303415283, + mapOf(y to 1u) to 1.5876716499288879, + mapOf(x to 1u, y to 1u) to -7.535152566659664, + mapOf(x to 2u, y to 1u) to 0.7549300500153517, + mapOf(y to 2u) to -5.242030058021028, + mapOf(x to 1u, y to 2u) to -0.7265704289690582, + mapOf(x to 2u, y to 2u) to -7.139677818189821, + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to 6.593754860231304, + mapOf(x to 1u) to -7.853302571550634, + mapOf(x to 2u) to 1.2265042281530025, + mapOf(y to 1u) to 3.762648877294904, + mapOf(x to 1u, y to 1u) to -8.945144619305292, + mapOf(x to 2u, y to 1u) to -5.141384718042281, + mapOf(y to 2u) to 7.359794483988782, + mapOf(x to 1u, y to 2u) to -4.3526172680518815, + mapOf(x to 2u, y to 2u) to 0.907910924854372, + ), + LabeledPolynomialAsIs( + mapOf() to 9.533292132172562, + mapOf(x to 1u) to -1.982814534018857, + mapOf(x to 2u) to -5.974248303415283, + mapOf(y to 1u) to 1.5876716499288879, + mapOf(x to 1u, y to 1u) to -7.535152566659664, + mapOf(x to 2u, y to 1u) to 0.7549300500153517, + mapOf(y to 2u) to -5.242030058021028, + mapOf(x to 1u, y to 2u) to -0.7265704289690582, + mapOf(x to 2u, y to 2u) to -7.139677818189821, + ) + ).substitute(mapOf( + iota to 0.9211194782050933 + )), + 0.001, + "test 2'" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to 151.1502229133916, + mapOf(y to 1u) to -262.3790170577034, + mapOf(y to 2u) to 102.5097937392923, + ), + LabeledPolynomialAsIs( + mapOf() to -367.9969733169944, + mapOf(y to 1u) to 112.4911133334554, + mapOf(y to 2u) to -469.755906895345, + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to 6.593754860231304, + mapOf(x to 1u) to -7.853302571550634, + mapOf(x to 2u) to 1.2265042281530025, + mapOf(y to 1u) to 3.762648877294904, + mapOf(x to 1u, y to 1u) to -8.945144619305292, + mapOf(x to 2u, y to 1u) to -5.141384718042281, + mapOf(y to 2u) to 7.359794483988782, + mapOf(x to 1u, y to 2u) to -4.3526172680518815, + mapOf(x to 2u, y to 2u) to 0.907910924854372, + ), + LabeledPolynomialAsIs( + mapOf() to 9.533292132172562, + mapOf(x to 1u) to -1.982814534018857, + mapOf(x to 2u) to -5.974248303415283, + mapOf(y to 1u) to 1.5876716499288879, + mapOf(x to 1u, y to 1u) to -7.535152566659664, + mapOf(x to 2u, y to 1u) to 0.7549300500153517, + mapOf(y to 2u) to -5.242030058021028, + mapOf(x to 1u, y to 2u) to -0.7265704289690582, + mapOf(x to 2u, y to 2u) to -7.139677818189821, + ) + ).substitute(mapOf( + x to -8.11707689492641, + )), + 0.001, + "test 3" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to 151.1502229133916, + mapOf(y to 1u) to -262.3790170577034, + mapOf(y to 2u) to 102.5097937392923, + ), + LabeledPolynomialAsIs( + mapOf() to -367.9969733169944, + mapOf(y to 1u) to 112.4911133334554, + mapOf(y to 2u) to -469.755906895345, + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to 6.593754860231304, + mapOf(x to 1u) to -7.853302571550634, + mapOf(x to 2u) to 1.2265042281530025, + mapOf(y to 1u) to 3.762648877294904, + mapOf(x to 1u, y to 1u) to -8.945144619305292, + mapOf(x to 2u, y to 1u) to -5.141384718042281, + mapOf(y to 2u) to 7.359794483988782, + mapOf(x to 1u, y to 2u) to -4.3526172680518815, + mapOf(x to 2u, y to 2u) to 0.907910924854372, + ), + LabeledPolynomialAsIs( + mapOf() to 9.533292132172562, + mapOf(x to 1u) to -1.982814534018857, + mapOf(x to 2u) to -5.974248303415283, + mapOf(y to 1u) to 1.5876716499288879, + mapOf(x to 1u, y to 1u) to -7.535152566659664, + mapOf(x to 2u, y to 1u) to 0.7549300500153517, + mapOf(y to 2u) to -5.242030058021028, + mapOf(x to 1u, y to 2u) to -0.7265704289690582, + mapOf(x to 2u, y to 2u) to -7.139677818189821, + ) + ).substitute(mapOf( + x to -8.11707689492641, + iota to 0.9211194782050933 + )), + 0.001, + "test 3'" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to 14.24074356896978, + mapOf(x to 1u) to -17.71987055153461, + mapOf(x to 2u) to -2.288056483312383, + ), + LabeledPolynomialAsIs( + mapOf() to 7.480604285873397, + mapOf(x to 1u) to -8.43478016688617, + mapOf(x to 2u) to -9.88934943900592, + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to 6.593754860231304, + mapOf(x to 1u) to -7.853302571550634, + mapOf(x to 2u) to 1.2265042281530025, + mapOf(y to 1u) to 3.762648877294904, + mapOf(x to 1u, y to 1u) to -8.945144619305292, + mapOf(x to 2u, y to 1u) to -5.141384718042281, + mapOf(y to 2u) to 7.359794483988782, + mapOf(x to 1u, y to 2u) to -4.3526172680518815, + mapOf(x to 2u, y to 2u) to 0.907910924854372, + ), + LabeledPolynomialAsIs( + mapOf() to 9.533292132172562, + mapOf(x to 1u) to -1.982814534018857, + mapOf(x to 2u) to -5.974248303415283, + mapOf(y to 1u) to 1.5876716499288879, + mapOf(x to 1u, y to 1u) to -7.535152566659664, + mapOf(x to 2u, y to 1u) to 0.7549300500153517, + mapOf(y to 2u) to -5.242030058021028, + mapOf(x to 1u, y to 2u) to -0.7265704289690582, + mapOf(x to 2u, y to 2u) to -7.139677818189821, + ) + ).substitute(mapOf( + y to 0.795265651276015, + )), + 0.001, + "test 4" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to 14.24074356896978, + mapOf(x to 1u) to -17.71987055153461, + mapOf(x to 2u) to -2.288056483312383, + ), + LabeledPolynomialAsIs( + mapOf() to 7.480604285873397, + mapOf(x to 1u) to -8.43478016688617, + mapOf(x to 2u) to -9.88934943900592, + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to 6.593754860231304, + mapOf(x to 1u) to -7.853302571550634, + mapOf(x to 2u) to 1.2265042281530025, + mapOf(y to 1u) to 3.762648877294904, + mapOf(x to 1u, y to 1u) to -8.945144619305292, + mapOf(x to 2u, y to 1u) to -5.141384718042281, + mapOf(y to 2u) to 7.359794483988782, + mapOf(x to 1u, y to 2u) to -4.3526172680518815, + mapOf(x to 2u, y to 2u) to 0.907910924854372, + ), + LabeledPolynomialAsIs( + mapOf() to 9.533292132172562, + mapOf(x to 1u) to -1.982814534018857, + mapOf(x to 2u) to -5.974248303415283, + mapOf(y to 1u) to 1.5876716499288879, + mapOf(x to 1u, y to 1u) to -7.535152566659664, + mapOf(x to 2u, y to 1u) to 0.7549300500153517, + mapOf(y to 2u) to -5.242030058021028, + mapOf(x to 1u, y to 2u) to -0.7265704289690582, + mapOf(x to 2u, y to 2u) to -7.139677818189821, + ) + ).substitute(mapOf( + y to 0.795265651276015, + iota to 0.9211194782050933 + )), + 0.001, + "test 4'" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to 7.321261307532708, + ), + LabeledPolynomialAsIs( + mapOf() to -575.6325831127576, + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to 6.593754860231304, + mapOf(x to 1u) to -7.853302571550634, + mapOf(x to 2u) to 1.2265042281530025, + mapOf(y to 1u) to 3.762648877294904, + mapOf(x to 1u, y to 1u) to -8.945144619305292, + mapOf(x to 2u, y to 1u) to -5.141384718042281, + mapOf(y to 2u) to 7.359794483988782, + mapOf(x to 1u, y to 2u) to -4.3526172680518815, + mapOf(x to 2u, y to 2u) to 0.907910924854372, + ), + LabeledPolynomialAsIs( + mapOf() to 9.533292132172562, + mapOf(x to 1u) to -1.982814534018857, + mapOf(x to 2u) to -5.974248303415283, + mapOf(y to 1u) to 1.5876716499288879, + mapOf(x to 1u, y to 1u) to -7.535152566659664, + mapOf(x to 2u, y to 1u) to 0.7549300500153517, + mapOf(y to 2u) to -5.242030058021028, + mapOf(x to 1u, y to 2u) to -0.7265704289690582, + mapOf(x to 2u, y to 2u) to -7.139677818189821, + ) + ).substitute(mapOf( + x to -8.11707689492641, + y to 0.795265651276015, + )), + 0.001, + "test 5" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to 7.321261307532708, + ), + LabeledPolynomialAsIs( + mapOf() to -575.6325831127576, + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to 6.593754860231304, + mapOf(x to 1u) to -7.853302571550634, + mapOf(x to 2u) to 1.2265042281530025, + mapOf(y to 1u) to 3.762648877294904, + mapOf(x to 1u, y to 1u) to -8.945144619305292, + mapOf(x to 2u, y to 1u) to -5.141384718042281, + mapOf(y to 2u) to 7.359794483988782, + mapOf(x to 1u, y to 2u) to -4.3526172680518815, + mapOf(x to 2u, y to 2u) to 0.907910924854372, + ), + LabeledPolynomialAsIs( + mapOf() to 9.533292132172562, + mapOf(x to 1u) to -1.982814534018857, + mapOf(x to 2u) to -5.974248303415283, + mapOf(y to 1u) to 1.5876716499288879, + mapOf(x to 1u, y to 1u) to -7.535152566659664, + mapOf(x to 2u, y to 1u) to 0.7549300500153517, + mapOf(y to 2u) to -5.242030058021028, + mapOf(x to 1u, y to 2u) to -0.7265704289690582, + mapOf(x to 2u, y to 2u) to -7.139677818189821, + ) + ).substitute(mapOf( + x to -8.11707689492641, + y to 0.795265651276015, + iota to 0.9211194782050933 + )), + 0.001, + "test 5'" + ) + } + @Test + fun test_RationalFunction_substitute_Constant_Map() { + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(0) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1) + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1) + ) + ).substitute(RationalField, mapOf( + x to Rational(1) + )), + "test 1" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(22047, 2450), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-2204953, 147000), + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 5), + mapOf(x to 1u) to Rational(-18, 4), + mapOf(x to 2u) to Rational(9, 8), + mapOf(y to 1u) to Rational(-11, 6), + mapOf(x to 1u, y to 1u) to Rational(-16, 3), + mapOf(x to 2u, y to 1u) to Rational(12, 2), + mapOf(y to 2u) to Rational(5, 3), + mapOf(x to 1u, y to 2u) to Rational(17, 8), + mapOf(x to 2u, y to 2u) to Rational(1, 3), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(11, 1), + mapOf(x to 1u) to Rational(4, 1), + mapOf(x to 2u) to Rational(-18, 3), + mapOf(y to 1u) to Rational(12, 9), + mapOf(x to 1u, y to 1u) to Rational(14, 7), + mapOf(x to 2u, y to 1u) to Rational(-17, 5), + mapOf(y to 2u) to Rational(-4, 1), + mapOf(x to 1u, y to 2u) to Rational(-5, 5), + mapOf(x to 2u, y to 2u) to Rational(-7, 8), + ) + ).substitute(RationalField, mapOf( + x to Rational(7, 5), + y to Rational(-13, 7), + )), + "test 2" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(22047, 2450), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-2204953, 147000), + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 5), + mapOf(x to 1u) to Rational(-18, 4), + mapOf(x to 2u) to Rational(9, 8), + mapOf(y to 1u) to Rational(-11, 6), + mapOf(x to 1u, y to 1u) to Rational(-16, 3), + mapOf(x to 2u, y to 1u) to Rational(12, 2), + mapOf(y to 2u) to Rational(5, 3), + mapOf(x to 1u, y to 2u) to Rational(17, 8), + mapOf(x to 2u, y to 2u) to Rational(1, 3), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(11, 1), + mapOf(x to 1u) to Rational(4, 1), + mapOf(x to 2u) to Rational(-18, 3), + mapOf(y to 1u) to Rational(12, 9), + mapOf(x to 1u, y to 1u) to Rational(14, 7), + mapOf(x to 2u, y to 1u) to Rational(-17, 5), + mapOf(y to 2u) to Rational(-4, 1), + mapOf(x to 1u, y to 2u) to Rational(-5, 5), + mapOf(x to 2u, y to 2u) to Rational(-7, 8), + ) + ).substitute(RationalField, mapOf( + x to Rational(7, 5), + y to Rational(-13, 7), + iota to Rational(-16, 4), + )), + "test 2'" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(4191, 490), + mapOf(x to 1u) to Rational(14975, 1176), + mapOf(x to 2u) to Rational(-10429, 1176) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-775, 147), + mapOf(x to 1u) to Rational(-155, 49), + mapOf(x to 2u) to Rational(-757, 280) + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 5), + mapOf(x to 1u) to Rational(-18, 4), + mapOf(x to 2u) to Rational(9, 8), + mapOf(y to 1u) to Rational(-11, 6), + mapOf(x to 1u, y to 1u) to Rational(-16, 3), + mapOf(x to 2u, y to 1u) to Rational(12, 2), + mapOf(y to 2u) to Rational(5, 3), + mapOf(x to 1u, y to 2u) to Rational(17, 8), + mapOf(x to 2u, y to 2u) to Rational(1, 3), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(11, 1), + mapOf(x to 1u) to Rational(4, 1), + mapOf(x to 2u) to Rational(-18, 3), + mapOf(y to 1u) to Rational(12, 9), + mapOf(x to 1u, y to 1u) to Rational(14, 7), + mapOf(x to 2u, y to 1u) to Rational(-17, 5), + mapOf(y to 2u) to Rational(-4, 1), + mapOf(x to 1u, y to 2u) to Rational(-5, 5), + mapOf(x to 2u, y to 2u) to Rational(-7, 8), + ) + ).substitute(RationalField, mapOf( + y to Rational(-13, 7), + )), + "test 3" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(4191, 490), + mapOf(x to 1u) to Rational(14975, 1176), + mapOf(x to 2u) to Rational(-10429, 1176) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-775, 147), + mapOf(x to 1u) to Rational(-155, 49), + mapOf(x to 2u) to Rational(-757, 280) + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 5), + mapOf(x to 1u) to Rational(-18, 4), + mapOf(x to 2u) to Rational(9, 8), + mapOf(y to 1u) to Rational(-11, 6), + mapOf(x to 1u, y to 1u) to Rational(-16, 3), + mapOf(x to 2u, y to 1u) to Rational(12, 2), + mapOf(y to 2u) to Rational(5, 3), + mapOf(x to 1u, y to 2u) to Rational(17, 8), + mapOf(x to 2u, y to 2u) to Rational(1, 3), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(11, 1), + mapOf(x to 1u) to Rational(4, 1), + mapOf(x to 2u) to Rational(-18, 3), + mapOf(y to 1u) to Rational(12, 9), + mapOf(x to 1u, y to 1u) to Rational(14, 7), + mapOf(x to 2u, y to 1u) to Rational(-17, 5), + mapOf(y to 2u) to Rational(-4, 1), + mapOf(x to 1u, y to 2u) to Rational(-5, 5), + mapOf(x to 2u, y to 2u) to Rational(-7, 8), + ) + ).substitute(RationalField, mapOf( + y to Rational(-13, 7), + iota to Rational(-16, 4), + )), + "test 3'" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-939, 200), + mapOf(y to 1u) to Rational(123, 50), + mapOf(y to 2u) to Rational(1059, 200) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(121, 25), + mapOf(y to 1u) to Rational(-949, 375), + mapOf(y to 2u) to Rational(-1423, 200) + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 5), + mapOf(x to 1u) to Rational(-18, 4), + mapOf(x to 2u) to Rational(9, 8), + mapOf(y to 1u) to Rational(-11, 6), + mapOf(x to 1u, y to 1u) to Rational(-16, 3), + mapOf(x to 2u, y to 1u) to Rational(12, 2), + mapOf(y to 2u) to Rational(5, 3), + mapOf(x to 1u, y to 2u) to Rational(17, 8), + mapOf(x to 2u, y to 2u) to Rational(1, 3), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(11, 1), + mapOf(x to 1u) to Rational(4, 1), + mapOf(x to 2u) to Rational(-18, 3), + mapOf(y to 1u) to Rational(12, 9), + mapOf(x to 1u, y to 1u) to Rational(14, 7), + mapOf(x to 2u, y to 1u) to Rational(-17, 5), + mapOf(y to 2u) to Rational(-4, 1), + mapOf(x to 1u, y to 2u) to Rational(-5, 5), + mapOf(x to 2u, y to 2u) to Rational(-7, 8), + ) + ).substitute(RationalField, mapOf( + x to Rational(7, 5), + )), + "test 4" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-939, 200), + mapOf(y to 1u) to Rational(123, 50), + mapOf(y to 2u) to Rational(1059, 200) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(121, 25), + mapOf(y to 1u) to Rational(-949, 375), + mapOf(y to 2u) to Rational(-1423, 200) + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 5), + mapOf(x to 1u) to Rational(-18, 4), + mapOf(x to 2u) to Rational(9, 8), + mapOf(y to 1u) to Rational(-11, 6), + mapOf(x to 1u, y to 1u) to Rational(-16, 3), + mapOf(x to 2u, y to 1u) to Rational(12, 2), + mapOf(y to 2u) to Rational(5, 3), + mapOf(x to 1u, y to 2u) to Rational(17, 8), + mapOf(x to 2u, y to 2u) to Rational(1, 3), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(11, 1), + mapOf(x to 1u) to Rational(4, 1), + mapOf(x to 2u) to Rational(-18, 3), + mapOf(y to 1u) to Rational(12, 9), + mapOf(x to 1u, y to 1u) to Rational(14, 7), + mapOf(x to 2u, y to 1u) to Rational(-17, 5), + mapOf(y to 2u) to Rational(-4, 1), + mapOf(x to 1u, y to 2u) to Rational(-5, 5), + mapOf(x to 2u, y to 2u) to Rational(-7, 8), + ) + ).substitute(RationalField, mapOf( + x to Rational(7, 5), + iota to Rational(-16, 4), + )), + "test 4'" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 5), + mapOf(x to 1u) to Rational(-18, 4), + mapOf(x to 2u) to Rational(9, 8), + mapOf(y to 1u) to Rational(-11, 6), + mapOf(x to 1u, y to 1u) to Rational(-16, 3), + mapOf(x to 2u, y to 1u) to Rational(12, 2), + mapOf(y to 2u) to Rational(5, 3), + mapOf(x to 1u, y to 2u) to Rational(17, 8), + mapOf(x to 2u, y to 2u) to Rational(1, 3), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(11, 1), + mapOf(x to 1u) to Rational(4, 1), + mapOf(x to 2u) to Rational(-18, 3), + mapOf(y to 1u) to Rational(12, 9), + mapOf(x to 1u, y to 1u) to Rational(14, 7), + mapOf(x to 2u, y to 1u) to Rational(-17, 5), + mapOf(y to 2u) to Rational(-4, 1), + mapOf(x to 1u, y to 2u) to Rational(-5, 5), + mapOf(x to 2u, y to 2u) to Rational(-7, 8), + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 5), + mapOf(x to 1u) to Rational(-18, 4), + mapOf(x to 2u) to Rational(9, 8), + mapOf(y to 1u) to Rational(-11, 6), + mapOf(x to 1u, y to 1u) to Rational(-16, 3), + mapOf(x to 2u, y to 1u) to Rational(12, 2), + mapOf(y to 2u) to Rational(5, 3), + mapOf(x to 1u, y to 2u) to Rational(17, 8), + mapOf(x to 2u, y to 2u) to Rational(1, 3), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(11, 1), + mapOf(x to 1u) to Rational(4, 1), + mapOf(x to 2u) to Rational(-18, 3), + mapOf(y to 1u) to Rational(12, 9), + mapOf(x to 1u, y to 1u) to Rational(14, 7), + mapOf(x to 2u, y to 1u) to Rational(-17, 5), + mapOf(y to 2u) to Rational(-4, 1), + mapOf(x to 1u, y to 2u) to Rational(-5, 5), + mapOf(x to 2u, y to 2u) to Rational(-7, 8), + ) + ).substitute(RationalField, mapOf()), + "test 5" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 5), + mapOf(x to 1u) to Rational(-18, 4), + mapOf(x to 2u) to Rational(9, 8), + mapOf(y to 1u) to Rational(-11, 6), + mapOf(x to 1u, y to 1u) to Rational(-16, 3), + mapOf(x to 2u, y to 1u) to Rational(12, 2), + mapOf(y to 2u) to Rational(5, 3), + mapOf(x to 1u, y to 2u) to Rational(17, 8), + mapOf(x to 2u, y to 2u) to Rational(1, 3), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(11, 1), + mapOf(x to 1u) to Rational(4, 1), + mapOf(x to 2u) to Rational(-18, 3), + mapOf(y to 1u) to Rational(12, 9), + mapOf(x to 1u, y to 1u) to Rational(14, 7), + mapOf(x to 2u, y to 1u) to Rational(-17, 5), + mapOf(y to 2u) to Rational(-4, 1), + mapOf(x to 1u, y to 2u) to Rational(-5, 5), + mapOf(x to 2u, y to 2u) to Rational(-7, 8), + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 5), + mapOf(x to 1u) to Rational(-18, 4), + mapOf(x to 2u) to Rational(9, 8), + mapOf(y to 1u) to Rational(-11, 6), + mapOf(x to 1u, y to 1u) to Rational(-16, 3), + mapOf(x to 2u, y to 1u) to Rational(12, 2), + mapOf(y to 2u) to Rational(5, 3), + mapOf(x to 1u, y to 2u) to Rational(17, 8), + mapOf(x to 2u, y to 2u) to Rational(1, 3), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(11, 1), + mapOf(x to 1u) to Rational(4, 1), + mapOf(x to 2u) to Rational(-18, 3), + mapOf(y to 1u) to Rational(12, 9), + mapOf(x to 1u, y to 1u) to Rational(14, 7), + mapOf(x to 2u, y to 1u) to Rational(-17, 5), + mapOf(y to 2u) to Rational(-4, 1), + mapOf(x to 1u, y to 2u) to Rational(-5, 5), + mapOf(x to 2u, y to 2u) to Rational(-7, 8), + ) + ).substitute(RationalField, mapOf( + iota to Rational(-16, 4), + )), + "test 5'" + ) + } + @Test + fun test_RationalFunction_substitute_Polynomial_Map() { + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(0) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1) + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1) + ) + ).substitute(RationalField, mapOf( + x to LabeledPolynomialAsIs( + mapOf() to Rational(1) + ) + )), + "test 1" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(5, 6), + mapOf(x to 1u) to Rational(211, 4), + mapOf(x to 2u) to Rational(88, 3), + mapOf(x to 3u) to Rational(-63, 8), + mapOf(x to 4u) to Rational(441, 16), + mapOf(y to 1u) to Rational(-671, 15), + mapOf(x to 1u, y to 1u) to Rational(-551, 21), + mapOf(x to 2u, y to 1u) to Rational(279, 25), + mapOf(x to 3u, y to 1u) to Rational(231, 20), + mapOf(y to 2u) to Rational(-1436, 1575), + mapOf(x to 1u, y to 2u) to Rational(2471, 250), + mapOf(x to 2u, y to 2u) to Rational(-4919, 100), + mapOf(y to 3u) to Rational(-1464, 125), + mapOf(x to 1u, y to 3u) to Rational(-264, 25), + mapOf(y to 4u) to Rational(576, 25), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-11, 9), + mapOf(x to 1u) to Rational(-9, 4), + mapOf(x to 2u) to Rational(943, 8), + mapOf(x to 3u) to Rational(117, 8), + mapOf(x to 4u) to Rational(147, 16), + mapOf(y to 1u) to Rational(289, 90), + mapOf(x to 1u, y to 1u) to Rational(-2692, 15), + mapOf(x to 2u, y to 1u) to Rational(-1629, 140), + mapOf(x to 3u, y to 1u) to Rational(77, 20), + mapOf(y to 2u) to Rational(6187, 75), + mapOf(x to 1u, y to 2u) to Rational(-2879, 175), + mapOf(x to 2u, y to 2u) to Rational(-4919, 300), + mapOf(y to 3u) to Rational(336, 25), + mapOf(x to 1u, y to 3u) to Rational(-88, 25), + mapOf(y to 4u) to Rational(192, 25), + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(5, 6), + mapOf(x to 1u) to Rational(1, 6), + mapOf(x to 2u) to Rational(-2, 9), + mapOf(y to 1u) to Rational(15, 1), + mapOf(x to 1u, y to 1u) to Rational(18, 7), + mapOf(x to 2u, y to 1u) to Rational(2, 5), + mapOf(y to 2u) to Rational(12, 9), + mapOf(x to 1u, y to 2u) to Rational(-3, 5), + mapOf(x to 2u, y to 2u) to Rational(4, 4), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-11, 9), + mapOf(x to 1u) to Rational(4, 9), + mapOf(x to 2u) to Rational(11, 6), + mapOf(y to 1u) to Rational(-5, 6), + mapOf(x to 1u, y to 1u) to Rational(4, 6), + mapOf(x to 2u, y to 1u) to Rational(-1, 7), + mapOf(y to 2u) to Rational(9, 1), + mapOf(x to 1u, y to 2u) to Rational(6, 7), + mapOf(x to 2u, y to 2u) to Rational(1, 3), + ) + ).substitute(RationalField, mapOf( + x to LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(3, 2), + mapOf(y to 1u) to Rational(8, 5), + ), + y to LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(7, 2), + mapOf(y to 1u) to Rational(-3, 1), + ) + )), + "test 2" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(1202861, 210), + mapOf(x to 1u) to Rational(-215117, 45), + mapOf(x to 2u) to Rational(10889651, 19845), + mapOf(x to 3u) to Rational(-3503956, 6615), + mapOf(x to 4u) to Rational(809066, 2205), + mapOf(x to 5u) to Rational(-9056, 735), + mapOf(x to 6u) to Rational(5396, 315), + mapOf(x to 7u) to Rational(-752, 147), + mapOf(x to 8u) to Rational(16, 49), + mapOf(y to 1u) to Rational(1738469, 1470), + mapOf(x to 1u, y to 1u) to Rational(-926238703, 52920), + mapOf(x to 2u, y to 1u) to Rational(-44113982, 6615), + mapOf(x to 3u, y to 1u) to Rational(10423519, 5292), + mapOf(x to 4u, y to 1u) to Rational(3769712, 2205), + mapOf(x to 5u, y to 1u) to Rational(8905046, 6615), + mapOf(x to 6u, y to 1u) to Rational(1186972, 6615), + mapOf(x to 7u, y to 1u) to Rational(22124, 441), + mapOf(x to 8u, y to 1u) to Rational(-1504, 147), + mapOf(y to 2u) to Rational(-54723628, 2205), + mapOf(x to 1u, y to 2u) to Rational(70109407, 1323), + mapOf(x to 2u, y to 2u) to Rational(151072591, 17640), + mapOf(x to 3u, y to 2u) to Rational(1216428107, 52920), + mapOf(x to 4u, y to 2u) to Rational(2587873193, 317520), + mapOf(x to 5u, y to 2u) to Rational(393536369, 79380), + mapOf(x to 6u, y to 2u) to Rational(137614937, 79380), + mapOf(x to 7u, y to 2u) to Rational(566866, 1323), + mapOf(x to 8u, y to 2u) to Rational(41848, 441), + mapOf(y to 3u) to Rational(-19470406, 2205), + mapOf(x to 1u, y to 3u) to Rational(72514195, 882), + mapOf(x to 2u, y to 3u) to Rational(-78090707, 1764), + mapOf(x to 3u, y to 3u) to Rational(-1988237707, 26460), + mapOf(x to 4u, y to 3u) to Rational(-802137919, 17640), + mapOf(x to 5u, y to 3u) to Rational(-139989463, 5880), + mapOf(x to 6u, y to 3u) to Rational(-26066641, 3780), + mapOf(x to 7u, y to 3u) to Rational(-2363369, 1323), + mapOf(x to 8u, y to 3u) to Rational(-108280, 441), + mapOf(y to 4u) to Rational(14878516, 441), + mapOf(x to 1u, y to 4u) to Rational(-253416724, 2205), + mapOf(x to 2u, y to 4u) to Rational(16699157, 840), + mapOf(x to 3u, y to 4u) to Rational(-105220979, 13230), + mapOf(x to 4u, y to 4u) to Rational(208266383, 5880), + mapOf(x to 5u, y to 4u) to Rational(650135309, 26460), + mapOf(x to 6u, y to 4u) to Rational(123808663, 11760), + mapOf(x to 7u, y to 4u) to Rational(8563385, 2646), + mapOf(x to 8u, y to 4u) to Rational(19721, 49), + mapOf(y to 5u) to Rational(675645, 49), + mapOf(x to 1u, y to 5u) to Rational(-70554077, 588), + mapOf(x to 2u, y to 5u) to Rational(157884029, 980), + mapOf(x to 3u, y to 5u) to Rational(489548623, 4410), + mapOf(x to 4u, y to 5u) to Rational(148540519, 17640), + mapOf(x to 5u, y to 5u) to Rational(-5559551, 392), + mapOf(x to 6u, y to 5u) to Rational(-18335711, 1470), + mapOf(x to 7u, y to 5u) to Rational(-38437, 9), + mapOf(x to 8u, y to 5u) to Rational(-29620, 63), + mapOf(y to 6u) to Rational(-727625, 49), + mapOf(x to 1u, y to 6u) to Rational(7046685, 98), + mapOf(x to 2u, y to 6u) to Rational(-334814231, 7056), + mapOf(x to 3u, y to 6u) to Rational(-243971737, 17640), + mapOf(x to 4u, y to 6u) to Rational(-571116659, 35280), + mapOf(x to 5u, y to 6u) to Rational(567538, 315), + mapOf(x to 6u, y to 6u) to Rational(3199768, 315), + mapOf(x to 7u, y to 6u) to Rational(227744, 63), + mapOf(x to 8u, y to 6u) to Rational(23116, 63), + mapOf(y to 7u) to Rational(-27500, 7), + mapOf(x to 1u, y to 7u) to Rational(120125, 3), + mapOf(x to 2u, y to 7u) to Rational(-279200, 3), + mapOf(x to 3u, y to 7u) to Rational(-100160, 7), + mapOf(x to 4u, y to 7u) to Rational(920452, 21), + mapOf(x to 5u, y to 7u) to Rational(226481, 21), + mapOf(x to 6u, y to 7u) to Rational(-34428, 7), + mapOf(x to 7u, y to 7u) to Rational(-6232, 3), + mapOf(x to 8u, y to 7u) to Rational(-608, 3), + mapOf(y to 8u) to Rational(2500, 1), + mapOf(x to 1u, y to 8u) to Rational(-19000, 1), + mapOf(x to 2u, y to 8u) to Rational(37900, 1), + mapOf(x to 3u, y to 8u) to Rational(-1840, 1), + mapOf(x to 4u, y to 8u) to Rational(-17876, 1), + mapOf(x to 5u, y to 8u) to Rational(-1240, 1), + mapOf(x to 6u, y to 8u) to Rational(2788, 1), + mapOf(x to 7u, y to 8u) to Rational(800, 1), + mapOf(x to 8u, y to 8u) to Rational(64, 1) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(162487, 63), + mapOf(x to 1u) to Rational(-92713, 54), + mapOf(x to 2u) to Rational(802436, 1323), + mapOf(x to 3u) to Rational(-55088, 441), + mapOf(x to 4u) to Rational(1404034, 9261), + mapOf(x to 5u) to Rational(-5804, 1029), + mapOf(x to 6u) to Rational(51556, 9261), + mapOf(x to 7u) to Rational(-752, 441), + mapOf(x to 8u) to Rational(16, 147), + mapOf(y to 1u) to Rational(296071, 441), + mapOf(x to 1u, y to 1u) to Rational(-4991281, 882), + mapOf(x to 2u, y to 1u) to Rational(-18702811, 9261), + mapOf(x to 3u, y to 1u) to Rational(40759043, 27783), + mapOf(x to 4u, y to 1u) to Rational(19768501, 27783), + mapOf(x to 5u, y to 1u) to Rational(14307337, 27783), + mapOf(x to 6u, y to 1u) to Rational(1655684, 27783), + mapOf(x to 7u, y to 1u) to Rational(22124, 1323), + mapOf(x to 8u, y to 1u) to Rational(-1504, 441), + mapOf(y to 2u) to Rational(-27667474, 3087), + mapOf(x to 1u, y to 2u) to Rational(265605901, 12348), + mapOf(x to 2u, y to 2u) to Rational(160360775, 98784), + mapOf(x to 3u, y to 2u) to Rational(1169992093, 148176), + mapOf(x to 4u, y to 2u) to Rational(3978014077, 1333584), + mapOf(x to 5u, y to 2u) to Rational(567058123, 333396), + mapOf(x to 6u, y to 2u) to Rational(205132579, 333396), + mapOf(x to 7u, y to 2u) to Rational(566866, 3969), + mapOf(x to 8u, y to 2u) to Rational(41848, 1323), + mapOf(y to 3u) to Rational(-2228822, 1029), + mapOf(x to 1u, y to 3u) to Rational(80179390, 3087), + mapOf(x to 2u, y to 3u) to Rational(-1378630487, 74088), + mapOf(x to 3u, y to 3u) to Rational(-3385811693, 111132), + mapOf(x to 4u, y to 3u) to Rational(-820686977, 49392), + mapOf(x to 5u, y to 3u) to Rational(-89101027, 10584), + mapOf(x to 6u, y to 3u) to Rational(-37847387, 15876), + mapOf(x to 7u, y to 3u) to Rational(-2363369, 3969), + mapOf(x to 8u, y to 3u) to Rational(-108280, 1323), + mapOf(y to 4u) to Rational(12619982, 1029), + mapOf(x to 1u, y to 4u) to Rational(-277723177, 6174), + mapOf(x to 2u, y to 4u) to Rational(649414169, 49392), + mapOf(x to 3u, y to 4u) to Rational(14457595, 63504), + mapOf(x to 4u, y to 4u) to Rational(139270339, 10584), + mapOf(x to 5u, y to 4u) to Rational(140367961, 15876), + mapOf(x to 6u, y to 4u) to Rational(25467083, 7056), + mapOf(x to 7u, y to 4u) to Rational(8563385, 7938), + mapOf(x to 8u, y to 4u) to Rational(19721, 147), + mapOf(y to 5u) to Rational(643850, 147), + mapOf(x to 1u, y to 5u) to Rational(-11818025, 294), + mapOf(x to 2u, y to 5u) to Rational(33963203, 588), + mapOf(x to 3u, y to 5u) to Rational(207216235, 5292), + mapOf(x to 4u, y to 5u) to Rational(2861021, 1512), + mapOf(x to 5u, y to 5u) to Rational(-6302335, 1176), + mapOf(x to 6u, y to 5u) to Rational(-3738587, 882), + mapOf(x to 7u, y to 5u) to Rational(-38437, 27), + mapOf(x to 8u, y to 5u) to Rational(-29620, 189), + mapOf(y to 6u) to Rational(-248725, 49), + mapOf(x to 1u, y to 6u) to Rational(2478535, 98), + mapOf(x to 2u, y to 6u) to Rational(-399721367, 21168), + mapOf(x to 3u, y to 6u) to Rational(-54309317, 10584), + mapOf(x to 4u, y to 6u) to Rational(-95398327, 21168), + mapOf(x to 5u, y to 6u) to Rational(173750, 189), + mapOf(x to 6u, y to 6u) to Rational(92216, 27), + mapOf(x to 7u, y to 6u) to Rational(227744, 189), + mapOf(x to 8u, y to 6u) to Rational(23116, 189), + mapOf(y to 7u) to Rational(-27500, 21), + mapOf(x to 1u, y to 7u) to Rational(120125, 9), + mapOf(x to 2u, y to 7u) to Rational(-279200, 9), + mapOf(x to 3u, y to 7u) to Rational(-100160, 21), + mapOf(x to 4u, y to 7u) to Rational(920452, 63), + mapOf(x to 5u, y to 7u) to Rational(226481, 63), + mapOf(x to 6u, y to 7u) to Rational(-11476, 7), + mapOf(x to 7u, y to 7u) to Rational(-6232, 9), + mapOf(x to 8u, y to 7u) to Rational(-608, 9), + mapOf(y to 8u) to Rational(2500, 3), + mapOf(x to 1u, y to 8u) to Rational(-19000, 3), + mapOf(x to 2u, y to 8u) to Rational(37900, 3), + mapOf(x to 3u, y to 8u) to Rational(-1840, 3), + mapOf(x to 4u, y to 8u) to Rational(-17876, 3), + mapOf(x to 5u, y to 8u) to Rational(-1240, 3), + mapOf(x to 6u, y to 8u) to Rational(2788, 3), + mapOf(x to 7u, y to 8u) to Rational(800, 3), + mapOf(x to 8u, y to 8u) to Rational(64, 3) + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(5, 6), + mapOf(x to 1u) to Rational(1, 6), + mapOf(x to 2u) to Rational(-2, 9), + mapOf(y to 1u) to Rational(15, 1), + mapOf(x to 1u, y to 1u) to Rational(18, 7), + mapOf(x to 2u, y to 1u) to Rational(2, 5), + mapOf(y to 2u) to Rational(12, 9), + mapOf(x to 1u, y to 2u) to Rational(-3, 5), + mapOf(x to 2u, y to 2u) to Rational(4, 4), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-11, 9), + mapOf(x to 1u) to Rational(4, 9), + mapOf(x to 2u) to Rational(11, 6), + mapOf(y to 1u) to Rational(-5, 6), + mapOf(x to 1u, y to 1u) to Rational(4, 6), + mapOf(x to 2u, y to 1u) to Rational(-1, 7), + mapOf(y to 2u) to Rational(9, 1), + mapOf(x to 1u, y to 2u) to Rational(6, 7), + mapOf(x to 2u, y to 2u) to Rational(1, 3), + ) + ).substitute(RationalField, mapOf( + x to LabeledPolynomialAsIs( + mapOf() to Rational(18, 1), + mapOf(x to 1u) to Rational(16, 3), + mapOf(x to 2u) to Rational(12, 6), + mapOf(y to 1u) to Rational(13, 1), + mapOf(x to 1u, y to 1u) to Rational(-11, 4), + mapOf(x to 2u, y to 1u) to Rational(-1, 1), + mapOf(y to 2u) to Rational(-10, 1), + mapOf(x to 1u, y to 2u) to Rational(4, 1), + mapOf(x to 2u, y to 2u) to Rational(2, 1), + ), + y to LabeledPolynomialAsIs( + mapOf() to Rational(8, 2), + mapOf(x to 1u) to Rational(-15, 5), + mapOf(x to 2u) to Rational(2, 7), + mapOf(y to 1u) to Rational(-18, 7), + mapOf(x to 1u, y to 1u) to Rational(-16, 6), + mapOf(x to 2u, y to 1u) to Rational(-13, 3), + mapOf(y to 2u) to Rational(-5, 1), + mapOf(x to 1u, y to 2u) to Rational(17, 1), + mapOf(x to 2u, y to 2u) to Rational(8, 2), + ), + )), + "test 3" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(1202861, 210), + mapOf(x to 1u) to Rational(-215117, 45), + mapOf(x to 2u) to Rational(10889651, 19845), + mapOf(x to 3u) to Rational(-3503956, 6615), + mapOf(x to 4u) to Rational(809066, 2205), + mapOf(x to 5u) to Rational(-9056, 735), + mapOf(x to 6u) to Rational(5396, 315), + mapOf(x to 7u) to Rational(-752, 147), + mapOf(x to 8u) to Rational(16, 49), + mapOf(y to 1u) to Rational(1738469, 1470), + mapOf(x to 1u, y to 1u) to Rational(-926238703, 52920), + mapOf(x to 2u, y to 1u) to Rational(-44113982, 6615), + mapOf(x to 3u, y to 1u) to Rational(10423519, 5292), + mapOf(x to 4u, y to 1u) to Rational(3769712, 2205), + mapOf(x to 5u, y to 1u) to Rational(8905046, 6615), + mapOf(x to 6u, y to 1u) to Rational(1186972, 6615), + mapOf(x to 7u, y to 1u) to Rational(22124, 441), + mapOf(x to 8u, y to 1u) to Rational(-1504, 147), + mapOf(y to 2u) to Rational(-54723628, 2205), + mapOf(x to 1u, y to 2u) to Rational(70109407, 1323), + mapOf(x to 2u, y to 2u) to Rational(151072591, 17640), + mapOf(x to 3u, y to 2u) to Rational(1216428107, 52920), + mapOf(x to 4u, y to 2u) to Rational(2587873193, 317520), + mapOf(x to 5u, y to 2u) to Rational(393536369, 79380), + mapOf(x to 6u, y to 2u) to Rational(137614937, 79380), + mapOf(x to 7u, y to 2u) to Rational(566866, 1323), + mapOf(x to 8u, y to 2u) to Rational(41848, 441), + mapOf(y to 3u) to Rational(-19470406, 2205), + mapOf(x to 1u, y to 3u) to Rational(72514195, 882), + mapOf(x to 2u, y to 3u) to Rational(-78090707, 1764), + mapOf(x to 3u, y to 3u) to Rational(-1988237707, 26460), + mapOf(x to 4u, y to 3u) to Rational(-802137919, 17640), + mapOf(x to 5u, y to 3u) to Rational(-139989463, 5880), + mapOf(x to 6u, y to 3u) to Rational(-26066641, 3780), + mapOf(x to 7u, y to 3u) to Rational(-2363369, 1323), + mapOf(x to 8u, y to 3u) to Rational(-108280, 441), + mapOf(y to 4u) to Rational(14878516, 441), + mapOf(x to 1u, y to 4u) to Rational(-253416724, 2205), + mapOf(x to 2u, y to 4u) to Rational(16699157, 840), + mapOf(x to 3u, y to 4u) to Rational(-105220979, 13230), + mapOf(x to 4u, y to 4u) to Rational(208266383, 5880), + mapOf(x to 5u, y to 4u) to Rational(650135309, 26460), + mapOf(x to 6u, y to 4u) to Rational(123808663, 11760), + mapOf(x to 7u, y to 4u) to Rational(8563385, 2646), + mapOf(x to 8u, y to 4u) to Rational(19721, 49), + mapOf(y to 5u) to Rational(675645, 49), + mapOf(x to 1u, y to 5u) to Rational(-70554077, 588), + mapOf(x to 2u, y to 5u) to Rational(157884029, 980), + mapOf(x to 3u, y to 5u) to Rational(489548623, 4410), + mapOf(x to 4u, y to 5u) to Rational(148540519, 17640), + mapOf(x to 5u, y to 5u) to Rational(-5559551, 392), + mapOf(x to 6u, y to 5u) to Rational(-18335711, 1470), + mapOf(x to 7u, y to 5u) to Rational(-38437, 9), + mapOf(x to 8u, y to 5u) to Rational(-29620, 63), + mapOf(y to 6u) to Rational(-727625, 49), + mapOf(x to 1u, y to 6u) to Rational(7046685, 98), + mapOf(x to 2u, y to 6u) to Rational(-334814231, 7056), + mapOf(x to 3u, y to 6u) to Rational(-243971737, 17640), + mapOf(x to 4u, y to 6u) to Rational(-571116659, 35280), + mapOf(x to 5u, y to 6u) to Rational(567538, 315), + mapOf(x to 6u, y to 6u) to Rational(3199768, 315), + mapOf(x to 7u, y to 6u) to Rational(227744, 63), + mapOf(x to 8u, y to 6u) to Rational(23116, 63), + mapOf(y to 7u) to Rational(-27500, 7), + mapOf(x to 1u, y to 7u) to Rational(120125, 3), + mapOf(x to 2u, y to 7u) to Rational(-279200, 3), + mapOf(x to 3u, y to 7u) to Rational(-100160, 7), + mapOf(x to 4u, y to 7u) to Rational(920452, 21), + mapOf(x to 5u, y to 7u) to Rational(226481, 21), + mapOf(x to 6u, y to 7u) to Rational(-34428, 7), + mapOf(x to 7u, y to 7u) to Rational(-6232, 3), + mapOf(x to 8u, y to 7u) to Rational(-608, 3), + mapOf(y to 8u) to Rational(2500, 1), + mapOf(x to 1u, y to 8u) to Rational(-19000, 1), + mapOf(x to 2u, y to 8u) to Rational(37900, 1), + mapOf(x to 3u, y to 8u) to Rational(-1840, 1), + mapOf(x to 4u, y to 8u) to Rational(-17876, 1), + mapOf(x to 5u, y to 8u) to Rational(-1240, 1), + mapOf(x to 6u, y to 8u) to Rational(2788, 1), + mapOf(x to 7u, y to 8u) to Rational(800, 1), + mapOf(x to 8u, y to 8u) to Rational(64, 1) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(162487, 63), + mapOf(x to 1u) to Rational(-92713, 54), + mapOf(x to 2u) to Rational(802436, 1323), + mapOf(x to 3u) to Rational(-55088, 441), + mapOf(x to 4u) to Rational(1404034, 9261), + mapOf(x to 5u) to Rational(-5804, 1029), + mapOf(x to 6u) to Rational(51556, 9261), + mapOf(x to 7u) to Rational(-752, 441), + mapOf(x to 8u) to Rational(16, 147), + mapOf(y to 1u) to Rational(296071, 441), + mapOf(x to 1u, y to 1u) to Rational(-4991281, 882), + mapOf(x to 2u, y to 1u) to Rational(-18702811, 9261), + mapOf(x to 3u, y to 1u) to Rational(40759043, 27783), + mapOf(x to 4u, y to 1u) to Rational(19768501, 27783), + mapOf(x to 5u, y to 1u) to Rational(14307337, 27783), + mapOf(x to 6u, y to 1u) to Rational(1655684, 27783), + mapOf(x to 7u, y to 1u) to Rational(22124, 1323), + mapOf(x to 8u, y to 1u) to Rational(-1504, 441), + mapOf(y to 2u) to Rational(-27667474, 3087), + mapOf(x to 1u, y to 2u) to Rational(265605901, 12348), + mapOf(x to 2u, y to 2u) to Rational(160360775, 98784), + mapOf(x to 3u, y to 2u) to Rational(1169992093, 148176), + mapOf(x to 4u, y to 2u) to Rational(3978014077, 1333584), + mapOf(x to 5u, y to 2u) to Rational(567058123, 333396), + mapOf(x to 6u, y to 2u) to Rational(205132579, 333396), + mapOf(x to 7u, y to 2u) to Rational(566866, 3969), + mapOf(x to 8u, y to 2u) to Rational(41848, 1323), + mapOf(y to 3u) to Rational(-2228822, 1029), + mapOf(x to 1u, y to 3u) to Rational(80179390, 3087), + mapOf(x to 2u, y to 3u) to Rational(-1378630487, 74088), + mapOf(x to 3u, y to 3u) to Rational(-3385811693, 111132), + mapOf(x to 4u, y to 3u) to Rational(-820686977, 49392), + mapOf(x to 5u, y to 3u) to Rational(-89101027, 10584), + mapOf(x to 6u, y to 3u) to Rational(-37847387, 15876), + mapOf(x to 7u, y to 3u) to Rational(-2363369, 3969), + mapOf(x to 8u, y to 3u) to Rational(-108280, 1323), + mapOf(y to 4u) to Rational(12619982, 1029), + mapOf(x to 1u, y to 4u) to Rational(-277723177, 6174), + mapOf(x to 2u, y to 4u) to Rational(649414169, 49392), + mapOf(x to 3u, y to 4u) to Rational(14457595, 63504), + mapOf(x to 4u, y to 4u) to Rational(139270339, 10584), + mapOf(x to 5u, y to 4u) to Rational(140367961, 15876), + mapOf(x to 6u, y to 4u) to Rational(25467083, 7056), + mapOf(x to 7u, y to 4u) to Rational(8563385, 7938), + mapOf(x to 8u, y to 4u) to Rational(19721, 147), + mapOf(y to 5u) to Rational(643850, 147), + mapOf(x to 1u, y to 5u) to Rational(-11818025, 294), + mapOf(x to 2u, y to 5u) to Rational(33963203, 588), + mapOf(x to 3u, y to 5u) to Rational(207216235, 5292), + mapOf(x to 4u, y to 5u) to Rational(2861021, 1512), + mapOf(x to 5u, y to 5u) to Rational(-6302335, 1176), + mapOf(x to 6u, y to 5u) to Rational(-3738587, 882), + mapOf(x to 7u, y to 5u) to Rational(-38437, 27), + mapOf(x to 8u, y to 5u) to Rational(-29620, 189), + mapOf(y to 6u) to Rational(-248725, 49), + mapOf(x to 1u, y to 6u) to Rational(2478535, 98), + mapOf(x to 2u, y to 6u) to Rational(-399721367, 21168), + mapOf(x to 3u, y to 6u) to Rational(-54309317, 10584), + mapOf(x to 4u, y to 6u) to Rational(-95398327, 21168), + mapOf(x to 5u, y to 6u) to Rational(173750, 189), + mapOf(x to 6u, y to 6u) to Rational(92216, 27), + mapOf(x to 7u, y to 6u) to Rational(227744, 189), + mapOf(x to 8u, y to 6u) to Rational(23116, 189), + mapOf(y to 7u) to Rational(-27500, 21), + mapOf(x to 1u, y to 7u) to Rational(120125, 9), + mapOf(x to 2u, y to 7u) to Rational(-279200, 9), + mapOf(x to 3u, y to 7u) to Rational(-100160, 21), + mapOf(x to 4u, y to 7u) to Rational(920452, 63), + mapOf(x to 5u, y to 7u) to Rational(226481, 63), + mapOf(x to 6u, y to 7u) to Rational(-11476, 7), + mapOf(x to 7u, y to 7u) to Rational(-6232, 9), + mapOf(x to 8u, y to 7u) to Rational(-608, 9), + mapOf(y to 8u) to Rational(2500, 3), + mapOf(x to 1u, y to 8u) to Rational(-19000, 3), + mapOf(x to 2u, y to 8u) to Rational(37900, 3), + mapOf(x to 3u, y to 8u) to Rational(-1840, 3), + mapOf(x to 4u, y to 8u) to Rational(-17876, 3), + mapOf(x to 5u, y to 8u) to Rational(-1240, 3), + mapOf(x to 6u, y to 8u) to Rational(2788, 3), + mapOf(x to 7u, y to 8u) to Rational(800, 3), + mapOf(x to 8u, y to 8u) to Rational(64, 3) + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(5, 6), + mapOf(x to 1u) to Rational(1, 6), + mapOf(x to 2u) to Rational(-2, 9), + mapOf(y to 1u) to Rational(15, 1), + mapOf(x to 1u, y to 1u) to Rational(18, 7), + mapOf(x to 2u, y to 1u) to Rational(2, 5), + mapOf(y to 2u) to Rational(12, 9), + mapOf(x to 1u, y to 2u) to Rational(-3, 5), + mapOf(x to 2u, y to 2u) to Rational(4, 4), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-11, 9), + mapOf(x to 1u) to Rational(4, 9), + mapOf(x to 2u) to Rational(11, 6), + mapOf(y to 1u) to Rational(-5, 6), + mapOf(x to 1u, y to 1u) to Rational(4, 6), + mapOf(x to 2u, y to 1u) to Rational(-1, 7), + mapOf(y to 2u) to Rational(9, 1), + mapOf(x to 1u, y to 2u) to Rational(6, 7), + mapOf(x to 2u, y to 2u) to Rational(1, 3), + ) + ).substitute(RationalField, mapOf( + x to LabeledPolynomialAsIs( + mapOf() to Rational(18, 1), + mapOf(x to 1u) to Rational(16, 3), + mapOf(x to 2u) to Rational(12, 6), + mapOf(y to 1u) to Rational(13, 1), + mapOf(x to 1u, y to 1u) to Rational(-11, 4), + mapOf(x to 2u, y to 1u) to Rational(-1, 1), + mapOf(y to 2u) to Rational(-10, 1), + mapOf(x to 1u, y to 2u) to Rational(4, 1), + mapOf(x to 2u, y to 2u) to Rational(2, 1), + ), + y to LabeledPolynomialAsIs( + mapOf() to Rational(8, 2), + mapOf(x to 1u) to Rational(-15, 5), + mapOf(x to 2u) to Rational(2, 7), + mapOf(y to 1u) to Rational(-18, 7), + mapOf(x to 1u, y to 1u) to Rational(-16, 6), + mapOf(x to 2u, y to 1u) to Rational(-13, 3), + mapOf(y to 2u) to Rational(-5, 1), + mapOf(x to 1u, y to 2u) to Rational(17, 1), + mapOf(x to 2u, y to 2u) to Rational(8, 2), + ), + iota to LabeledPolynomialAsIs( + mapOf() to Rational(-6, 1), + mapOf(x to 1u) to Rational(-9, 8), + mapOf(x to 2u) to Rational(17, 5), + mapOf(y to 1u) to Rational(-2, 3), + mapOf(x to 1u, y to 1u) to Rational(1, 5), + mapOf(x to 2u, y to 1u) to Rational(-11, 7), + mapOf(y to 2u) to Rational(13, 6), + mapOf(x to 1u, y to 2u) to Rational(-15, 2), + mapOf(x to 2u, y to 2u) to Rational(-14, 4), + ) + )), + "test 3'" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(493, 6), + mapOf(x to 1u) to Rational(-15991, 210), + mapOf(x to 2u) to Rational(2734, 63), + mapOf(x to 3u) to Rational(-8213, 245), + mapOf(x to 4u) to Rational(1843, 147), + mapOf(x to 5u) to Rational(-432, 245), + mapOf(x to 6u) to Rational(4, 49), + mapOf(y to 1u) to Rational(-66, 1), + mapOf(x to 1u, y to 1u) to Rational(-92924, 2205), + mapOf(x to 2u, y to 1u) to Rational(-257461, 2205), + mapOf(x to 3u, y to 1u) to Rational(58658, 2205), + mapOf(x to 4u, y to 1u) to Rational(-87884, 2205), + mapOf(x to 5u, y to 1u) to Rational(2726, 105), + mapOf(x to 6u, y to 1u) to Rational(-52, 21), + mapOf(y to 2u) to Rational(-17569, 147), + mapOf(x to 1u, y to 2u) to Rational(368819, 735), + mapOf(x to 2u, y to 2u) to Rational(-644626, 6615), + mapOf(x to 3u, y to 2u) to Rational(221738, 945), + mapOf(x to 4u, y to 2u) to Rational(-18022, 945), + mapOf(x to 5u, y to 2u) to Rational(-1201, 315), + mapOf(x to 6u, y to 2u) to Rational(1327, 63), + mapOf(y to 3u) to Rational(240, 7), + mapOf(x to 1u, y to 3u) to Rational(-868, 9), + mapOf(x to 2u, y to 3u) to Rational(-8936, 315), + mapOf(x to 3u, y to 3u) to Rational(-77146, 315), + mapOf(x to 4u, y to 3u) to Rational(-4072, 315), + mapOf(x to 5u, y to 3u) to Rational(-2218, 15), + mapOf(x to 6u, y to 3u) to Rational(-104, 3), + mapOf(y to 4u) to Rational(100, 3), + mapOf(x to 1u, y to 4u) to Rational(-725, 3), + mapOf(x to 2u, y to 4u) to Rational(459, 1), + mapOf(x to 3u, y to 4u) to Rational(-2071, 15), + mapOf(x to 4u, y to 4u) to Rational(2831, 15), + mapOf(x to 5u, y to 4u) to Rational(632, 5), + mapOf(x to 6u, y to 4u) to Rational(16, 1) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1255, 9), + mapOf(x to 1u) to Rational(-24781, 126), + mapOf(x to 2u) to Rational(1195, 14), + mapOf(x to 3u) to Rational(-1931, 147), + mapOf(x to 4u) to Rational(439, 147), + mapOf(x to 5u) to Rational(-172, 343), + mapOf(x to 6u) to Rational(4, 147), + mapOf(y to 1u) to Rational(-183, 1), + mapOf(x to 1u, y to 1u) to Rational(-30988, 441), + mapOf(x to 2u, y to 1u) to Rational(-56137, 294), + mapOf(x to 3u, y to 1u) to Rational(204308, 1029), + mapOf(x to 4u, y to 1u) to Rational(-3263, 441), + mapOf(x to 5u, y to 1u) to Rational(2662, 441), + mapOf(x to 6u, y to 1u) to Rational(-52, 63), + mapOf(y to 2u) to Rational(-87119, 294), + mapOf(x to 1u, y to 2u) to Rational(1077919, 686), + mapOf(x to 2u, y to 2u) to Rational(-35209, 147), + mapOf(x to 3u, y to 2u) to Rational(15041, 147), + mapOf(x to 4u, y to 2u) to Rational(240889, 1323), + mapOf(x to 5u, y to 2u) to Rational(27778, 1323), + mapOf(x to 6u, y to 2u) to Rational(1327, 189), + mapOf(y to 3u) to Rational(1620, 7), + mapOf(x to 1u, y to 3u) to Rational(-25716, 49), + mapOf(x to 2u, y to 3u) to Rational(-32078, 49), + mapOf(x to 3u, y to 3u) to Rational(-704038, 441), + mapOf(x to 4u, y to 3u) to Rational(-30190, 63), + mapOf(x to 5u, y to 3u) to Rational(-5414, 63), + mapOf(x to 6u, y to 3u) to Rational(-104, 9), + mapOf(y to 4u) to Rational(225, 1), + mapOf(x to 1u, y to 4u) to Rational(-10560, 7), + mapOf(x to 2u, y to 4u) to Rational(44176, 21), + mapOf(x to 3u, y to 4u) to Rational(28996, 21), + mapOf(x to 4u, y to 4u) to Rational(2405, 7), + mapOf(x to 5u, y to 4u) to Rational(1240, 21), + mapOf(x to 6u, y to 4u) to Rational(16, 3) + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(5, 6), + mapOf(x to 1u) to Rational(1, 6), + mapOf(x to 2u) to Rational(-2, 9), + mapOf(y to 1u) to Rational(15, 1), + mapOf(x to 1u, y to 1u) to Rational(18, 7), + mapOf(x to 2u, y to 1u) to Rational(2, 5), + mapOf(y to 2u) to Rational(12, 9), + mapOf(x to 1u, y to 2u) to Rational(-3, 5), + mapOf(x to 2u, y to 2u) to Rational(4, 4), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-11, 9), + mapOf(x to 1u) to Rational(4, 9), + mapOf(x to 2u) to Rational(11, 6), + mapOf(y to 1u) to Rational(-5, 6), + mapOf(x to 1u, y to 1u) to Rational(4, 6), + mapOf(x to 2u, y to 1u) to Rational(-1, 7), + mapOf(y to 2u) to Rational(9, 1), + mapOf(x to 1u, y to 2u) to Rational(6, 7), + mapOf(x to 2u, y to 2u) to Rational(1, 3), + ) + ).substitute(RationalField, mapOf( + y to LabeledPolynomialAsIs( + mapOf() to Rational(8, 2), + mapOf(x to 1u) to Rational(-15, 5), + mapOf(x to 2u) to Rational(2, 7), + mapOf(y to 1u) to Rational(-18, 7), + mapOf(x to 1u, y to 1u) to Rational(-16, 6), + mapOf(x to 2u, y to 1u) to Rational(-13, 3), + mapOf(y to 2u) to Rational(-5, 1), + mapOf(x to 1u, y to 2u) to Rational(17, 1), + mapOf(x to 2u, y to 2u) to Rational(8, 2), + ), + )), + "test 4" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(493, 6), + mapOf(x to 1u) to Rational(-15991, 210), + mapOf(x to 2u) to Rational(2734, 63), + mapOf(x to 3u) to Rational(-8213, 245), + mapOf(x to 4u) to Rational(1843, 147), + mapOf(x to 5u) to Rational(-432, 245), + mapOf(x to 6u) to Rational(4, 49), + mapOf(y to 1u) to Rational(-66, 1), + mapOf(x to 1u, y to 1u) to Rational(-92924, 2205), + mapOf(x to 2u, y to 1u) to Rational(-257461, 2205), + mapOf(x to 3u, y to 1u) to Rational(58658, 2205), + mapOf(x to 4u, y to 1u) to Rational(-87884, 2205), + mapOf(x to 5u, y to 1u) to Rational(2726, 105), + mapOf(x to 6u, y to 1u) to Rational(-52, 21), + mapOf(y to 2u) to Rational(-17569, 147), + mapOf(x to 1u, y to 2u) to Rational(368819, 735), + mapOf(x to 2u, y to 2u) to Rational(-644626, 6615), + mapOf(x to 3u, y to 2u) to Rational(221738, 945), + mapOf(x to 4u, y to 2u) to Rational(-18022, 945), + mapOf(x to 5u, y to 2u) to Rational(-1201, 315), + mapOf(x to 6u, y to 2u) to Rational(1327, 63), + mapOf(y to 3u) to Rational(240, 7), + mapOf(x to 1u, y to 3u) to Rational(-868, 9), + mapOf(x to 2u, y to 3u) to Rational(-8936, 315), + mapOf(x to 3u, y to 3u) to Rational(-77146, 315), + mapOf(x to 4u, y to 3u) to Rational(-4072, 315), + mapOf(x to 5u, y to 3u) to Rational(-2218, 15), + mapOf(x to 6u, y to 3u) to Rational(-104, 3), + mapOf(y to 4u) to Rational(100, 3), + mapOf(x to 1u, y to 4u) to Rational(-725, 3), + mapOf(x to 2u, y to 4u) to Rational(459, 1), + mapOf(x to 3u, y to 4u) to Rational(-2071, 15), + mapOf(x to 4u, y to 4u) to Rational(2831, 15), + mapOf(x to 5u, y to 4u) to Rational(632, 5), + mapOf(x to 6u, y to 4u) to Rational(16, 1) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1255, 9), + mapOf(x to 1u) to Rational(-24781, 126), + mapOf(x to 2u) to Rational(1195, 14), + mapOf(x to 3u) to Rational(-1931, 147), + mapOf(x to 4u) to Rational(439, 147), + mapOf(x to 5u) to Rational(-172, 343), + mapOf(x to 6u) to Rational(4, 147), + mapOf(y to 1u) to Rational(-183, 1), + mapOf(x to 1u, y to 1u) to Rational(-30988, 441), + mapOf(x to 2u, y to 1u) to Rational(-56137, 294), + mapOf(x to 3u, y to 1u) to Rational(204308, 1029), + mapOf(x to 4u, y to 1u) to Rational(-3263, 441), + mapOf(x to 5u, y to 1u) to Rational(2662, 441), + mapOf(x to 6u, y to 1u) to Rational(-52, 63), + mapOf(y to 2u) to Rational(-87119, 294), + mapOf(x to 1u, y to 2u) to Rational(1077919, 686), + mapOf(x to 2u, y to 2u) to Rational(-35209, 147), + mapOf(x to 3u, y to 2u) to Rational(15041, 147), + mapOf(x to 4u, y to 2u) to Rational(240889, 1323), + mapOf(x to 5u, y to 2u) to Rational(27778, 1323), + mapOf(x to 6u, y to 2u) to Rational(1327, 189), + mapOf(y to 3u) to Rational(1620, 7), + mapOf(x to 1u, y to 3u) to Rational(-25716, 49), + mapOf(x to 2u, y to 3u) to Rational(-32078, 49), + mapOf(x to 3u, y to 3u) to Rational(-704038, 441), + mapOf(x to 4u, y to 3u) to Rational(-30190, 63), + mapOf(x to 5u, y to 3u) to Rational(-5414, 63), + mapOf(x to 6u, y to 3u) to Rational(-104, 9), + mapOf(y to 4u) to Rational(225, 1), + mapOf(x to 1u, y to 4u) to Rational(-10560, 7), + mapOf(x to 2u, y to 4u) to Rational(44176, 21), + mapOf(x to 3u, y to 4u) to Rational(28996, 21), + mapOf(x to 4u, y to 4u) to Rational(2405, 7), + mapOf(x to 5u, y to 4u) to Rational(1240, 21), + mapOf(x to 6u, y to 4u) to Rational(16, 3) + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(5, 6), + mapOf(x to 1u) to Rational(1, 6), + mapOf(x to 2u) to Rational(-2, 9), + mapOf(y to 1u) to Rational(15, 1), + mapOf(x to 1u, y to 1u) to Rational(18, 7), + mapOf(x to 2u, y to 1u) to Rational(2, 5), + mapOf(y to 2u) to Rational(12, 9), + mapOf(x to 1u, y to 2u) to Rational(-3, 5), + mapOf(x to 2u, y to 2u) to Rational(4, 4), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-11, 9), + mapOf(x to 1u) to Rational(4, 9), + mapOf(x to 2u) to Rational(11, 6), + mapOf(y to 1u) to Rational(-5, 6), + mapOf(x to 1u, y to 1u) to Rational(4, 6), + mapOf(x to 2u, y to 1u) to Rational(-1, 7), + mapOf(y to 2u) to Rational(9, 1), + mapOf(x to 1u, y to 2u) to Rational(6, 7), + mapOf(x to 2u, y to 2u) to Rational(1, 3), + ) + ).substitute(RationalField, mapOf( + y to LabeledPolynomialAsIs( + mapOf() to Rational(8, 2), + mapOf(x to 1u) to Rational(-15, 5), + mapOf(x to 2u) to Rational(2, 7), + mapOf(y to 1u) to Rational(-18, 7), + mapOf(x to 1u, y to 1u) to Rational(-16, 6), + mapOf(x to 2u, y to 1u) to Rational(-13, 3), + mapOf(y to 2u) to Rational(-5, 1), + mapOf(x to 1u, y to 2u) to Rational(17, 1), + mapOf(x to 2u, y to 2u) to Rational(8, 2), + ), + iota to LabeledPolynomialAsIs( + mapOf() to Rational(-6, 1), + mapOf(x to 1u) to Rational(-9, 8), + mapOf(x to 2u) to Rational(17, 5), + mapOf(y to 1u) to Rational(-2, 3), + mapOf(x to 1u, y to 1u) to Rational(1, 5), + mapOf(x to 2u, y to 1u) to Rational(-11, 7), + mapOf(y to 2u) to Rational(13, 6), + mapOf(x to 1u, y to 2u) to Rational(-15, 2), + mapOf(x to 2u, y to 2u) to Rational(-14, 4), + ) + )), + "test 4'" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-409, 6), + mapOf(x to 1u) to Rational(-376, 9), + mapOf(x to 2u) to Rational(-1781, 81), + mapOf(x to 3u) to Rational(-128, 27), + mapOf(x to 4u) to Rational(-8, 9), + mapOf(y to 1u) to Rational(18701, 210), + mapOf(x to 1u, y to 1u) to Rational(614183, 7560), + mapOf(x to 2u, y to 1u) to Rational(90941, 1890), + mapOf(x to 3u, y to 1u) to Rational(1802, 135), + mapOf(x to 4u, y to 1u) to Rational(112, 45), + mapOf(y to 2u) to Rational(181421, 315), + mapOf(x to 1u, y to 2u) to Rational(77813, 378), + mapOf(x to 2u, y to 2u) to Rational(598583, 7560), + mapOf(x to 3u, y to 2u) to Rational(85, 27), + mapOf(x to 4u, y to 2u) to Rational(2, 5), + mapOf(y to 3u) to Rational(130997, 315), + mapOf(x to 1u, y to 3u) to Rational(1093, 420), + mapOf(x to 2u, y to 3u) to Rational(9551, 2520), + mapOf(x to 3u, y to 3u) to Rational(-14, 45), + mapOf(x to 4u, y to 3u) to Rational(22, 45), + mapOf(y to 4u) to Rational(-2801, 9), + mapOf(x to 1u, y to 4u) to Rational(4033, 90), + mapOf(x to 2u, y to 4u) to Rational(6429, 80), + mapOf(x to 3u, y to 4u) to Rational(2851, 90), + mapOf(x to 4u, y to 4u) to Rational(293, 45), + mapOf(y to 5u) to Rational(-220, 1), + mapOf(x to 1u, y to 5u) to Rational(127, 1), + mapOf(x to 2u, y to 5u) to Rational(202, 5), + mapOf(x to 3u, y to 5u) to Rational(-63, 5), + mapOf(x to 4u, y to 5u) to Rational(-12, 5), + mapOf(y to 6u) to Rational(100, 1), + mapOf(x to 1u, y to 6u) to Rational(-80, 1), + mapOf(x to 2u, y to 6u) to Rational(-24, 1), + mapOf(x to 3u, y to 6u) to Rational(16, 1), + mapOf(x to 4u, y to 6u) to Rational(4, 1) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(5407, 9), + mapOf(x to 1u) to Rational(9568, 27), + mapOf(x to 2u) to Rational(4996, 27), + mapOf(x to 3u) to Rational(352, 9), + mapOf(x to 4u) to Rational(22, 3), + mapOf(y to 1u) to Rational(104411, 126), + mapOf(x to 1u, y to 1u) to Rational(6001, 126), + mapOf(x to 2u, y to 1u) to Rational(-796, 21), + mapOf(x to 3u, y to 1u) to Rational(-5389, 126), + mapOf(x to 4u, y to 1u) to Rational(-166, 21), + mapOf(y to 2u) to Rational(-35327, 126), + mapOf(x to 1u, y to 2u) to Rational(53, 252), + mapOf(x to 2u, y to 2u) to Rational(849197, 6048), + mapOf(x to 3u, y to 2u) to Rational(22361, 252), + mapOf(x to 4u, y to 2u) to Rational(773, 42), + mapOf(y to 3u) to Rational(-6067, 21), + mapOf(x to 1u, y to 3u) to Rational(39049, 126), + mapOf(x to 2u, y to 3u) to Rational(80303, 1008), + mapOf(x to 3u, y to 3u) to Rational(-3035, 63), + mapOf(x to 4u, y to 3u) to Rational(-209, 21), + mapOf(y to 4u) to Rational(3113, 21), + mapOf(x to 1u, y to 4u) to Rational(-22345, 126), + mapOf(x to 2u, y to 4u) to Rational(-30931, 1008), + mapOf(x to 3u, y to 4u) to Rational(5837, 126), + mapOf(x to 4u, y to 4u) to Rational(229, 21), + mapOf(y to 5u) to Rational(-2120, 21), + mapOf(x to 1u, y to 5u) to Rational(451, 7), + mapOf(x to 2u, y to 5u) to Rational(422, 21), + mapOf(x to 3u, y to 5u) to Rational(-181, 21), + mapOf(x to 4u, y to 5u) to Rational(-40, 21), + mapOf(y to 6u) to Rational(100, 3), + mapOf(x to 1u, y to 6u) to Rational(-80, 3), + mapOf(x to 2u, y to 6u) to Rational(-8, 1), + mapOf(x to 3u, y to 6u) to Rational(16, 3), + mapOf(x to 4u, y to 6u) to Rational(4, 3) + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(5, 6), + mapOf(x to 1u) to Rational(1, 6), + mapOf(x to 2u) to Rational(-2, 9), + mapOf(y to 1u) to Rational(15, 1), + mapOf(x to 1u, y to 1u) to Rational(18, 7), + mapOf(x to 2u, y to 1u) to Rational(2, 5), + mapOf(y to 2u) to Rational(12, 9), + mapOf(x to 1u, y to 2u) to Rational(-3, 5), + mapOf(x to 2u, y to 2u) to Rational(4, 4), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-11, 9), + mapOf(x to 1u) to Rational(4, 9), + mapOf(x to 2u) to Rational(11, 6), + mapOf(y to 1u) to Rational(-5, 6), + mapOf(x to 1u, y to 1u) to Rational(4, 6), + mapOf(x to 2u, y to 1u) to Rational(-1, 7), + mapOf(y to 2u) to Rational(9, 1), + mapOf(x to 1u, y to 2u) to Rational(6, 7), + mapOf(x to 2u, y to 2u) to Rational(1, 3), + ) + ).substitute(RationalField, mapOf( + x to LabeledPolynomialAsIs( + mapOf() to Rational(18, 1), + mapOf(x to 1u) to Rational(16, 3), + mapOf(x to 2u) to Rational(12, 6), + mapOf(y to 1u) to Rational(13, 1), + mapOf(x to 1u, y to 1u) to Rational(-11, 4), + mapOf(x to 2u, y to 1u) to Rational(-1, 1), + mapOf(y to 2u) to Rational(-10, 1), + mapOf(x to 1u, y to 2u) to Rational(4, 1), + mapOf(x to 2u, y to 2u) to Rational(2, 1), + ), + )), + "test 5" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-409, 6), + mapOf(x to 1u) to Rational(-376, 9), + mapOf(x to 2u) to Rational(-1781, 81), + mapOf(x to 3u) to Rational(-128, 27), + mapOf(x to 4u) to Rational(-8, 9), + mapOf(y to 1u) to Rational(18701, 210), + mapOf(x to 1u, y to 1u) to Rational(614183, 7560), + mapOf(x to 2u, y to 1u) to Rational(90941, 1890), + mapOf(x to 3u, y to 1u) to Rational(1802, 135), + mapOf(x to 4u, y to 1u) to Rational(112, 45), + mapOf(y to 2u) to Rational(181421, 315), + mapOf(x to 1u, y to 2u) to Rational(77813, 378), + mapOf(x to 2u, y to 2u) to Rational(598583, 7560), + mapOf(x to 3u, y to 2u) to Rational(85, 27), + mapOf(x to 4u, y to 2u) to Rational(2, 5), + mapOf(y to 3u) to Rational(130997, 315), + mapOf(x to 1u, y to 3u) to Rational(1093, 420), + mapOf(x to 2u, y to 3u) to Rational(9551, 2520), + mapOf(x to 3u, y to 3u) to Rational(-14, 45), + mapOf(x to 4u, y to 3u) to Rational(22, 45), + mapOf(y to 4u) to Rational(-2801, 9), + mapOf(x to 1u, y to 4u) to Rational(4033, 90), + mapOf(x to 2u, y to 4u) to Rational(6429, 80), + mapOf(x to 3u, y to 4u) to Rational(2851, 90), + mapOf(x to 4u, y to 4u) to Rational(293, 45), + mapOf(y to 5u) to Rational(-220, 1), + mapOf(x to 1u, y to 5u) to Rational(127, 1), + mapOf(x to 2u, y to 5u) to Rational(202, 5), + mapOf(x to 3u, y to 5u) to Rational(-63, 5), + mapOf(x to 4u, y to 5u) to Rational(-12, 5), + mapOf(y to 6u) to Rational(100, 1), + mapOf(x to 1u, y to 6u) to Rational(-80, 1), + mapOf(x to 2u, y to 6u) to Rational(-24, 1), + mapOf(x to 3u, y to 6u) to Rational(16, 1), + mapOf(x to 4u, y to 6u) to Rational(4, 1) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(5407, 9), + mapOf(x to 1u) to Rational(9568, 27), + mapOf(x to 2u) to Rational(4996, 27), + mapOf(x to 3u) to Rational(352, 9), + mapOf(x to 4u) to Rational(22, 3), + mapOf(y to 1u) to Rational(104411, 126), + mapOf(x to 1u, y to 1u) to Rational(6001, 126), + mapOf(x to 2u, y to 1u) to Rational(-796, 21), + mapOf(x to 3u, y to 1u) to Rational(-5389, 126), + mapOf(x to 4u, y to 1u) to Rational(-166, 21), + mapOf(y to 2u) to Rational(-35327, 126), + mapOf(x to 1u, y to 2u) to Rational(53, 252), + mapOf(x to 2u, y to 2u) to Rational(849197, 6048), + mapOf(x to 3u, y to 2u) to Rational(22361, 252), + mapOf(x to 4u, y to 2u) to Rational(773, 42), + mapOf(y to 3u) to Rational(-6067, 21), + mapOf(x to 1u, y to 3u) to Rational(39049, 126), + mapOf(x to 2u, y to 3u) to Rational(80303, 1008), + mapOf(x to 3u, y to 3u) to Rational(-3035, 63), + mapOf(x to 4u, y to 3u) to Rational(-209, 21), + mapOf(y to 4u) to Rational(3113, 21), + mapOf(x to 1u, y to 4u) to Rational(-22345, 126), + mapOf(x to 2u, y to 4u) to Rational(-30931, 1008), + mapOf(x to 3u, y to 4u) to Rational(5837, 126), + mapOf(x to 4u, y to 4u) to Rational(229, 21), + mapOf(y to 5u) to Rational(-2120, 21), + mapOf(x to 1u, y to 5u) to Rational(451, 7), + mapOf(x to 2u, y to 5u) to Rational(422, 21), + mapOf(x to 3u, y to 5u) to Rational(-181, 21), + mapOf(x to 4u, y to 5u) to Rational(-40, 21), + mapOf(y to 6u) to Rational(100, 3), + mapOf(x to 1u, y to 6u) to Rational(-80, 3), + mapOf(x to 2u, y to 6u) to Rational(-8, 1), + mapOf(x to 3u, y to 6u) to Rational(16, 3), + mapOf(x to 4u, y to 6u) to Rational(4, 3) + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(5, 6), + mapOf(x to 1u) to Rational(1, 6), + mapOf(x to 2u) to Rational(-2, 9), + mapOf(y to 1u) to Rational(15, 1), + mapOf(x to 1u, y to 1u) to Rational(18, 7), + mapOf(x to 2u, y to 1u) to Rational(2, 5), + mapOf(y to 2u) to Rational(12, 9), + mapOf(x to 1u, y to 2u) to Rational(-3, 5), + mapOf(x to 2u, y to 2u) to Rational(4, 4), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-11, 9), + mapOf(x to 1u) to Rational(4, 9), + mapOf(x to 2u) to Rational(11, 6), + mapOf(y to 1u) to Rational(-5, 6), + mapOf(x to 1u, y to 1u) to Rational(4, 6), + mapOf(x to 2u, y to 1u) to Rational(-1, 7), + mapOf(y to 2u) to Rational(9, 1), + mapOf(x to 1u, y to 2u) to Rational(6, 7), + mapOf(x to 2u, y to 2u) to Rational(1, 3), + ) + ).substitute(RationalField, mapOf( + x to LabeledPolynomialAsIs( + mapOf() to Rational(18, 1), + mapOf(x to 1u) to Rational(16, 3), + mapOf(x to 2u) to Rational(12, 6), + mapOf(y to 1u) to Rational(13, 1), + mapOf(x to 1u, y to 1u) to Rational(-11, 4), + mapOf(x to 2u, y to 1u) to Rational(-1, 1), + mapOf(y to 2u) to Rational(-10, 1), + mapOf(x to 1u, y to 2u) to Rational(4, 1), + mapOf(x to 2u, y to 2u) to Rational(2, 1), + ), + iota to LabeledPolynomialAsIs( + mapOf() to Rational(-6, 1), + mapOf(x to 1u) to Rational(-9, 8), + mapOf(x to 2u) to Rational(17, 5), + mapOf(y to 1u) to Rational(-2, 3), + mapOf(x to 1u, y to 1u) to Rational(1, 5), + mapOf(x to 2u, y to 1u) to Rational(-11, 7), + mapOf(y to 2u) to Rational(13, 6), + mapOf(x to 1u, y to 2u) to Rational(-15, 2), + mapOf(x to 2u, y to 2u) to Rational(-14, 4), + ) + )), + "test 5'" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(5, 6), + mapOf(x to 1u) to Rational(1, 6), + mapOf(x to 2u) to Rational(-2, 9), + mapOf(y to 1u) to Rational(15, 1), + mapOf(x to 1u, y to 1u) to Rational(18, 7), + mapOf(x to 2u, y to 1u) to Rational(2, 5), + mapOf(y to 2u) to Rational(12, 9), + mapOf(x to 1u, y to 2u) to Rational(-3, 5), + mapOf(x to 2u, y to 2u) to Rational(4, 4), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-11, 9), + mapOf(x to 1u) to Rational(4, 9), + mapOf(x to 2u) to Rational(11, 6), + mapOf(y to 1u) to Rational(-5, 6), + mapOf(x to 1u, y to 1u) to Rational(4, 6), + mapOf(x to 2u, y to 1u) to Rational(-1, 7), + mapOf(y to 2u) to Rational(9, 1), + mapOf(x to 1u, y to 2u) to Rational(6, 7), + mapOf(x to 2u, y to 2u) to Rational(1, 3), + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(5, 6), + mapOf(x to 1u) to Rational(1, 6), + mapOf(x to 2u) to Rational(-2, 9), + mapOf(y to 1u) to Rational(15, 1), + mapOf(x to 1u, y to 1u) to Rational(18, 7), + mapOf(x to 2u, y to 1u) to Rational(2, 5), + mapOf(y to 2u) to Rational(12, 9), + mapOf(x to 1u, y to 2u) to Rational(-3, 5), + mapOf(x to 2u, y to 2u) to Rational(4, 4), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-11, 9), + mapOf(x to 1u) to Rational(4, 9), + mapOf(x to 2u) to Rational(11, 6), + mapOf(y to 1u) to Rational(-5, 6), + mapOf(x to 1u, y to 1u) to Rational(4, 6), + mapOf(x to 2u, y to 1u) to Rational(-1, 7), + mapOf(y to 2u) to Rational(9, 1), + mapOf(x to 1u, y to 2u) to Rational(6, 7), + mapOf(x to 2u, y to 2u) to Rational(1, 3), + ) + ).substitute(RationalField, mapOf>()), + "test 6" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(5, 6), + mapOf(x to 1u) to Rational(1, 6), + mapOf(x to 2u) to Rational(-2, 9), + mapOf(y to 1u) to Rational(15, 1), + mapOf(x to 1u, y to 1u) to Rational(18, 7), + mapOf(x to 2u, y to 1u) to Rational(2, 5), + mapOf(y to 2u) to Rational(12, 9), + mapOf(x to 1u, y to 2u) to Rational(-3, 5), + mapOf(x to 2u, y to 2u) to Rational(4, 4), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-11, 9), + mapOf(x to 1u) to Rational(4, 9), + mapOf(x to 2u) to Rational(11, 6), + mapOf(y to 1u) to Rational(-5, 6), + mapOf(x to 1u, y to 1u) to Rational(4, 6), + mapOf(x to 2u, y to 1u) to Rational(-1, 7), + mapOf(y to 2u) to Rational(9, 1), + mapOf(x to 1u, y to 2u) to Rational(6, 7), + mapOf(x to 2u, y to 2u) to Rational(1, 3), + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(5, 6), + mapOf(x to 1u) to Rational(1, 6), + mapOf(x to 2u) to Rational(-2, 9), + mapOf(y to 1u) to Rational(15, 1), + mapOf(x to 1u, y to 1u) to Rational(18, 7), + mapOf(x to 2u, y to 1u) to Rational(2, 5), + mapOf(y to 2u) to Rational(12, 9), + mapOf(x to 1u, y to 2u) to Rational(-3, 5), + mapOf(x to 2u, y to 2u) to Rational(4, 4), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-11, 9), + mapOf(x to 1u) to Rational(4, 9), + mapOf(x to 2u) to Rational(11, 6), + mapOf(y to 1u) to Rational(-5, 6), + mapOf(x to 1u, y to 1u) to Rational(4, 6), + mapOf(x to 2u, y to 1u) to Rational(-1, 7), + mapOf(y to 2u) to Rational(9, 1), + mapOf(x to 1u, y to 2u) to Rational(6, 7), + mapOf(x to 2u, y to 2u) to Rational(1, 3), + ) + ).substitute(RationalField, mapOf( + iota to LabeledPolynomialAsIs( + mapOf() to Rational(-6, 1), + mapOf(x to 1u) to Rational(-9, 8), + mapOf(x to 2u) to Rational(17, 5), + mapOf(y to 1u) to Rational(-2, 3), + mapOf(x to 1u, y to 1u) to Rational(1, 5), + mapOf(x to 2u, y to 1u) to Rational(-11, 7), + mapOf(y to 2u) to Rational(13, 6), + mapOf(x to 1u, y to 2u) to Rational(-15, 2), + mapOf(x to 2u, y to 2u) to Rational(-14, 4), + ) + )), + "test 6'" + ) + } + @Test + @Ignore // FIXME: This tests work only for sane realisations of the substitutions. Currently, it is not. + // Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should return denominator r^deg(p), + // not r^(deg(p)(deg(p)+1)/2) as it is now. + fun test_RationalFunction_substitute_RationalFunction_Map() { + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(0) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1) + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1) + ), + ).substitute(RationalField, mapOf( + x to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(1) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1) + ) + ) + )), + "test 1" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf(x to 4u) to Rational(-17166109, 793800), + mapOf(x to 3u, y to 1u) to Rational(-930960143, 5556600), + mapOf(x to 2u, y to 2u) to Rational(-144665109691, 350065800), + mapOf(x to 1u, y to 3u) to Rational(-17232577, 52920), + mapOf(y to 4u) to Rational(-68141, 1323), + ), + LabeledPolynomialAsIs( + mapOf(x to 4u) to Rational(-57522533, 14288400), + mapOf(x to 3u, y to 1u) to Rational(-13085162953, 300056400), + mapOf(x to 2u, y to 2u) to Rational(-92093367341, 525098700), + mapOf(x to 1u, y to 3u) to Rational(-1979342797, 6667920), + mapOf(y to 4u) to Rational(-3082727, 21168), + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(10, 2), + mapOf(x to 1u) to Rational(6, 7), + mapOf(x to 2u) to Rational(-16, 1), + mapOf(y to 1u) to Rational(13, 8), + mapOf(x to 1u, y to 1u) to Rational(-12, 1), + mapOf(x to 2u, y to 1u) to Rational(16, 8), + mapOf(y to 2u) to Rational(10, 4), + mapOf(x to 1u, y to 2u) to Rational(4, 1), + mapOf(x to 2u, y to 2u) to Rational(-11, 3), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1, 4), + mapOf(x to 1u) to Rational(-17, 4), + mapOf(x to 2u) to Rational(-14, 8), + mapOf(y to 1u) to Rational(17, 9), + mapOf(x to 1u, y to 1u) to Rational(1, 3), + mapOf(x to 2u, y to 1u) to Rational(7, 6), + mapOf(y to 2u) to Rational(16, 3), + mapOf(x to 1u, y to 2u) to Rational(-17, 1), + mapOf(x to 2u, y to 2u) to Rational(-10, 8), + ) + ).substitute(RationalField, mapOf( + x to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(11, 5), + mapOf(y to 1u) to Rational(8, 4), + ), + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(1, 9), + mapOf(y to 1u) to Rational(11, 7), + ) + ), + y to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(-2, 7), + mapOf(y to 1u) to Rational(-4, 3), + ), + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(3, 6), + mapOf(y to 1u) to Rational(12, 8), + ) + ), + )), + "test 2" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-130778291, 76800), + mapOf(x to 1u) to Rational(-445270919, 230400), + mapOf(x to 2u) to Rational(44578444937, 14515200), + mapOf(x to 3u) to Rational(17329402153, 1555200), + mapOf(x to 4u) to Rational(89239926809, 2332800), + mapOf(x to 5u) to Rational(2808812267, 145152), + mapOf(x to 6u) to Rational(-21362661007, 725760), + mapOf(x to 7u) to Rational(-258455443, 2016), + mapOf(x to 8u) to Rational(-21454693, 96), + mapOf(y to 1u) to Rational(-1002137, 15360), + mapOf(x to 1u, y to 1u) to Rational(-1704849697, 430080), + mapOf(x to 2u, y to 1u) to Rational(-57657676789, 4838400), + mapOf(x to 3u, y to 1u) to Rational(-101331731, 89600), + mapOf(x to 4u, y to 1u) to Rational(5362280079329, 130636800), + mapOf(x to 5u, y to 1u) to Rational(4069896167053, 130636800), + mapOf(x to 6u, y to 1u) to Rational(12011514569, 544320), + mapOf(x to 7u, y to 1u) to Rational(138293195623, 725760), + mapOf(x to 8u, y to 1u) to Rational(6228779419, 48384), + mapOf(y to 2u) to Rational(-32395872823, 8064000), + mapOf(x to 1u, y to 2u) to Rational(-7398505523, 2304000), + mapOf(x to 2u, y to 2u) to Rational(95217051699521, 3048192000), + mapOf(x to 3u, y to 2u) to Rational(198026968812079, 3657830400), + mapOf(x to 4u, y to 2u) to Rational(4291645618499, 228614400), + mapOf(x to 5u, y to 2u) to Rational(-33211690942439, 914457600), + mapOf(x to 6u, y to 2u) to Rational(-637385538163153, 1371686400), + mapOf(x to 7u, y to 2u) to Rational(-138671528276273, 182891520), + mapOf(x to 8u, y to 2u) to Rational(-14566368751, 217728), + mapOf(y to 3u) to Rational(-10538718719, 2016000), + mapOf(x to 1u, y to 3u) to Rational(-1844485375199, 84672000), + mapOf(x to 2u, y to 3u) to Rational(103968665891, 12096000), + mapOf(x to 3u, y to 3u) to Rational(175402107278351, 1828915200), + mapOf(x to 4u, y to 3u) to Rational(8020699588879, 114307200), + mapOf(x to 5u, y to 3u) to Rational(3414841894991, 38102400), + mapOf(x to 6u, y to 3u) to Rational(1848405591611, 4665600), + mapOf(x to 7u, y to 3u) to Rational(39486708738989, 137168640), + mapOf(x to 8u, y to 3u) to Rational(255926289517, 9144576), + mapOf(y to 4u) to Rational(-655379564629, 105840000), + mapOf(x to 1u, y to 4u) to Rational(-208336039441, 127008000), + mapOf(x to 2u, y to 4u) to Rational(40173146771411, 1143072000), + mapOf(x to 3u, y to 4u) to Rational(150473493581239, 2667168000), + mapOf(x to 4u, y to 4u) to Rational(38833783990483, 1143072000), + mapOf(x to 5u, y to 4u) to Rational(-1963676248203053, 4800902400), + mapOf(x to 6u, y to 4u) to Rational(-2598759412825747, 3200601600), + mapOf(x to 7u, y to 4u) to Rational(-192895352019667, 1280240640), + mapOf(x to 8u, y to 4u) to Rational(3737382679, 6858432), + mapOf(y to 5u) to Rational(-16959378721, 1890000), + mapOf(x to 1u, y to 5u) to Rational(-1864802244743, 79380000), + mapOf(x to 2u, y to 5u) to Rational(13449261536489, 666792000), + mapOf(x to 3u, y to 5u) to Rational(215272234137329, 2667168000), + mapOf(x to 4u, y to 5u) to Rational(6040691379277, 83349000), + mapOf(x to 5u, y to 5u) to Rational(153687143525887, 800150400), + mapOf(x to 6u, y to 5u) to Rational(475602854903563, 2400451200), + mapOf(x to 7u, y to 5u) to Rational(27315599358749, 640120320), + mapOf(x to 8u, y to 5u) to Rational(-2630413357, 10668672), + mapOf(y to 6u) to Rational(-6654999511, 2646000), + mapOf(x to 1u, y to 6u) to Rational(-67885252327, 15876000), + mapOf(x to 2u, y to 6u) to Rational(5786776220983, 2667168000), + mapOf(x to 3u, y to 6u) to Rational(60615922629083, 1143072000), + mapOf(x to 4u, y to 6u) to Rational(-34703539637627407, 672126336000), + mapOf(x to 5u, y to 6u) to Rational(-744694192134101, 2240421120), + mapOf(x to 6u, y to 6u) to Rational(-1782470617231, 14817600), + mapOf(x to 7u, y to 6u) to Rational(59123208433, 8890560), + mapOf(x to 8u, y to 6u) to Rational(-141653, 5292), + mapOf(y to 7u) to Rational(-338051969, 441000), + mapOf(x to 1u, y to 7u) to Rational(468850013, 1764000), + mapOf(x to 2u, y to 7u) to Rational(2102343426101, 222264000), + mapOf(x to 3u, y to 7u) to Rational(7836130602007, 1333584000), + mapOf(x to 4u, y to 7u) to Rational(16239111865997, 746807040), + mapOf(x to 5u, y to 7u) to Rational(3824649185383, 88905600), + mapOf(x to 6u, y to 7u) to Rational(56058614459, 3457440), + mapOf(x to 7u, y to 7u) to Rational(-396766339, 493920), + mapOf(x to 8u, y to 7u) to Rational(-165147, 2744), + mapOf(y to 8u) to Rational(-3088619, 58800), + mapOf(x to 1u, y to 8u) to Rational(155343347, 88200), + mapOf(x to 2u, y to 8u) to Rational(100098736469, 7408800), + mapOf(x to 3u, y to 8u) to Rational(109725511381, 7408800), + mapOf(x to 4u, y to 8u) to Rational(-2431199641013, 59270400), + mapOf(x to 5u, y to 8u) to Rational(-102872383249, 3457440), + mapOf(x to 6u, y to 8u) to Rational(1449461309, 576240), + mapOf(x to 7u, y to 8u) to Rational(812775, 1372), + mapOf(x to 8u, y to 8u) to Rational(-16461, 343) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(164202773, 230400), + mapOf(x to 1u) to Rational(-70345303, 518400), + mapOf(x to 2u) to Rational(-4229702731, 4665600), + mapOf(x to 3u) to Rational(3262171027, 6998400), + mapOf(x to 4u) to Rational(-25423104169, 13996800), + mapOf(x to 5u) to Rational(64061869, 349920), + mapOf(x to 6u) to Rational(-1655878091, 116640), + mapOf(x to 7u) to Rational(-7991441, 648), + mapOf(x to 8u) to Rational(-502591, 18), + mapOf(y to 1u) to Rational(-8780429, 3840), + mapOf(x to 1u, y to 1u) to Rational(434272361, 115200), + mapOf(x to 2u, y to 1u) to Rational(429825727, 41472), + mapOf(x to 3u, y to 1u) to Rational(-10066790339, 6998400), + mapOf(x to 4u, y to 1u) to Rational(70022035471, 20995200), + mapOf(x to 5u, y to 1u) to Rational(-32070283493, 1399680), + mapOf(x to 6u, y to 1u) to Rational(-22051101001, 1399680), + mapOf(x to 7u, y to 1u) to Rational(-126493427, 12960), + mapOf(x to 8u, y to 1u) to Rational(3050245, 864), + mapOf(y to 2u) to Rational(-1194654631, 345600), + mapOf(x to 1u, y to 2u) to Rational(-542961452671, 31104000), + mapOf(x to 2u, y to 2u) to Rational(-234000873607, 48988800), + mapOf(x to 3u, y to 2u) to Rational(140520538087, 3628800), + mapOf(x to 4u, y to 2u) to Rational(9215088876563, 130636800), + mapOf(x to 5u, y to 2u) to Rational(27590569647253, 293932800), + mapOf(x to 6u, y to 2u) to Rational(5129057792891, 97977600), + mapOf(x to 7u, y to 2u) to Rational(-106334191, 5103), + mapOf(x to 8u, y to 2u) to Rational(-1024113911, 435456), + mapOf(y to 3u) to Rational(76223843, 6000), + mapOf(x to 1u, y to 3u) to Rational(57425857357, 2592000), + mapOf(x to 2u, y to 3u) to Rational(-2044736497573, 46656000), + mapOf(x to 3u, y to 3u) to Rational(-26155810120031, 293932800), + mapOf(x to 4u, y to 3u) to Rational(-1064419459813, 6998400), + mapOf(x to 5u, y to 3u) to Rational(-753782018389, 4082400), + mapOf(x to 6u, y to 3u) to Rational(-291973360873, 2799360), + mapOf(x to 7u, y to 3u) to Rational(-46372122599, 816480), + mapOf(x to 8u, y to 3u) to Rational(3579859657, 653184), + mapOf(y to 4u) to Rational(-13374241901, 4320000), + mapOf(x to 1u, y to 4u) to Rational(306606499811, 54432000), + mapOf(x to 2u, y to 4u) to Rational(964267124745437, 13716864000), + mapOf(x to 3u, y to 4u) to Rational(21603809415373, 182891520), + mapOf(x to 4u, y to 4u) to Rational(1097860214654027, 6858432000), + mapOf(x to 5u, y to 4u) to Rational(161615254570669, 914457600), + mapOf(x to 6u, y to 4u) to Rational(758415239461, 22861440), + mapOf(x to 7u, y to 4u) to Rational(2585568355471, 274337280), + mapOf(x to 8u, y to 4u) to Rational(-70433747863, 9144576), + mapOf(y to 5u) to Rational(-9582586217, 2520000), + mapOf(x to 1u, y to 5u) to Rational(-19093471394171, 635040000), + mapOf(x to 2u, y to 5u) to Rational(-13010261944411, 381024000), + mapOf(x to 3u, y to 5u) to Rational(-259039825301861, 4572288000), + mapOf(x to 4u, y to 5u) to Rational(-305081119071079, 2286144000), + mapOf(x to 5u, y to 5u) to Rational(-1923114383311, 19595520), + mapOf(x to 6u, y to 5u) to Rational(-14181787253231, 228614400), + mapOf(x to 7u, y to 5u) to Rational(-3959584789, 4354560), + mapOf(x to 8u, y to 5u) to Rational(4691742523, 762048), + mapOf(y to 6u) to Rational(-588323437, 180000), + mapOf(x to 1u, y to 6u) to Rational(5952234691, 52920000), + mapOf(x to 2u, y to 6u) to Rational(21001851056959, 1088640000), + mapOf(x to 3u, y to 6u) to Rational(84668034357563, 2133734400), + mapOf(x to 4u, y to 6u) to Rational(2029754605811557, 25604812800), + mapOf(x to 5u, y to 6u) to Rational(11721216739823, 426746880), + mapOf(x to 6u, y to 6u) to Rational(-8275903187003, 2133734400), + mapOf(x to 7u, y to 6u) to Rational(-4730447299, 2540160), + mapOf(x to 8u, y to 6u) to Rational(-46069985, 21168), + mapOf(y to 7u) to Rational(-75711301, 117600), + mapOf(x to 1u, y to 7u) to Rational(32430417413, 7056000), + mapOf(x to 2u, y to 7u) to Rational(677988533153, 98784000), + mapOf(x to 3u, y to 7u) to Rational(-948417645827, 71124480), + mapOf(x to 4u, y to 7u) to Rational(-11320265215207, 711244800), + mapOf(x to 5u, y to 7u) to Rational(-676438627783, 50803200), + mapOf(x to 6u, y to 7u) to Rational(-7382274253, 1975680), + mapOf(x to 7u, y to 7u) to Rational(6505733, 2205), + mapOf(x to 8u, y to 7u) to Rational(450137, 882), + mapOf(y to 8u) to Rational(-8368253, 78400), + mapOf(x to 1u, y to 8u) to Rational(6833783, 117600), + mapOf(x to 2u, y to 8u) to Rational(4528971133, 5927040), + mapOf(x to 3u, y to 8u) to Rational(146252636617, 29635200), + mapOf(x to 4u, y to 8u) to Rational(8321882556889, 1659571200), + mapOf(x to 5u, y to 8u) to Rational(-4686033011, 1975680), + mapOf(x to 6u, y to 8u) to Rational(-1074445963, 987840), + mapOf(x to 7u, y to 8u) to Rational(-142313, 588), + mapOf(x to 8u, y to 8u) to Rational(-4281, 49) + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(10, 2), + mapOf(x to 1u) to Rational(6, 7), + mapOf(x to 2u) to Rational(-16, 1), + mapOf(y to 1u) to Rational(13, 8), + mapOf(x to 1u, y to 1u) to Rational(-12, 1), + mapOf(x to 2u, y to 1u) to Rational(16, 8), + mapOf(y to 2u) to Rational(10, 4), + mapOf(x to 1u, y to 2u) to Rational(4, 1), + mapOf(x to 2u, y to 2u) to Rational(-11, 3), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1, 4), + mapOf(x to 1u) to Rational(-17, 4), + mapOf(x to 2u) to Rational(-14, 8), + mapOf(y to 1u) to Rational(17, 9), + mapOf(x to 1u, y to 1u) to Rational(1, 3), + mapOf(x to 2u, y to 1u) to Rational(7, 6), + mapOf(y to 2u) to Rational(16, 3), + mapOf(x to 1u, y to 2u) to Rational(-17, 1), + mapOf(x to 2u, y to 2u) to Rational(-10, 8), + ) + ).substitute(RationalField, mapOf( + x to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-17, 5), + mapOf(x to 1u) to Rational(2, 6), + mapOf(x to 2u) to Rational(14, 1), + mapOf(y to 1u) to Rational(-6, 6), + mapOf(x to 1u, y to 1u) to Rational(-7, 3), + mapOf(x to 2u, y to 1u) to Rational(-2, 9), + mapOf(y to 2u) to Rational(-9, 6), + mapOf(x to 1u, y to 2u) to Rational(17, 4), + mapOf(x to 2u, y to 2u) to Rational(2, 1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(5, 4), + mapOf(x to 1u) to Rational(-5, 9), + mapOf(x to 2u) to Rational(-3, 6), + mapOf(y to 1u) to Rational(6, 5), + mapOf(x to 1u, y to 1u) to Rational(14, 5), + mapOf(x to 2u, y to 1u) to Rational(5, 2), + mapOf(y to 2u) to Rational(-18, 7), + mapOf(x to 1u, y to 2u) to Rational(-8, 2), + mapOf(x to 2u, y to 2u) to Rational(18, 9), + ) + ), + y to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(14, 4), + mapOf(x to 1u) to Rational(7, 6), + mapOf(x to 2u) to Rational(7, 2), + mapOf(y to 1u) to Rational(-15, 2), + mapOf(x to 1u, y to 1u) to Rational(-13, 8), + mapOf(x to 2u, y to 1u) to Rational(-14, 3), + mapOf(y to 2u) to Rational(-7, 6), + mapOf(x to 1u, y to 2u) to Rational(7, 4), + mapOf(x to 2u, y to 2u) to Rational(9, 7), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-7, 4), + mapOf(x to 1u) to Rational(-6, 3), + mapOf(x to 2u) to Rational(-16, 2), + mapOf(y to 1u) to Rational(-15, 5), + mapOf(x to 1u, y to 1u) to Rational(4, 6), + mapOf(x to 2u, y to 1u) to Rational(5, 4), + mapOf(y to 2u) to Rational(-12, 5), + mapOf(x to 1u, y to 2u) to Rational(-18, 2), + mapOf(x to 2u, y to 2u) to Rational(6, 7), + ) + ), + )), + "test 3" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-130778291, 76800), + mapOf(x to 1u) to Rational(-445270919, 230400), + mapOf(x to 2u) to Rational(44578444937, 14515200), + mapOf(x to 3u) to Rational(17329402153, 1555200), + mapOf(x to 4u) to Rational(89239926809, 2332800), + mapOf(x to 5u) to Rational(2808812267, 145152), + mapOf(x to 6u) to Rational(-21362661007, 725760), + mapOf(x to 7u) to Rational(-258455443, 2016), + mapOf(x to 8u) to Rational(-21454693, 96), + mapOf(y to 1u) to Rational(-1002137, 15360), + mapOf(x to 1u, y to 1u) to Rational(-1704849697, 430080), + mapOf(x to 2u, y to 1u) to Rational(-57657676789, 4838400), + mapOf(x to 3u, y to 1u) to Rational(-101331731, 89600), + mapOf(x to 4u, y to 1u) to Rational(5362280079329, 130636800), + mapOf(x to 5u, y to 1u) to Rational(4069896167053, 130636800), + mapOf(x to 6u, y to 1u) to Rational(12011514569, 544320), + mapOf(x to 7u, y to 1u) to Rational(138293195623, 725760), + mapOf(x to 8u, y to 1u) to Rational(6228779419, 48384), + mapOf(y to 2u) to Rational(-32395872823, 8064000), + mapOf(x to 1u, y to 2u) to Rational(-7398505523, 2304000), + mapOf(x to 2u, y to 2u) to Rational(95217051699521, 3048192000), + mapOf(x to 3u, y to 2u) to Rational(198026968812079, 3657830400), + mapOf(x to 4u, y to 2u) to Rational(4291645618499, 228614400), + mapOf(x to 5u, y to 2u) to Rational(-33211690942439, 914457600), + mapOf(x to 6u, y to 2u) to Rational(-637385538163153, 1371686400), + mapOf(x to 7u, y to 2u) to Rational(-138671528276273, 182891520), + mapOf(x to 8u, y to 2u) to Rational(-14566368751, 217728), + mapOf(y to 3u) to Rational(-10538718719, 2016000), + mapOf(x to 1u, y to 3u) to Rational(-1844485375199, 84672000), + mapOf(x to 2u, y to 3u) to Rational(103968665891, 12096000), + mapOf(x to 3u, y to 3u) to Rational(175402107278351, 1828915200), + mapOf(x to 4u, y to 3u) to Rational(8020699588879, 114307200), + mapOf(x to 5u, y to 3u) to Rational(3414841894991, 38102400), + mapOf(x to 6u, y to 3u) to Rational(1848405591611, 4665600), + mapOf(x to 7u, y to 3u) to Rational(39486708738989, 137168640), + mapOf(x to 8u, y to 3u) to Rational(255926289517, 9144576), + mapOf(y to 4u) to Rational(-655379564629, 105840000), + mapOf(x to 1u, y to 4u) to Rational(-208336039441, 127008000), + mapOf(x to 2u, y to 4u) to Rational(40173146771411, 1143072000), + mapOf(x to 3u, y to 4u) to Rational(150473493581239, 2667168000), + mapOf(x to 4u, y to 4u) to Rational(38833783990483, 1143072000), + mapOf(x to 5u, y to 4u) to Rational(-1963676248203053, 4800902400), + mapOf(x to 6u, y to 4u) to Rational(-2598759412825747, 3200601600), + mapOf(x to 7u, y to 4u) to Rational(-192895352019667, 1280240640), + mapOf(x to 8u, y to 4u) to Rational(3737382679, 6858432), + mapOf(y to 5u) to Rational(-16959378721, 1890000), + mapOf(x to 1u, y to 5u) to Rational(-1864802244743, 79380000), + mapOf(x to 2u, y to 5u) to Rational(13449261536489, 666792000), + mapOf(x to 3u, y to 5u) to Rational(215272234137329, 2667168000), + mapOf(x to 4u, y to 5u) to Rational(6040691379277, 83349000), + mapOf(x to 5u, y to 5u) to Rational(153687143525887, 800150400), + mapOf(x to 6u, y to 5u) to Rational(475602854903563, 2400451200), + mapOf(x to 7u, y to 5u) to Rational(27315599358749, 640120320), + mapOf(x to 8u, y to 5u) to Rational(-2630413357, 10668672), + mapOf(y to 6u) to Rational(-6654999511, 2646000), + mapOf(x to 1u, y to 6u) to Rational(-67885252327, 15876000), + mapOf(x to 2u, y to 6u) to Rational(5786776220983, 2667168000), + mapOf(x to 3u, y to 6u) to Rational(60615922629083, 1143072000), + mapOf(x to 4u, y to 6u) to Rational(-34703539637627407, 672126336000), + mapOf(x to 5u, y to 6u) to Rational(-744694192134101, 2240421120), + mapOf(x to 6u, y to 6u) to Rational(-1782470617231, 14817600), + mapOf(x to 7u, y to 6u) to Rational(59123208433, 8890560), + mapOf(x to 8u, y to 6u) to Rational(-141653, 5292), + mapOf(y to 7u) to Rational(-338051969, 441000), + mapOf(x to 1u, y to 7u) to Rational(468850013, 1764000), + mapOf(x to 2u, y to 7u) to Rational(2102343426101, 222264000), + mapOf(x to 3u, y to 7u) to Rational(7836130602007, 1333584000), + mapOf(x to 4u, y to 7u) to Rational(16239111865997, 746807040), + mapOf(x to 5u, y to 7u) to Rational(3824649185383, 88905600), + mapOf(x to 6u, y to 7u) to Rational(56058614459, 3457440), + mapOf(x to 7u, y to 7u) to Rational(-396766339, 493920), + mapOf(x to 8u, y to 7u) to Rational(-165147, 2744), + mapOf(y to 8u) to Rational(-3088619, 58800), + mapOf(x to 1u, y to 8u) to Rational(155343347, 88200), + mapOf(x to 2u, y to 8u) to Rational(100098736469, 7408800), + mapOf(x to 3u, y to 8u) to Rational(109725511381, 7408800), + mapOf(x to 4u, y to 8u) to Rational(-2431199641013, 59270400), + mapOf(x to 5u, y to 8u) to Rational(-102872383249, 3457440), + mapOf(x to 6u, y to 8u) to Rational(1449461309, 576240), + mapOf(x to 7u, y to 8u) to Rational(812775, 1372), + mapOf(x to 8u, y to 8u) to Rational(-16461, 343) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(164202773, 230400), + mapOf(x to 1u) to Rational(-70345303, 518400), + mapOf(x to 2u) to Rational(-4229702731, 4665600), + mapOf(x to 3u) to Rational(3262171027, 6998400), + mapOf(x to 4u) to Rational(-25423104169, 13996800), + mapOf(x to 5u) to Rational(64061869, 349920), + mapOf(x to 6u) to Rational(-1655878091, 116640), + mapOf(x to 7u) to Rational(-7991441, 648), + mapOf(x to 8u) to Rational(-502591, 18), + mapOf(y to 1u) to Rational(-8780429, 3840), + mapOf(x to 1u, y to 1u) to Rational(434272361, 115200), + mapOf(x to 2u, y to 1u) to Rational(429825727, 41472), + mapOf(x to 3u, y to 1u) to Rational(-10066790339, 6998400), + mapOf(x to 4u, y to 1u) to Rational(70022035471, 20995200), + mapOf(x to 5u, y to 1u) to Rational(-32070283493, 1399680), + mapOf(x to 6u, y to 1u) to Rational(-22051101001, 1399680), + mapOf(x to 7u, y to 1u) to Rational(-126493427, 12960), + mapOf(x to 8u, y to 1u) to Rational(3050245, 864), + mapOf(y to 2u) to Rational(-1194654631, 345600), + mapOf(x to 1u, y to 2u) to Rational(-542961452671, 31104000), + mapOf(x to 2u, y to 2u) to Rational(-234000873607, 48988800), + mapOf(x to 3u, y to 2u) to Rational(140520538087, 3628800), + mapOf(x to 4u, y to 2u) to Rational(9215088876563, 130636800), + mapOf(x to 5u, y to 2u) to Rational(27590569647253, 293932800), + mapOf(x to 6u, y to 2u) to Rational(5129057792891, 97977600), + mapOf(x to 7u, y to 2u) to Rational(-106334191, 5103), + mapOf(x to 8u, y to 2u) to Rational(-1024113911, 435456), + mapOf(y to 3u) to Rational(76223843, 6000), + mapOf(x to 1u, y to 3u) to Rational(57425857357, 2592000), + mapOf(x to 2u, y to 3u) to Rational(-2044736497573, 46656000), + mapOf(x to 3u, y to 3u) to Rational(-26155810120031, 293932800), + mapOf(x to 4u, y to 3u) to Rational(-1064419459813, 6998400), + mapOf(x to 5u, y to 3u) to Rational(-753782018389, 4082400), + mapOf(x to 6u, y to 3u) to Rational(-291973360873, 2799360), + mapOf(x to 7u, y to 3u) to Rational(-46372122599, 816480), + mapOf(x to 8u, y to 3u) to Rational(3579859657, 653184), + mapOf(y to 4u) to Rational(-13374241901, 4320000), + mapOf(x to 1u, y to 4u) to Rational(306606499811, 54432000), + mapOf(x to 2u, y to 4u) to Rational(964267124745437, 13716864000), + mapOf(x to 3u, y to 4u) to Rational(21603809415373, 182891520), + mapOf(x to 4u, y to 4u) to Rational(1097860214654027, 6858432000), + mapOf(x to 5u, y to 4u) to Rational(161615254570669, 914457600), + mapOf(x to 6u, y to 4u) to Rational(758415239461, 22861440), + mapOf(x to 7u, y to 4u) to Rational(2585568355471, 274337280), + mapOf(x to 8u, y to 4u) to Rational(-70433747863, 9144576), + mapOf(y to 5u) to Rational(-9582586217, 2520000), + mapOf(x to 1u, y to 5u) to Rational(-19093471394171, 635040000), + mapOf(x to 2u, y to 5u) to Rational(-13010261944411, 381024000), + mapOf(x to 3u, y to 5u) to Rational(-259039825301861, 4572288000), + mapOf(x to 4u, y to 5u) to Rational(-305081119071079, 2286144000), + mapOf(x to 5u, y to 5u) to Rational(-1923114383311, 19595520), + mapOf(x to 6u, y to 5u) to Rational(-14181787253231, 228614400), + mapOf(x to 7u, y to 5u) to Rational(-3959584789, 4354560), + mapOf(x to 8u, y to 5u) to Rational(4691742523, 762048), + mapOf(y to 6u) to Rational(-588323437, 180000), + mapOf(x to 1u, y to 6u) to Rational(5952234691, 52920000), + mapOf(x to 2u, y to 6u) to Rational(21001851056959, 1088640000), + mapOf(x to 3u, y to 6u) to Rational(84668034357563, 2133734400), + mapOf(x to 4u, y to 6u) to Rational(2029754605811557, 25604812800), + mapOf(x to 5u, y to 6u) to Rational(11721216739823, 426746880), + mapOf(x to 6u, y to 6u) to Rational(-8275903187003, 2133734400), + mapOf(x to 7u, y to 6u) to Rational(-4730447299, 2540160), + mapOf(x to 8u, y to 6u) to Rational(-46069985, 21168), + mapOf(y to 7u) to Rational(-75711301, 117600), + mapOf(x to 1u, y to 7u) to Rational(32430417413, 7056000), + mapOf(x to 2u, y to 7u) to Rational(677988533153, 98784000), + mapOf(x to 3u, y to 7u) to Rational(-948417645827, 71124480), + mapOf(x to 4u, y to 7u) to Rational(-11320265215207, 711244800), + mapOf(x to 5u, y to 7u) to Rational(-676438627783, 50803200), + mapOf(x to 6u, y to 7u) to Rational(-7382274253, 1975680), + mapOf(x to 7u, y to 7u) to Rational(6505733, 2205), + mapOf(x to 8u, y to 7u) to Rational(450137, 882), + mapOf(y to 8u) to Rational(-8368253, 78400), + mapOf(x to 1u, y to 8u) to Rational(6833783, 117600), + mapOf(x to 2u, y to 8u) to Rational(4528971133, 5927040), + mapOf(x to 3u, y to 8u) to Rational(146252636617, 29635200), + mapOf(x to 4u, y to 8u) to Rational(8321882556889, 1659571200), + mapOf(x to 5u, y to 8u) to Rational(-4686033011, 1975680), + mapOf(x to 6u, y to 8u) to Rational(-1074445963, 987840), + mapOf(x to 7u, y to 8u) to Rational(-142313, 588), + mapOf(x to 8u, y to 8u) to Rational(-4281, 49) + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(10, 2), + mapOf(x to 1u) to Rational(6, 7), + mapOf(x to 2u) to Rational(-16, 1), + mapOf(y to 1u) to Rational(13, 8), + mapOf(x to 1u, y to 1u) to Rational(-12, 1), + mapOf(x to 2u, y to 1u) to Rational(16, 8), + mapOf(y to 2u) to Rational(10, 4), + mapOf(x to 1u, y to 2u) to Rational(4, 1), + mapOf(x to 2u, y to 2u) to Rational(-11, 3), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1, 4), + mapOf(x to 1u) to Rational(-17, 4), + mapOf(x to 2u) to Rational(-14, 8), + mapOf(y to 1u) to Rational(17, 9), + mapOf(x to 1u, y to 1u) to Rational(1, 3), + mapOf(x to 2u, y to 1u) to Rational(7, 6), + mapOf(y to 2u) to Rational(16, 3), + mapOf(x to 1u, y to 2u) to Rational(-17, 1), + mapOf(x to 2u, y to 2u) to Rational(-10, 8), + ) + ).substitute(RationalField, mapOf( + x to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-17, 5), + mapOf(x to 1u) to Rational(2, 6), + mapOf(x to 2u) to Rational(14, 1), + mapOf(y to 1u) to Rational(-6, 6), + mapOf(x to 1u, y to 1u) to Rational(-7, 3), + mapOf(x to 2u, y to 1u) to Rational(-2, 9), + mapOf(y to 2u) to Rational(-9, 6), + mapOf(x to 1u, y to 2u) to Rational(17, 4), + mapOf(x to 2u, y to 2u) to Rational(2, 1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(5, 4), + mapOf(x to 1u) to Rational(-5, 9), + mapOf(x to 2u) to Rational(-3, 6), + mapOf(y to 1u) to Rational(6, 5), + mapOf(x to 1u, y to 1u) to Rational(14, 5), + mapOf(x to 2u, y to 1u) to Rational(5, 2), + mapOf(y to 2u) to Rational(-18, 7), + mapOf(x to 1u, y to 2u) to Rational(-8, 2), + mapOf(x to 2u, y to 2u) to Rational(18, 9), + ) + ), + y to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(14, 4), + mapOf(x to 1u) to Rational(7, 6), + mapOf(x to 2u) to Rational(7, 2), + mapOf(y to 1u) to Rational(-15, 2), + mapOf(x to 1u, y to 1u) to Rational(-13, 8), + mapOf(x to 2u, y to 1u) to Rational(-14, 3), + mapOf(y to 2u) to Rational(-7, 6), + mapOf(x to 1u, y to 2u) to Rational(7, 4), + mapOf(x to 2u, y to 2u) to Rational(9, 7), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-7, 4), + mapOf(x to 1u) to Rational(-6, 3), + mapOf(x to 2u) to Rational(-16, 2), + mapOf(y to 1u) to Rational(-15, 5), + mapOf(x to 1u, y to 1u) to Rational(4, 6), + mapOf(x to 2u, y to 1u) to Rational(5, 4), + mapOf(y to 2u) to Rational(-12, 5), + mapOf(x to 1u, y to 2u) to Rational(-18, 2), + mapOf(x to 2u, y to 2u) to Rational(6, 7), + ) + ), + iota to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(5, 8), + mapOf(x to 1u) to Rational(-12, 6), + mapOf(x to 2u) to Rational(7, 6), + mapOf(y to 1u) to Rational(-10, 4), + mapOf(x to 1u, y to 1u) to Rational(-7, 6), + mapOf(x to 2u, y to 1u) to Rational(8, 9), + mapOf(y to 2u) to Rational(16, 3), + mapOf(x to 1u, y to 2u) to Rational(-13, 4), + mapOf(x to 2u, y to 2u) to Rational(5, 1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(10, 6), + mapOf(x to 1u) to Rational(-18, 6), + mapOf(x to 2u) to Rational(5, 1), + mapOf(y to 1u) to Rational(17, 7), + mapOf(x to 1u, y to 1u) to Rational(8, 4), + mapOf(x to 2u, y to 1u) to Rational(-4, 9), + mapOf(y to 2u) to Rational(-6, 5), + mapOf(x to 1u, y to 2u) to Rational(-15, 8), + mapOf(x to 2u, y to 2u) to Rational(-18, 5), + ) + ), + )), + "test 3'" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(2303, 64), + mapOf(x to 1u) to Rational(31843, 192), + mapOf(x to 2u) to Rational(118891, 576), + mapOf(x to 3u) to Rational(94453, 168), + mapOf(x to 4u) to Rational(-179203, 1512), + mapOf(x to 5u) to Rational(-16979, 126), + mapOf(x to 6u) to Rational(-13499, 12), + mapOf(y to 1u) to Rational(-4767, 64), + mapOf(x to 1u, y to 1u) to Rational(-58689, 256), + mapOf(x to 2u, y to 1u) to Rational(-757333, 4032), + mapOf(x to 3u, y to 1u) to Rational(-4921205, 4032), + mapOf(x to 4u, y to 1u) to Rational(-2930815, 4032), + mapOf(x to 5u, y to 1u) to Rational(-398803, 1512), + mapOf(x to 6u, y to 1u) to Rational(18835, 36), + mapOf(y to 2u) to Rational(224101, 960), + mapOf(x to 1u, y to 2u) to Rational(9139699, 40320), + mapOf(x to 2u, y to 2u) to Rational(3848803, 5760), + mapOf(x to 3u, y to 2u) to Rational(93102371, 241920), + mapOf(x to 4u, y to 2u) to Rational(-65821229, 141120), + mapOf(x to 5u, y to 2u) to Rational(-15675899, 7056), + mapOf(x to 6u, y to 2u) to Rational(10459, 189), + mapOf(y to 3u) to Rational(2411, 16), + mapOf(x to 1u, y to 3u) to Rational(1294543, 10080), + mapOf(x to 2u, y to 3u) to Rational(-1740199, 1440), + mapOf(x to 3u, y to 3u) to Rational(-266994841, 282240), + mapOf(x to 4u, y to 3u) to Rational(-41261893, 211680), + mapOf(x to 5u, y to 3u) to Rational(1717357, 3528), + mapOf(x to 6u, y to 3u) to Rational(69, 14), + mapOf(y to 4u) to Rational(13231, 360), + mapOf(x to 1u, y to 4u) to Rational(4858831, 25200), + mapOf(x to 2u, y to 4u) to Rational(15565759, 75600), + mapOf(x to 3u, y to 4u) to Rational(-15583391, 35280), + mapOf(x to 4u, y to 4u) to Rational(-13345747, 11760), + mapOf(x to 5u, y to 4u) to Rational(140103, 686), + mapOf(x to 6u, y to 4u) to Rational(-765, 49) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(31409, 576), + mapOf(x to 1u) to Rational(-337099, 1728), + mapOf(x to 2u) to Rational(-211429, 1728), + mapOf(x to 3u) to Rational(-259241, 432), + mapOf(x to 4u) to Rational(-13777, 36), + mapOf(x to 5u) to Rational(-41389, 72), + mapOf(x to 6u) to Rational(-7679, 48), + mapOf(y to 1u) to Rational(-3269, 12), + mapOf(x to 1u, y to 1u) to Rational(629569, 864), + mapOf(x to 2u, y to 1u) to Rational(53867, 324), + mapOf(x to 3u, y to 1u) to Rational(2290577, 1728), + mapOf(x to 4u, y to 1u) to Rational(101507, 216), + mapOf(x to 5u, y to 1u) to Rational(213109, 288), + mapOf(x to 6u, y to 1u) to Rational(17927, 144), + mapOf(y to 2u) to Rational(314587, 1080), + mapOf(x to 1u, y to 2u) to Rational(-109771, 144), + mapOf(x to 2u, y to 2u) to Rational(-6469, 16), + mapOf(x to 3u, y to 2u) to Rational(-298291681, 181440), + mapOf(x to 4u, y to 2u) to Rational(-59147357, 48384), + mapOf(x to 5u, y to 2u) to Rational(-4982365, 6048), + mapOf(x to 6u, y to 2u) to Rational(-18727, 576), + mapOf(y to 3u) to Rational(12379, 90), + mapOf(x to 1u, y to 3u) to Rational(-542911, 1620), + mapOf(x to 2u, y to 3u) to Rational(143123, 1260), + mapOf(x to 3u, y to 3u) to Rational(9859177, 30240), + mapOf(x to 4u, y to 3u) to Rational(9312529, 20160), + mapOf(x to 5u, y to 3u) to Rational(207001, 672), + mapOf(x to 6u, y to 3u) to Rational(203, 24), + mapOf(y to 4u) to Rational(9442, 675), + mapOf(x to 1u, y to 4u) to Rational(-13729, 300), + mapOf(x to 2u, y to 4u) to Rational(-3490471, 25200), + mapOf(x to 3u, y to 4u) to Rational(-333031, 840), + mapOf(x to 4u, y to 4u) to Rational(-7572211, 47040), + mapOf(x to 5u, y to 4u) to Rational(-1189, 56), + mapOf(x to 6u, y to 4u) to Rational(-405, 196) + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(10, 2), + mapOf(x to 1u) to Rational(6, 7), + mapOf(x to 2u) to Rational(-16, 1), + mapOf(y to 1u) to Rational(13, 8), + mapOf(x to 1u, y to 1u) to Rational(-12, 1), + mapOf(x to 2u, y to 1u) to Rational(16, 8), + mapOf(y to 2u) to Rational(10, 4), + mapOf(x to 1u, y to 2u) to Rational(4, 1), + mapOf(x to 2u, y to 2u) to Rational(-11, 3), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1, 4), + mapOf(x to 1u) to Rational(-17, 4), + mapOf(x to 2u) to Rational(-14, 8), + mapOf(y to 1u) to Rational(17, 9), + mapOf(x to 1u, y to 1u) to Rational(1, 3), + mapOf(x to 2u, y to 1u) to Rational(7, 6), + mapOf(y to 2u) to Rational(16, 3), + mapOf(x to 1u, y to 2u) to Rational(-17, 1), + mapOf(x to 2u, y to 2u) to Rational(-10, 8), + ) + ).substitute(RationalField, mapOf( + y to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(14, 4), + mapOf(x to 1u) to Rational(7, 6), + mapOf(x to 2u) to Rational(7, 2), + mapOf(y to 1u) to Rational(-15, 2), + mapOf(x to 1u, y to 1u) to Rational(-13, 8), + mapOf(x to 2u, y to 1u) to Rational(-14, 3), + mapOf(y to 2u) to Rational(-7, 6), + mapOf(x to 1u, y to 2u) to Rational(7, 4), + mapOf(x to 2u, y to 2u) to Rational(9, 7), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-7, 4), + mapOf(x to 1u) to Rational(-6, 3), + mapOf(x to 2u) to Rational(-16, 2), + mapOf(y to 1u) to Rational(-15, 5), + mapOf(x to 1u, y to 1u) to Rational(4, 6), + mapOf(x to 2u, y to 1u) to Rational(5, 4), + mapOf(y to 2u) to Rational(-12, 5), + mapOf(x to 1u, y to 2u) to Rational(-18, 2), + mapOf(x to 2u, y to 2u) to Rational(6, 7), + ) + ), + )), + "test 4" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(2303, 64), + mapOf(x to 1u) to Rational(31843, 192), + mapOf(x to 2u) to Rational(118891, 576), + mapOf(x to 3u) to Rational(94453, 168), + mapOf(x to 4u) to Rational(-179203, 1512), + mapOf(x to 5u) to Rational(-16979, 126), + mapOf(x to 6u) to Rational(-13499, 12), + mapOf(y to 1u) to Rational(-4767, 64), + mapOf(x to 1u, y to 1u) to Rational(-58689, 256), + mapOf(x to 2u, y to 1u) to Rational(-757333, 4032), + mapOf(x to 3u, y to 1u) to Rational(-4921205, 4032), + mapOf(x to 4u, y to 1u) to Rational(-2930815, 4032), + mapOf(x to 5u, y to 1u) to Rational(-398803, 1512), + mapOf(x to 6u, y to 1u) to Rational(18835, 36), + mapOf(y to 2u) to Rational(224101, 960), + mapOf(x to 1u, y to 2u) to Rational(9139699, 40320), + mapOf(x to 2u, y to 2u) to Rational(3848803, 5760), + mapOf(x to 3u, y to 2u) to Rational(93102371, 241920), + mapOf(x to 4u, y to 2u) to Rational(-65821229, 141120), + mapOf(x to 5u, y to 2u) to Rational(-15675899, 7056), + mapOf(x to 6u, y to 2u) to Rational(10459, 189), + mapOf(y to 3u) to Rational(2411, 16), + mapOf(x to 1u, y to 3u) to Rational(1294543, 10080), + mapOf(x to 2u, y to 3u) to Rational(-1740199, 1440), + mapOf(x to 3u, y to 3u) to Rational(-266994841, 282240), + mapOf(x to 4u, y to 3u) to Rational(-41261893, 211680), + mapOf(x to 5u, y to 3u) to Rational(1717357, 3528), + mapOf(x to 6u, y to 3u) to Rational(69, 14), + mapOf(y to 4u) to Rational(13231, 360), + mapOf(x to 1u, y to 4u) to Rational(4858831, 25200), + mapOf(x to 2u, y to 4u) to Rational(15565759, 75600), + mapOf(x to 3u, y to 4u) to Rational(-15583391, 35280), + mapOf(x to 4u, y to 4u) to Rational(-13345747, 11760), + mapOf(x to 5u, y to 4u) to Rational(140103, 686), + mapOf(x to 6u, y to 4u) to Rational(-765, 49) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(31409, 576), + mapOf(x to 1u) to Rational(-337099, 1728), + mapOf(x to 2u) to Rational(-211429, 1728), + mapOf(x to 3u) to Rational(-259241, 432), + mapOf(x to 4u) to Rational(-13777, 36), + mapOf(x to 5u) to Rational(-41389, 72), + mapOf(x to 6u) to Rational(-7679, 48), + mapOf(y to 1u) to Rational(-3269, 12), + mapOf(x to 1u, y to 1u) to Rational(629569, 864), + mapOf(x to 2u, y to 1u) to Rational(53867, 324), + mapOf(x to 3u, y to 1u) to Rational(2290577, 1728), + mapOf(x to 4u, y to 1u) to Rational(101507, 216), + mapOf(x to 5u, y to 1u) to Rational(213109, 288), + mapOf(x to 6u, y to 1u) to Rational(17927, 144), + mapOf(y to 2u) to Rational(314587, 1080), + mapOf(x to 1u, y to 2u) to Rational(-109771, 144), + mapOf(x to 2u, y to 2u) to Rational(-6469, 16), + mapOf(x to 3u, y to 2u) to Rational(-298291681, 181440), + mapOf(x to 4u, y to 2u) to Rational(-59147357, 48384), + mapOf(x to 5u, y to 2u) to Rational(-4982365, 6048), + mapOf(x to 6u, y to 2u) to Rational(-18727, 576), + mapOf(y to 3u) to Rational(12379, 90), + mapOf(x to 1u, y to 3u) to Rational(-542911, 1620), + mapOf(x to 2u, y to 3u) to Rational(143123, 1260), + mapOf(x to 3u, y to 3u) to Rational(9859177, 30240), + mapOf(x to 4u, y to 3u) to Rational(9312529, 20160), + mapOf(x to 5u, y to 3u) to Rational(207001, 672), + mapOf(x to 6u, y to 3u) to Rational(203, 24), + mapOf(y to 4u) to Rational(9442, 675), + mapOf(x to 1u, y to 4u) to Rational(-13729, 300), + mapOf(x to 2u, y to 4u) to Rational(-3490471, 25200), + mapOf(x to 3u, y to 4u) to Rational(-333031, 840), + mapOf(x to 4u, y to 4u) to Rational(-7572211, 47040), + mapOf(x to 5u, y to 4u) to Rational(-1189, 56), + mapOf(x to 6u, y to 4u) to Rational(-405, 196) + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(10, 2), + mapOf(x to 1u) to Rational(6, 7), + mapOf(x to 2u) to Rational(-16, 1), + mapOf(y to 1u) to Rational(13, 8), + mapOf(x to 1u, y to 1u) to Rational(-12, 1), + mapOf(x to 2u, y to 1u) to Rational(16, 8), + mapOf(y to 2u) to Rational(10, 4), + mapOf(x to 1u, y to 2u) to Rational(4, 1), + mapOf(x to 2u, y to 2u) to Rational(-11, 3), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1, 4), + mapOf(x to 1u) to Rational(-17, 4), + mapOf(x to 2u) to Rational(-14, 8), + mapOf(y to 1u) to Rational(17, 9), + mapOf(x to 1u, y to 1u) to Rational(1, 3), + mapOf(x to 2u, y to 1u) to Rational(7, 6), + mapOf(y to 2u) to Rational(16, 3), + mapOf(x to 1u, y to 2u) to Rational(-17, 1), + mapOf(x to 2u, y to 2u) to Rational(-10, 8), + ) + ).substitute(RationalField, mapOf( + y to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(14, 4), + mapOf(x to 1u) to Rational(7, 6), + mapOf(x to 2u) to Rational(7, 2), + mapOf(y to 1u) to Rational(-15, 2), + mapOf(x to 1u, y to 1u) to Rational(-13, 8), + mapOf(x to 2u, y to 1u) to Rational(-14, 3), + mapOf(y to 2u) to Rational(-7, 6), + mapOf(x to 1u, y to 2u) to Rational(7, 4), + mapOf(x to 2u, y to 2u) to Rational(9, 7), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-7, 4), + mapOf(x to 1u) to Rational(-6, 3), + mapOf(x to 2u) to Rational(-16, 2), + mapOf(y to 1u) to Rational(-15, 5), + mapOf(x to 1u, y to 1u) to Rational(4, 6), + mapOf(x to 2u, y to 1u) to Rational(5, 4), + mapOf(y to 2u) to Rational(-12, 5), + mapOf(x to 1u, y to 2u) to Rational(-18, 2), + mapOf(x to 2u, y to 2u) to Rational(6, 7), + ) + ), + iota to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(5, 8), + mapOf(x to 1u) to Rational(-12, 6), + mapOf(x to 2u) to Rational(7, 6), + mapOf(y to 1u) to Rational(-10, 4), + mapOf(x to 1u, y to 1u) to Rational(-7, 6), + mapOf(x to 2u, y to 1u) to Rational(8, 9), + mapOf(y to 2u) to Rational(16, 3), + mapOf(x to 1u, y to 2u) to Rational(-13, 4), + mapOf(x to 2u, y to 2u) to Rational(5, 1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(10, 6), + mapOf(x to 1u) to Rational(-18, 6), + mapOf(x to 2u) to Rational(5, 1), + mapOf(y to 1u) to Rational(17, 7), + mapOf(x to 1u, y to 1u) to Rational(8, 4), + mapOf(x to 2u, y to 1u) to Rational(-4, 9), + mapOf(y to 2u) to Rational(-6, 5), + mapOf(x to 1u, y to 2u) to Rational(-15, 8), + mapOf(x to 2u, y to 2u) to Rational(-18, 5), + ) + ), + )), + "test 4'" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-506213, 2800), + mapOf(x to 1u) to Rational(9859, 315), + mapOf(x to 2u) to Rational(17384377, 11340), + mapOf(x to 3u) to Rational(-9662, 63), + mapOf(x to 4u) to Rational(-12563, 4), + mapOf(y to 1u) to Rational(-486293, 22400), + mapOf(x to 1u, y to 1u) to Rational(-6530947, 25200), + mapOf(x to 2u, y to 1u) to Rational(866125, 18144), + mapOf(x to 3u, y to 1u) to Rational(2948747, 2520), + mapOf(x to 4u, y to 1u) to Rational(1196611, 2016), + mapOf(y to 2u) to Rational(-20266021, 117600), + mapOf(x to 1u, y to 2u) to Rational(26656339, 44100), + mapOf(x to 2u, y to 2u) to Rational(19499183, 18144), + mapOf(x to 3u, y to 2u) to Rational(-19801849, 7560), + mapOf(x to 4u, y to 2u) to Rational(-2639635, 1296), + mapOf(y to 3u) to Rational(-5017697, 29400), + mapOf(x to 1u, y to 3u) to Rational(-606007, 1575), + mapOf(x to 2u, y to 3u) to Rational(127494487, 132300), + mapOf(x to 3u, y to 3u) to Rational(166567, 105), + mapOf(x to 4u, y to 3u) to Rational(486403, 18144), + mapOf(y to 4u) to Rational(-32182, 735), + mapOf(x to 1u, y to 4u) to Rational(2420671, 8820), + mapOf(x to 2u, y to 4u) to Rational(-12619193, 26460), + mapOf(x to 3u, y to 4u) to Rational(-6823067, 5670), + mapOf(x to 4u, y to 4u) to Rational(-2311693, 13608), + mapOf(y to 5u) to Rational(-13324, 245), + mapOf(x to 1u, y to 5u) to Rational(1966, 35), + mapOf(x to 2u, y to 5u) to Rational(1052719, 2520), + mapOf(x to 3u, y to 5u) to Rational(19153, 270), + mapOf(x to 4u, y to 5u) to Rational(701, 54), + mapOf(y to 6u) to Rational(4647, 196), + mapOf(x to 1u, y to 6u) to Rational(2197, 28), + mapOf(x to 2u, y to 6u) to Rational(-43853, 336), + mapOf(x to 3u, y to 6u) to Rational(-301, 3), + mapOf(x to 4u, y to 6u) to Rational(34, 3) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-2843, 1600), + mapOf(x to 1u) to Rational(-1483, 240), + mapOf(x to 2u) to Rational(110623, 1296), + mapOf(x to 3u) to Rational(1265, 72), + mapOf(x to 4u) to Rational(-5011, 16), + mapOf(y to 1u) to Rational(47743, 1800), + mapOf(x to 1u, y to 1u) to Rational(619229, 32400), + mapOf(x to 2u, y to 1u) to Rational(-5978369, 58320), + mapOf(x to 3u, y to 1u) to Rational(-86081, 1620), + mapOf(x to 4u, y to 1u) to Rational(6325, 72), + mapOf(y to 2u) to Rational(110951, 3360), + mapOf(x to 1u, y to 2u) to Rational(-9550649, 302400), + mapOf(x to 2u, y to 2u) to Rational(6542933, 85050), + mapOf(x to 3u, y to 2u) to Rational(4708291, 38880), + mapOf(x to 4u, y to 2u) to Rational(-433327, 1296), + mapOf(y to 3u) to Rational(56143, 600), + mapOf(x to 1u, y to 3u) to Rational(94243, 720), + mapOf(x to 2u, y to 3u) to Rational(-46779139, 226800), + mapOf(x to 3u, y to 3u) to Rational(-6948253, 12960), + mapOf(x to 4u, y to 3u) to Rational(-260261, 486), + mapOf(y to 4u) to Rational(-3205317, 19600), + mapOf(x to 1u, y to 4u) to Rational(-201253, 1050), + mapOf(x to 2u, y to 4u) to Rational(332192677, 302400), + mapOf(x to 3u, y to 4u) to Rational(351511, 360), + mapOf(x to 4u, y to 4u) to Rational(-40547, 81), + mapOf(y to 5u) to Rational(-65421, 1960), + mapOf(x to 1u, y to 5u) to Rational(-10118, 35), + mapOf(x to 2u, y to 5u) to Rational(-4341709, 10080), + mapOf(x to 3u, y to 5u) to Rational(-91703, 360), + mapOf(x to 4u, y to 5u) to Rational(-85, 9), + mapOf(y to 6u) to Rational(-25965, 784), + mapOf(x to 1u, y to 6u) to Rational(3351, 16), + mapOf(x to 2u, y to 6u) to Rational(595159, 1344), + mapOf(x to 3u, y to 6u) to Rational(-1381, 12), + mapOf(x to 4u, y to 6u) to Rational(-155, 3) + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(10, 2), + mapOf(x to 1u) to Rational(6, 7), + mapOf(x to 2u) to Rational(-16, 1), + mapOf(y to 1u) to Rational(13, 8), + mapOf(x to 1u, y to 1u) to Rational(-12, 1), + mapOf(x to 2u, y to 1u) to Rational(16, 8), + mapOf(y to 2u) to Rational(10, 4), + mapOf(x to 1u, y to 2u) to Rational(4, 1), + mapOf(x to 2u, y to 2u) to Rational(-11, 3), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1, 4), + mapOf(x to 1u) to Rational(-17, 4), + mapOf(x to 2u) to Rational(-14, 8), + mapOf(y to 1u) to Rational(17, 9), + mapOf(x to 1u, y to 1u) to Rational(1, 3), + mapOf(x to 2u, y to 1u) to Rational(7, 6), + mapOf(y to 2u) to Rational(16, 3), + mapOf(x to 1u, y to 2u) to Rational(-17, 1), + mapOf(x to 2u, y to 2u) to Rational(-10, 8), + ) + ).substitute(RationalField, mapOf( + x to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-17, 5), + mapOf(x to 1u) to Rational(2, 6), + mapOf(x to 2u) to Rational(14, 1), + mapOf(y to 1u) to Rational(-6, 6), + mapOf(x to 1u, y to 1u) to Rational(-7, 3), + mapOf(x to 2u, y to 1u) to Rational(-2, 9), + mapOf(y to 2u) to Rational(-9, 6), + mapOf(x to 1u, y to 2u) to Rational(17, 4), + mapOf(x to 2u, y to 2u) to Rational(2, 1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(5, 4), + mapOf(x to 1u) to Rational(-5, 9), + mapOf(x to 2u) to Rational(-3, 6), + mapOf(y to 1u) to Rational(6, 5), + mapOf(x to 1u, y to 1u) to Rational(14, 5), + mapOf(x to 2u, y to 1u) to Rational(5, 2), + mapOf(y to 2u) to Rational(-18, 7), + mapOf(x to 1u, y to 2u) to Rational(-8, 2), + mapOf(x to 2u, y to 2u) to Rational(18, 9), + ) + ), + )), + "test 5" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-506213, 2800), + mapOf(x to 1u) to Rational(9859, 315), + mapOf(x to 2u) to Rational(17384377, 11340), + mapOf(x to 3u) to Rational(-9662, 63), + mapOf(x to 4u) to Rational(-12563, 4), + mapOf(y to 1u) to Rational(-486293, 22400), + mapOf(x to 1u, y to 1u) to Rational(-6530947, 25200), + mapOf(x to 2u, y to 1u) to Rational(866125, 18144), + mapOf(x to 3u, y to 1u) to Rational(2948747, 2520), + mapOf(x to 4u, y to 1u) to Rational(1196611, 2016), + mapOf(y to 2u) to Rational(-20266021, 117600), + mapOf(x to 1u, y to 2u) to Rational(26656339, 44100), + mapOf(x to 2u, y to 2u) to Rational(19499183, 18144), + mapOf(x to 3u, y to 2u) to Rational(-19801849, 7560), + mapOf(x to 4u, y to 2u) to Rational(-2639635, 1296), + mapOf(y to 3u) to Rational(-5017697, 29400), + mapOf(x to 1u, y to 3u) to Rational(-606007, 1575), + mapOf(x to 2u, y to 3u) to Rational(127494487, 132300), + mapOf(x to 3u, y to 3u) to Rational(166567, 105), + mapOf(x to 4u, y to 3u) to Rational(486403, 18144), + mapOf(y to 4u) to Rational(-32182, 735), + mapOf(x to 1u, y to 4u) to Rational(2420671, 8820), + mapOf(x to 2u, y to 4u) to Rational(-12619193, 26460), + mapOf(x to 3u, y to 4u) to Rational(-6823067, 5670), + mapOf(x to 4u, y to 4u) to Rational(-2311693, 13608), + mapOf(y to 5u) to Rational(-13324, 245), + mapOf(x to 1u, y to 5u) to Rational(1966, 35), + mapOf(x to 2u, y to 5u) to Rational(1052719, 2520), + mapOf(x to 3u, y to 5u) to Rational(19153, 270), + mapOf(x to 4u, y to 5u) to Rational(701, 54), + mapOf(y to 6u) to Rational(4647, 196), + mapOf(x to 1u, y to 6u) to Rational(2197, 28), + mapOf(x to 2u, y to 6u) to Rational(-43853, 336), + mapOf(x to 3u, y to 6u) to Rational(-301, 3), + mapOf(x to 4u, y to 6u) to Rational(34, 3) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-2843, 1600), + mapOf(x to 1u) to Rational(-1483, 240), + mapOf(x to 2u) to Rational(110623, 1296), + mapOf(x to 3u) to Rational(1265, 72), + mapOf(x to 4u) to Rational(-5011, 16), + mapOf(y to 1u) to Rational(47743, 1800), + mapOf(x to 1u, y to 1u) to Rational(619229, 32400), + mapOf(x to 2u, y to 1u) to Rational(-5978369, 58320), + mapOf(x to 3u, y to 1u) to Rational(-86081, 1620), + mapOf(x to 4u, y to 1u) to Rational(6325, 72), + mapOf(y to 2u) to Rational(110951, 3360), + mapOf(x to 1u, y to 2u) to Rational(-9550649, 302400), + mapOf(x to 2u, y to 2u) to Rational(6542933, 85050), + mapOf(x to 3u, y to 2u) to Rational(4708291, 38880), + mapOf(x to 4u, y to 2u) to Rational(-433327, 1296), + mapOf(y to 3u) to Rational(56143, 600), + mapOf(x to 1u, y to 3u) to Rational(94243, 720), + mapOf(x to 2u, y to 3u) to Rational(-46779139, 226800), + mapOf(x to 3u, y to 3u) to Rational(-6948253, 12960), + mapOf(x to 4u, y to 3u) to Rational(-260261, 486), + mapOf(y to 4u) to Rational(-3205317, 19600), + mapOf(x to 1u, y to 4u) to Rational(-201253, 1050), + mapOf(x to 2u, y to 4u) to Rational(332192677, 302400), + mapOf(x to 3u, y to 4u) to Rational(351511, 360), + mapOf(x to 4u, y to 4u) to Rational(-40547, 81), + mapOf(y to 5u) to Rational(-65421, 1960), + mapOf(x to 1u, y to 5u) to Rational(-10118, 35), + mapOf(x to 2u, y to 5u) to Rational(-4341709, 10080), + mapOf(x to 3u, y to 5u) to Rational(-91703, 360), + mapOf(x to 4u, y to 5u) to Rational(-85, 9), + mapOf(y to 6u) to Rational(-25965, 784), + mapOf(x to 1u, y to 6u) to Rational(3351, 16), + mapOf(x to 2u, y to 6u) to Rational(595159, 1344), + mapOf(x to 3u, y to 6u) to Rational(-1381, 12), + mapOf(x to 4u, y to 6u) to Rational(-155, 3) + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(10, 2), + mapOf(x to 1u) to Rational(6, 7), + mapOf(x to 2u) to Rational(-16, 1), + mapOf(y to 1u) to Rational(13, 8), + mapOf(x to 1u, y to 1u) to Rational(-12, 1), + mapOf(x to 2u, y to 1u) to Rational(16, 8), + mapOf(y to 2u) to Rational(10, 4), + mapOf(x to 1u, y to 2u) to Rational(4, 1), + mapOf(x to 2u, y to 2u) to Rational(-11, 3), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1, 4), + mapOf(x to 1u) to Rational(-17, 4), + mapOf(x to 2u) to Rational(-14, 8), + mapOf(y to 1u) to Rational(17, 9), + mapOf(x to 1u, y to 1u) to Rational(1, 3), + mapOf(x to 2u, y to 1u) to Rational(7, 6), + mapOf(y to 2u) to Rational(16, 3), + mapOf(x to 1u, y to 2u) to Rational(-17, 1), + mapOf(x to 2u, y to 2u) to Rational(-10, 8), + ) + ).substitute(RationalField, mapOf( + x to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-17, 5), + mapOf(x to 1u) to Rational(2, 6), + mapOf(x to 2u) to Rational(14, 1), + mapOf(y to 1u) to Rational(-6, 6), + mapOf(x to 1u, y to 1u) to Rational(-7, 3), + mapOf(x to 2u, y to 1u) to Rational(-2, 9), + mapOf(y to 2u) to Rational(-9, 6), + mapOf(x to 1u, y to 2u) to Rational(17, 4), + mapOf(x to 2u, y to 2u) to Rational(2, 1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(5, 4), + mapOf(x to 1u) to Rational(-5, 9), + mapOf(x to 2u) to Rational(-3, 6), + mapOf(y to 1u) to Rational(6, 5), + mapOf(x to 1u, y to 1u) to Rational(14, 5), + mapOf(x to 2u, y to 1u) to Rational(5, 2), + mapOf(y to 2u) to Rational(-18, 7), + mapOf(x to 1u, y to 2u) to Rational(-8, 2), + mapOf(x to 2u, y to 2u) to Rational(18, 9), + ) + ), + iota to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(5, 8), + mapOf(x to 1u) to Rational(-12, 6), + mapOf(x to 2u) to Rational(7, 6), + mapOf(y to 1u) to Rational(-10, 4), + mapOf(x to 1u, y to 1u) to Rational(-7, 6), + mapOf(x to 2u, y to 1u) to Rational(8, 9), + mapOf(y to 2u) to Rational(16, 3), + mapOf(x to 1u, y to 2u) to Rational(-13, 4), + mapOf(x to 2u, y to 2u) to Rational(5, 1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(10, 6), + mapOf(x to 1u) to Rational(-18, 6), + mapOf(x to 2u) to Rational(5, 1), + mapOf(y to 1u) to Rational(17, 7), + mapOf(x to 1u, y to 1u) to Rational(8, 4), + mapOf(x to 2u, y to 1u) to Rational(-4, 9), + mapOf(y to 2u) to Rational(-6, 5), + mapOf(x to 1u, y to 2u) to Rational(-15, 8), + mapOf(x to 2u, y to 2u) to Rational(-18, 5), + ) + ), + )), + "test 5'" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(10, 2), + mapOf(x to 1u) to Rational(6, 7), + mapOf(x to 2u) to Rational(-16, 1), + mapOf(y to 1u) to Rational(13, 8), + mapOf(x to 1u, y to 1u) to Rational(-12, 1), + mapOf(x to 2u, y to 1u) to Rational(16, 8), + mapOf(y to 2u) to Rational(10, 4), + mapOf(x to 1u, y to 2u) to Rational(4, 1), + mapOf(x to 2u, y to 2u) to Rational(-11, 3), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1, 4), + mapOf(x to 1u) to Rational(-17, 4), + mapOf(x to 2u) to Rational(-14, 8), + mapOf(y to 1u) to Rational(17, 9), + mapOf(x to 1u, y to 1u) to Rational(1, 3), + mapOf(x to 2u, y to 1u) to Rational(7, 6), + mapOf(y to 2u) to Rational(16, 3), + mapOf(x to 1u, y to 2u) to Rational(-17, 1), + mapOf(x to 2u, y to 2u) to Rational(-10, 8), + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(10, 2), + mapOf(x to 1u) to Rational(6, 7), + mapOf(x to 2u) to Rational(-16, 1), + mapOf(y to 1u) to Rational(13, 8), + mapOf(x to 1u, y to 1u) to Rational(-12, 1), + mapOf(x to 2u, y to 1u) to Rational(16, 8), + mapOf(y to 2u) to Rational(10, 4), + mapOf(x to 1u, y to 2u) to Rational(4, 1), + mapOf(x to 2u, y to 2u) to Rational(-11, 3), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1, 4), + mapOf(x to 1u) to Rational(-17, 4), + mapOf(x to 2u) to Rational(-14, 8), + mapOf(y to 1u) to Rational(17, 9), + mapOf(x to 1u, y to 1u) to Rational(1, 3), + mapOf(x to 2u, y to 1u) to Rational(7, 6), + mapOf(y to 2u) to Rational(16, 3), + mapOf(x to 1u, y to 2u) to Rational(-17, 1), + mapOf(x to 2u, y to 2u) to Rational(-10, 8), + ) + ).substitute(RationalField, mapOf>()), + "test 6" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(10, 2), + mapOf(x to 1u) to Rational(6, 7), + mapOf(x to 2u) to Rational(-16, 1), + mapOf(y to 1u) to Rational(13, 8), + mapOf(x to 1u, y to 1u) to Rational(-12, 1), + mapOf(x to 2u, y to 1u) to Rational(16, 8), + mapOf(y to 2u) to Rational(10, 4), + mapOf(x to 1u, y to 2u) to Rational(4, 1), + mapOf(x to 2u, y to 2u) to Rational(-11, 3), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1, 4), + mapOf(x to 1u) to Rational(-17, 4), + mapOf(x to 2u) to Rational(-14, 8), + mapOf(y to 1u) to Rational(17, 9), + mapOf(x to 1u, y to 1u) to Rational(1, 3), + mapOf(x to 2u, y to 1u) to Rational(7, 6), + mapOf(y to 2u) to Rational(16, 3), + mapOf(x to 1u, y to 2u) to Rational(-17, 1), + mapOf(x to 2u, y to 2u) to Rational(-10, 8), + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(10, 2), + mapOf(x to 1u) to Rational(6, 7), + mapOf(x to 2u) to Rational(-16, 1), + mapOf(y to 1u) to Rational(13, 8), + mapOf(x to 1u, y to 1u) to Rational(-12, 1), + mapOf(x to 2u, y to 1u) to Rational(16, 8), + mapOf(y to 2u) to Rational(10, 4), + mapOf(x to 1u, y to 2u) to Rational(4, 1), + mapOf(x to 2u, y to 2u) to Rational(-11, 3), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1, 4), + mapOf(x to 1u) to Rational(-17, 4), + mapOf(x to 2u) to Rational(-14, 8), + mapOf(y to 1u) to Rational(17, 9), + mapOf(x to 1u, y to 1u) to Rational(1, 3), + mapOf(x to 2u, y to 1u) to Rational(7, 6), + mapOf(y to 2u) to Rational(16, 3), + mapOf(x to 1u, y to 2u) to Rational(-17, 1), + mapOf(x to 2u, y to 2u) to Rational(-10, 8), + ) + ).substitute(RationalField, mapOf( + iota to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(5, 8), + mapOf(x to 1u) to Rational(-12, 6), + mapOf(x to 2u) to Rational(7, 6), + mapOf(y to 1u) to Rational(-10, 4), + mapOf(x to 1u, y to 1u) to Rational(-7, 6), + mapOf(x to 2u, y to 1u) to Rational(8, 9), + mapOf(y to 2u) to Rational(16, 3), + mapOf(x to 1u, y to 2u) to Rational(-13, 4), + mapOf(x to 2u, y to 2u) to Rational(5, 1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(10, 6), + mapOf(x to 1u) to Rational(-18, 6), + mapOf(x to 2u) to Rational(5, 1), + mapOf(y to 1u) to Rational(17, 7), + mapOf(x to 1u, y to 1u) to Rational(8, 4), + mapOf(x to 2u, y to 1u) to Rational(-4, 9), + mapOf(y to 2u) to Rational(-6, 5), + mapOf(x to 1u, y to 2u) to Rational(-15, 8), + mapOf(x to 2u, y to 2u) to Rational(-18, 5), + ) + ), + )), + "test 6'" + ) + } + @Test + @OptIn(UnstableKMathAPI::class) + fun test_Polynomial_derivativeWithRespectTo_variable() { + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-2), + mapOf(x to 1u) to Rational(2), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).derivativeWithRespectTo(RationalField, x), + "test 1" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-2, 3), + mapOf(x to 1u) to Rational(1, 1), + mapOf(x to 2u) to Rational(-33, 8), + mapOf(x to 3u) to Rational(72, 1), + mapOf(y to 1u) to Rational(2, 3), + mapOf(x to 1u, y to 1u) to Rational(-22, 1), + mapOf(x to 2u, y to 1u) to Rational(-1, 1), + mapOf(x to 3u, y to 1u) to Rational(-36, 1), + mapOf(y to 2u) to Rational(-8, 5), + mapOf(x to 1u, y to 2u) to Rational(-1, 4), + mapOf(x to 2u, y to 2u) to Rational(12, 7), + mapOf(x to 3u, y to 2u) to Rational(-2, 1), + mapOf(y to 3u) to Rational(16, 8), + mapOf(x to 1u, y to 3u) to Rational(-4, 1), + mapOf(x to 2u, y to 3u) to Rational(9, 2), + mapOf(x to 3u, y to 3u) to Rational(20, 9), + mapOf(y to 4u) to Rational(-10, 1), + mapOf(x to 1u, y to 4u) to Rational(-14, 1), + mapOf(x to 2u, y to 4u) to Rational(3, 7), + mapOf(x to 3u, y to 4u) to Rational(20, 1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(-11, 8), + mapOf(x to 4u) to Rational(18, 1), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(-1, 3), + mapOf(x to 4u, y to 1u) to Rational(-18, 2), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(3, 7), + mapOf(x to 1u, y to 3u) to Rational(16, 8), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(-18, 8), + mapOf(x to 1u, y to 4u) to Rational(-10, 1), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).derivativeWithRespectTo(RationalField, x), + "test 2a" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-18, 3), + mapOf(x to 1u) to Rational(2, 3), + mapOf(x to 2u) to Rational(-11, 1), + mapOf(x to 3u) to Rational(-1, 3), + mapOf(x to 4u) to Rational(-18, 2), + mapOf(y to 1u) to Rational(-20, 3), + mapOf(x to 1u, y to 1u) to Rational(-16, 5), + mapOf(x to 2u, y to 1u) to Rational(-1, 4), + mapOf(x to 3u, y to 1u) to Rational(8, 7), + mapOf(x to 4u, y to 1u) to Rational(-1, 1), + mapOf(y to 2u) to Rational(9, 7), + mapOf(x to 1u, y to 2u) to Rational(6, 1), + mapOf(x to 2u, y to 2u) to Rational(-6, 1), + mapOf(x to 3u, y to 2u) to Rational(9, 2), + mapOf(x to 4u, y to 2u) to Rational(5, 3), + mapOf(y to 3u) to Rational(-9, 1), + mapOf(x to 1u, y to 3u) to Rational(-40, 1), + mapOf(x to 2u, y to 3u) to Rational(-28, 1), + mapOf(x to 3u, y to 3u) to Rational(4, 7), + mapOf(x to 4u, y to 3u) to Rational(20, 1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(-11, 8), + mapOf(x to 4u) to Rational(18, 1), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(-1, 3), + mapOf(x to 4u, y to 1u) to Rational(-18, 2), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(3, 7), + mapOf(x to 1u, y to 3u) to Rational(16, 8), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(-18, 8), + mapOf(x to 1u, y to 4u) to Rational(-10, 1), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).derivativeWithRespectTo(RationalField, y), + "test 2b" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(0), + mapOf(x to 1u) to Rational(0), + mapOf(x to 2u) to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(y to 1u) to Rational(0), + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(-1, 4), + mapOf(x to 2u, y to 2u) to Rational(12, 7), + mapOf(x to 3u, y to 2u) to Rational(-2, 1), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(-4, 1), + mapOf(x to 2u, y to 3u) to Rational(9, 2), + mapOf(x to 3u, y to 3u) to Rational(20, 9), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(-14, 1), + mapOf(x to 2u, y to 4u) to Rational(3, 7), + mapOf(x to 3u, y to 4u) to Rational(20, 1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(0), + mapOf(x to 1u) to Rational(0), + mapOf(x to 2u) to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(0), + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).derivativeWithRespectTo(RationalField, x), + "test 3a" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(0), + mapOf(x to 1u) to Rational(0), + mapOf(x to 2u) to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(0), + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(-1, 4), + mapOf(x to 3u, y to 1u) to Rational(8, 7), + mapOf(x to 4u, y to 1u) to Rational(-1, 1), + mapOf(y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(-6, 1), + mapOf(x to 3u, y to 2u) to Rational(9, 2), + mapOf(x to 4u, y to 2u) to Rational(5, 3), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(-28, 1), + mapOf(x to 3u, y to 3u) to Rational(4, 7), + mapOf(x to 4u, y to 3u) to Rational(20, 1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(0), + mapOf(x to 1u) to Rational(0), + mapOf(x to 2u) to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(0), + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).derivativeWithRespectTo(RationalField, y), + "test 3b" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-2, 3), + mapOf(x to 1u) to Rational(1, 1), + mapOf(x to 2u) to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(y to 1u) to Rational(2, 3), + mapOf(x to 1u, y to 1u) to Rational(-22, 1), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(-8, 5), + mapOf(x to 1u, y to 2u) to Rational(-1, 4), + mapOf(x to 2u, y to 2u) to Rational(0), + mapOf(x to 3u, y to 2u) to Rational(0), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(0), + mapOf(x to 3u, y to 3u) to Rational(0), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(0), + mapOf(x to 3u, y to 4u) to Rational(0), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(0), + mapOf(x to 4u, y to 2u) to Rational(0), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(0), + mapOf(x to 3u, y to 3u) to Rational(0), + mapOf(x to 4u, y to 3u) to Rational(0), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(0), + mapOf(x to 3u, y to 4u) to Rational(0), + mapOf(x to 4u, y to 4u) to Rational(0), + ).derivativeWithRespectTo(RationalField, x), + "test 4a" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-18, 3), + mapOf(x to 1u) to Rational(2, 3), + mapOf(x to 2u) to Rational(-11, 1), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(-20, 3), + mapOf(x to 1u, y to 1u) to Rational(-16, 5), + mapOf(x to 2u, y to 1u) to Rational(-1, 4), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(0), + mapOf(x to 3u, y to 2u) to Rational(0), + mapOf(x to 4u, y to 2u) to Rational(0), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(0), + mapOf(x to 3u, y to 3u) to Rational(0), + mapOf(x to 4u, y to 3u) to Rational(0), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(0), + mapOf(x to 4u, y to 2u) to Rational(0), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(0), + mapOf(x to 3u, y to 3u) to Rational(0), + mapOf(x to 4u, y to 3u) to Rational(0), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(0), + mapOf(x to 3u, y to 4u) to Rational(0), + mapOf(x to 4u, y to 4u) to Rational(0), + ).derivativeWithRespectTo(RationalField, y), + "test 4b" + ) + assertEquals( + LabeledPolynomialAsIs(), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(-11, 8), + mapOf(x to 4u) to Rational(18, 1), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(-1, 3), + mapOf(x to 4u, y to 1u) to Rational(-18, 2), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(3, 7), + mapOf(x to 1u, y to 3u) to Rational(16, 8), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(-18, 8), + mapOf(x to 1u, y to 4u) to Rational(-10, 1), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).derivativeWithRespectTo(RationalField, iota), + "test 5" + ) + } + @Test + @OptIn(UnstableKMathAPI::class) + fun test_Polynomial_nthDerivativeWithRespectTo_variable_order() { + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-2), + mapOf(x to 1u) to Rational(2), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, x, 1u), + "test 1" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, x, 0u), + "test 2" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(2), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, x, 2u), + "test 3" + ) + assertEquals( + LabeledPolynomialAsIs(), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, x, 3u), + "test 4" + ) + assertEquals( + LabeledPolynomialAsIs(), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, x, 4u), + "test 5" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, y, 0u), + "test 6" + ) + assertEquals( + LabeledPolynomialAsIs(), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, y, 1u), + "test 7" + ) + assertEquals( + LabeledPolynomialAsIs(), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, y, 2u), + "test 8" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(1, 1), + mapOf(x to 1u) to Rational(-33, 4), + mapOf(x to 2u) to Rational(216, 1), + mapOf(y to 1u) to Rational(-22, 1), + mapOf(x to 1u, y to 1u) to Rational(-2, 1), + mapOf(x to 2u, y to 1u) to Rational(-108, 1), + mapOf(y to 2u) to Rational(-1, 4), + mapOf(x to 1u, y to 2u) to Rational(24, 7), + mapOf(x to 2u, y to 2u) to Rational(-6, 1), + mapOf(y to 3u) to Rational(-4, 1), + mapOf(x to 1u, y to 3u) to Rational(9, 1), + mapOf(x to 2u, y to 3u) to Rational(20, 3), + mapOf(y to 4u) to Rational(-14, 1), + mapOf(x to 1u, y to 4u) to Rational(6, 7), + mapOf(x to 2u, y to 4u) to Rational(60, 1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(-11, 8), + mapOf(x to 4u) to Rational(18, 1), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(-1, 3), + mapOf(x to 4u, y to 1u) to Rational(-18, 2), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(3, 7), + mapOf(x to 1u, y to 3u) to Rational(16, 8), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(-18, 8), + mapOf(x to 1u, y to 4u) to Rational(-10, 1), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).nthDerivativeWithRespectTo(RationalField, x, 2u), + "test 9a" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-20, 3), + mapOf(x to 1u) to Rational(-16, 5), + mapOf(x to 2u) to Rational(-1, 4), + mapOf(x to 3u) to Rational(8, 7), + mapOf(x to 4u) to Rational(-1, 1), + mapOf(y to 1u) to Rational(18, 7), + mapOf(x to 1u, y to 1u) to Rational(12, 1), + mapOf(x to 2u, y to 1u) to Rational(-12, 1), + mapOf(x to 3u, y to 1u) to Rational(9, 1), + mapOf(x to 4u, y to 1u) to Rational(10, 3), + mapOf(y to 2u) to Rational(-27, 1), + mapOf(x to 1u, y to 2u) to Rational(-120, 1), + mapOf(x to 2u, y to 2u) to Rational(-84, 1), + mapOf(x to 3u, y to 2u) to Rational(12, 7), + mapOf(x to 4u, y to 2u) to Rational(60, 1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(-11, 8), + mapOf(x to 4u) to Rational(18, 1), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(-1, 3), + mapOf(x to 4u, y to 1u) to Rational(-18, 2), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(3, 7), + mapOf(x to 1u, y to 3u) to Rational(16, 8), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(-18, 8), + mapOf(x to 1u, y to 4u) to Rational(-10, 1), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).nthDerivativeWithRespectTo(RationalField, y, 2u), + "test 9b" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(0), + mapOf(x to 1u) to Rational(0), + mapOf(x to 2u) to Rational(0), + mapOf(y to 1u) to Rational(0), + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(-1, 4), + mapOf(x to 1u, y to 2u) to Rational(24, 7), + mapOf(x to 2u, y to 2u) to Rational(-6, 1), + mapOf(y to 3u) to Rational(-4, 1), + mapOf(x to 1u, y to 3u) to Rational(9, 1), + mapOf(x to 2u, y to 3u) to Rational(20, 3), + mapOf(y to 4u) to Rational(-14, 1), + mapOf(x to 1u, y to 4u) to Rational(6, 7), + mapOf(x to 2u, y to 4u) to Rational(60, 1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(0), + mapOf(x to 1u) to Rational(0), + mapOf(x to 2u) to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(0), + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).nthDerivativeWithRespectTo(RationalField, x, 2u), + "test 10a" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(0), + mapOf(x to 1u) to Rational(0), + mapOf(x to 2u) to Rational(-1, 4), + mapOf(x to 3u) to Rational(8, 7), + mapOf(x to 4u) to Rational(-1, 1), + mapOf(y to 1u) to Rational(0), + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(-12, 1), + mapOf(x to 3u, y to 1u) to Rational(9, 1), + mapOf(x to 4u, y to 1u) to Rational(10, 3), + mapOf(y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(-84, 1), + mapOf(x to 3u, y to 2u) to Rational(12, 7), + mapOf(x to 4u, y to 2u) to Rational(60, 1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(0), + mapOf(x to 1u) to Rational(0), + mapOf(x to 2u) to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(0), + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).nthDerivativeWithRespectTo(RationalField, y, 2u), + "test 10b" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(1, 1), + mapOf(x to 1u) to Rational(0), + mapOf(x to 2u) to Rational(0), + mapOf(y to 1u) to Rational(-22, 1), + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(-1, 4), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(0), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(0), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(0), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(0), + mapOf(x to 4u, y to 2u) to Rational(0), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(0), + mapOf(x to 3u, y to 3u) to Rational(0), + mapOf(x to 4u, y to 3u) to Rational(0), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(0), + mapOf(x to 3u, y to 4u) to Rational(0), + mapOf(x to 4u, y to 4u) to Rational(0), + ).nthDerivativeWithRespectTo(RationalField, x, 2u), + "test 11a" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-20, 3), + mapOf(x to 1u) to Rational(-16, 5), + mapOf(x to 2u) to Rational(-1, 4), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(0), + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(0), + mapOf(x to 3u, y to 2u) to Rational(0), + mapOf(x to 4u, y to 2u) to Rational(0), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(0), + mapOf(x to 4u, y to 2u) to Rational(0), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(0), + mapOf(x to 3u, y to 3u) to Rational(0), + mapOf(x to 4u, y to 3u) to Rational(0), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(0), + mapOf(x to 3u, y to 4u) to Rational(0), + mapOf(x to 4u, y to 4u) to Rational(0), + ).nthDerivativeWithRespectTo(RationalField, y, 2u), + "test 11b" + ) + } + @Test + @OptIn(UnstableKMathAPI::class) + fun test_Polynomial_nthDerivativeWithRespectTo_variablesAndOrders() { + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-2), + mapOf(x to 1u) to Rational(2), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, mapOf(x to 1u)), + "test 1" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, mapOf(x to 0u)), + "test 2" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(2), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, mapOf(x to 2u)), + "test 3" + ) + assertEquals( + LabeledPolynomialAsIs(), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, mapOf(x to 3u)), + "test 4" + ) + assertEquals( + LabeledPolynomialAsIs(), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, mapOf(x to 4u)), + "test 5" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, mapOf(y to 0u)), + "test 6" + ) + assertEquals( + LabeledPolynomialAsIs(), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, mapOf(y to 1u)), + "test 7" + ) + assertEquals( + LabeledPolynomialAsIs(), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, mapOf(y to 2u)), + "test 8" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, mapOf()), + "test 9" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-2), + mapOf(x to 1u) to Rational(2), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, mapOf( + x to 1u, + y to 0u + )), + "test 10" + ) + assertEquals( + LabeledPolynomialAsIs(), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, mapOf( + x to 0u, + y to 1u + )), + "test 11" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(1, 1), + mapOf(x to 1u) to Rational(-33, 4), + mapOf(x to 2u) to Rational(216, 1), + mapOf(y to 1u) to Rational(-22, 1), + mapOf(x to 1u, y to 1u) to Rational(-2, 1), + mapOf(x to 2u, y to 1u) to Rational(-108, 1), + mapOf(y to 2u) to Rational(-1, 4), + mapOf(x to 1u, y to 2u) to Rational(24, 7), + mapOf(x to 2u, y to 2u) to Rational(-6, 1), + mapOf(y to 3u) to Rational(-4, 1), + mapOf(x to 1u, y to 3u) to Rational(9, 1), + mapOf(x to 2u, y to 3u) to Rational(20, 3), + mapOf(y to 4u) to Rational(-14, 1), + mapOf(x to 1u, y to 4u) to Rational(6, 7), + mapOf(x to 2u, y to 4u) to Rational(60, 1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(-11, 8), + mapOf(x to 4u) to Rational(18, 1), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(-1, 3), + mapOf(x to 4u, y to 1u) to Rational(-18, 2), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(3, 7), + mapOf(x to 1u, y to 3u) to Rational(16, 8), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(-18, 8), + mapOf(x to 1u, y to 4u) to Rational(-10, 1), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).nthDerivativeWithRespectTo(RationalField, mapOf(x to 2u)), + "test 12a" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(2, 3), + mapOf(x to 1u) to Rational(-22, 1), + mapOf(x to 2u) to Rational(-1, 1), + mapOf(x to 3u) to Rational(-36, 1), + mapOf(y to 1u) to Rational(-16, 5), + mapOf(x to 1u, y to 1u) to Rational(-1, 2), + mapOf(x to 2u, y to 1u) to Rational(24, 7), + mapOf(x to 3u, y to 1u) to Rational(-4, 1), + mapOf(y to 2u) to Rational(6, 1), + mapOf(x to 1u, y to 2u) to Rational(-12, 1), + mapOf(x to 2u, y to 2u) to Rational(27, 2), + mapOf(x to 3u, y to 2u) to Rational(20, 3), + mapOf(y to 3u) to Rational(-40, 1), + mapOf(x to 1u, y to 3u) to Rational(-56, 1), + mapOf(x to 2u, y to 3u) to Rational(12, 7), + mapOf(x to 3u, y to 3u) to Rational(80, 1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(-11, 8), + mapOf(x to 4u) to Rational(18, 1), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(-1, 3), + mapOf(x to 4u, y to 1u) to Rational(-18, 2), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(3, 7), + mapOf(x to 1u, y to 3u) to Rational(16, 8), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(-18, 8), + mapOf(x to 1u, y to 4u) to Rational(-10, 1), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).nthDerivativeWithRespectTo(RationalField, mapOf(x to 1u, y to 1u)), + "test 12b" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-20, 3), + mapOf(x to 1u) to Rational(-16, 5), + mapOf(x to 2u) to Rational(-1, 4), + mapOf(x to 3u) to Rational(8, 7), + mapOf(x to 4u) to Rational(-1, 1), + mapOf(y to 1u) to Rational(18, 7), + mapOf(x to 1u, y to 1u) to Rational(12, 1), + mapOf(x to 2u, y to 1u) to Rational(-12, 1), + mapOf(x to 3u, y to 1u) to Rational(9, 1), + mapOf(x to 4u, y to 1u) to Rational(10, 3), + mapOf(y to 2u) to Rational(-27, 1), + mapOf(x to 1u, y to 2u) to Rational(-120, 1), + mapOf(x to 2u, y to 2u) to Rational(-84, 1), + mapOf(x to 3u, y to 2u) to Rational(12, 7), + mapOf(x to 4u, y to 2u) to Rational(60, 1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(-11, 8), + mapOf(x to 4u) to Rational(18, 1), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(-1, 3), + mapOf(x to 4u, y to 1u) to Rational(-18, 2), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(3, 7), + mapOf(x to 1u, y to 3u) to Rational(16, 8), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(-18, 8), + mapOf(x to 1u, y to 4u) to Rational(-10, 1), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).nthDerivativeWithRespectTo(RationalField, mapOf(y to 2u)), + "test 12c" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(0), + mapOf(x to 1u) to Rational(0), + mapOf(x to 2u) to Rational(0), + mapOf(y to 1u) to Rational(0), + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(-1, 4), + mapOf(x to 1u, y to 2u) to Rational(24, 7), + mapOf(x to 2u, y to 2u) to Rational(-6, 1), + mapOf(y to 3u) to Rational(-4, 1), + mapOf(x to 1u, y to 3u) to Rational(9, 1), + mapOf(x to 2u, y to 3u) to Rational(20, 3), + mapOf(y to 4u) to Rational(-14, 1), + mapOf(x to 1u, y to 4u) to Rational(6, 7), + mapOf(x to 2u, y to 4u) to Rational(60, 1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(0), + mapOf(x to 1u) to Rational(0), + mapOf(x to 2u) to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(0), + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).nthDerivativeWithRespectTo(RationalField, mapOf(x to 2u)), + "test 13a" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(0), + mapOf(x to 1u) to Rational(0), + mapOf(x to 2u) to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(y to 1u) to Rational(0), + mapOf(x to 1u, y to 1u) to Rational(-1, 2), + mapOf(x to 2u, y to 1u) to Rational(24, 7), + mapOf(x to 3u, y to 1u) to Rational(-4, 1), + mapOf(y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(-12, 1), + mapOf(x to 2u, y to 2u) to Rational(27, 2), + mapOf(x to 3u, y to 2u) to Rational(20, 3), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(-56, 1), + mapOf(x to 2u, y to 3u) to Rational(12, 7), + mapOf(x to 3u, y to 3u) to Rational(80, 1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(0), + mapOf(x to 1u) to Rational(0), + mapOf(x to 2u) to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(0), + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).nthDerivativeWithRespectTo(RationalField, mapOf(x to 1u, y to 1u)), + "test 13b" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(0), + mapOf(x to 1u) to Rational(0), + mapOf(x to 2u) to Rational(-1, 4), + mapOf(x to 3u) to Rational(8, 7), + mapOf(x to 4u) to Rational(-1, 1), + mapOf(y to 1u) to Rational(0), + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(-12, 1), + mapOf(x to 3u, y to 1u) to Rational(9, 1), + mapOf(x to 4u, y to 1u) to Rational(10, 3), + mapOf(y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(-84, 1), + mapOf(x to 3u, y to 2u) to Rational(12, 7), + mapOf(x to 4u, y to 2u) to Rational(60, 1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(0), + mapOf(x to 1u) to Rational(0), + mapOf(x to 2u) to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(0), + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).nthDerivativeWithRespectTo(RationalField, mapOf(y to 2u)), + "test 13c" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(1, 1), + mapOf(x to 1u) to Rational(0), + mapOf(x to 2u) to Rational(0), + mapOf(y to 1u) to Rational(-22, 1), + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(-1, 4), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(0), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(0), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(0), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(0), + mapOf(x to 4u, y to 2u) to Rational(0), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(0), + mapOf(x to 3u, y to 3u) to Rational(0), + mapOf(x to 4u, y to 3u) to Rational(0), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(0), + mapOf(x to 3u, y to 4u) to Rational(0), + mapOf(x to 4u, y to 4u) to Rational(0), + ).nthDerivativeWithRespectTo(RationalField, mapOf(x to 2u)), + "test 14a" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(2, 3), + mapOf(x to 1u) to Rational(-22, 1), + mapOf(x to 2u) to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(y to 1u) to Rational(-16, 5), + mapOf(x to 1u, y to 1u) to Rational(-1, 2), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(0), + mapOf(x to 3u, y to 2u) to Rational(0), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(0), + mapOf(x to 3u, y to 3u) to Rational(0), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(0), + mapOf(x to 4u, y to 2u) to Rational(0), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(0), + mapOf(x to 3u, y to 3u) to Rational(0), + mapOf(x to 4u, y to 3u) to Rational(0), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(0), + mapOf(x to 3u, y to 4u) to Rational(0), + mapOf(x to 4u, y to 4u) to Rational(0), + ).nthDerivativeWithRespectTo(RationalField, mapOf(x to 1u, y to 1u)), + "test 14b" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-20, 3), + mapOf(x to 1u) to Rational(-16, 5), + mapOf(x to 2u) to Rational(-1, 4), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(0), + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(0), + mapOf(x to 3u, y to 2u) to Rational(0), + mapOf(x to 4u, y to 2u) to Rational(0), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(0), + mapOf(x to 4u, y to 2u) to Rational(0), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(0), + mapOf(x to 3u, y to 3u) to Rational(0), + mapOf(x to 4u, y to 3u) to Rational(0), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(0), + mapOf(x to 3u, y to 4u) to Rational(0), + mapOf(x to 4u, y to 4u) to Rational(0), + ).nthDerivativeWithRespectTo(RationalField, mapOf(y to 2u)), + "test 14c" + ) + } + @Test + @OptIn(UnstableKMathAPI::class) + fun test_Polynomial_antiderivativeWithRespectTo_variable() { + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(1), + mapOf(x to 2u) to Rational(-1), + mapOf(x to 3u) to Rational(1, 3), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).antiderivativeWithRespectTo(RationalField, x), + "test 1" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(-6, 8), + mapOf(x to 2u) to Rational(-1, 3), + mapOf(x to 3u) to Rational(1, 6), + mapOf(x to 4u) to Rational(-11, 32), + mapOf(x to 5u) to Rational(18, 5), + mapOf(x to 1u, y to 1u) to Rational(-18, 3), + mapOf(x to 2u, y to 1u) to Rational(1, 3), + mapOf(x to 3u, y to 1u) to Rational(-11, 3), + mapOf(x to 4u, y to 1u) to Rational(-1, 12), + mapOf(x to 5u, y to 1u) to Rational(-18, 10), + mapOf(x to 1u, y to 2u) to Rational(-10, 3), + mapOf(x to 2u, y to 2u) to Rational(-4, 5), + mapOf(x to 3u, y to 2u) to Rational(-1, 24), + mapOf(x to 4u, y to 2u) to Rational(1, 7), + mapOf(x to 5u, y to 2u) to Rational(-1, 10), + mapOf(x to 1u, y to 3u) to Rational(3, 7), + mapOf(x to 2u, y to 3u) to Rational(1, 1), + mapOf(x to 3u, y to 3u) to Rational(-2, 3), + mapOf(x to 4u, y to 3u) to Rational(3, 8), + mapOf(x to 5u, y to 3u) to Rational(1, 9), + mapOf(x to 1u, y to 4u) to Rational(-18, 8), + mapOf(x to 2u, y to 4u) to Rational(-5, 1), + mapOf(x to 3u, y to 4u) to Rational(-7, 3), + mapOf(x to 4u, y to 4u) to Rational(1, 28), + mapOf(x to 5u, y to 4u) to Rational(1, 1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(-11, 8), + mapOf(x to 4u) to Rational(18, 1), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(-1, 3), + mapOf(x to 4u, y to 1u) to Rational(-18, 2), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(3, 7), + mapOf(x to 1u, y to 3u) to Rational(16, 8), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(-18, 8), + mapOf(x to 1u, y to 4u) to Rational(-10, 1), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).antiderivativeWithRespectTo(RationalField, x), + "test 2a" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(y to 1u) to Rational(-6, 8), + mapOf(x to 1u, y to 1u) to Rational(-2, 3), + mapOf(x to 2u, y to 1u) to Rational(1, 2), + mapOf(x to 3u, y to 1u) to Rational(-11, 8), + mapOf(x to 4u, y to 1u) to Rational(18, 1), + mapOf(y to 2u) to Rational(-9, 3), + mapOf(x to 1u, y to 2u) to Rational(1, 3), + mapOf(x to 2u, y to 2u) to Rational(-11, 2), + mapOf(x to 3u, y to 2u) to Rational(-1, 6), + mapOf(x to 4u, y to 2u) to Rational(-9, 2), + mapOf(y to 3u) to Rational(-10, 9), + mapOf(x to 1u, y to 3u) to Rational(-8, 15), + mapOf(x to 2u, y to 3u) to Rational(-1, 24), + mapOf(x to 3u, y to 3u) to Rational(4, 21), + mapOf(x to 4u, y to 3u) to Rational(-1, 6), + mapOf(y to 4u) to Rational(3, 28), + mapOf(x to 1u, y to 4u) to Rational(1, 2), + mapOf(x to 2u, y to 4u) to Rational(-1, 2), + mapOf(x to 3u, y to 4u) to Rational(3, 8), + mapOf(x to 4u, y to 4u) to Rational(5, 36), + mapOf(y to 5u) to Rational(-9, 20), + mapOf(x to 1u, y to 5u) to Rational(-2, 1), + mapOf(x to 2u, y to 5u) to Rational(-7, 5), + mapOf(x to 3u, y to 5u) to Rational(1, 35), + mapOf(x to 4u, y to 5u) to Rational(1, 1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(-11, 8), + mapOf(x to 4u) to Rational(18, 1), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(-1, 3), + mapOf(x to 4u, y to 1u) to Rational(-18, 2), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(3, 7), + mapOf(x to 1u, y to 3u) to Rational(16, 8), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(-18, 8), + mapOf(x to 1u, y to 4u) to Rational(-10, 1), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).antiderivativeWithRespectTo(RationalField, y), + "test 2b" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(0), + mapOf(x to 2u) to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(x to 5u) to Rational(0), + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(x to 5u, y to 1u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(0), + mapOf(x to 3u, y to 2u) to Rational(-1, 24), + mapOf(x to 4u, y to 2u) to Rational(1, 7), + mapOf(x to 5u, y to 2u) to Rational(-1, 10), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(0), + mapOf(x to 3u, y to 3u) to Rational(-2, 3), + mapOf(x to 4u, y to 3u) to Rational(3, 8), + mapOf(x to 5u, y to 3u) to Rational(1, 9), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(0), + mapOf(x to 3u, y to 4u) to Rational(-7, 3), + mapOf(x to 4u, y to 4u) to Rational(1, 28), + mapOf(x to 5u, y to 4u) to Rational(1, 1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(0), + mapOf(x to 1u) to Rational(0), + mapOf(x to 2u) to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(0), + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).antiderivativeWithRespectTo(RationalField, x), + "test 3a" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(y to 1u) to Rational(0), + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(0), + mapOf(x to 3u, y to 2u) to Rational(0), + mapOf(x to 4u, y to 2u) to Rational(0), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(-1, 24), + mapOf(x to 3u, y to 3u) to Rational(4, 21), + mapOf(x to 4u, y to 3u) to Rational(-1, 6), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(-1, 2), + mapOf(x to 3u, y to 4u) to Rational(3, 8), + mapOf(x to 4u, y to 4u) to Rational(5, 36), + mapOf(y to 5u) to Rational(0), + mapOf(x to 1u, y to 5u) to Rational(0), + mapOf(x to 2u, y to 5u) to Rational(-7, 5), + mapOf(x to 3u, y to 5u) to Rational(1, 35), + mapOf(x to 4u, y to 5u) to Rational(1, 1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(0), + mapOf(x to 1u) to Rational(0), + mapOf(x to 2u) to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(0), + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).antiderivativeWithRespectTo(RationalField, y), + "test 3b" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(-6, 8), + mapOf(x to 2u) to Rational(-1, 3), + mapOf(x to 3u) to Rational(1, 6), + mapOf(x to 4u) to Rational(0), + mapOf(x to 5u) to Rational(0), + mapOf(x to 1u, y to 1u) to Rational(-18, 3), + mapOf(x to 2u, y to 1u) to Rational(1, 3), + mapOf(x to 3u, y to 1u) to Rational(-11, 3), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(x to 5u, y to 1u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(-10, 3), + mapOf(x to 2u, y to 2u) to Rational(-4, 5), + mapOf(x to 3u, y to 2u) to Rational(-1, 24), + mapOf(x to 4u, y to 2u) to Rational(0), + mapOf(x to 5u, y to 2u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(0), + mapOf(x to 3u, y to 3u) to Rational(0), + mapOf(x to 4u, y to 3u) to Rational(0), + mapOf(x to 5u, y to 3u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(0), + mapOf(x to 3u, y to 4u) to Rational(0), + mapOf(x to 4u, y to 4u) to Rational(0), + mapOf(x to 5u, y to 4u) to Rational(0), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(0), + mapOf(x to 4u, y to 2u) to Rational(0), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(0), + mapOf(x to 3u, y to 3u) to Rational(0), + mapOf(x to 4u, y to 3u) to Rational(0), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(0), + mapOf(x to 3u, y to 4u) to Rational(0), + mapOf(x to 4u, y to 4u) to Rational(0), + ).antiderivativeWithRespectTo(RationalField, x), + "test 4a" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(y to 1u) to Rational(-6, 8), + mapOf(x to 1u, y to 1u) to Rational(-2, 3), + mapOf(x to 2u, y to 1u) to Rational(1, 2), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(-9, 3), + mapOf(x to 1u, y to 2u) to Rational(1, 3), + mapOf(x to 2u, y to 2u) to Rational(-11, 2), + mapOf(x to 3u, y to 2u) to Rational(0), + mapOf(x to 4u, y to 2u) to Rational(0), + mapOf(y to 3u) to Rational(-10, 9), + mapOf(x to 1u, y to 3u) to Rational(-8, 15), + mapOf(x to 2u, y to 3u) to Rational(-1, 24), + mapOf(x to 3u, y to 3u) to Rational(0), + mapOf(x to 4u, y to 3u) to Rational(0), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(0), + mapOf(x to 3u, y to 4u) to Rational(0), + mapOf(x to 4u, y to 4u) to Rational(0), + mapOf(y to 5u) to Rational(0), + mapOf(x to 1u, y to 5u) to Rational(0), + mapOf(x to 2u, y to 5u) to Rational(0), + mapOf(x to 3u, y to 5u) to Rational(0), + mapOf(x to 4u, y to 5u) to Rational(0), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(0), + mapOf(x to 4u, y to 2u) to Rational(0), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(0), + mapOf(x to 3u, y to 3u) to Rational(0), + mapOf(x to 4u, y to 3u) to Rational(0), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(0), + mapOf(x to 3u, y to 4u) to Rational(0), + mapOf(x to 4u, y to 4u) to Rational(0), + ).antiderivativeWithRespectTo(RationalField, y), + "test 4b" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(iota to 1u) to Rational(-6, 8), + mapOf(x to 1u, iota to 1u) to Rational(-2, 3), + mapOf(x to 2u, iota to 1u) to Rational(1, 2), + mapOf(x to 3u, iota to 1u) to Rational(-11, 8), + mapOf(x to 4u, iota to 1u) to Rational(18, 1), + mapOf(y to 1u, iota to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u, iota to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u, iota to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u, iota to 1u) to Rational(-1, 3), + mapOf(x to 4u, y to 1u, iota to 1u) to Rational(-18, 2), + mapOf(y to 2u, iota to 1u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u, iota to 1u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u, iota to 1u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u, iota to 1u) to Rational(4, 7), + mapOf(x to 4u, y to 2u, iota to 1u) to Rational(-4, 8), + mapOf(y to 3u, iota to 1u) to Rational(3, 7), + mapOf(x to 1u, y to 3u, iota to 1u) to Rational(16, 8), + mapOf(x to 2u, y to 3u, iota to 1u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u, iota to 1u) to Rational(12, 8), + mapOf(x to 4u, y to 3u, iota to 1u) to Rational(5, 9), + mapOf(y to 4u, iota to 1u) to Rational(-18, 8), + mapOf(x to 1u, y to 4u, iota to 1u) to Rational(-10, 1), + mapOf(x to 2u, y to 4u, iota to 1u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u, iota to 1u) to Rational(1, 7), + mapOf(x to 4u, y to 4u, iota to 1u) to Rational(15, 3), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(-11, 8), + mapOf(x to 4u) to Rational(18, 1), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(-1, 3), + mapOf(x to 4u, y to 1u) to Rational(-18, 2), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(3, 7), + mapOf(x to 1u, y to 3u) to Rational(16, 8), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(-18, 8), + mapOf(x to 1u, y to 4u) to Rational(-10, 1), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).antiderivativeWithRespectTo(RationalField, iota), + "test 5" + ) + } + @Test + @OptIn(UnstableKMathAPI::class) + fun test_Polynomial_nthAntiderivativeWithRespectTo_variable_order() { + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(1), + mapOf(x to 2u) to Rational(-1), + mapOf(x to 3u) to Rational(1, 3), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, x, 1u), + "test 1" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, x, 0u), + "test 2" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(-1, 3), + mapOf(x to 4u) to Rational(1, 12), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, x, 2u), + "test 3" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 3u) to Rational(1, 6), + mapOf(x to 4u) to Rational(-1, 12), + mapOf(x to 5u) to Rational(1, 60), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, x, 3u), + "test 4" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 4u) to Rational(1, 24), + mapOf(x to 5u) to Rational(-1, 60), + mapOf(x to 6u) to Rational(1, 360), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, x, 4u), + "test 5" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, y, 0u), + "test 6" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(y to 1u) to Rational(1), + mapOf(x to 1u, y to 1u) to Rational(-2), + mapOf(x to 2u, y to 1u) to Rational(1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, y, 1u), + "test 7" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(y to 2u) to Rational(1, 2), + mapOf(x to 1u, y to 2u) to Rational(-1), + mapOf(x to 2u, y to 2u) to Rational(1, 2), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, y, 2u), + "test 8" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 2u) to Rational(-3, 8), + mapOf(x to 3u) to Rational(-1, 9), + mapOf(x to 4u) to Rational(1, 24), + mapOf(x to 5u) to Rational(-11, 160), + mapOf(x to 6u) to Rational(3, 5), + mapOf(x to 2u, y to 1u) to Rational(-9, 3), + mapOf(x to 3u, y to 1u) to Rational(1, 9), + mapOf(x to 4u, y to 1u) to Rational(-11, 12), + mapOf(x to 5u, y to 1u) to Rational(-1, 60), + mapOf(x to 6u, y to 1u) to Rational(-3, 10), + mapOf(x to 2u, y to 2u) to Rational(-5, 3), + mapOf(x to 3u, y to 2u) to Rational(-4, 15), + mapOf(x to 4u, y to 2u) to Rational(-1, 96), + mapOf(x to 5u, y to 2u) to Rational(1, 35), + mapOf(x to 6u, y to 2u) to Rational(-1, 60), + mapOf(x to 2u, y to 3u) to Rational(3, 14), + mapOf(x to 3u, y to 3u) to Rational(1, 3), + mapOf(x to 4u, y to 3u) to Rational(-1, 6), + mapOf(x to 5u, y to 3u) to Rational(3, 40), + mapOf(x to 6u, y to 3u) to Rational(1, 54), + mapOf(x to 2u, y to 4u) to Rational(-9, 8), + mapOf(x to 3u, y to 4u) to Rational(-5, 3), + mapOf(x to 4u, y to 4u) to Rational(-7, 12), + mapOf(x to 5u, y to 4u) to Rational(1, 140), + mapOf(x to 6u, y to 4u) to Rational(1, 6), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(-11, 8), + mapOf(x to 4u) to Rational(18, 1), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(-1, 3), + mapOf(x to 4u, y to 1u) to Rational(-18, 2), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(3, 7), + mapOf(x to 1u, y to 3u) to Rational(16, 8), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(-18, 8), + mapOf(x to 1u, y to 4u) to Rational(-10, 1), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).nthAntiderivativeWithRespectTo(RationalField, x, 2u), + "test 9a" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(y to 2u) to Rational(-3, 8), + mapOf(x to 1u, y to 2u) to Rational(-1, 3), + mapOf(x to 2u, y to 2u) to Rational(1, 4), + mapOf(x to 3u, y to 2u) to Rational(-11, 16), + mapOf(x to 4u, y to 2u) to Rational(9, 1), + mapOf(y to 3u) to Rational(-1, 1), + mapOf(x to 1u, y to 3u) to Rational(1, 9), + mapOf(x to 2u, y to 3u) to Rational(-11, 6), + mapOf(x to 3u, y to 3u) to Rational(-1, 18), + mapOf(x to 4u, y to 3u) to Rational(-9, 6), + mapOf(y to 4u) to Rational(-5, 18), + mapOf(x to 1u, y to 4u) to Rational(-2, 15), + mapOf(x to 2u, y to 4u) to Rational(-1, 96), + mapOf(x to 3u, y to 4u) to Rational(1, 21), + mapOf(x to 4u, y to 4u) to Rational(-1, 24), + mapOf(y to 5u) to Rational(3, 140), + mapOf(x to 1u, y to 5u) to Rational(1, 10), + mapOf(x to 2u, y to 5u) to Rational(-1, 10), + mapOf(x to 3u, y to 5u) to Rational(3, 40), + mapOf(x to 4u, y to 5u) to Rational(1, 36), + mapOf(y to 6u) to Rational(-3, 40), + mapOf(x to 1u, y to 6u) to Rational(-1, 3), + mapOf(x to 2u, y to 6u) to Rational(-7, 30), + mapOf(x to 3u, y to 6u) to Rational(1, 210), + mapOf(x to 4u, y to 6u) to Rational(1, 6), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(-11, 8), + mapOf(x to 4u) to Rational(18, 1), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(-1, 3), + mapOf(x to 4u, y to 1u) to Rational(-18, 2), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(3, 7), + mapOf(x to 1u, y to 3u) to Rational(16, 8), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(-18, 8), + mapOf(x to 1u, y to 4u) to Rational(-10, 1), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).nthAntiderivativeWithRespectTo(RationalField, y, 2u), + "test 9b" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 2u) to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(x to 5u) to Rational(0), + mapOf(x to 6u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(x to 5u, y to 1u) to Rational(0), + mapOf(x to 6u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(0), + mapOf(x to 3u, y to 2u) to Rational(0), + mapOf(x to 4u, y to 2u) to Rational(-1, 96), + mapOf(x to 5u, y to 2u) to Rational(1, 35), + mapOf(x to 6u, y to 2u) to Rational(-1, 60), + mapOf(x to 2u, y to 3u) to Rational(0), + mapOf(x to 3u, y to 3u) to Rational(0), + mapOf(x to 4u, y to 3u) to Rational(-1, 6), + mapOf(x to 5u, y to 3u) to Rational(3, 40), + mapOf(x to 6u, y to 3u) to Rational(1, 54), + mapOf(x to 2u, y to 4u) to Rational(0), + mapOf(x to 3u, y to 4u) to Rational(0), + mapOf(x to 4u, y to 4u) to Rational(-7, 12), + mapOf(x to 5u, y to 4u) to Rational(1, 140), + mapOf(x to 6u, y to 4u) to Rational(1, 6), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(0), + mapOf(x to 1u) to Rational(0), + mapOf(x to 2u) to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(0), + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).nthAntiderivativeWithRespectTo(RationalField, x, 2u), + "test 10a" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(0), + mapOf(x to 3u, y to 2u) to Rational(0), + mapOf(x to 4u, y to 2u) to Rational(0), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(0), + mapOf(x to 3u, y to 3u) to Rational(0), + mapOf(x to 4u, y to 3u) to Rational(0), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(-1, 96), + mapOf(x to 3u, y to 4u) to Rational(1, 21), + mapOf(x to 4u, y to 4u) to Rational(-1, 24), + mapOf(y to 5u) to Rational(0), + mapOf(x to 1u, y to 5u) to Rational(0), + mapOf(x to 2u, y to 5u) to Rational(-1, 10), + mapOf(x to 3u, y to 5u) to Rational(3, 40), + mapOf(x to 4u, y to 5u) to Rational(1, 36), + mapOf(y to 6u) to Rational(0), + mapOf(x to 1u, y to 6u) to Rational(0), + mapOf(x to 2u, y to 6u) to Rational(-7, 30), + mapOf(x to 3u, y to 6u) to Rational(1, 210), + mapOf(x to 4u, y to 6u) to Rational(1, 6), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(0), + mapOf(x to 1u) to Rational(0), + mapOf(x to 2u) to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(0), + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).nthAntiderivativeWithRespectTo(RationalField, y, 2u), + "test 10b" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 2u) to Rational(-3, 8), + mapOf(x to 3u) to Rational(-1, 9), + mapOf(x to 4u) to Rational(1, 24), + mapOf(x to 5u) to Rational(0), + mapOf(x to 6u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(-9, 3), + mapOf(x to 3u, y to 1u) to Rational(1, 9), + mapOf(x to 4u, y to 1u) to Rational(-11, 12), + mapOf(x to 5u, y to 1u) to Rational(0), + mapOf(x to 6u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(-5, 3), + mapOf(x to 3u, y to 2u) to Rational(-4, 15), + mapOf(x to 4u, y to 2u) to Rational(-1, 96), + mapOf(x to 5u, y to 2u) to Rational(0), + mapOf(x to 6u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(0), + mapOf(x to 3u, y to 3u) to Rational(0), + mapOf(x to 4u, y to 3u) to Rational(0), + mapOf(x to 5u, y to 3u) to Rational(0), + mapOf(x to 6u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(0), + mapOf(x to 3u, y to 4u) to Rational(0), + mapOf(x to 4u, y to 4u) to Rational(0), + mapOf(x to 5u, y to 4u) to Rational(0), + mapOf(x to 6u, y to 4u) to Rational(0), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(0), + mapOf(x to 4u, y to 2u) to Rational(0), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(0), + mapOf(x to 3u, y to 3u) to Rational(0), + mapOf(x to 4u, y to 3u) to Rational(0), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(0), + mapOf(x to 3u, y to 4u) to Rational(0), + mapOf(x to 4u, y to 4u) to Rational(0), + ).nthAntiderivativeWithRespectTo(RationalField, x, 2u), + "test 11a" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(y to 2u) to Rational(-3, 8), + mapOf(x to 1u, y to 2u) to Rational(-1, 3), + mapOf(x to 2u, y to 2u) to Rational(1, 4), + mapOf(x to 3u, y to 2u) to Rational(0), + mapOf(x to 4u, y to 2u) to Rational(0), + mapOf(y to 3u) to Rational(-1, 1), + mapOf(x to 1u, y to 3u) to Rational(1, 9), + mapOf(x to 2u, y to 3u) to Rational(-11, 6), + mapOf(x to 3u, y to 3u) to Rational(0), + mapOf(x to 4u, y to 3u) to Rational(0), + mapOf(y to 4u) to Rational(-5, 18), + mapOf(x to 1u, y to 4u) to Rational(-2, 15), + mapOf(x to 2u, y to 4u) to Rational(-1, 96), + mapOf(x to 3u, y to 4u) to Rational(0), + mapOf(x to 4u, y to 4u) to Rational(0), + mapOf(y to 5u) to Rational(0), + mapOf(x to 1u, y to 5u) to Rational(0), + mapOf(x to 2u, y to 5u) to Rational(0), + mapOf(x to 3u, y to 5u) to Rational(0), + mapOf(x to 4u, y to 5u) to Rational(0), + mapOf(y to 6u) to Rational(0), + mapOf(x to 1u, y to 6u) to Rational(0), + mapOf(x to 2u, y to 6u) to Rational(0), + mapOf(x to 3u, y to 6u) to Rational(0), + mapOf(x to 4u, y to 6u) to Rational(0), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(0), + mapOf(x to 4u, y to 2u) to Rational(0), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(0), + mapOf(x to 3u, y to 3u) to Rational(0), + mapOf(x to 4u, y to 3u) to Rational(0), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(0), + mapOf(x to 3u, y to 4u) to Rational(0), + mapOf(x to 4u, y to 4u) to Rational(0), + ).nthAntiderivativeWithRespectTo(RationalField, y, 2u), + "test 11b" + ) + } + @Test + @OptIn(UnstableKMathAPI::class) + fun test_Polynomial_nthAntiderivativeWithRespectTo_variablesAndOrders() { + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(1), + mapOf(x to 2u) to Rational(-1), + mapOf(x to 3u) to Rational(1, 3), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, mapOf(x to 1u)), + "test 1" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, x, 0u), + "test 2" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(-1, 3), + mapOf(x to 4u) to Rational(1, 12), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, x, 2u), + "test 3" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 3u) to Rational(1, 6), + mapOf(x to 4u) to Rational(-1, 12), + mapOf(x to 5u) to Rational(1, 60), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, x, 3u), + "test 4" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 4u) to Rational(1, 24), + mapOf(x to 5u) to Rational(-1, 60), + mapOf(x to 6u) to Rational(1, 360), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, x, 4u), + "test 5" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, y, 0u), + "test 6" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(y to 1u) to Rational(1), + mapOf(x to 1u, y to 1u) to Rational(-2), + mapOf(x to 2u, y to 1u) to Rational(1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, y, 1u), + "test 7" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(y to 2u) to Rational(1, 2), + mapOf(x to 1u, y to 2u) to Rational(-1), + mapOf(x to 2u, y to 2u) to Rational(1, 2), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, y, 2u), + "test 8" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, mapOf()), + "test 9" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(1), + mapOf(x to 2u) to Rational(-1), + mapOf(x to 3u) to Rational(1, 3), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, mapOf( + x to 1u, + y to 0u + )), + "test 10" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(y to 1u) to Rational(1), + mapOf(x to 1u, y to 1u) to Rational(-2), + mapOf(x to 2u, y to 1u) to Rational(1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, mapOf( + x to 0u, + y to 1u + )), + "test 11" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 2u) to Rational(-3, 8), + mapOf(x to 3u) to Rational(-1, 9), + mapOf(x to 4u) to Rational(1, 24), + mapOf(x to 5u) to Rational(-11, 160), + mapOf(x to 6u) to Rational(3, 5), + mapOf(x to 2u, y to 1u) to Rational(-9, 3), + mapOf(x to 3u, y to 1u) to Rational(1, 9), + mapOf(x to 4u, y to 1u) to Rational(-11, 12), + mapOf(x to 5u, y to 1u) to Rational(-1, 60), + mapOf(x to 6u, y to 1u) to Rational(-3, 10), + mapOf(x to 2u, y to 2u) to Rational(-5, 3), + mapOf(x to 3u, y to 2u) to Rational(-4, 15), + mapOf(x to 4u, y to 2u) to Rational(-1, 96), + mapOf(x to 5u, y to 2u) to Rational(1, 35), + mapOf(x to 6u, y to 2u) to Rational(-1, 60), + mapOf(x to 2u, y to 3u) to Rational(3, 14), + mapOf(x to 3u, y to 3u) to Rational(1, 3), + mapOf(x to 4u, y to 3u) to Rational(-1, 6), + mapOf(x to 5u, y to 3u) to Rational(3, 40), + mapOf(x to 6u, y to 3u) to Rational(1, 54), + mapOf(x to 2u, y to 4u) to Rational(-9, 8), + mapOf(x to 3u, y to 4u) to Rational(-5, 3), + mapOf(x to 4u, y to 4u) to Rational(-7, 12), + mapOf(x to 5u, y to 4u) to Rational(1, 140), + mapOf(x to 6u, y to 4u) to Rational(1, 6), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(-11, 8), + mapOf(x to 4u) to Rational(18, 1), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(-1, 3), + mapOf(x to 4u, y to 1u) to Rational(-18, 2), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(3, 7), + mapOf(x to 1u, y to 3u) to Rational(16, 8), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(-18, 8), + mapOf(x to 1u, y to 4u) to Rational(-10, 1), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).nthAntiderivativeWithRespectTo(RationalField, mapOf(x to 2u)), + "test 12a" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 1u, y to 1u) to Rational(-6, 8), + mapOf(x to 2u, y to 1u) to Rational(-1, 3), + mapOf(x to 3u, y to 1u) to Rational(1, 6), + mapOf(x to 4u, y to 1u) to Rational(-11, 32), + mapOf(x to 5u, y to 1u) to Rational(18, 5), + mapOf(x to 1u, y to 2u) to Rational(-9, 3), + mapOf(x to 2u, y to 2u) to Rational(1, 6), + mapOf(x to 3u, y to 2u) to Rational(-11, 6), + mapOf(x to 4u, y to 2u) to Rational(-1, 24), + mapOf(x to 5u, y to 2u) to Rational(-9, 10), + mapOf(x to 1u, y to 3u) to Rational(-10, 9), + mapOf(x to 2u, y to 3u) to Rational(-4, 15), + mapOf(x to 3u, y to 3u) to Rational(-1, 72), + mapOf(x to 4u, y to 3u) to Rational(1, 21), + mapOf(x to 5u, y to 3u) to Rational(-1, 30), + mapOf(x to 1u, y to 4u) to Rational(3, 28), + mapOf(x to 2u, y to 4u) to Rational(1, 4), + mapOf(x to 3u, y to 4u) to Rational(-1, 6), + mapOf(x to 4u, y to 4u) to Rational(3, 32), + mapOf(x to 5u, y to 4u) to Rational(1, 36), + mapOf(x to 1u, y to 5u) to Rational(-9, 20), + mapOf(x to 2u, y to 5u) to Rational(-1, 1), + mapOf(x to 3u, y to 5u) to Rational(-7, 15), + mapOf(x to 4u, y to 5u) to Rational(1, 140), + mapOf(x to 5u, y to 5u) to Rational(1, 5), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(-11, 8), + mapOf(x to 4u) to Rational(18, 1), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(-1, 3), + mapOf(x to 4u, y to 1u) to Rational(-18, 2), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(3, 7), + mapOf(x to 1u, y to 3u) to Rational(16, 8), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(-18, 8), + mapOf(x to 1u, y to 4u) to Rational(-10, 1), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).nthAntiderivativeWithRespectTo(RationalField, mapOf(x to 1u, y to 1u)), + "test 12b" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(y to 2u) to Rational(-3, 8), + mapOf(x to 1u, y to 2u) to Rational(-1, 3), + mapOf(x to 2u, y to 2u) to Rational(1, 4), + mapOf(x to 3u, y to 2u) to Rational(-11, 16), + mapOf(x to 4u, y to 2u) to Rational(9, 1), + mapOf(y to 3u) to Rational(-1, 1), + mapOf(x to 1u, y to 3u) to Rational(1, 9), + mapOf(x to 2u, y to 3u) to Rational(-11, 6), + mapOf(x to 3u, y to 3u) to Rational(-1, 18), + mapOf(x to 4u, y to 3u) to Rational(-9, 6), + mapOf(y to 4u) to Rational(-5, 18), + mapOf(x to 1u, y to 4u) to Rational(-2, 15), + mapOf(x to 2u, y to 4u) to Rational(-1, 96), + mapOf(x to 3u, y to 4u) to Rational(1, 21), + mapOf(x to 4u, y to 4u) to Rational(-1, 24), + mapOf(y to 5u) to Rational(3, 140), + mapOf(x to 1u, y to 5u) to Rational(1, 10), + mapOf(x to 2u, y to 5u) to Rational(-1, 10), + mapOf(x to 3u, y to 5u) to Rational(3, 40), + mapOf(x to 4u, y to 5u) to Rational(1, 36), + mapOf(y to 6u) to Rational(-3, 40), + mapOf(x to 1u, y to 6u) to Rational(-1, 3), + mapOf(x to 2u, y to 6u) to Rational(-7, 30), + mapOf(x to 3u, y to 6u) to Rational(1, 210), + mapOf(x to 4u, y to 6u) to Rational(1, 6), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(-11, 8), + mapOf(x to 4u) to Rational(18, 1), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(-1, 3), + mapOf(x to 4u, y to 1u) to Rational(-18, 2), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(3, 7), + mapOf(x to 1u, y to 3u) to Rational(16, 8), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(-18, 8), + mapOf(x to 1u, y to 4u) to Rational(-10, 1), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).nthAntiderivativeWithRespectTo(RationalField, mapOf(y to 2u)), + "test 12c" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 2u) to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(x to 5u) to Rational(0), + mapOf(x to 6u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(x to 5u, y to 1u) to Rational(0), + mapOf(x to 6u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(0), + mapOf(x to 3u, y to 2u) to Rational(0), + mapOf(x to 4u, y to 2u) to Rational(-1, 96), + mapOf(x to 5u, y to 2u) to Rational(1, 35), + mapOf(x to 6u, y to 2u) to Rational(-1, 60), + mapOf(x to 2u, y to 3u) to Rational(0), + mapOf(x to 3u, y to 3u) to Rational(0), + mapOf(x to 4u, y to 3u) to Rational(-1, 6), + mapOf(x to 5u, y to 3u) to Rational(3, 40), + mapOf(x to 6u, y to 3u) to Rational(1, 54), + mapOf(x to 2u, y to 4u) to Rational(0), + mapOf(x to 3u, y to 4u) to Rational(0), + mapOf(x to 4u, y to 4u) to Rational(-7, 12), + mapOf(x to 5u, y to 4u) to Rational(1, 140), + mapOf(x to 6u, y to 4u) to Rational(1, 6), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(0), + mapOf(x to 1u) to Rational(0), + mapOf(x to 2u) to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(0), + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).nthAntiderivativeWithRespectTo(RationalField, mapOf(x to 2u)), + "test 13a" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(x to 5u, y to 1u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(0), + mapOf(x to 3u, y to 2u) to Rational(0), + mapOf(x to 4u, y to 2u) to Rational(0), + mapOf(x to 5u, y to 2u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(0), + mapOf(x to 3u, y to 3u) to Rational(-1, 72), + mapOf(x to 4u, y to 3u) to Rational(1, 21), + mapOf(x to 5u, y to 3u) to Rational(-1, 30), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(0), + mapOf(x to 3u, y to 4u) to Rational(-1, 6), + mapOf(x to 4u, y to 4u) to Rational(3, 32), + mapOf(x to 5u, y to 4u) to Rational(1, 36), + mapOf(x to 1u, y to 5u) to Rational(0), + mapOf(x to 2u, y to 5u) to Rational(0), + mapOf(x to 3u, y to 5u) to Rational(-7, 15), + mapOf(x to 4u, y to 5u) to Rational(1, 140), + mapOf(x to 5u, y to 5u) to Rational(1, 5), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(0), + mapOf(x to 1u) to Rational(0), + mapOf(x to 2u) to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(0), + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).nthAntiderivativeWithRespectTo(RationalField, mapOf(x to 1u, y to 1u)), + "test 13b" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(0), + mapOf(x to 3u, y to 2u) to Rational(0), + mapOf(x to 4u, y to 2u) to Rational(0), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(0), + mapOf(x to 3u, y to 3u) to Rational(0), + mapOf(x to 4u, y to 3u) to Rational(0), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(-1, 96), + mapOf(x to 3u, y to 4u) to Rational(1, 21), + mapOf(x to 4u, y to 4u) to Rational(-1, 24), + mapOf(y to 5u) to Rational(0), + mapOf(x to 1u, y to 5u) to Rational(0), + mapOf(x to 2u, y to 5u) to Rational(-1, 10), + mapOf(x to 3u, y to 5u) to Rational(3, 40), + mapOf(x to 4u, y to 5u) to Rational(1, 36), + mapOf(y to 6u) to Rational(0), + mapOf(x to 1u, y to 6u) to Rational(0), + mapOf(x to 2u, y to 6u) to Rational(-7, 30), + mapOf(x to 3u, y to 6u) to Rational(1, 210), + mapOf(x to 4u, y to 6u) to Rational(1, 6), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(0), + mapOf(x to 1u) to Rational(0), + mapOf(x to 2u) to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(0), + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).nthAntiderivativeWithRespectTo(RationalField, mapOf(y to 2u)), + "test 13c" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 2u) to Rational(-3, 8), + mapOf(x to 3u) to Rational(-1, 9), + mapOf(x to 4u) to Rational(1, 24), + mapOf(x to 5u) to Rational(0), + mapOf(x to 6u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(-9, 3), + mapOf(x to 3u, y to 1u) to Rational(1, 9), + mapOf(x to 4u, y to 1u) to Rational(-11, 12), + mapOf(x to 5u, y to 1u) to Rational(0), + mapOf(x to 6u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(-5, 3), + mapOf(x to 3u, y to 2u) to Rational(-4, 15), + mapOf(x to 4u, y to 2u) to Rational(-1, 96), + mapOf(x to 5u, y to 2u) to Rational(0), + mapOf(x to 6u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(0), + mapOf(x to 3u, y to 3u) to Rational(0), + mapOf(x to 4u, y to 3u) to Rational(0), + mapOf(x to 5u, y to 3u) to Rational(0), + mapOf(x to 6u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(0), + mapOf(x to 3u, y to 4u) to Rational(0), + mapOf(x to 4u, y to 4u) to Rational(0), + mapOf(x to 5u, y to 4u) to Rational(0), + mapOf(x to 6u, y to 4u) to Rational(0), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(0), + mapOf(x to 4u, y to 2u) to Rational(0), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(0), + mapOf(x to 3u, y to 3u) to Rational(0), + mapOf(x to 4u, y to 3u) to Rational(0), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(0), + mapOf(x to 3u, y to 4u) to Rational(0), + mapOf(x to 4u, y to 4u) to Rational(0), + ).nthAntiderivativeWithRespectTo(RationalField, mapOf(x to 2u)), + "test 14a" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 1u, y to 1u) to Rational(-6, 8), + mapOf(x to 2u, y to 1u) to Rational(-1, 3), + mapOf(x to 3u, y to 1u) to Rational(1, 6), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(x to 5u, y to 1u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(-9, 3), + mapOf(x to 2u, y to 2u) to Rational(1, 6), + mapOf(x to 3u, y to 2u) to Rational(-11, 6), + mapOf(x to 4u, y to 2u) to Rational(0), + mapOf(x to 5u, y to 2u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(-10, 9), + mapOf(x to 2u, y to 3u) to Rational(-4, 15), + mapOf(x to 3u, y to 3u) to Rational(-1, 72), + mapOf(x to 4u, y to 3u) to Rational(0), + mapOf(x to 5u, y to 3u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(0), + mapOf(x to 3u, y to 4u) to Rational(0), + mapOf(x to 4u, y to 4u) to Rational(0), + mapOf(x to 5u, y to 4u) to Rational(0), + mapOf(x to 1u, y to 5u) to Rational(0), + mapOf(x to 2u, y to 5u) to Rational(0), + mapOf(x to 3u, y to 5u) to Rational(0), + mapOf(x to 4u, y to 5u) to Rational(0), + mapOf(x to 5u, y to 5u) to Rational(0), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(0), + mapOf(x to 4u, y to 2u) to Rational(0), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(0), + mapOf(x to 3u, y to 3u) to Rational(0), + mapOf(x to 4u, y to 3u) to Rational(0), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(0), + mapOf(x to 3u, y to 4u) to Rational(0), + mapOf(x to 4u, y to 4u) to Rational(0), + ).nthAntiderivativeWithRespectTo(RationalField, mapOf(x to 1u, y to 1u)), + "test 14b" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(y to 2u) to Rational(-3, 8), + mapOf(x to 1u, y to 2u) to Rational(-1, 3), + mapOf(x to 2u, y to 2u) to Rational(1, 4), + mapOf(x to 3u, y to 2u) to Rational(0), + mapOf(x to 4u, y to 2u) to Rational(0), + mapOf(y to 3u) to Rational(-1, 1), + mapOf(x to 1u, y to 3u) to Rational(1, 9), + mapOf(x to 2u, y to 3u) to Rational(-11, 6), + mapOf(x to 3u, y to 3u) to Rational(0), + mapOf(x to 4u, y to 3u) to Rational(0), + mapOf(y to 4u) to Rational(-5, 18), + mapOf(x to 1u, y to 4u) to Rational(-2, 15), + mapOf(x to 2u, y to 4u) to Rational(-1, 96), + mapOf(x to 3u, y to 4u) to Rational(0), + mapOf(x to 4u, y to 4u) to Rational(0), + mapOf(y to 5u) to Rational(0), + mapOf(x to 1u, y to 5u) to Rational(0), + mapOf(x to 2u, y to 5u) to Rational(0), + mapOf(x to 3u, y to 5u) to Rational(0), + mapOf(x to 4u, y to 5u) to Rational(0), + mapOf(y to 6u) to Rational(0), + mapOf(x to 1u, y to 6u) to Rational(0), + mapOf(x to 2u, y to 6u) to Rational(0), + mapOf(x to 3u, y to 6u) to Rational(0), + mapOf(x to 4u, y to 6u) to Rational(0), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(0), + mapOf(x to 4u, y to 2u) to Rational(0), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(0), + mapOf(x to 3u, y to 3u) to Rational(0), + mapOf(x to 4u, y to 3u) to Rational(0), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(0), + mapOf(x to 3u, y to 4u) to Rational(0), + mapOf(x to 4u, y to 4u) to Rational(0), + ).nthAntiderivativeWithRespectTo(RationalField, mapOf(y to 2u)), + "test 14c" + ) + } +} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt index f0a1128b4..007c3e5e9 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt @@ -7,14 +7,19 @@ package space.kscience.kmath.functions -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.test.misc.* -import kotlin.test.* +import space.kscience.kmath.test.misc.IntModuloRing +import space.kscience.kmath.test.misc.Rational +import space.kscience.kmath.test.misc.RationalField +import space.kscience.kmath.test.misc.m +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertSame +import kotlin.test.fail -@UnstableKMathAPI class NumberedPolynomialTest { - private val o = Rational(0) + val o = Rational(0) + @Test fun test_Polynomial_Int_plus() { RationalField.numberedPolynomialSpace { @@ -557,6 +562,7 @@ class NumberedPolynomialTest { ) assertEquals( NumberedPolynomial( + listOf() to Rational(0), listOf(3u) to Rational(-8, 9), listOf(0u, 4u) to Rational(-8, 7), ), @@ -650,6 +656,7 @@ class NumberedPolynomialTest { ) assertEquals( NumberedPolynomial( + listOf() to Rational(0), listOf(3u) to Rational(-8, 9), listOf(0u, 4u) to Rational(-8, 7), ), @@ -816,6 +823,7 @@ class NumberedPolynomialTest { ) assertEquals( NumberedPolynomial( + listOf() to Rational(0), listOf(3u) to Rational(-8, 9), listOf(0u, 4u) to Rational(-8, 7), ), diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/assertion.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/assertion.kt index 3ad482454..85180bd2a 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/assertion.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/assertion.kt @@ -5,6 +5,8 @@ package space.kscience.kmath.test.misc +import space.kscience.kmath.functions.LabeledPolynomial +import space.kscience.kmath.functions.LabeledRationalFunction import space.kscience.kmath.functions.NumberedPolynomial import space.kscience.kmath.functions.NumberedRationalFunction import kotlin.test.assertEquals @@ -28,6 +30,18 @@ fun assertEquals( message ) +fun assertEquals( + expected: LabeledPolynomial, + actual: LabeledPolynomial, + absoluteTolerance: Double, + message: String? = null +) = assertContentEquals( + expected.coefficients, + actual.coefficients, + absoluteTolerance, + message +) + fun assertEquals( expected: NumberedRationalFunction, actual: NumberedRationalFunction, @@ -48,6 +62,26 @@ fun assertEquals( ) } +fun assertEquals( + expected: LabeledRationalFunction, + actual: LabeledRationalFunction, + absoluteTolerance: Double, + message: String? = null +) { + assertEquals( + expected.numerator, + actual.numerator, + absoluteTolerance, + message + ) + assertEquals( + expected.denominator, + actual.denominator, + absoluteTolerance, + message + ) +} + inline fun assertFailsWithTypeAndMessage( expectedMessage: String? = null, assertionMessage: String? = null, -- 2.34.1 From d3be07987c30e5dd786cdfb04cec4801d22b6d30 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Wed, 6 Jul 2022 23:16:25 +0300 Subject: [PATCH 099/123] Simplify usages of LabeledPolynomial constructing fabrics. Fix bugs. Add tests for variable's interoperability. --- .../kmath/functions/LabeledPolynomial.kt | 150 ++-- .../kmath/functions/ListPolynomial.kt | 5 - .../kmath/functions/NumberedPolynomial.kt | 5 - .../kscience/kmath/functions/Polynomial.kt | 2 +- .../kmath/functions/LabeledPolynomialTest.kt | 800 ++++++++++++++++-- 5 files changed, 816 insertions(+), 146 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt index 1477796ea..7f107a87f 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt @@ -77,63 +77,63 @@ public class LabeledPolynomialSpace>( * Returns sum of the variable represented as a monic monomial and the integer represented as a constant polynomial. */ public override operator fun Symbol.plus(other: Int): LabeledPolynomial = - if (other == 0) LabeledPolynomialAsIs(mapOf( + if (other == 0) LabeledPolynomialAsIs( mapOf(this@plus to 1U) to constantOne, - )) - else LabeledPolynomialAsIs(mapOf( + ) + else LabeledPolynomialAsIs( mapOf(this@plus to 1U) to constantOne, emptyMap() to constantOne * other, - )) + ) /** * Returns difference between the variable represented as a monic monomial and the integer represented as a constant polynomial. */ public override operator fun Symbol.minus(other: Int): LabeledPolynomial = - if (other == 0) LabeledPolynomialAsIs(mapOf( - mapOf(this@minus to 1U) to -constantOne, - )) - else LabeledPolynomialAsIs(mapOf( - mapOf(this@minus to 1U) to -constantOne, - emptyMap() to constantOne * other, - )) + if (other == 0) LabeledPolynomialAsIs( + mapOf(this@minus to 1U) to constantOne, + ) + else LabeledPolynomialAsIs( + mapOf(this@minus to 1U) to constantOne, + emptyMap() to constantOne * -other, + ) /** * Returns product of the variable represented as a monic monomial and the integer represented as a constant polynomial. */ public override operator fun Symbol.times(other: Int): LabeledPolynomial = if (other == 0) zero - else LabeledPolynomialAsIs(mapOf( + else LabeledPolynomialAsIs( mapOf(this to 1U) to constantOne * other, - )) + ) /** * Returns sum of the integer represented as a constant polynomial and the variable represented as a monic monomial. */ public override operator fun Int.plus(other: Symbol): LabeledPolynomial = - if (this == 0) LabeledPolynomialAsIs(mapOf( + if (this == 0) LabeledPolynomialAsIs( mapOf(other to 1U) to constantOne, - )) - else LabeledPolynomialAsIs(mapOf( + ) + else LabeledPolynomialAsIs( mapOf(other to 1U) to constantOne, emptyMap() to constantOne * this@plus, - )) + ) /** * Returns difference between the integer represented as a constant polynomial and the variable represented as a monic monomial. */ public override operator fun Int.minus(other: Symbol): LabeledPolynomial = - if (this == 0) LabeledPolynomialAsIs(mapOf( + if (this == 0) LabeledPolynomialAsIs( mapOf(other to 1U) to -constantOne, - )) - else LabeledPolynomialAsIs(mapOf( + ) + else LabeledPolynomialAsIs( mapOf(other to 1U) to -constantOne, emptyMap() to constantOne * this@minus, - )) + ) /** * Returns product of the integer represented as a constant polynomial and the variable represented as a monic monomial. */ public override operator fun Int.times(other: Symbol): LabeledPolynomial = if (this == 0) zero - else LabeledPolynomialAsIs(mapOf( + else LabeledPolynomialAsIs( mapOf(other to 1U) to constantOne * this@times, - )) + ) /** * Returns sum of the polynomial and the integer represented as a polynomial. @@ -143,7 +143,7 @@ public class LabeledPolynomialSpace>( public override operator fun LabeledPolynomial.plus(other: Int): LabeledPolynomial = if (other == 0) this else with(coefficients) { - if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap() to other.asConstant())) + if (isEmpty()) other.asPolynomial() else LabeledPolynomialAsIs( toMutableMap() .apply { @@ -161,7 +161,7 @@ public class LabeledPolynomialSpace>( public override operator fun LabeledPolynomial.minus(other: Int): LabeledPolynomial = if (other == 0) this else with(coefficients) { - if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap() to (-other).asConstant())) + if (isEmpty()) (-other).asPolynomial() else LabeledPolynomialAsIs( toMutableMap() .apply { @@ -180,7 +180,7 @@ public class LabeledPolynomialSpace>( when(other) { 0 -> zero 1 -> this - else -> LabeledPolynomial( + else -> LabeledPolynomialAsIs( coefficients .toMutableMap() .apply { @@ -197,7 +197,7 @@ public class LabeledPolynomialSpace>( public override operator fun Int.plus(other: LabeledPolynomial): LabeledPolynomial = if (this == 0) other else with(other.coefficients) { - if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap() to this@plus.asConstant())) + if (isEmpty()) this@plus.asPolynomial() else LabeledPolynomialAsIs( toMutableMap() .apply { @@ -215,7 +215,7 @@ public class LabeledPolynomialSpace>( public override operator fun Int.minus(other: LabeledPolynomial): LabeledPolynomial = if (this == 0) -other else with(other.coefficients) { - if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap() to this@minus.asConstant())) + if (isEmpty()) this@minus.asPolynomial() else LabeledPolynomialAsIs( toMutableMap() .apply { @@ -236,7 +236,7 @@ public class LabeledPolynomialSpace>( when(this) { 0 -> zero 1 -> other - else -> LabeledPolynomial( + else -> LabeledPolynomialAsIs( other.coefficients .toMutableMap() .apply { @@ -245,65 +245,60 @@ public class LabeledPolynomialSpace>( ) } - /** - * Converts the integer [value] to polynomial. - */ - public override fun number(value: Int): LabeledPolynomial = number(constantNumber(value)) - /** * Returns sum of the variable represented as a monic monomial and the constant represented as a constant polynomial. */ public override operator fun Symbol.plus(other: C): LabeledPolynomial = - LabeledPolynomialAsIs(mapOf( + LabeledPolynomialAsIs( mapOf(this@plus to 1U) to constantOne, emptyMap() to other, - )) + ) /** * Returns difference between the variable represented as a monic monomial and the constant represented as a constant polynomial. */ public override operator fun Symbol.minus(other: C): LabeledPolynomial = - LabeledPolynomialAsIs(mapOf( - mapOf(this@minus to 1U) to -constantOne, - emptyMap() to other, - )) + LabeledPolynomialAsIs( + mapOf(this@minus to 1U) to constantOne, + emptyMap() to -other, + ) /** * Returns product of the variable represented as a monic monomial and the constant represented as a constant polynomial. */ public override operator fun Symbol.times(other: C): LabeledPolynomial = - LabeledPolynomialAsIs(mapOf( + LabeledPolynomialAsIs( mapOf(this@times to 1U) to other, - )) + ) /** * Returns sum of the constant represented as a constant polynomial and the variable represented as a monic monomial. */ public override operator fun C.plus(other: Symbol): LabeledPolynomial = - LabeledPolynomialAsIs(mapOf( + LabeledPolynomialAsIs( mapOf(other to 1U) to constantOne, emptyMap() to this@plus, - )) + ) /** * Returns difference between the constant represented as a constant polynomial and the variable represented as a monic monomial. */ public override operator fun C.minus(other: Symbol): LabeledPolynomial = - LabeledPolynomialAsIs(mapOf( + LabeledPolynomialAsIs( mapOf(other to 1U) to -constantOne, emptyMap() to this@minus, - )) + ) /** * Returns product of the constant represented as a constant polynomial and the variable represented as a monic monomial. */ public override operator fun C.times(other: Symbol): LabeledPolynomial = - LabeledPolynomialAsIs(mapOf( + LabeledPolynomialAsIs( mapOf(other to 1U) to this@times, - )) + ) /** * Returns sum of the constant represented as a polynomial and the polynomial. */ override operator fun C.plus(other: LabeledPolynomial): LabeledPolynomial = with(other.coefficients) { - if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap() to this@plus)) + if (isEmpty()) this@plus.asLabeledPolynomial() else LabeledPolynomialAsIs( toMutableMap() .apply { @@ -318,7 +313,7 @@ public class LabeledPolynomialSpace>( */ override operator fun C.minus(other: LabeledPolynomial): LabeledPolynomial = with(other.coefficients) { - if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap() to this@minus)) + if (isEmpty()) this@minus.asLabeledPolynomial() else LabeledPolynomialAsIs( toMutableMap() .apply { @@ -347,7 +342,7 @@ public class LabeledPolynomialSpace>( */ override operator fun LabeledPolynomial.plus(other: C): LabeledPolynomial = with(coefficients) { - if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap() to other)) + if (isEmpty()) other.asLabeledPolynomial() else LabeledPolynomialAsIs( toMutableMap() .apply { @@ -362,7 +357,7 @@ public class LabeledPolynomialSpace>( */ override operator fun LabeledPolynomial.minus(other: C): LabeledPolynomial = with(coefficients) { - if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap() to other)) + if (isEmpty()) other.asLabeledPolynomial() else LabeledPolynomialAsIs( toMutableMap() .apply { @@ -387,60 +382,59 @@ public class LabeledPolynomialSpace>( /** * Converts the constant [value] to polynomial. */ - public override fun number(value: C): LabeledPolynomial = - LabeledPolynomial(mapOf(emptyMap() to value)) + public override fun number(value: C): LabeledPolynomial = value.asLabeledPolynomial() /** * Represents the variable as a monic monomial. */ public override operator fun Symbol.unaryPlus(): LabeledPolynomial = - LabeledPolynomialAsIs(mapOf( + LabeledPolynomialAsIs( mapOf(this to 1U) to constantOne, - )) + ) /** * Returns negation of representation of the variable as a monic monomial. */ public override operator fun Symbol.unaryMinus(): LabeledPolynomial = - LabeledPolynomialAsIs(mapOf( + LabeledPolynomialAsIs( mapOf(this to 1U) to -constantOne, - )) + ) /** * Returns sum of the variables represented as monic monomials. */ public override operator fun Symbol.plus(other: Symbol): LabeledPolynomial = - if (this == other) LabeledPolynomialAsIs(mapOf( + if (this == other) LabeledPolynomialAsIs( mapOf(this to 1U) to constantOne * 2 - )) - else LabeledPolynomialAsIs(mapOf( + ) + else LabeledPolynomialAsIs( mapOf(this to 1U) to constantOne, mapOf(other to 1U) to constantOne, - )) + ) /** * Returns difference between the variables represented as monic monomials. */ public override operator fun Symbol.minus(other: Symbol): LabeledPolynomial = if (this == other) zero - else LabeledPolynomialAsIs(mapOf( + else LabeledPolynomialAsIs( mapOf(this to 1U) to constantOne, mapOf(other to 1U) to -constantOne, - )) + ) /** * Returns product of the variables represented as monic monomials. */ public override operator fun Symbol.times(other: Symbol): LabeledPolynomial = - if (this == other) LabeledPolynomialAsIs(mapOf( + if (this == other) LabeledPolynomialAsIs( mapOf(this to 2U) to constantOne - )) - else LabeledPolynomialAsIs(mapOf( + ) + else LabeledPolynomialAsIs( mapOf(this to 1U, other to 1U) to constantOne, - )) + ) /** * Returns sum of the variable represented as a monic monomial and the polynomial. */ public override operator fun Symbol.plus(other: LabeledPolynomial): LabeledPolynomial = with(other.coefficients) { - if (isEmpty()) LabeledPolynomialAsIs(mapOf(mapOf(this@plus to 1u) to constantOne)) + if (isEmpty()) this@plus.asPolynomial() else LabeledPolynomialAsIs( toMutableMap() .apply { @@ -455,15 +449,15 @@ public class LabeledPolynomialSpace>( */ public override operator fun Symbol.minus(other: LabeledPolynomial): LabeledPolynomial = with(other.coefficients) { - if (isEmpty()) LabeledPolynomialAsIs(mapOf(mapOf(this@minus to 1u) to constantOne)) + if (isEmpty()) this@minus.asPolynomial() else LabeledPolynomialAsIs( toMutableMap() .apply { - val degs = mapOf(this@minus to 1U) + val theVariableDegs = mapOf(this@minus to 1U) - forEach { (degs, c) -> if(degs != degs) this[degs] = -c } + forEach { (degs, c) -> if(degs != theVariableDegs) this[degs] = -c } - this[degs] = constantOne - getOrElse(degs) { constantZero } + this[theVariableDegs] = constantOne - getOrElse(theVariableDegs) { constantZero } } ) } @@ -481,7 +475,7 @@ public class LabeledPolynomialSpace>( */ public override operator fun LabeledPolynomial.plus(other: Symbol): LabeledPolynomial = with(coefficients) { - if (isEmpty()) LabeledPolynomialAsIs(mapOf(mapOf(other to 1u) to constantOne)) + if (isEmpty()) other.asPolynomial() else LabeledPolynomialAsIs( toMutableMap() .apply { @@ -496,13 +490,13 @@ public class LabeledPolynomialSpace>( */ public override operator fun LabeledPolynomial.minus(other: Symbol): LabeledPolynomial = with(coefficients) { - if (isEmpty()) LabeledPolynomialAsIs(mapOf(mapOf(other to 1u) to constantOne)) + if (isEmpty()) other.asPolynomial() else LabeledPolynomialAsIs( toMutableMap() .apply { val degs = mapOf(other to 1U) - this[degs] = constantOne - getOrElse(degs) { constantZero } + this[degs] = getOrElse(degs) { constantZero } - constantOne } ) } @@ -560,11 +554,11 @@ public class LabeledPolynomialSpace>( /** * Instance of zero polynomial (zero of the polynomial ring). */ - override val zero: LabeledPolynomial = LabeledPolynomialAsIs(mapOf(emptyMap() to constantZero)) + override val zero: LabeledPolynomial = LabeledPolynomialAsIs() /** * Instance of unit polynomial (unit of the polynomial ring). */ - override val one: LabeledPolynomial = LabeledPolynomialAsIs(mapOf(emptyMap() to constantOne)) + override val one: LabeledPolynomial = constantOne.asLabeledPolynomial() /** * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt index a83b3915a..76e1a6bb6 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt @@ -172,11 +172,6 @@ public open class ListPolynomialSpace>( ) } - /** - * Converts the integer [value] to polynomial. - */ - public override fun number(value: Int): ListPolynomial = number(constantNumber(value)) - /** * Returns sum of the constant represented as a polynomial and the polynomial. */ diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt index ad421d7d3..f7dd9d8de 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -169,11 +169,6 @@ public class NumberedPolynomialSpace>( ) } - /** - * Converts the integer [value] to polynomial. - */ - public override fun number(value: Int): NumberedPolynomial = number(constantNumber(value)) - /** * Returns sum of the constant represented as a polynomial and the polynomial. */ 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 12490d133..61ea5a342 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 @@ -112,7 +112,7 @@ public interface PolynomialSpace> : Ring

{ /** * Converts the integer [value] to polynomial. */ - public fun number(value: Int): P = one * value + public fun number(value: Int): P = number(constantNumber(value)) /** * Converts the integer to polynomial. */ diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialTest.kt index 15c4c3656..95481f2ef 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialTest.kt @@ -3,6 +3,8 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ +@file:Suppress("LocalVariableName") + package space.kscience.kmath.functions import space.kscience.kmath.expressions.Symbol @@ -26,34 +28,118 @@ class LabeledPolynomialTest { val o = Rational(0) @Test - @Ignore fun test_Variable_Int_plus() { - // TODO + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(5), + mapOf(x to 1u) to Rational(1), + ), + x + 5, + "test 1" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(1), + ), + x + 0, + "test 2" + ) + } } @Test - @Ignore fun test_Variable_Int_minus() { - // TODO + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-5), + mapOf(x to 1u) to Rational(1), + ), + x - 5, + "test 1" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(1), + ), + x - 0, + "test 2" + ) + } } @Test - @Ignore fun test_Variable_Int_times() { - // TODO + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(5), + ), + x * 5, + "test 1" + ) + assertSame( + zero, + x * 0, + "test 2" + ) + } } @Test - @Ignore fun test_Int_Variable_plus() { - // TODO + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(5), + mapOf(x to 1u) to Rational(1), + ), + 5 + x, + "test 1" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(1), + ), + 0 + x, + "test 2" + ) + } } @Test - @Ignore fun test_Int_Variable_minus() { - // TODO + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(5), + mapOf(x to 1u) to Rational(-1), + ), + 5 - x, + "test 1" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(-1), + ), + 0 - x, + "test 2" + ) + } } @Test - @Ignore fun test_Int_Variable_times() { - // TODO + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(5), + ), + 5 * x, + "test 1" + ) + assertSame( + zero, + 0 * x, + "test 2" + ) + } } @Test fun test_Polynomial_Int_plus() { @@ -516,34 +602,126 @@ class LabeledPolynomialTest { } } @Test - @Ignore fun test_Variable_Constant_plus() { - // TODO + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(5), + mapOf(x to 1u) to Rational(1), + ), + x + Rational(5), + "test 1" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(0), + mapOf(x to 1u) to Rational(1), + ), + x + Rational(0), + "test 2" + ) + } } @Test - @Ignore fun test_Variable_Constant_minus() { - // TODO + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-5), + mapOf(x to 1u) to Rational(1), + ), + x - Rational(5), + "test 1" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(0), + mapOf(x to 1u) to Rational(1), + ), + x - Rational(0), + "test 2" + ) + } } @Test - @Ignore fun test_Variable_Constant_times() { - // TODO + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(5), + ), + x * Rational(5), + "test 1" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(0), + ), + x * Rational(0), + "test 2" + ) + } } @Test - @Ignore fun test_Constant_Variable_plus() { - // TODO + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(5), + mapOf(x to 1u) to Rational(1), + ), + Rational(5) + x, + "test 1" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(0), + mapOf(x to 1u) to Rational(1), + ), + Rational(0) + x, + "test 2" + ) + } } @Test - @Ignore fun test_Constant_Variable_minus() { - // TODO + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(5), + mapOf(x to 1u) to Rational(-1), + ), + Rational(5) - x, + "test 1" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(0), + mapOf(x to 1u) to Rational(-1), + ), + Rational(0) - x, + "test 2" + ) + } } @Test - @Ignore fun test_Constant_Variable_times() { - // TODO + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(5), + ), + Rational(5) * x, + "test 1" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(0), + ), + Rational(0) * x, + "test 2" + ) + } } @Test fun test_Polynomial_Constant_plus() { @@ -1068,59 +1246,567 @@ class LabeledPolynomialTest { } } @Test - @Ignore - fun test_Variable_unaryPlus(){ - // TODO + fun test_Variable_unaryPlus() { + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(1), + ), + +x + ) + } } @Test - @Ignore - fun test_Variable_unaryMinus(){ - // TODO + fun test_Variable_unaryMinus() { + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(-1), + ), + -x + ) + } } @Test - @Ignore - fun test_Variable_Variable_plus(){ - // TODO + fun test_Variable_Variable_plus() { + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(1), + mapOf(y to 1u) to Rational(1), + ), + x + y, + "test 1" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(2), + ), + x + x, + "test 2" + ) + } } @Test - @Ignore - fun test_Variable_Variable_minus(){ - // TODO + fun test_Variable_Variable_minus() { + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(1), + mapOf(y to 1u) to Rational(-1), + ), + x - y, + "test 1" + ) + assertSame( + zero, + x - x, + "test 2" + ) + } } @Test - @Ignore - fun test_Variable_Variable_times(){ - // TODO + fun test_Variable_Variable_times() { + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 1u, y to 1u) to Rational(1), + ), + x * y, + "test 1" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 2u) to Rational(1), + ), + x * x, + "test 2" + ) + } } @Test - @Ignore - fun test_Variable_Polynomial_plus(){ - // TODO + fun test_Variable_Polynomial_plus() { + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-16, 4), + mapOf(x to 1u) to Rational(7, 3), + mapOf(x to 2u) to Rational(3, 8), + mapOf(y to 1u) to Rational(-1, 7), + mapOf(x to 1u, y to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u) to Rational(6, 5), + mapOf(y to 2u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u) to Rational(13, 4), + mapOf(x to 2u, y to 2u) to Rational(11, 8), + ), + x + LabeledPolynomialAsIs( + mapOf() to Rational(-16, 4), + mapOf(x to 1u) to Rational(4, 3), + mapOf(x to 2u) to Rational(3, 8), + mapOf(y to 1u) to Rational(-1, 7), + mapOf(x to 1u, y to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u) to Rational(6, 5), + mapOf(y to 2u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u) to Rational(13, 4), + mapOf(x to 2u, y to 2u) to Rational(11, 8), + ), + "test 1" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-16, 4), + mapOf(x to 1u) to Rational(4, 3), + mapOf(x to 2u) to Rational(3, 8), + mapOf(y to 1u) to Rational(6, 7), + mapOf(x to 1u, y to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u) to Rational(6, 5), + mapOf(y to 2u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u) to Rational(13, 4), + mapOf(x to 2u, y to 2u) to Rational(11, 8), + ), + y + LabeledPolynomialAsIs( + mapOf() to Rational(-16, 4), + mapOf(x to 1u) to Rational(4, 3), + mapOf(x to 2u) to Rational(3, 8), + mapOf(y to 1u) to Rational(-1, 7), + mapOf(x to 1u, y to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u) to Rational(6, 5), + mapOf(y to 2u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u) to Rational(13, 4), + mapOf(x to 2u, y to 2u) to Rational(11, 8), + ), + "test 2" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-16, 4), + mapOf(x to 1u) to Rational(4, 3), + mapOf(x to 2u) to Rational(3, 8), + mapOf(y to 1u) to Rational(-1, 7), + mapOf(x to 1u, y to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u) to Rational(6, 5), + mapOf(y to 2u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u) to Rational(13, 4), + mapOf(x to 2u, y to 2u) to Rational(11, 8), + mapOf(iota to 1u) to Rational(1), + ), + iota + LabeledPolynomialAsIs( + mapOf() to Rational(-16, 4), + mapOf(x to 1u) to Rational(4, 3), + mapOf(x to 2u) to Rational(3, 8), + mapOf(y to 1u) to Rational(-1, 7), + mapOf(x to 1u, y to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u) to Rational(6, 5), + mapOf(y to 2u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u) to Rational(13, 4), + mapOf(x to 2u, y to 2u) to Rational(11, 8), + ), + "test 3" + ) + } } @Test - @Ignore - fun test_Variable_Polynomial_minus(){ - // TODO + fun test_Variable_Polynomial_minus() { + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(16, 4), + mapOf(x to 1u) to Rational(-1, 3), + mapOf(x to 2u) to Rational(-3, 8), + mapOf(y to 1u) to Rational(1, 7), + mapOf(x to 1u, y to 1u) to Rational(15, 3), + mapOf(x to 2u, y to 1u) to Rational(-6, 5), + mapOf(y to 2u) to Rational(13, 3), + mapOf(x to 1u, y to 2u) to Rational(-13, 4), + mapOf(x to 2u, y to 2u) to Rational(-11, 8), + ), + x - LabeledPolynomialAsIs( + mapOf() to Rational(-16, 4), + mapOf(x to 1u) to Rational(4, 3), + mapOf(x to 2u) to Rational(3, 8), + mapOf(y to 1u) to Rational(-1, 7), + mapOf(x to 1u, y to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u) to Rational(6, 5), + mapOf(y to 2u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u) to Rational(13, 4), + mapOf(x to 2u, y to 2u) to Rational(11, 8), + ), + "test 1" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(16, 4), + mapOf(x to 1u) to Rational(-4, 3), + mapOf(x to 2u) to Rational(-3, 8), + mapOf(y to 1u) to Rational(8, 7), + mapOf(x to 1u, y to 1u) to Rational(15, 3), + mapOf(x to 2u, y to 1u) to Rational(-6, 5), + mapOf(y to 2u) to Rational(13, 3), + mapOf(x to 1u, y to 2u) to Rational(-13, 4), + mapOf(x to 2u, y to 2u) to Rational(-11, 8), + ), + y - LabeledPolynomialAsIs( + mapOf() to Rational(-16, 4), + mapOf(x to 1u) to Rational(4, 3), + mapOf(x to 2u) to Rational(3, 8), + mapOf(y to 1u) to Rational(-1, 7), + mapOf(x to 1u, y to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u) to Rational(6, 5), + mapOf(y to 2u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u) to Rational(13, 4), + mapOf(x to 2u, y to 2u) to Rational(11, 8), + ), + "test 2" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(16, 4), + mapOf(x to 1u) to Rational(-4, 3), + mapOf(x to 2u) to Rational(-3, 8), + mapOf(y to 1u) to Rational(1, 7), + mapOf(x to 1u, y to 1u) to Rational(15, 3), + mapOf(x to 2u, y to 1u) to Rational(-6, 5), + mapOf(y to 2u) to Rational(13, 3), + mapOf(x to 1u, y to 2u) to Rational(-13, 4), + mapOf(x to 2u, y to 2u) to Rational(-11, 8), + mapOf(iota to 1u) to Rational(1), + ), + iota - LabeledPolynomialAsIs( + mapOf() to Rational(-16, 4), + mapOf(x to 1u) to Rational(4, 3), + mapOf(x to 2u) to Rational(3, 8), + mapOf(y to 1u) to Rational(-1, 7), + mapOf(x to 1u, y to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u) to Rational(6, 5), + mapOf(y to 2u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u) to Rational(13, 4), + mapOf(x to 2u, y to 2u) to Rational(11, 8), + ), + "test 3" + ) + } } @Test - @Ignore - fun test_Variable_Polynomial_times(){ - // TODO + fun test_Variable_Polynomial_times() { + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(-16, 4), + mapOf(x to 2u) to Rational(4, 3), + mapOf(x to 3u) to Rational(3, 8), + mapOf(x to 1u, y to 1u) to Rational(-1, 7), + mapOf(x to 2u, y to 1u) to Rational(-15, 3), + mapOf(x to 3u, y to 1u) to Rational(6, 5), + mapOf(x to 1u, y to 2u) to Rational(-13, 3), + mapOf(x to 2u, y to 2u) to Rational(13, 4), + mapOf(x to 3u, y to 2u) to Rational(11, 8), + ), + x * LabeledPolynomialAsIs( + mapOf() to Rational(-16, 4), + mapOf(x to 1u) to Rational(4, 3), + mapOf(x to 2u) to Rational(3, 8), + mapOf(y to 1u) to Rational(-1, 7), + mapOf(x to 1u, y to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u) to Rational(6, 5), + mapOf(y to 2u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u) to Rational(13, 4), + mapOf(x to 2u, y to 2u) to Rational(11, 8), + ), + "test 1" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(y to 1u) to Rational(-16, 4), + mapOf(x to 1u, y to 1u) to Rational(4, 3), + mapOf(x to 2u, y to 1u) to Rational(3, 8), + mapOf(y to 2u) to Rational(-1, 7), + mapOf(x to 1u, y to 2u) to Rational(-15, 3), + mapOf(x to 2u, y to 2u) to Rational(6, 5), + mapOf(y to 3u) to Rational(-13, 3), + mapOf(x to 1u, y to 3u) to Rational(13, 4), + mapOf(x to 2u, y to 3u) to Rational(11, 8), + ), + y * LabeledPolynomialAsIs( + mapOf() to Rational(-16, 4), + mapOf(x to 1u) to Rational(4, 3), + mapOf(x to 2u) to Rational(3, 8), + mapOf(y to 1u) to Rational(-1, 7), + mapOf(x to 1u, y to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u) to Rational(6, 5), + mapOf(y to 2u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u) to Rational(13, 4), + mapOf(x to 2u, y to 2u) to Rational(11, 8), + ), + "test 2" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(iota to 1u) to Rational(-16, 4), + mapOf(x to 1u, iota to 1u) to Rational(4, 3), + mapOf(x to 2u, iota to 1u) to Rational(3, 8), + mapOf(y to 1u, iota to 1u) to Rational(-1, 7), + mapOf(x to 1u, y to 1u, iota to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u, iota to 1u) to Rational(6, 5), + mapOf(y to 2u, iota to 1u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u, iota to 1u) to Rational(13, 4), + mapOf(x to 2u, y to 2u, iota to 1u) to Rational(11, 8), + ), + iota * LabeledPolynomialAsIs( + mapOf() to Rational(-16, 4), + mapOf(x to 1u) to Rational(4, 3), + mapOf(x to 2u) to Rational(3, 8), + mapOf(y to 1u) to Rational(-1, 7), + mapOf(x to 1u, y to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u) to Rational(6, 5), + mapOf(y to 2u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u) to Rational(13, 4), + mapOf(x to 2u, y to 2u) to Rational(11, 8), + ), + "test 3" + ) + } } @Test - @Ignore - fun test_Polynomial_Variable_plus(){ - // TODO + fun test_Polynomial_Variable_plus() { + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-16, 4), + mapOf(x to 1u) to Rational(7, 3), + mapOf(x to 2u) to Rational(3, 8), + mapOf(y to 1u) to Rational(-1, 7), + mapOf(x to 1u, y to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u) to Rational(6, 5), + mapOf(y to 2u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u) to Rational(13, 4), + mapOf(x to 2u, y to 2u) to Rational(11, 8), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-16, 4), + mapOf(x to 1u) to Rational(4, 3), + mapOf(x to 2u) to Rational(3, 8), + mapOf(y to 1u) to Rational(-1, 7), + mapOf(x to 1u, y to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u) to Rational(6, 5), + mapOf(y to 2u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u) to Rational(13, 4), + mapOf(x to 2u, y to 2u) to Rational(11, 8), + ) + x, + "test 1" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-16, 4), + mapOf(x to 1u) to Rational(4, 3), + mapOf(x to 2u) to Rational(3, 8), + mapOf(y to 1u) to Rational(6, 7), + mapOf(x to 1u, y to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u) to Rational(6, 5), + mapOf(y to 2u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u) to Rational(13, 4), + mapOf(x to 2u, y to 2u) to Rational(11, 8), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-16, 4), + mapOf(x to 1u) to Rational(4, 3), + mapOf(x to 2u) to Rational(3, 8), + mapOf(y to 1u) to Rational(-1, 7), + mapOf(x to 1u, y to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u) to Rational(6, 5), + mapOf(y to 2u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u) to Rational(13, 4), + mapOf(x to 2u, y to 2u) to Rational(11, 8), + ) + y, + "test 2" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-16, 4), + mapOf(x to 1u) to Rational(4, 3), + mapOf(x to 2u) to Rational(3, 8), + mapOf(y to 1u) to Rational(-1, 7), + mapOf(x to 1u, y to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u) to Rational(6, 5), + mapOf(y to 2u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u) to Rational(13, 4), + mapOf(x to 2u, y to 2u) to Rational(11, 8), + mapOf(iota to 1u) to Rational(1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-16, 4), + mapOf(x to 1u) to Rational(4, 3), + mapOf(x to 2u) to Rational(3, 8), + mapOf(y to 1u) to Rational(-1, 7), + mapOf(x to 1u, y to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u) to Rational(6, 5), + mapOf(y to 2u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u) to Rational(13, 4), + mapOf(x to 2u, y to 2u) to Rational(11, 8), + ) + iota, + "test 3" + ) + } } @Test - @Ignore - fun test_Polynomial_Variable_minus(){ - // TODO + fun test_Polynomial_Variable_minus() { + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-16, 4), + mapOf(x to 1u) to Rational(1, 3), + mapOf(x to 2u) to Rational(3, 8), + mapOf(y to 1u) to Rational(-1, 7), + mapOf(x to 1u, y to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u) to Rational(6, 5), + mapOf(y to 2u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u) to Rational(13, 4), + mapOf(x to 2u, y to 2u) to Rational(11, 8), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-16, 4), + mapOf(x to 1u) to Rational(4, 3), + mapOf(x to 2u) to Rational(3, 8), + mapOf(y to 1u) to Rational(-1, 7), + mapOf(x to 1u, y to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u) to Rational(6, 5), + mapOf(y to 2u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u) to Rational(13, 4), + mapOf(x to 2u, y to 2u) to Rational(11, 8), + ) - x, + "test 1" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-16, 4), + mapOf(x to 1u) to Rational(4, 3), + mapOf(x to 2u) to Rational(3, 8), + mapOf(y to 1u) to Rational(-8, 7), + mapOf(x to 1u, y to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u) to Rational(6, 5), + mapOf(y to 2u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u) to Rational(13, 4), + mapOf(x to 2u, y to 2u) to Rational(11, 8), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-16, 4), + mapOf(x to 1u) to Rational(4, 3), + mapOf(x to 2u) to Rational(3, 8), + mapOf(y to 1u) to Rational(-1, 7), + mapOf(x to 1u, y to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u) to Rational(6, 5), + mapOf(y to 2u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u) to Rational(13, 4), + mapOf(x to 2u, y to 2u) to Rational(11, 8), + ) - y, + "test 2" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-16, 4), + mapOf(x to 1u) to Rational(4, 3), + mapOf(x to 2u) to Rational(3, 8), + mapOf(y to 1u) to Rational(-1, 7), + mapOf(x to 1u, y to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u) to Rational(6, 5), + mapOf(y to 2u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u) to Rational(13, 4), + mapOf(x to 2u, y to 2u) to Rational(11, 8), + mapOf(iota to 1u) to Rational(-1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-16, 4), + mapOf(x to 1u) to Rational(4, 3), + mapOf(x to 2u) to Rational(3, 8), + mapOf(y to 1u) to Rational(-1, 7), + mapOf(x to 1u, y to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u) to Rational(6, 5), + mapOf(y to 2u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u) to Rational(13, 4), + mapOf(x to 2u, y to 2u) to Rational(11, 8), + ) - iota, + "test 3" + ) + } } @Test - @Ignore - fun test_Polynomial_Variable_times(){ - // TODO + fun test_Polynomial_Variable_times() { + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(-16, 4), + mapOf(x to 2u) to Rational(4, 3), + mapOf(x to 3u) to Rational(3, 8), + mapOf(x to 1u, y to 1u) to Rational(-1, 7), + mapOf(x to 2u, y to 1u) to Rational(-15, 3), + mapOf(x to 3u, y to 1u) to Rational(6, 5), + mapOf(x to 1u, y to 2u) to Rational(-13, 3), + mapOf(x to 2u, y to 2u) to Rational(13, 4), + mapOf(x to 3u, y to 2u) to Rational(11, 8), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-16, 4), + mapOf(x to 1u) to Rational(4, 3), + mapOf(x to 2u) to Rational(3, 8), + mapOf(y to 1u) to Rational(-1, 7), + mapOf(x to 1u, y to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u) to Rational(6, 5), + mapOf(y to 2u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u) to Rational(13, 4), + mapOf(x to 2u, y to 2u) to Rational(11, 8), + ) * x, + "test 1" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(y to 1u) to Rational(-16, 4), + mapOf(x to 1u, y to 1u) to Rational(4, 3), + mapOf(x to 2u, y to 1u) to Rational(3, 8), + mapOf(y to 2u) to Rational(-1, 7), + mapOf(x to 1u, y to 2u) to Rational(-15, 3), + mapOf(x to 2u, y to 2u) to Rational(6, 5), + mapOf(y to 3u) to Rational(-13, 3), + mapOf(x to 1u, y to 3u) to Rational(13, 4), + mapOf(x to 2u, y to 3u) to Rational(11, 8), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-16, 4), + mapOf(x to 1u) to Rational(4, 3), + mapOf(x to 2u) to Rational(3, 8), + mapOf(y to 1u) to Rational(-1, 7), + mapOf(x to 1u, y to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u) to Rational(6, 5), + mapOf(y to 2u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u) to Rational(13, 4), + mapOf(x to 2u, y to 2u) to Rational(11, 8), + ) * y, + "test 2" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(iota to 1u) to Rational(-16, 4), + mapOf(x to 1u, iota to 1u) to Rational(4, 3), + mapOf(x to 2u, iota to 1u) to Rational(3, 8), + mapOf(y to 1u, iota to 1u) to Rational(-1, 7), + mapOf(x to 1u, y to 1u, iota to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u, iota to 1u) to Rational(6, 5), + mapOf(y to 2u, iota to 1u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u, iota to 1u) to Rational(13, 4), + mapOf(x to 2u, y to 2u, iota to 1u) to Rational(11, 8), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-16, 4), + mapOf(x to 1u) to Rational(4, 3), + mapOf(x to 2u) to Rational(3, 8), + mapOf(y to 1u) to Rational(-1, 7), + mapOf(x to 1u, y to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u) to Rational(6, 5), + mapOf(y to 2u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u) to Rational(13, 4), + mapOf(x to 2u, y to 2u) to Rational(11, 8), + ) * iota, + "test 3" + ) + } } @Test fun test_Polynomial_unaryMinus() { -- 2.34.1 From d44a48bdb1c7d9fa1d8d0918373cf068d04a4c6a Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Mon, 11 Jul 2022 17:27:59 +0300 Subject: [PATCH 100/123] Moving to new modules. --- kmath-functions/build.gradle.kts | 13 +- .../kmath/functions/ListPolynomialTest.kt | 5 +- .../kmath/functions/ListPolynomialUtilTest.kt | 14 +- kmath-polynomialX/build.gradle.kts | 30 ++++ .../LabeledPolynomial.kt | 0 .../LabeledRationalFunction.kt | 0 .../NumberedPolynomial.kt | 0 .../NumberedRationalFunction.kt | 0 .../algebraicStub.kt | 146 ++++++++++++++++++ .../labeledConstructors.kt | 0 .../labeledUtil.kt | 0 .../numberedConstructors.kt | 0 .../numberedUtil.kt | 0 .../functions/LabeledConstructorsTest.kt | 10 +- .../kmath/functions/LabeledPolynomialTest.kt | 25 ++- .../functions/LabeledPolynomialUtilTest.kt | 14 +- .../functions/NumberedConstructorsTest.kt | 0 .../kmath/functions/NumberedPolynomialTest.kt | 11 +- .../functions/NumberedPolynomialUtilTest.kt | 13 +- settings.gradle.kts | 3 + test-utils-functions/build.gradle.kts | 14 ++ .../kmath/functions/testUtils}/IntModulo.kt | 55 +++---- .../functions/testUtils/IntModuloUtils.kt | 19 +++ .../kmath/functions/testUtils}/Rational.kt | 56 +++---- .../kmath/functions/testUtils/assertion.kt | 22 +++ .../kmath/functions/testUtils}/misc.kt | 8 +- test-utils-polynomialX/build.gradle.kts | 16 ++ .../kmath/functions/testUtils/BufferUtils.kt | 12 ++ .../kmath/functions/testUtils}/assertion.kt | 53 ++++--- .../kmath/functions/testUtils/misc.kt | 19 +++ 30 files changed, 419 insertions(+), 139 deletions(-) create mode 100644 kmath-polynomialX/build.gradle.kts rename {kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions => kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions}/LabeledPolynomial.kt (100%) rename {kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions => kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions}/LabeledRationalFunction.kt (100%) rename {kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions => kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions}/NumberedPolynomial.kt (100%) rename {kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions => kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions}/NumberedRationalFunction.kt (100%) create mode 100644 kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/algebraicStub.kt rename {kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions => kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions}/labeledConstructors.kt (100%) rename {kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions => kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions}/labeledUtil.kt (100%) rename {kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions => kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions}/numberedConstructors.kt (100%) rename {kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions => kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions}/numberedUtil.kt (100%) rename {kmath-functions => kmath-polynomialX}/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledConstructorsTest.kt (94%) rename {kmath-functions => kmath-polynomialX}/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialTest.kt (99%) rename {kmath-functions => kmath-polynomialX}/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialUtilTest.kt (99%) rename {kmath-functions => kmath-polynomialX}/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt (100%) rename {kmath-functions => kmath-polynomialX}/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt (99%) rename {kmath-functions => kmath-polynomialX}/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt (99%) create mode 100644 test-utils-functions/build.gradle.kts rename {kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc => test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils}/IntModulo.kt (70%) create mode 100644 test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt rename {kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc => test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils}/Rational.kt (77%) create mode 100644 test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt rename {kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc => test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils}/misc.kt (76%) create mode 100644 test-utils-polynomialX/build.gradle.kts create mode 100644 test-utils-polynomialX/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/BufferUtils.kt rename {kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc => test-utils-polynomialX/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils}/assertion.kt (72%) create mode 100644 test-utils-polynomialX/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/misc.kt diff --git a/kmath-functions/build.gradle.kts b/kmath-functions/build.gradle.kts index fadbac091..0a8e8a1be 100644 --- a/kmath-functions/build.gradle.kts +++ b/kmath-functions/build.gradle.kts @@ -6,9 +6,16 @@ plugins { description = "Functions, integration and interpolation" -kotlin.sourceSets.commonMain { - dependencies { - api(project(":kmath-core")) +kotlin.sourceSets { + commonMain { + dependencies { + api(project(":kmath-core")) + } + } + commonTest { + dependencies { + api(projects.testUtilsFunctions) + } } } diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt index c4a7cc564..e7d8dfd8c 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt @@ -7,7 +7,10 @@ package space.kscience.kmath.functions -import space.kscience.kmath.test.misc.* +import space.kscience.kmath.functions.testUtils.IntModuloRing +import space.kscience.kmath.functions.testUtils.ListPolynomial +import space.kscience.kmath.functions.testUtils.Rational +import space.kscience.kmath.functions.testUtils.RationalField import kotlin.test.* diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt index 685a2a506..339643d02 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt @@ -6,9 +6,9 @@ package space.kscience.kmath.functions import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.test.misc.Rational -import space.kscience.kmath.test.misc.RationalField -import space.kscience.kmath.test.misc.assertFailsWithTypeAndMessage +import space.kscience.kmath.functions.testUtils.Rational +import space.kscience.kmath.functions.testUtils.RationalField +import space.kscience.kmath.functions.testUtils.assertFailsWithTypeAndMessage import kotlin.test.Ignore import kotlin.test.Test import kotlin.test.assertEquals @@ -64,7 +64,7 @@ class ListPolynomialUtilTest { ) assertEquals( Rational(25057, 21000), - ListPolynomial(Rational(5,8), Rational(8, 3), Rational(4, 7), Rational(3, 2)) + ListPolynomial(Rational(5, 8), Rational(8, 3), Rational(4, 7), Rational(3, 2)) .substitute(RationalField, Rational(1, 5)), "test 2" ) @@ -76,13 +76,13 @@ class ListPolynomialUtilTest { ) assertEquals( Rational(4961, 4200), - ListPolynomial(Rational(5,8), Rational(8, 3), Rational(4, 7), Rational(0)) + ListPolynomial(Rational(5, 8), Rational(8, 3), Rational(4, 7), Rational(0)) .substitute(RationalField, Rational(1, 5)), "test 4" ) assertEquals( Rational(3511, 3000), - ListPolynomial(Rational(5,8), Rational(8, 3), Rational(0), Rational(3, 2)) + ListPolynomial(Rational(5, 8), Rational(8, 3), Rational(0), Rational(3, 2)) .substitute(RationalField, Rational(1, 5)), "test 5" ) @@ -233,7 +233,7 @@ class ListPolynomialUtilTest { ListPolynomial( Rational(-13, 9), Rational(5, 3), - Rational(-5, 4) , + Rational(-5, 4), Rational(0), Rational(0), Rational(0), diff --git a/kmath-polynomialX/build.gradle.kts b/kmath-polynomialX/build.gradle.kts new file mode 100644 index 000000000..51b3c0665 --- /dev/null +++ b/kmath-polynomialX/build.gradle.kts @@ -0,0 +1,30 @@ +plugins { + kotlin("multiplatform") + id("ru.mipt.npm.gradle.common") + id("ru.mipt.npm.gradle.native") +} + +description = "Polynomial extra utilities and rational functions" + +kotlin.sourceSets { + commonMain { + dependencies { + api(projects.kmathCore) + api(projects.kmathFunctions) + } + } + commonTest { + dependencies { + api(projects.testUtilsFunctions) + api(projects.testUtilsPolynomialX) + api(kotlin("test")) + } + } +} + +readme { + maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE + propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) + +// feature("TODO") { "TODO" } +} diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt b/kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledPolynomial.kt similarity index 100% rename from kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt rename to kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledPolynomial.kt diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt b/kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledRationalFunction.kt similarity index 100% rename from kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt rename to kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledRationalFunction.kt diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedPolynomial.kt similarity index 100% rename from kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt rename to kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedPolynomial.kt diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt b/kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedRationalFunction.kt similarity index 100% rename from kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt rename to kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedRationalFunction.kt diff --git a/kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/algebraicStub.kt b/kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/algebraicStub.kt new file mode 100644 index 000000000..b40aa4775 --- /dev/null +++ b/kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/algebraicStub.kt @@ -0,0 +1,146 @@ +/* + * 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.functions + +import space.kscience.kmath.operations.* + + +// TODO: All of this should be moved to algebraic structures' place for utilities +// FIXME: Move receiver to context receiver +/** + * Returns product of [arg] and integer [multiplier]. + * + * @param arg the multiplicand. + * @param multiplier the integer multiplier. + * @return product of the multiplicand [arg] and the multiplier [multiplier]. + * @author Gleb Minaev + */ +internal fun Group.multiplyByDoubling(arg: C, multiplier: Int): C = + if (multiplier >= 0) multiplyByDoubling(arg, multiplier.toUInt()) + else multiplyByDoubling(-arg, (-multiplier).toUInt()) + +// FIXME: Move receiver to context receiver +/** + * Adds product of [arg] and [multiplier] to [base]. + * + * @param base the augend. + * @param arg the multiplicand. + * @param multiplier the integer multiplier. + * @return sum of the augend [base] and product of the multiplicand [arg] and the multiplier [multiplier]. + * @author Gleb Minaev + */ +internal fun GroupOps.addMultipliedByDoubling(base: C, arg: C, multiplier: Int): C = + if (multiplier >= 0) addMultipliedByDoubling(base, arg, multiplier.toUInt()) + else addMultipliedByDoubling(base, -arg, (-multiplier).toUInt()) + +// FIXME: Move receiver to context receiver +/** + * Returns product of [arg] and integer [multiplier]. + * + * This is implementation of variation of [exponentiation by squaring](https://en.wikipedia.org/wiki/Exponentiation_by_squaring) + * + * @param arg the multiplicand. + * @param multiplier the integer multiplier. + * @return product of the multiplicand [arg] and the multiplier [multiplier]. + * @author Gleb Minaev + */ +internal tailrec fun Group.multiplyByDoubling(arg: C, multiplier: UInt): C = + when { + multiplier == 0u -> zero + multiplier == 1u -> arg + multiplier and 1u == 0u -> multiplyByDoubling(arg + arg, multiplier shr 1) + multiplier and 1u == 1u -> addMultipliedByDoubling(arg, arg + arg, multiplier shr 1) + else -> error("Error in multiplication group instant by unsigned integer: got reminder by division by 2 different from 0 and 1") + } + +// FIXME: Move receiver to context receiver +/** + * Adds product of [arg] and [multiplier] to [base]. + * + * This is implementation of variation of [exponentiation by squaring](https://en.wikipedia.org/wiki/Exponentiation_by_squaring) + * + * @param base the augend. + * @param arg the multiplicand. + * @param multiplier the integer multiplier. + * @return sum of the augend [base] and product of the multiplicand [arg] and the multiplier [multiplier]. + * @author Gleb Minaev + */ +internal tailrec fun GroupOps.addMultipliedByDoubling(base: C, arg: C, multiplier: UInt): C = + when { + multiplier == 0u -> base + multiplier == 1u -> base + arg + multiplier and 1u == 0u -> addMultipliedByDoubling(base, arg + arg, multiplier shr 1) + multiplier and 1u == 1u -> addMultipliedByDoubling(base + arg, arg + arg, multiplier shr 1) + else -> error("Error in multiplication group instant by unsigned integer: got reminder by division by 2 different from 0 and 1") + } + +// FIXME: Move receiver to context receiver +/** + * Raises [arg] to the integer power [exponent]. + * + * @param arg the base of the power. + * @param exponent the exponent of the power. + * @return [arg] raised to the power [exponent]. + * @author Gleb Minaev + */ +internal fun Field.exponentiateBySquaring(arg: C, exponent: Int): C = + if (exponent >= 0) exponentiateBySquaring(arg, exponent.toUInt()) + else exponentiateBySquaring(one / arg, (-exponent).toUInt()) + +// FIXME: Move receiver to context receiver +/** + * Multiplies [base] and [arg] raised to the integer power [exponent]. + * + * @param base the multiplicand. + * @param arg the base of the power. + * @param exponent the exponent of the power. + * @return product of [base] and [arg] raised to the power [exponent]. + * @author Gleb Minaev + */ +internal fun Field.multiplyExponentiatedBySquaring(base: C, arg: C, exponent: Int): C = + if (exponent >= 0) multiplyExponentiatedBySquaring(base, arg, exponent.toUInt()) + else multiplyExponentiatedBySquaring(base, one / arg, (-exponent).toUInt()) + +// FIXME: Move receiver to context receiver +/** + * Raises [arg] to the integer power [exponent]. + * + * This is implementation of variation of [exponentiation by squaring](https://en.wikipedia.org/wiki/Exponentiation_by_squaring) + * + * @param arg the base of the power. + * @param exponent the exponent of the power. + * @return [arg] raised to the power [exponent]. + * @author Gleb Minaev + */ +internal tailrec fun Ring.exponentiateBySquaring(arg: C, exponent: UInt): C = + when { + exponent == 0u -> zero + exponent == 1u -> arg + exponent and 1u == 0u -> exponentiateBySquaring(arg * arg, exponent shr 1) + exponent and 1u == 1u -> multiplyExponentiatedBySquaring(arg, arg * arg, exponent shr 1) + else -> error("Error in multiplication group instant by unsigned integer: got reminder by division by 2 different from 0 and 1") + } + +// FIXME: Move receiver to context receiver +/** + * Multiplies [base] and [arg] raised to the integer power [exponent]. + * + * This is implementation of variation of [exponentiation by squaring](https://en.wikipedia.org/wiki/Exponentiation_by_squaring) + * + * @param base the multiplicand. + * @param arg the base of the power. + * @param exponent the exponent of the power. + * @return product of [base] and [arg] raised to the power [exponent]. + * @author Gleb Minaev + */ +internal tailrec fun RingOps.multiplyExponentiatedBySquaring(base: C, arg: C, exponent: UInt): C = + when { + exponent == 0u -> base + exponent == 1u -> base * arg + exponent and 1u == 0u -> multiplyExponentiatedBySquaring(base, arg * arg, exponent shr 1) + exponent and 1u == 1u -> multiplyExponentiatedBySquaring(base * arg, arg * arg, exponent shr 1) + else -> error("Error in multiplication group instant by unsigned integer: got reminder by division by 2 different from 0 and 1") + } \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt b/kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/labeledConstructors.kt similarity index 100% rename from kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt rename to kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/labeledConstructors.kt diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledUtil.kt b/kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/labeledUtil.kt similarity index 100% rename from kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledUtil.kt rename to kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/labeledUtil.kt diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt b/kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/numberedConstructors.kt similarity index 100% rename from kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt rename to kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/numberedConstructors.kt diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt b/kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/numberedUtil.kt similarity index 100% rename from kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt rename to kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/numberedUtil.kt diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledConstructorsTest.kt b/kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledConstructorsTest.kt similarity index 94% rename from kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledConstructorsTest.kt rename to kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledConstructorsTest.kt index edeaef6a7..081cf06e4 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledConstructorsTest.kt +++ b/kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledConstructorsTest.kt @@ -6,19 +6,17 @@ package space.kscience.kmath.functions import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.expressions.symbol import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.algebra import space.kscience.kmath.operations.invoke +import space.kscience.kmath.functions.testUtils.t +import space.kscience.kmath.functions.testUtils.x +import space.kscience.kmath.functions.testUtils.y +import space.kscience.kmath.functions.testUtils.z import kotlin.test.Test import kotlin.test.assertEquals class LabeledConstructorsTest { - val x by symbol - val y by symbol - val z by symbol - val t by symbol - @Test @UnstableKMathAPI fun testDSL1() { diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialTest.kt b/kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialTest.kt similarity index 99% rename from kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialTest.kt rename to kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialTest.kt index 95481f2ef..d2d417a02 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialTest.kt +++ b/kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialTest.kt @@ -8,25 +8,22 @@ package space.kscience.kmath.functions import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.expressions.symbol -import space.kscience.kmath.test.misc.IntModuloRing -import space.kscience.kmath.test.misc.Rational -import space.kscience.kmath.test.misc.RationalField -import space.kscience.kmath.test.misc.m +import space.kscience.kmath.functions.testUtils.IntModuloRing +import space.kscience.kmath.functions.testUtils.Rational +import space.kscience.kmath.functions.testUtils.RationalField +import space.kscience.kmath.functions.testUtils.o +import space.kscience.kmath.functions.testUtils.m import kotlin.test.* +import space.kscience.kmath.functions.testUtils.x +import space.kscience.kmath.functions.testUtils.y +import space.kscience.kmath.functions.testUtils.z +import space.kscience.kmath.functions.testUtils.t +import space.kscience.kmath.functions.testUtils.s +import space.kscience.kmath.functions.testUtils.iota // TODO: Тесты на конвертацию. class LabeledPolynomialTest { - val x by symbol - val y by symbol - val z by symbol - val t by symbol - val s by symbol - val iota by symbol - - val o = Rational(0) - @Test fun test_Variable_Int_plus() { RationalField.labeledPolynomialSpace { diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialUtilTest.kt b/kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialUtilTest.kt similarity index 99% rename from kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialUtilTest.kt rename to kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialUtilTest.kt index cdfe309f9..37329a318 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialUtilTest.kt +++ b/kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialUtilTest.kt @@ -6,20 +6,18 @@ package space.kscience.kmath.functions import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.expressions.symbol import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.test.misc.Rational -import space.kscience.kmath.test.misc.RationalField -import space.kscience.kmath.test.misc.assertEquals +import space.kscience.kmath.functions.testUtils.Rational +import space.kscience.kmath.functions.testUtils.RationalField import kotlin.test.Ignore import kotlin.test.Test import kotlin.test.assertEquals +import space.kscience.kmath.functions.testUtils.x +import space.kscience.kmath.functions.testUtils.y +import space.kscience.kmath.functions.testUtils.iota +import space.kscience.kmath.functions.testUtils.assertEquals class LabeledPolynomialUtilTest { - val x by symbol - val y by symbol - val iota by symbol - @Test fun test_Polynomial_substitute_Double() { assertEquals( diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt b/kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt similarity index 100% rename from kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt rename to kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt b/kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt similarity index 99% rename from kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt rename to kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt index 007c3e5e9..ec2e34520 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt +++ b/kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt @@ -7,10 +7,11 @@ package space.kscience.kmath.functions -import space.kscience.kmath.test.misc.IntModuloRing -import space.kscience.kmath.test.misc.Rational -import space.kscience.kmath.test.misc.RationalField -import space.kscience.kmath.test.misc.m +import space.kscience.kmath.functions.testUtils.IntModuloRing +import space.kscience.kmath.functions.testUtils.Rational +import space.kscience.kmath.functions.testUtils.RationalField +import space.kscience.kmath.functions.testUtils.m +import space.kscience.kmath.functions.testUtils.o import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertSame @@ -18,8 +19,6 @@ import kotlin.test.fail class NumberedPolynomialTest { - val o = Rational(0) - @Test fun test_Polynomial_Int_plus() { RationalField.numberedPolynomialSpace { diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt b/kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt similarity index 99% rename from kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt rename to kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt index 1b87d3fcf..82f1e561a 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt +++ b/kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt @@ -6,19 +6,16 @@ package space.kscience.kmath.functions import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.asBuffer -import space.kscience.kmath.test.misc.Rational -import space.kscience.kmath.test.misc.RationalField -import space.kscience.kmath.test.misc.assertEquals -import space.kscience.kmath.test.misc.assertFailsWithTypeAndMessage +import space.kscience.kmath.functions.testUtils.Rational +import space.kscience.kmath.functions.testUtils.RationalField +import space.kscience.kmath.functions.testUtils.assertFailsWithTypeAndMessage import kotlin.test.Ignore import kotlin.test.Test import kotlin.test.assertEquals +import space.kscience.kmath.functions.testUtils.bufferOf +import space.kscience.kmath.functions.testUtils.assertEquals -fun bufferOf(vararg elements: T): Buffer = elements.asBuffer() - class NumberedPolynomialUtilTest { @Test fun test_Polynomial_substitute_Double_Map() { diff --git a/settings.gradle.kts b/settings.gradle.kts index e3c621e9a..543d08001 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -26,6 +26,9 @@ include( ":kmath-core", ":kmath-coroutines", ":kmath-functions", + ":test-utils-functions", + ":kmath-polynomialX", + ":test-utils-polynomialX", ":kmath-histograms", ":kmath-commons", ":kmath-viktor", diff --git a/test-utils-functions/build.gradle.kts b/test-utils-functions/build.gradle.kts new file mode 100644 index 000000000..8476abecc --- /dev/null +++ b/test-utils-functions/build.gradle.kts @@ -0,0 +1,14 @@ +plugins { + id("ru.mipt.npm.gradle.mpp") + id("ru.mipt.npm.gradle.native") +} + +kotlin.sourceSets { + commonMain { + dependencies { + api(projects.kmathCore) + api(projects.kmathFunctions) + api(kotlin("test")) + } + } +} diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt b/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt similarity index 70% rename from kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt rename to test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt index f6e8457bb..933c4dc4c 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt +++ b/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt @@ -5,40 +5,37 @@ @file:Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress") -package space.kscience.kmath.test.misc +package space.kscience.kmath.functions.testUtils -import space.kscience.kmath.functions.ListPolynomial -import space.kscience.kmath.functions.ListPolynomialSpace -import space.kscience.kmath.functions.PolynomialSpaceOverRing import space.kscience.kmath.operations.Ring -class IntModulo { - val residue: Int - val modulus: Int +public class IntModulo { + public val residue: Int + public val modulus: Int @PublishedApi internal constructor(residue: Int, modulus: Int, toCheckInput: Boolean = true) { if (toCheckInput) { require(modulus != 0) { "modulus can not be zero" } this.modulus = if (modulus < 0) -modulus else modulus - this.residue = residue.mod(modulus) + this.residue = residue.mod(this.modulus) } else { this.residue = residue this.modulus = modulus } } - constructor(residue: Int, modulus: Int) : this(residue, modulus, true) + public constructor(residue: Int, modulus: Int) : this(residue, modulus, true) - operator fun unaryPlus(): IntModulo = this - operator fun unaryMinus(): IntModulo = + public operator fun unaryPlus(): IntModulo = this + public operator fun unaryMinus(): IntModulo = IntModulo( if (residue == 0) 0 else modulus - residue, modulus, toCheckInput = false ) - operator fun plus(other: IntModulo): IntModulo { + public operator fun plus(other: IntModulo): IntModulo { require(modulus == other.modulus) { "can not add two residue different modulo" } return IntModulo( (residue + other.residue) % modulus, @@ -46,13 +43,13 @@ class IntModulo { toCheckInput = false ) } - operator fun plus(other: Int): IntModulo = + public operator fun plus(other: Int): IntModulo = IntModulo( (residue + other) % modulus, modulus, toCheckInput = false ) - operator fun minus(other: IntModulo): IntModulo { + public operator fun minus(other: IntModulo): IntModulo { require(modulus == other.modulus) { "can not subtract two residue different modulo" } return IntModulo( (residue - other.residue) % modulus, @@ -60,13 +57,13 @@ class IntModulo { toCheckInput = false ) } - operator fun minus(other: Int): IntModulo = + public operator fun minus(other: Int): IntModulo = IntModulo( (residue - other) % modulus, modulus, toCheckInput = false ) - operator fun times(other: IntModulo): IntModulo { + public operator fun times(other: IntModulo): IntModulo { require(modulus == other.modulus) { "can not multiply two residue different modulo" } return IntModulo( (residue * other.residue) % modulus, @@ -74,13 +71,13 @@ class IntModulo { toCheckInput = false ) } - operator fun times(other: Int): IntModulo = + public operator fun times(other: Int): IntModulo = IntModulo( (residue * other) % modulus, modulus, toCheckInput = false ) - operator fun div(other: IntModulo): IntModulo { + public operator fun div(other: IntModulo): IntModulo { require(modulus == other.modulus) { "can not divide two residue different modulo" } val (reciprocalCandidate, gcdOfOtherResidueAndModulus) = bezoutIdentityWithGCD(other.residue, modulus) require(gcdOfOtherResidueAndModulus == 1) { "can not divide to residue that has non-trivial GCD with modulo" } @@ -90,7 +87,7 @@ class IntModulo { toCheckInput = false ) } - operator fun div(other: Int): IntModulo { + public operator fun div(other: Int): IntModulo { val (reciprocalCandidate, gcdOfOtherResidueAndModulus) = bezoutIdentityWithGCD(other, modulus) require(gcdOfOtherResidueAndModulus == 1) { "can not divide to residue that has non-trivial GCD with modulo" } return IntModulo( @@ -111,11 +108,11 @@ class IntModulo { } @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE") -class IntModuloRing : Ring { +public class IntModuloRing : Ring { - val modulus: Int + public val modulus: Int - constructor(modulus: Int) { + public constructor(modulus: Int) { require(modulus != 0) { "modulus can not be zero" } this.modulus = if (modulus < 0) -modulus else modulus } @@ -123,7 +120,7 @@ class IntModuloRing : Ring { override inline val zero: IntModulo get() = IntModulo(0, modulus, toCheckInput = false) override inline val one: IntModulo get() = IntModulo(1, modulus, toCheckInput = false) - fun number(arg: Int) = IntModulo(arg, modulus, toCheckInput = false) + public fun number(arg: Int): IntModulo = IntModulo(arg, modulus, toCheckInput = false) override inline fun add(left: IntModulo, right: IntModulo): IntModulo = left + right override inline fun multiply(left: IntModulo, right: IntModulo): IntModulo = left * right @@ -132,13 +129,5 @@ class IntModuloRing : Ring { override inline fun IntModulo.plus(arg: IntModulo): IntModulo = this + arg override inline fun IntModulo.minus(arg: IntModulo): IntModulo = this - arg override inline fun IntModulo.times(arg: IntModulo): IntModulo = this * arg - inline fun IntModulo.div(arg: IntModulo): IntModulo = this / arg -} - -fun ListPolynomialSpace.ListPolynomial(vararg coefs: Int): ListPolynomial = - ListPolynomial(coefs.map { IntModulo(it, ring.modulus) }) -fun IntModuloRing.ListPolynomial(vararg coefs: Int): ListPolynomial = - ListPolynomial(coefs.map { IntModulo(it, modulus) }) - -fun IntModuloRing.m(arg: Int) = IntModulo(arg, modulus) -fun PolynomialSpaceOverRing.m(arg: Int) = IntModulo(arg, ring.modulus) \ No newline at end of file + public inline fun IntModulo.div(arg: IntModulo): IntModulo = this / arg +} \ No newline at end of file diff --git a/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt b/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt new file mode 100644 index 000000000..4b65fbea1 --- /dev/null +++ b/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt @@ -0,0 +1,19 @@ +/* + * 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.functions.testUtils + +import space.kscience.kmath.functions.ListPolynomial +import space.kscience.kmath.functions.ListPolynomialSpace +import space.kscience.kmath.functions.PolynomialSpaceOverRing + + +public fun ListPolynomialSpace.ListPolynomial(vararg coefs: Int): ListPolynomial = + ListPolynomial(coefs.map { IntModulo(it, ring.modulus) }) +public fun IntModuloRing.ListPolynomial(vararg coefs: Int): ListPolynomial = + ListPolynomial(coefs.map { IntModulo(it, modulus) }) + +public fun IntModuloRing.m(arg: Int): IntModulo = IntModulo(arg, modulus) +public fun PolynomialSpaceOverRing.m(arg: Int): IntModulo = IntModulo(arg, ring.modulus) \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt b/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt similarity index 77% rename from kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt rename to test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt index 731621658..27b0eb21e 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt +++ b/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt @@ -5,21 +5,21 @@ @file:Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress") -package space.kscience.kmath.test.misc +package space.kscience.kmath.functions.testUtils import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.Field import space.kscience.kmath.operations.NumbersAddOps @Suppress("NAME_SHADOWING") -class Rational { - companion object { - val ZERO: Rational = Rational(0L) - val ONE: Rational = Rational(1L) +public class Rational { + public companion object { + public val ZERO: Rational = Rational(0L) + public val ONE: Rational = Rational(1L) } - val numerator: Long - val denominator: Long + public val numerator: Long + public val denominator: Long internal constructor(numerator: Long, denominator: Long, toCheckInput: Boolean = true) { if (toCheckInput) { @@ -35,16 +35,16 @@ class Rational { } } - constructor(numerator: Int, denominator: Int) : this(numerator.toLong(), denominator.toLong(), true) - constructor(numerator: Int, denominator: Long) : this(numerator.toLong(), denominator, true) - constructor(numerator: Long, denominator: Int) : this(numerator, denominator.toLong(), true) - constructor(numerator: Long, denominator: Long) : this(numerator, denominator, true) - constructor(numerator: Int) : this(numerator.toLong(), 1L, false) - constructor(numerator: Long) : this(numerator, 1L, false) + public constructor(numerator: Int, denominator: Int) : this(numerator.toLong(), denominator.toLong(), true) + public constructor(numerator: Int, denominator: Long) : this(numerator.toLong(), denominator, true) + public constructor(numerator: Long, denominator: Int) : this(numerator, denominator.toLong(), true) + public constructor(numerator: Long, denominator: Long) : this(numerator, denominator, true) + public constructor(numerator: Int) : this(numerator.toLong(), 1L, false) + public constructor(numerator: Long) : this(numerator, 1L, false) - operator fun unaryPlus(): Rational = this - operator fun unaryMinus(): Rational = Rational(-this.numerator, this.denominator) - operator fun plus(other: Rational): Rational { + public operator fun unaryPlus(): Rational = this + public operator fun unaryMinus(): Rational = Rational(-this.numerator, this.denominator) + public operator fun plus(other: Rational): Rational { val denominatorsGcd = gcd(denominator, other.denominator) val dividedThisDenominator = denominator / denominatorsGcd val dividedOtherDenominator = other.denominator / denominatorsGcd @@ -56,19 +56,19 @@ class Rational { toCheckInput = false ) } - operator fun plus(other: Int): Rational = + public operator fun plus(other: Int): Rational = Rational( numerator + denominator * other.toLong(), denominator, toCheckInput = false ) - operator fun plus(other: Long): Rational = + public operator fun plus(other: Long): Rational = Rational( numerator + denominator * other, denominator, toCheckInput = false ) - operator fun minus(other: Rational): Rational { + public operator fun minus(other: Rational): Rational { val denominatorsGcd = gcd(denominator, other.denominator) val dividedThisDenominator = denominator / denominatorsGcd val dividedOtherDenominator = other.denominator / denominatorsGcd @@ -80,19 +80,19 @@ class Rational { toCheckInput = false ) } - operator fun minus(other: Int): Rational = + public operator fun minus(other: Int): Rational = Rational( numerator - denominator * other.toLong(), denominator, toCheckInput = false ) - operator fun minus(other: Long): Rational = + public operator fun minus(other: Long): Rational = Rational( numerator - denominator * other, denominator, toCheckInput = false ) - operator fun times(other: Rational): Rational { + public operator fun times(other: Rational): Rational { val thisDenominatorAndOtherNumeratorGcd = gcd(denominator, other.numerator) val otherDenominatorAndThisNumeratorGcd = gcd(other.denominator, numerator) return Rational( @@ -101,7 +101,7 @@ class Rational { toCheckInput = false ) } - operator fun times(other: Int): Rational { + public operator fun times(other: Int): Rational { val other = other.toLong() val denominatorAndOtherGcd = gcd(denominator, other) return Rational( @@ -110,7 +110,7 @@ class Rational { toCheckInput = false ) } - operator fun times(other: Long): Rational { + public operator fun times(other: Long): Rational { val denominatorAndOtherGcd = gcd(denominator, other) return Rational( numerator * (other / denominatorAndOtherGcd), @@ -118,7 +118,7 @@ class Rational { toCheckInput = false ) } - operator fun div(other: Rational): Rational { + public operator fun div(other: Rational): Rational { val denominatorsGcd = gcd(denominator, other.denominator) val numeratorsGcd = gcd(numerator, other.numerator) return Rational( @@ -126,7 +126,7 @@ class Rational { (denominator / denominatorsGcd) * (other.numerator / numeratorsGcd) ) } - operator fun div(other: Int): Rational { + public operator fun div(other: Int): Rational { val other = other.toLong() val numeratorAndOtherGcd = gcd(numerator, other) return Rational( @@ -135,7 +135,7 @@ class Rational { toCheckInput = false ) } - operator fun div(other: Long): Rational { + public operator fun div(other: Long): Rational { val numeratorAndOtherGcd = gcd(numerator, other) return Rational( numerator / numeratorAndOtherGcd, @@ -158,7 +158,7 @@ class Rational { @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE") @OptIn(UnstableKMathAPI::class) -object RationalField : Field, NumbersAddOps { +public object RationalField : Field, NumbersAddOps { override inline val zero: Rational get() = Rational.ZERO override inline val one: Rational get() = Rational.ONE diff --git a/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt b/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt new file mode 100644 index 000000000..5cf82996f --- /dev/null +++ b/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt @@ -0,0 +1,22 @@ +/* + * 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.functions.testUtils + +import kotlin.test.assertEquals +import kotlin.test.assertFailsWith + + +public inline fun assertFailsWithTypeAndMessage( + expectedMessage: String? = null, + assertionMessage: String? = null, + block: () -> Unit +) { + assertEquals( + expectedMessage, + assertFailsWith(T::class, assertionMessage, block).message, + assertionMessage + ) +} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt b/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/misc.kt similarity index 76% rename from kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt rename to test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/misc.kt index ed41b9245..ff67f19d8 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt +++ b/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/misc.kt @@ -3,16 +3,16 @@ * 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 +package space.kscience.kmath.functions.testUtils import kotlin.math.abs -data class BezoutIdentityWithGCD(val first: T, val second: T, val gcd: T) +internal data class BezoutIdentityWithGCD(val first: T, val second: T, val gcd: T) -tailrec fun gcd(a: Long, b: Long): Long = if (a == 0L) abs(b) else gcd(b % a, a) +internal tailrec fun gcd(a: Long, b: Long): Long = if (a == 0L) abs(b) else gcd(b % a, a) -fun bezoutIdentityWithGCD(a: Int, b: Int): BezoutIdentityWithGCD = +internal fun bezoutIdentityWithGCD(a: Int, b: Int): BezoutIdentityWithGCD = when { a < 0 && b < 0 -> with(bezoutIdentityWithGCDInternalLogic(-a, -b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(-first, -second, gcd) } a < 0 -> with(bezoutIdentityWithGCDInternalLogic(-a, b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(-first, second, gcd) } diff --git a/test-utils-polynomialX/build.gradle.kts b/test-utils-polynomialX/build.gradle.kts new file mode 100644 index 000000000..f20e1b8bb --- /dev/null +++ b/test-utils-polynomialX/build.gradle.kts @@ -0,0 +1,16 @@ +plugins { + id("ru.mipt.npm.gradle.mpp") + id("ru.mipt.npm.gradle.native") +} + +kotlin.sourceSets { + commonMain { + dependencies { + api(projects.kmathCore) + api(projects.kmathFunctions) + api(projects.testUtilsFunctions) + api(projects.kmathPolynomialX) + api(kotlin("test")) + } + } +} diff --git a/test-utils-polynomialX/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/BufferUtils.kt b/test-utils-polynomialX/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/BufferUtils.kt new file mode 100644 index 000000000..afd26dd36 --- /dev/null +++ b/test-utils-polynomialX/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/BufferUtils.kt @@ -0,0 +1,12 @@ +/* + * 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.functions.testUtils + +import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.asBuffer + + +public fun bufferOf(vararg elements: T): Buffer = elements.asBuffer() \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/assertion.kt b/test-utils-polynomialX/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt similarity index 72% rename from kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/assertion.kt rename to test-utils-polynomialX/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt index 85180bd2a..9ca5f43a3 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/assertion.kt +++ b/test-utils-polynomialX/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt @@ -3,7 +3,7 @@ * 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 +package space.kscience.kmath.functions.testUtils import space.kscience.kmath.functions.LabeledPolynomial import space.kscience.kmath.functions.LabeledRationalFunction @@ -13,36 +13,45 @@ import kotlin.test.assertEquals import kotlin.test.assertFailsWith -fun assertContentEquals(expected: Map, actual: Map, absoluteTolerance: Double, message: String? = null) { +public fun assertContentEquals( + expected: Map, + actual: Map, + absoluteTolerance: Double, + message: String? = null +) { assertEquals(expected.keys, actual.keys, message) for ((key, expectedValue) in expected) assertEquals(expectedValue, actual[key]!!, absoluteTolerance, message) } -fun assertEquals( +public fun assertEquals( expected: NumberedPolynomial, actual: NumberedPolynomial, absoluteTolerance: Double, message: String? = null -) = assertContentEquals( - expected.coefficients, - actual.coefficients, - absoluteTolerance, - message -) +) { + assertContentEquals( + expected.coefficients, + actual.coefficients, + absoluteTolerance, + message + ) +} -fun assertEquals( +public fun assertEquals( expected: LabeledPolynomial, actual: LabeledPolynomial, absoluteTolerance: Double, message: String? = null -) = assertContentEquals( - expected.coefficients, - actual.coefficients, - absoluteTolerance, - message -) +) { + assertContentEquals( + expected.coefficients, + actual.coefficients, + absoluteTolerance, + message + ) +} -fun assertEquals( +public fun assertEquals( expected: NumberedRationalFunction, actual: NumberedRationalFunction, absoluteTolerance: Double, @@ -62,7 +71,7 @@ fun assertEquals( ) } -fun assertEquals( +public fun assertEquals( expected: LabeledRationalFunction, actual: LabeledRationalFunction, absoluteTolerance: Double, @@ -82,13 +91,15 @@ fun assertEquals( ) } -inline fun assertFailsWithTypeAndMessage( +// FIXME: Don't understand why but the same function from test-utils-functions module can not be used +public inline fun assertFailsWithTypeAndMessage( expectedMessage: String? = null, assertionMessage: String? = null, block: () -> Unit -) = +) { assertEquals( expectedMessage, assertFailsWith(T::class, assertionMessage, block).message, assertionMessage - ) \ No newline at end of file + ) +} \ No newline at end of file diff --git a/test-utils-polynomialX/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/misc.kt b/test-utils-polynomialX/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/misc.kt new file mode 100644 index 000000000..051fc0f37 --- /dev/null +++ b/test-utils-polynomialX/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/misc.kt @@ -0,0 +1,19 @@ +/* + * 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.functions.testUtils + +import space.kscience.kmath.expressions.Symbol +import space.kscience.kmath.expressions.symbol + + +public val o: Rational = Rational(0) + +public val x: Symbol by symbol +public val y: Symbol by symbol +public val z: Symbol by symbol +public val t: Symbol by symbol +public val s: Symbol by symbol +public val iota: Symbol by symbol \ No newline at end of file -- 2.34.1 From 1c719b9e709ec07920545a99db6c7c9f274b8908 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Mon, 11 Jul 2022 17:52:46 +0300 Subject: [PATCH 101/123] Fix examples. --- examples/build.gradle.kts | 2 ++ .../main/kotlin/space/kscience/kmath/functions/polynomials.kt | 2 ++ 2 files changed, 4 insertions(+) diff --git a/examples/build.gradle.kts b/examples/build.gradle.kts index 60f8f5aed..67b28cd85 100644 --- a/examples/build.gradle.kts +++ b/examples/build.gradle.kts @@ -15,6 +15,8 @@ dependencies { implementation(project(":kmath-coroutines")) implementation(project(":kmath-commons")) implementation(project(":kmath-complex")) + implementation(project(":kmath-functions")) + implementation(project(":kmath-polynomialX")) implementation(project(":kmath-optimization")) implementation(project(":kmath-stat")) implementation(project(":kmath-viktor")) diff --git a/examples/src/main/kotlin/space/kscience/kmath/functions/polynomials.kt b/examples/src/main/kotlin/space/kscience/kmath/functions/polynomials.kt index 7843a0210..4151b0283 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/functions/polynomials.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/functions/polynomials.kt @@ -3,6 +3,8 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ +@file:Suppress("LocalVariableName") + package space.kscience.kmath.functions import space.kscience.kmath.expressions.Symbol -- 2.34.1 From 51dd72e48f2043a00bc2a5da75dbf8b6c1c2039b Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Mon, 11 Jul 2022 22:39:13 +0300 Subject: [PATCH 102/123] Finish move. --- examples/build.gradle.kts | 2 +- .../build.gradle.kts | 4 +- .../LabeledPolynomial.kt | 0 .../LabeledRationalFunction.kt | 0 .../ListPolynomial.kt | 387 ++++++++++++++ .../ListRationalFunction.kt | 0 .../NumberedPolynomial.kt | 0 .../NumberedRationalFunction.kt | 0 .../Polynomial.kt | 502 ++++++++++++++++++ .../RationalFunction.kt | 3 +- .../algebraicStub.kt | 0 .../labeledConstructors.kt | 0 .../labeledUtil.kt | 2 +- .../listConstructors.kt | 92 ++++ .../listUtil.kt | 255 +++++++++ .../space.kscience.kmath.functions/misc.kt | 22 + .../numberedConstructors.kt | 0 .../numberedUtil.kt | 0 .../functions/LabeledConstructorsTest.kt | 6 +- .../kmath/functions/LabeledPolynomialTest.kt | 10 +- .../functions/LabeledPolynomialUtilTest.kt | 9 +- .../functions/NumberedConstructorsTest.kt | 0 .../kmath/functions/NumberedPolynomialTest.kt | 0 .../functions/NumberedPolynomialUtilTest.kt | 0 settings.gradle.kts | 4 +- .../build.gradle.kts | 4 +- .../kmath/functions/testUtils/BufferUtils.kt | 0 .../kmath/functions/testUtils/assertion.kt | 0 .../kmath/functions/testUtils/misc.kt | 0 29 files changed, 1278 insertions(+), 24 deletions(-) rename {kmath-polynomialX => kmath-polynomial}/build.gradle.kts (81%) rename {kmath-polynomialX => kmath-polynomial}/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledPolynomial.kt (100%) rename {kmath-polynomialX => kmath-polynomial}/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledRationalFunction.kt (100%) create mode 100644 kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/ListPolynomial.kt rename {kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions => kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions}/ListRationalFunction.kt (100%) rename {kmath-polynomialX => kmath-polynomial}/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedPolynomial.kt (100%) rename {kmath-polynomialX => kmath-polynomial}/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedRationalFunction.kt (100%) create mode 100644 kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/Polynomial.kt rename {kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions => kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions}/RationalFunction.kt (99%) rename {kmath-polynomialX => kmath-polynomial}/src/commonMain/kotlin/space.kscience.kmath.functions/algebraicStub.kt (100%) rename {kmath-polynomialX => kmath-polynomial}/src/commonMain/kotlin/space.kscience.kmath.functions/labeledConstructors.kt (100%) rename {kmath-polynomialX => kmath-polynomial}/src/commonMain/kotlin/space.kscience.kmath.functions/labeledUtil.kt (99%) create mode 100644 kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/listConstructors.kt create mode 100644 kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/listUtil.kt create mode 100644 kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/misc.kt rename {kmath-polynomialX => kmath-polynomial}/src/commonMain/kotlin/space.kscience.kmath.functions/numberedConstructors.kt (100%) rename {kmath-polynomialX => kmath-polynomial}/src/commonMain/kotlin/space.kscience.kmath.functions/numberedUtil.kt (100%) rename {kmath-polynomialX => kmath-polynomial}/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledConstructorsTest.kt (99%) rename {kmath-polynomialX => kmath-polynomial}/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialTest.kt (99%) rename {kmath-polynomialX => kmath-polynomial}/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialUtilTest.kt (99%) rename {kmath-polynomialX => kmath-polynomial}/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt (100%) rename {kmath-polynomialX => kmath-polynomial}/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt (100%) rename {kmath-polynomialX => kmath-polynomial}/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt (100%) rename {test-utils-polynomialX => test-utils-polynomial}/build.gradle.kts (63%) rename {test-utils-polynomialX => test-utils-polynomial}/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/BufferUtils.kt (100%) rename {test-utils-polynomialX => test-utils-polynomial}/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt (100%) rename {test-utils-polynomialX => test-utils-polynomial}/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/misc.kt (100%) diff --git a/examples/build.gradle.kts b/examples/build.gradle.kts index 67b28cd85..aa5c1f47a 100644 --- a/examples/build.gradle.kts +++ b/examples/build.gradle.kts @@ -16,7 +16,7 @@ dependencies { implementation(project(":kmath-commons")) implementation(project(":kmath-complex")) implementation(project(":kmath-functions")) - implementation(project(":kmath-polynomialX")) + implementation(project(":kmath-polynomial")) implementation(project(":kmath-optimization")) implementation(project(":kmath-stat")) implementation(project(":kmath-viktor")) diff --git a/kmath-polynomialX/build.gradle.kts b/kmath-polynomial/build.gradle.kts similarity index 81% rename from kmath-polynomialX/build.gradle.kts rename to kmath-polynomial/build.gradle.kts index 51b3c0665..dcfcb1b46 100644 --- a/kmath-polynomialX/build.gradle.kts +++ b/kmath-polynomial/build.gradle.kts @@ -10,13 +10,11 @@ kotlin.sourceSets { commonMain { dependencies { api(projects.kmathCore) - api(projects.kmathFunctions) } } commonTest { dependencies { - api(projects.testUtilsFunctions) - api(projects.testUtilsPolynomialX) + api(projects.testUtilsPolynomial) api(kotlin("test")) } } diff --git a/kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledPolynomial.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledPolynomial.kt similarity index 100% rename from kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledPolynomial.kt rename to kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledPolynomial.kt diff --git a/kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledRationalFunction.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledRationalFunction.kt similarity index 100% rename from kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledRationalFunction.kt rename to kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledRationalFunction.kt diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/ListPolynomial.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/ListPolynomial.kt new file mode 100644 index 000000000..76e1a6bb6 --- /dev/null +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/ListPolynomial.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. + */ + +@file:Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress") + +package space.kscience.kmath.functions + +import space.kscience.kmath.operations.Ring +import space.kscience.kmath.operations.ScaleOperations +import space.kscience.kmath.operations.invoke +import kotlin.math.max +import kotlin.math.min + + +/** + * Represents univariate polynomial that stores its coefficients in a [List]. + * + * @param C the type of constants. + */ +public data class ListPolynomial( + /** + * List that contains coefficients of the polynomial. Every monomial `a x^d` is stored as a coefficient `a` placed + * into the list at index `d`. For example, coefficients of a polynomial `5 x^2 - 6` can be represented as + * ``` + * listOf( + * -6, // -6 + + * 0, // 0 x + + * 5, // 5 x^2 + * ) + * ``` + * and also as + * ``` + * listOf( + * -6, // -6 + + * 0, // 0 x + + * 5, // 5 x^2 + * 0, // 0 x^3 + * 0, // 0 x^4 + * ) + * ``` + * It is not prohibited to put extra zeros at end of the list (as for `0x^3` and `0x^4` in the example). But the + * longer the coefficients list the worse performance of arithmetical operations performed on it. Thus, it is + * recommended not to put (or even to remove) extra (or useless) coefficients at the end of the coefficients list. + */ + public val coefficients: List +) : Polynomial { + override fun toString(): String = "ListPolynomial$coefficients" +} + +/** + * Arithmetic context for univariate polynomials with coefficients stored as a [List] constructed with the provided + * [ring] of constants. + * + * @param C the type of constants. Polynomials have them a coefficients in their terms. + * @param A type of provided underlying ring of constants. It's [Ring] of [C]. + * @param ring underlying ring of constants of type [A]. + */ +public open class ListPolynomialSpace>( + public override val ring: A, +) : PolynomialSpaceOverRing, A> { + /** + * Returns sum of the polynomial and the integer represented as a polynomial. + * + * The operation is equivalent to adding [other] copies of unit polynomial to [this]. + */ + public override operator fun ListPolynomial.plus(other: Int): ListPolynomial = + if (other == 0) this + else + ListPolynomial( + coefficients + .toMutableList() + .apply { + val result = getOrElse(0) { constantZero } + other + + if(size == 0) add(result) + else this[0] = result + } + ) + /** + * Returns difference between the polynomial and the integer represented as a polynomial. + * + * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. + */ + public override operator fun ListPolynomial.minus(other: Int): ListPolynomial = + if (other == 0) this + else + ListPolynomial( + coefficients + .toMutableList() + .apply { + val result = getOrElse(0) { constantZero } - other + + if(size == 0) add(result) + else this[0] = result + } + ) + /** + * Returns product of the polynomial and the integer represented as a polynomial. + * + * The operation is equivalent to sum of [other] copies of [this]. + */ + public override operator fun ListPolynomial.times(other: Int): ListPolynomial = + when (other) { + 0 -> zero + 1 -> this + else -> ListPolynomial( + coefficients + .toMutableList() + .apply { + for (deg in indices) this[deg] = this[deg] * other + } + ) + } + + /** + * Returns sum of the integer represented as a polynomial and the polynomial. + * + * The operation is equivalent to adding [this] copies of unit polynomial to [other]. + */ + public override operator fun Int.plus(other: ListPolynomial): ListPolynomial = + if (this == 0) other + else + ListPolynomial( + other.coefficients + .toMutableList() + .apply { + val result = this@plus + getOrElse(0) { constantZero } + + if(size == 0) add(result) + else this[0] = result + } + ) + /** + * Returns difference between the integer represented as a polynomial and the polynomial. + * + * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. + */ + public override operator fun Int.minus(other: ListPolynomial): ListPolynomial = + ListPolynomial( + other.coefficients + .toMutableList() + .apply { + if (this@minus == 0) { + indices.forEach { this[it] = -this[it] } + } else { + (1..lastIndex).forEach { this[it] = -this[it] } + + val result = this@minus - getOrElse(0) { constantZero } + + if (size == 0) add(result) + else this[0] = result + } + } + ) + /** + * Returns product of the integer represented as a polynomial and the polynomial. + * + * The operation is equivalent to sum of [this] copies of [other]. + */ + public override operator fun Int.times(other: ListPolynomial): ListPolynomial = + when (this) { + 0 -> zero + 1 -> other + else -> ListPolynomial( + other.coefficients + .toMutableList() + .apply { + for (deg in indices) this[deg] = this@times * this[deg] + } + ) + } + + /** + * Returns sum of the constant represented as a polynomial and the polynomial. + */ + public override operator fun C.plus(other: ListPolynomial): ListPolynomial = + with(other.coefficients) { + if (isEmpty()) ListPolynomial(listOf(this@plus)) + else ListPolynomial( + toMutableList() + .apply { + val result = if (size == 0) this@plus else this@plus + get(0) + + if(size == 0) add(result) + else this[0] = result + } + ) + } + /** + * Returns difference between the constant represented as a polynomial and the polynomial. + */ + public override operator fun C.minus(other: ListPolynomial): ListPolynomial = + with(other.coefficients) { + if (isEmpty()) ListPolynomial(listOf(this@minus)) + else ListPolynomial( + toMutableList() + .apply { + (1 .. lastIndex).forEach { this[it] = -this[it] } + + val result = if (size == 0) this@minus else this@minus - get(0) + + if(size == 0) add(result) + else this[0] = result + } + ) + } + /** + * Returns product of the constant represented as a polynomial and the polynomial. + */ + public override operator fun C.times(other: ListPolynomial): ListPolynomial = + ListPolynomial( + other.coefficients + .toMutableList() + .apply { + for (deg in indices) this[deg] = this@times * this[deg] + } + ) + + /** + * Returns sum of the constant represented as a polynomial and the polynomial. + */ + public override operator fun ListPolynomial.plus(other: C): ListPolynomial = + with(coefficients) { + if (isEmpty()) ListPolynomial(listOf(other)) + else ListPolynomial( + toMutableList() + .apply { + val result = if (size == 0) other else get(0) + other + + if(size == 0) add(result) + else this[0] = result + } + ) + } + /** + * Returns difference between the constant represented as a polynomial and the polynomial. + */ + public override operator fun ListPolynomial.minus(other: C): ListPolynomial = + with(coefficients) { + if (isEmpty()) ListPolynomial(listOf(-other)) + else ListPolynomial( + toMutableList() + .apply { + val result = if (size == 0) other else get(0) - other + + if(size == 0) add(result) + else this[0] = result + } + ) + } + /** + * Returns product of the constant represented as a polynomial and the polynomial. + */ + public override operator fun ListPolynomial.times(other: C): ListPolynomial = + ListPolynomial( + coefficients + .toMutableList() + .apply { + for (deg in indices) this[deg] = this[deg] * other + } + ) + + /** + * Converts the constant [value] to polynomial. + */ + public override fun number(value: C): ListPolynomial = ListPolynomial(listOf(value)) + + /** + * Returns negation of the polynomial. + */ + public override operator fun ListPolynomial.unaryMinus(): ListPolynomial = + ListPolynomial(coefficients.map { -it }) + /** + * Returns sum of the polynomials. + */ + public override operator fun ListPolynomial.plus(other: ListPolynomial): ListPolynomial { + val thisDegree = degree + val otherDegree = other.degree + return ListPolynomial( + List(max(thisDegree, otherDegree) + 1) { + when { + it > thisDegree -> other.coefficients[it] + it > otherDegree -> coefficients[it] + else -> coefficients[it] + other.coefficients[it] + } + } + ) + } + /** + * Returns difference of the polynomials. + */ + public override operator fun ListPolynomial.minus(other: ListPolynomial): ListPolynomial { + val thisDegree = degree + val otherDegree = other.degree + return ListPolynomial( + List(max(thisDegree, otherDegree) + 1) { + when { + it > thisDegree -> -other.coefficients[it] + it > otherDegree -> coefficients[it] + else -> coefficients[it] - other.coefficients[it] + } + } + ) + } + /** + * Returns product of the polynomials. + */ + public override operator fun ListPolynomial.times(other: ListPolynomial): ListPolynomial { + val thisDegree = degree + val otherDegree = other.degree + return ListPolynomial( + List(thisDegree + otherDegree + 1) { d -> + (max(0, d - otherDegree)..min(thisDegree, d)) + .map { coefficients[it] * other.coefficients[d - it] } + .reduce { acc, rational -> acc + rational } + } + ) + } + /** + * Raises [arg] to the integer power [exponent]. + */ // TODO: To optimize boxing + override fun power(arg: ListPolynomial, exponent: UInt): ListPolynomial = super.power(arg, exponent) + + /** + * Instance of zero polynomial (zero of the polynomial ring). + */ + override val zero: ListPolynomial = ListPolynomial(emptyList()) + /** + * Instance of unit polynomial (unit of the polynomial ring). + */ + override val one: ListPolynomial by lazy { ListPolynomial(listOf(constantOne)) } + + /** + * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is + * zero, degree is -1. + */ + public override val ListPolynomial.degree: Int get() = coefficients.lastIndex + + // TODO: When context receivers will be ready move all of this substitutions and invocations to utilities with + // [ListPolynomialSpace] as a context receiver + /** + * Evaluates value of [this] polynomial on provided [argument]. + */ + public inline fun ListPolynomial.substitute(argument: C): C = substitute(ring, argument) + /** + * Substitutes provided polynomial [argument] into [this] polynomial. + */ + public inline fun ListPolynomial.substitute(argument: ListPolynomial): ListPolynomial = substitute(ring, argument) + + /** + * Represent [this] polynomial as a regular context-less function. + */ + public inline fun ListPolynomial.asFunction(): (C) -> C = asFunctionOver(ring) + /** + * Represent [this] polynomial as a regular context-less function. + */ + public inline fun ListPolynomial.asFunctionOfConstant(): (C) -> C = asFunctionOfConstantOver(ring) + /** + * Represent [this] polynomial as a regular context-less function. + */ + public inline fun ListPolynomial.asFunctionOfPolynomial(): (ListPolynomial) -> ListPolynomial = asFunctionOfPolynomialOver(ring) + + /** + * Evaluates value of [this] polynomial on provided [argument]. + */ + public inline operator fun ListPolynomial.invoke(argument: C): C = substitute(ring, argument) + /** + * Evaluates value of [this] polynomial on provided [argument]. + */ + public inline operator fun ListPolynomial.invoke(argument: ListPolynomial): ListPolynomial = substitute(ring, argument) +} + +/** + * Space of polynomials constructed over ring. + * + * @param C the type of constants. Polynomials have them as a coefficients in their terms. + * @param A type of underlying ring of constants. It's [Ring] of [C]. + * @param ring underlying ring of constants of type [A]. + */ +public class ScalableListPolynomialSpace( + ring: A, +) : ListPolynomialSpace(ring), ScaleOperations> where A : Ring, A : ScaleOperations { + override fun scale(a: ListPolynomial, value: Double): ListPolynomial = + ring { ListPolynomial(a.coefficients.map { scale(it, value) }) } +} diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/ListRationalFunction.kt similarity index 100% rename from kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt rename to kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/ListRationalFunction.kt diff --git a/kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedPolynomial.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedPolynomial.kt similarity index 100% rename from kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedPolynomial.kt rename to kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedPolynomial.kt diff --git a/kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedRationalFunction.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedRationalFunction.kt similarity index 100% rename from kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedRationalFunction.kt rename to kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedRationalFunction.kt diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/Polynomial.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/Polynomial.kt new file mode 100644 index 000000000..61ea5a342 --- /dev/null +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/Polynomial.kt @@ -0,0 +1,502 @@ +/* + * 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.functions + +import space.kscience.kmath.operations.Ring +import space.kscience.kmath.operations.invoke +import kotlin.js.JsName +import kotlin.jvm.JvmName + + +/** + * Abstraction of polynomials. + */ +public interface Polynomial + +/** + * Abstraction of ring of polynomials of type [P] over ring of constants of type [C]. + * + * @param C the type of constants. Polynomials have them as coefficients in their terms. + * @param P the type of polynomials. + */ +@Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") // FIXME: Waiting for KT-31420 +public interface PolynomialSpace> : Ring

{ + /** + * Returns sum of the constant and the integer represented as a constant (member of underlying ring). + * + * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. + */ + public operator fun C.plus(other: Int): C + /** + * Returns difference between the constant and the integer represented as a constant (member of underlying ring). + * + * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. + */ + public operator fun C.minus(other: Int): C + /** + * Returns product of the constant and the integer represented as a constant (member of underlying ring). + * + * The operation is equivalent to sum of [other] copies of [this]. + */ + public operator fun C.times(other: Int): C + + /** + * Returns sum of the integer represented as a constant (member of underlying ring) and the constant. + * + * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. + */ + public operator fun Int.plus(other: C): C + /** + * Returns difference between the integer represented as a constant (member of underlying ring) and the constant. + * + * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. + */ + public operator fun Int.minus(other: C): C + /** + * Returns product of the integer represented as a constant (member of underlying ring) and the constant. + * + * The operation is equivalent to sum of [this] copies of [other]. + */ + public operator fun Int.times(other: C): C + + /** + * Converts the integer [value] to constant. + */ + public fun constantNumber(value: Int): C = constantOne * value + /** + * Converts the integer to constant. + */ + public fun Int.asConstant(): C = constantNumber(this) + + /** + * Returns sum of the polynomial and the integer represented as a polynomial. + * + * The operation is equivalent to adding [other] copies of unit polynomial to [this]. + */ + public operator fun P.plus(other: Int): P = addMultipliedByDoubling(this, one, other) + /** + * Returns difference between the polynomial and the integer represented as a polynomial. + * + * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. + */ + public operator fun P.minus(other: Int): P = addMultipliedByDoubling(this, one, -other) + /** + * Returns product of the polynomial and the integer represented as a polynomial. + * + * The operation is equivalent to sum of [other] copies of [this]. + */ + public operator fun P.times(other: Int): P = multiplyByDoubling(this, other) + + /** + * Returns sum of the integer represented as a polynomial and the polynomial. + * + * The operation is equivalent to adding [this] copies of unit polynomial to [other]. + */ + public operator fun Int.plus(other: P): P = addMultipliedByDoubling(other, one, this) + /** + * Returns difference between the integer represented as a polynomial and the polynomial. + * + * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. + */ + public operator fun Int.minus(other: P): P = addMultipliedByDoubling(-other, one, this) + /** + * Returns product of the integer represented as a polynomial and the polynomial. + * + * The operation is equivalent to sum of [this] copies of [other]. + */ + public operator fun Int.times(other: P): P = multiplyByDoubling(other, this) + + /** + * Converts the integer [value] to polynomial. + */ + public fun number(value: Int): P = number(constantNumber(value)) + /** + * Converts the integer to polynomial. + */ + public fun Int.asPolynomial(): P = number(this) + + /** + * Returns the same constant. + */ + @JvmName("unaryPlusConstant") + @JsName("unaryPlusConstant") + public operator fun C.unaryPlus(): C = this + /** + * Returns negation of the constant. + */ + @JvmName("unaryMinusConstant") + @JsName("unaryMinusConstant") + public operator fun C.unaryMinus(): C + /** + * Returns sum of the constants. + */ + @JvmName("plusConstantConstant") + @JsName("plusConstantConstant") + public operator fun C.plus(other: C): C + /** + * Returns difference of the constants. + */ + @JvmName("minusConstantConstant") + @JsName("minusConstantConstant") + public operator fun C.minus(other: C): C + /** + * Returns product of the constants. + */ + @JvmName("timesConstantConstant") + @JsName("timesConstantConstant") + public operator fun C.times(other: C): C + /** + * Raises [arg] to the integer power [exponent]. + */ + @JvmName("powerConstant") + @JsName("powerConstant") + public fun power(arg: C, exponent: UInt) : C + + /** + * Instance of zero constant (zero of the underlying ring). + */ + public val constantZero: C + /** + * Instance of unit constant (unit of the underlying ring). + */ + public val constantOne: C + + /** + * Returns sum of the constant represented as a polynomial and the polynomial. + */ + public operator fun C.plus(other: P): P + /** + * Returns difference between the constant represented as a polynomial and the polynomial. + */ + public operator fun C.minus(other: P): P + /** + * Returns product of the constant represented as a polynomial and the polynomial. + */ + public operator fun C.times(other: P): P + + /** + * Returns sum of the constant represented as a polynomial and the polynomial. + */ + public operator fun P.plus(other: C): P + /** + * Returns difference between the constant represented as a polynomial and the polynomial. + */ + public operator fun P.minus(other: C): P + /** + * Returns product of the constant represented as a polynomial and the polynomial. + */ + public operator fun P.times(other: C): P + + /** + * Converts the constant [value] to polynomial. + */ + public fun number(value: C): P = one * value + /** + * Converts the constant to polynomial. + */ + public fun C.asPolynomial(): P = number(this) + + /** + * Returns the same polynomial. + */ + public override operator fun P.unaryPlus(): P = this + /** + * Returns negation of the polynomial. + */ + public override operator fun P.unaryMinus(): P + /** + * Returns sum of the polynomials. + */ + public override operator fun P.plus(other: P): P + /** + * Returns difference of the polynomials. + */ + public override operator fun P.minus(other: P): P + /** + * Returns product of the polynomials. + */ + public override operator fun P.times(other: P): P + /** + * Raises [arg] to the integer power [exponent]. + */ + public override fun power(arg: P, exponent: UInt) : P = exponentiateBySquaring(arg, exponent) + + /** + * Instance of zero polynomial (zero of the polynomial ring). + */ + public override val zero: P + /** + * Instance of unit polynomial (unit of the polynomial ring). + */ + public override val one: P + + /** + * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is + * zero, degree is -1. + */ + public val P.degree: Int + + override fun add(left: P, right: P): P = left + right + override fun multiply(left: P, right: P): P = left * right +} + +/** + * Abstraction of ring of polynomials of type [P] over ring of constants of type [C]. It also assumes that there is + * provided [ring] (of type [A]), that provides constant-wise operations. + * + * @param C the type of constants. Polynomials have them as coefficients in their terms. + * @param P the type of polynomials. + * @param A the type of algebraic structure (precisely, of ring) provided for constants. + */ +@Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 +public interface PolynomialSpaceOverRing, A: Ring> : PolynomialSpace { + + /** + * Underlying ring of constants. Its operations on constants are inherited by local operations on constants. + */ + public val ring: A + + /** + * Returns sum of the constant and the integer represented as a constant (member of underlying ring). + * + * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. + */ + public override operator fun C.plus(other: Int): C = ring { addMultipliedByDoubling(this@plus, one, other) } + /** + * Returns difference between the constant and the integer represented as a constant (member of underlying ring). + * + * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. + */ + public override operator fun C.minus(other: Int): C = ring { addMultipliedByDoubling(this@minus, one, -other) } + /** + * Returns product of the constant and the integer represented as a constant (member of underlying ring). + * + * The operation is equivalent to sum of [other] copies of [this]. + */ + public override operator fun C.times(other: Int): C = ring { multiplyByDoubling(this@times, other) } + + /** + * Returns sum of the integer represented as a constant (member of underlying ring) and the constant. + * + * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. + */ + public override operator fun Int.plus(other: C): C = ring { addMultipliedByDoubling(other, one, this@plus) } + /** + * Returns difference between the integer represented as a constant (member of underlying ring) and the constant. + * + * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. + */ + public override operator fun Int.minus(other: C): C = ring { addMultipliedByDoubling(-other, one, this@minus) } + /** + * Returns product of the integer represented as a constant (member of underlying ring) and the constant. + * + * The operation is equivalent to sum of [this] copies of [other]. + */ + public override operator fun Int.times(other: C): C = ring { multiplyByDoubling(other, this@times) } + + /** + * Returns negation of the constant. + */ + @JvmName("unaryMinusConstant") + public override operator fun C.unaryMinus(): C = ring { -this@unaryMinus } + /** + * Returns sum of the constants. + */ + @JvmName("plusConstantConstant") + public override operator fun C.plus(other: C): C = ring { this@plus + other } + /** + * Returns difference of the constants. + */ + @JvmName("minusConstantConstant") + public override operator fun C.minus(other: C): C = ring { this@minus - other } + /** + * Returns product of the constants. + */ + @JvmName("timesConstantConstant") + public override operator fun C.times(other: C): C = ring { this@times * other } + /** + * Raises [arg] to the integer power [exponent]. + */ + @JvmName("powerConstant") + override fun power(arg: C, exponent: UInt): C = ring { power(arg, exponent) } + + /** + * Instance of zero constant (zero of the underlying ring). + */ + public override val constantZero: C get() = ring.zero + /** + * Instance of unit constant (unit of the underlying ring). + */ + public override val constantOne: C get() = ring.one +} + +/** + * Abstraction of ring of polynomials of type [P] of variables of type [V] and over ring of constants of type [C]. + * + * @param C the type of constants. Polynomials have them as coefficients in their terms. + * @param V the type of variables. Polynomials have them in representations of terms. + * @param P the type of polynomials. + */ +@Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 +public interface MultivariatePolynomialSpace>: PolynomialSpace { + /** + * Returns sum of the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ + @JvmName("plusVariableInt") + public operator fun V.plus(other: Int): P + /** + * Returns difference between the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ + @JvmName("minusVariableInt") + public operator fun V.minus(other: Int): P + /** + * Returns product of the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ + @JvmName("timesVariableInt") + public operator fun V.times(other: Int): P + + /** + * Returns sum of the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("plusIntVariable") + public operator fun Int.plus(other: V): P + /** + * Returns difference between the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("minusIntVariable") + public operator fun Int.minus(other: V): P + /** + * Returns product of the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("timesIntVariable") + public operator fun Int.times(other: V): P + + /** + * Returns sum of the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ + @JvmName("plusVariableConstant") + public operator fun V.plus(other: C): P + /** + * Returns difference between the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ + @JvmName("minusVariableConstant") + public operator fun V.minus(other: C): P + /** + * Returns product of the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ + @JvmName("timesVariableConstant") + public operator fun V.times(other: C): P + + /** + * Returns sum of the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("plusConstantVariable") + public operator fun C.plus(other: V): P + /** + * Returns difference between the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("minusConstantVariable") + public operator fun C.minus(other: V): P + /** + * Returns product of the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("timesConstantVariable") + public operator fun C.times(other: V): P + + /** + * Represents the variable as a monic monomial. + */ + @JvmName("unaryPlusVariable") + public operator fun V.unaryPlus(): P + /** + * Returns negation of representation of the variable as a monic monomial. + */ + @JvmName("unaryMinusVariable") + public operator fun V.unaryMinus(): P + /** + * Returns sum of the variables represented as monic monomials. + */ + @JvmName("plusVariableVariable") + public operator fun V.plus(other: V): P + /** + * Returns difference between the variables represented as monic monomials. + */ + @JvmName("minusVariableVariable") + public operator fun V.minus(other: V): P + /** + * Returns product of the variables represented as monic monomials. + */ + @JvmName("timesVariableVariable") + public operator fun V.times(other: V): P + + /** + * Represents the [variable] as a monic monomial. + */ + @JvmName("numberVariable") + public fun number(variable: V): P = +variable + /** + * Represents the variable as a monic monomial. + */ + @JvmName("asPolynomialVariable") + public fun V.asPolynomial(): P = number(this) + + /** + * Returns sum of the variable represented as a monic monomial and the polynomial. + */ + @JvmName("plusVariablePolynomial") + public operator fun V.plus(other: P): P + /** + * Returns difference between the variable represented as a monic monomial and the polynomial. + */ + @JvmName("minusVariablePolynomial") + public operator fun V.minus(other: P): P + /** + * Returns product of the variable represented as a monic monomial and the polynomial. + */ + @JvmName("timesVariablePolynomial") + public operator fun V.times(other: P): P + + /** + * Returns sum of the polynomial and the variable represented as a monic monomial. + */ + @JvmName("plusPolynomialVariable") + public operator fun P.plus(other: V): P + /** + * Returns difference between the polynomial and the variable represented as a monic monomial. + */ + @JvmName("minusPolynomialVariable") + public operator fun P.minus(other: V): P + /** + * Returns product of the polynomial and the variable represented as a monic monomial. + */ + @JvmName("timesPolynomialVariable") + public operator fun P.times(other: V): P + + /** + * Map that associates variables (that appear in the polynomial in positive exponents) with their most exponents + * in which they are appeared in the polynomial. + * + * As consequence all values in the map are positive integers. Also, if the polynomial is constant, the map is empty. + * And keys of the map is the same as in [variables]. + */ + public val P.degrees: Map + /** + * Counts degree of the polynomial by the specified [variable]. + */ + public fun P.degreeBy(variable: V): UInt = degrees.getOrElse(variable) { 0u } + /** + * Counts degree of the polynomial by the specified [variables]. + */ + public fun P.degreeBy(variables: Collection): UInt + /** + * Set of all variables that appear in the polynomial in positive exponents. + */ + public val P.variables: Set get() = degrees.keys + /** + * Count of all variables that appear in the polynomial in positive exponents. + */ + public val P.countOfVariables: Int get() = variables.size +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/RationalFunction.kt similarity index 99% rename from kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt rename to kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/RationalFunction.kt index 1782dba74..f664ae9db 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/RationalFunction.kt @@ -5,7 +5,8 @@ package space.kscience.kmath.functions -import space.kscience.kmath.operations.* +import space.kscience.kmath.operations.Ring +import space.kscience.kmath.operations.invoke import kotlin.js.JsName import kotlin.jvm.JvmName diff --git a/kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/algebraicStub.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/algebraicStub.kt similarity index 100% rename from kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/algebraicStub.kt rename to kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/algebraicStub.kt diff --git a/kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/labeledConstructors.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledConstructors.kt similarity index 100% rename from kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/labeledConstructors.kt rename to kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledConstructors.kt diff --git a/kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/labeledUtil.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledUtil.kt similarity index 99% rename from kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/labeledUtil.kt rename to kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledUtil.kt index 4e799cb43..e3b35facc 100644 --- a/kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/labeledUtil.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledUtil.kt @@ -8,9 +8,9 @@ package space.kscience.kmath.functions import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.Field -import space.kscience.kmath.operations.invoke import space.kscience.kmath.operations.Ring import space.kscience.kmath.operations.algebra +import space.kscience.kmath.operations.invoke import kotlin.contracts.InvocationKind import kotlin.contracts.contract import kotlin.jvm.JvmName diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/listConstructors.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/listConstructors.kt new file mode 100644 index 000000000..e95361724 --- /dev/null +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/listConstructors.kt @@ -0,0 +1,92 @@ +/* + * 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.functions + +import space.kscience.kmath.operations.Ring + + +/** + * Constructs a [ListPolynomial] instance with provided [coefficients]. The collection of coefficients will be reversed + * if [reverse] parameter is true. + */ +@Suppress("FunctionName") +public fun ListPolynomial(coefficients: List, reverse: Boolean = false): ListPolynomial = + ListPolynomial(with(coefficients) { if (reverse) reversed() else this }) + +/** + * Constructs a [ListPolynomial] instance with provided [coefficients]. The collection of coefficients will be reversed + * if [reverse] parameter is true. + */ +@Suppress("FunctionName") +public fun ListPolynomial(vararg coefficients: C, reverse: Boolean = false): ListPolynomial = + ListPolynomial(with(coefficients) { if (reverse) reversed() else toList() }) + +/** + * Represents [this] constant as a [ListPolynomial]. + */ +public fun C.asListPolynomial() : ListPolynomial = ListPolynomial(listOf(this)) + + +// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available + +/** + * Constructs [ListRationalFunction] instance with numerator and denominator constructed with provided + * [numeratorCoefficients] and [denominatorCoefficients]. The both collections of coefficients will be reversed if + * [reverse] parameter is true. + */ +@Suppress("FunctionName") +public fun ListRationalFunction(numeratorCoefficients: List, denominatorCoefficients: List, reverse: Boolean = false): ListRationalFunction = + ListRationalFunction( + ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), + ListPolynomial( with(denominatorCoefficients) { if (reverse) reversed() else this } ) + ) +/** + * Constructs [ListRationalFunction] instance with provided [numerator] and unit denominator. + */ +@Suppress("FunctionName") +public fun > A.ListRationalFunction(numerator: ListPolynomial): ListRationalFunction = + ListRationalFunction(numerator, ListPolynomial(listOf(one))) +/** + * Constructs [ListRationalFunction] instance with provided [numerator] and unit denominator. + */ +@Suppress("FunctionName") +public fun > ListRationalFunctionSpace.ListRationalFunction(numerator: ListPolynomial): ListRationalFunction = + ListRationalFunction(numerator, polynomialOne) +/** + * Constructs [ListRationalFunction] instance with numerator constructed with provided [numeratorCoefficients] and unit + * denominator. The collection of numerator coefficients will be reversed if [reverse] parameter is true. + */ +@Suppress("FunctionName") +public fun > A.ListRationalFunction(numeratorCoefficients: List, reverse: Boolean = false): ListRationalFunction = + ListRationalFunction( + ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), + ListPolynomial(listOf(one)) + ) +/** + * Constructs [ListRationalFunction] instance with numerator constructed with provided [numeratorCoefficients] and unit + * denominator. The collection of numerator coefficients will be reversed if [reverse] parameter is true. + */ +@Suppress("FunctionName") +public fun > ListRationalFunctionSpace.ListRationalFunction(numeratorCoefficients: List, reverse: Boolean = false): ListRationalFunction = + ListRationalFunction( + ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), + polynomialOne + ) + +/** + * Represents [this] constant as a rational function. + */ // FIXME: When context receivers will be ready, delete this function and uncomment the following two +public fun > C.asListRationalFunction(ring: A) : ListRationalFunction = ring.ListRationalFunction(asListPolynomial()) +///** +// * Represents [this] constant as a rational function. +// */ +//context(A) +//public fun > C.asListRationalFunction() : ListRationalFunction = ListRationalFunction(asListPolynomial()) +///** +// * Represents [this] constant as a rational function. +// */ +//context(ListRationalFunctionSpace) +//public fun > C.asListRationalFunction() : ListRationalFunction = ListRationalFunction(asListPolynomial()) \ No newline at end of file diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/listUtil.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/listUtil.kt new file mode 100644 index 000000000..4f3f6d88e --- /dev/null +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/listUtil.kt @@ -0,0 +1,255 @@ +/* + * 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.functions + +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.* +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract +import kotlin.math.max +import kotlin.math.pow + + +/** + * Creates a [ListPolynomialSpace] over a received ring. + */ +public inline val > A.listPolynomialSpace: ListPolynomialSpace + get() = ListPolynomialSpace(this) + +/** + * Creates a [ListPolynomialSpace]'s scope over a received ring. + */ // TODO: When context will be ready move [ListPolynomialSpace] and add [A] to context receivers of [block] +public inline fun , R> A.listPolynomialSpace(block: ListPolynomialSpace.() -> R): R { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return ListPolynomialSpace(this).block() +} + +/** + * Creates a [ScalableListPolynomialSpace] over a received scalable ring. + */ +public inline val A.scalableListPolynomialSpace: ScalableListPolynomialSpace where A : Ring, A : ScaleOperations + get() = ScalableListPolynomialSpace(this) + +/** + * Creates a [ScalableListPolynomialSpace]'s scope over a received scalable ring. + */ // TODO: When context will be ready move [ListPolynomialSpace] and add [A] to context receivers of [block] +public inline fun A.scalableListPolynomialSpace(block: ScalableListPolynomialSpace.() -> R): R where A : Ring, A : ScaleOperations { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return ScalableListPolynomialSpace(this).block() +} + +/** + * Creates a [ListRationalFunctionSpace] over a received ring. + */ +public inline val > A.listRationalFunctionSpace: ListRationalFunctionSpace + get() = ListRationalFunctionSpace(this) + +/** + * Creates a [ListRationalFunctionSpace]'s scope over a received ring. + */ // TODO: When context will be ready move [ListRationalFunctionSpace] and add [A] to context receivers of [block] +public inline fun , R> A.listRationalFunctionSpace(block: ListRationalFunctionSpace.() -> R): R { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return ListRationalFunctionSpace(this).block() +} + + +/** + * Evaluates value of [this] Double polynomial on provided Double argument. + */ +public fun ListPolynomial.substitute(arg: Double): Double = + coefficients.reduceIndexedOrNull { index, acc, c -> + acc + c * arg.pow(index) + } ?: .0 + +/** + * Evaluates value of [this] polynomial on provided argument. + * + * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). + */ +public fun ListPolynomial.substitute(ring: Ring, arg: C): C = ring { + if (coefficients.isEmpty()) return zero + var result: C = coefficients.last() + for (j in coefficients.size - 2 downTo 0) { + result = (arg * result) + coefficients[j] + } + return result +} + +/** + * Substitutes provided polynomial [arg] into [this] polynomial. + * + * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). + */ // TODO: To optimize boxing +public fun ListPolynomial.substitute(ring: Ring, arg: ListPolynomial) : ListPolynomial = + ring.listPolynomialSpace { + if (coefficients.isEmpty()) return zero + var result: ListPolynomial = coefficients.last().asPolynomial() + for (j in coefficients.size - 2 downTo 0) { + result = (arg * result) + coefficients[j] + } + return result + } + +/** + * Substitutes provided rational function [arg] into [this] polynomial. + * + * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). + */ // TODO: To optimize boxing +public fun ListPolynomial.substitute(ring: Ring, arg: ListRationalFunction) : ListRationalFunction = + ring.listRationalFunctionSpace { + if (coefficients.isEmpty()) return zero + var result: ListRationalFunction = coefficients.last().asRationalFunction() + for (j in coefficients.size - 2 downTo 0) { + result = (arg * result) + coefficients[j] + } + return result + } + +/** + * Evaluates value of [this] Double rational function in provided Double argument. + */ +public fun ListRationalFunction.substitute(arg: Double): Double = + numerator.substitute(arg) / denominator.substitute(arg) + +/** + * Evaluates value of [this] polynomial for provided argument. + * + * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). + */ +public fun ListRationalFunction.substitute(ring: Field, arg: C): C = ring { + numerator.substitute(ring, arg) / denominator.substitute(ring, arg) +} + +/** + * Substitutes provided polynomial [arg] into [this] rational function. + */ // TODO: To optimize boxing +public fun ListRationalFunction.substitute(ring: Ring, arg: ListPolynomial) : ListRationalFunction = + ring.listRationalFunctionSpace { + numerator.substitute(ring, arg) / denominator.substitute(ring, arg) + } + +/** + * Substitutes provided rational function [arg] into [this] rational function. + */ // TODO: To optimize boxing +public fun ListRationalFunction.substitute(ring: Ring, arg: ListRationalFunction) : ListRationalFunction = + ring.listRationalFunctionSpace { + numerator.substitute(ring, arg) / denominator.substitute(ring, arg) + } + +/** + * Represent [this] polynomial as a regular context-less function. + */ +public fun > ListPolynomial.asFunctionOver(ring: A): (C) -> C = { substitute(ring, it) } + +/** + * Represent [this] polynomial as a regular context-less function. + */ +public fun > ListPolynomial.asFunctionOfConstantOver(ring: A): (C) -> C = { substitute(ring, it) } + +/** + * Represent [this] polynomial as a regular context-less function. + */ +public fun > ListPolynomial.asFunctionOfPolynomialOver(ring: A): (ListPolynomial) -> ListPolynomial = { substitute(ring, it) } + +/** + * Represent [this] polynomial as a regular context-less function. + */ +public fun > ListPolynomial.asFunctionOfRationalFunctionOver(ring: A): (ListRationalFunction) -> ListRationalFunction = { substitute(ring, it) } + +/** + * Represent [this] rational function as a regular context-less function. + */ +public fun > ListRationalFunction.asFunctionOver(ring: A): (C) -> C = { substitute(ring, it) } + +/** + * Represent [this] rational function as a regular context-less function. + */ +public fun > ListRationalFunction.asFunctionOfConstantOver(ring: A): (C) -> C = { substitute(ring, it) } + +/** + * Represent [this] rational function as a regular context-less function. + */ +public fun > ListRationalFunction.asFunctionOfPolynomialOver(ring: A): (ListPolynomial) -> ListRationalFunction = { substitute(ring, it) } + +/** + * Represent [this] rational function as a regular context-less function. + */ +public fun > ListRationalFunction.asFunctionOfRationalFunctionOver(ring: A): (ListRationalFunction) -> ListRationalFunction = { substitute(ring, it) } + +/** + * Returns algebraic derivative of received polynomial. + */ +@UnstableKMathAPI +public fun ListPolynomial.derivative( + ring: A, +): ListPolynomial where A : Ring, A : NumericAlgebra = ring { + ListPolynomial( + buildList(max(0, coefficients.size - 1)) { + for (deg in 1 .. coefficients.lastIndex) add(number(deg) * coefficients[deg]) + } + ) +} + +/** + * Returns algebraic derivative of received polynomial of specified [order]. The [order] should be non-negative integer. + */ +@UnstableKMathAPI +public fun ListPolynomial.nthDerivative( + ring: A, + order: Int, +): ListPolynomial where A : Ring, A : NumericAlgebra = ring { + require(order >= 0) { "Order of derivative must be non-negative" } + ListPolynomial( + buildList(max(0, coefficients.size - order)) { + for (deg in order.. coefficients.lastIndex) + add((deg - order + 1 .. deg).fold(coefficients[deg]) { acc, d -> acc * number(d) }) + } + ) +} + +/** + * Returns algebraic antiderivative of received polynomial. + */ +@UnstableKMathAPI +public fun ListPolynomial.antiderivative( + ring: A, +): ListPolynomial where A : Field, A : NumericAlgebra = ring { + ListPolynomial( + buildList(coefficients.size + 1) { + add(zero) + coefficients.mapIndexedTo(this) { index, t -> t / number(index + 1) } + } + ) +} + +/** + * Returns algebraic antiderivative of received polynomial of specified [order]. The [order] should be non-negative integer. + */ +@UnstableKMathAPI +public fun ListPolynomial.nthAntiderivative( + ring: A, + order: Int, +): ListPolynomial where A : Field, A : NumericAlgebra = ring { + require(order >= 0) { "Order of antiderivative must be non-negative" } + ListPolynomial( + buildList(coefficients.size + order) { + repeat(order) { add(zero) } + coefficients.mapIndexedTo(this) { index, c -> (1..order).fold(c) { acc, i -> acc / number(index + i) } } + } + ) +} + +/** + * Computes a definite integral of [this] polynomial in the specified [range]. + */ +@UnstableKMathAPI +public fun > ListPolynomial.integrate( + ring: Field, + range: ClosedRange, +): C = ring { + val antiderivative = antiderivative(ring) + antiderivative.substitute(ring, range.endInclusive) - antiderivative.substitute(ring, range.start) +} \ No newline at end of file diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/misc.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/misc.kt new file mode 100644 index 000000000..76f1c294e --- /dev/null +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/misc.kt @@ -0,0 +1,22 @@ +/* + * 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.functions + + +/** + * Marks declarations that give access to internal entities of polynomials delicate structure. Thus, it allows to + * optimize performance a bit by skipping standard steps, but such skips may cause critical errors if something is + * implemented badly. Make sure you fully read and understand documentation and don't break internal contracts. + */ +@RequiresOptIn( + message = "This declaration gives access to delicate internal structure of polynomials. " + + "It allows to optimize performance by skipping unnecessary arguments check. " + + "But at the same time makes it easy to make a mistake " + + "that will cause wrong computation result or even runtime error. " + + "Make sure you fully read and understand documentation.", + level = RequiresOptIn.Level.ERROR +) +public annotation class DelicatePolynomialAPI \ No newline at end of file diff --git a/kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/numberedConstructors.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/numberedConstructors.kt similarity index 100% rename from kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/numberedConstructors.kt rename to kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/numberedConstructors.kt diff --git a/kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/numberedUtil.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/numberedUtil.kt similarity index 100% rename from kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/numberedUtil.kt rename to kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/numberedUtil.kt diff --git a/kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledConstructorsTest.kt b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledConstructorsTest.kt similarity index 99% rename from kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledConstructorsTest.kt rename to kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledConstructorsTest.kt index 081cf06e4..80476050b 100644 --- a/kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledConstructorsTest.kt +++ b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledConstructorsTest.kt @@ -6,13 +6,13 @@ package space.kscience.kmath.functions import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.algebra -import space.kscience.kmath.operations.invoke import space.kscience.kmath.functions.testUtils.t import space.kscience.kmath.functions.testUtils.x import space.kscience.kmath.functions.testUtils.y import space.kscience.kmath.functions.testUtils.z +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.algebra +import space.kscience.kmath.operations.invoke import kotlin.test.Test import kotlin.test.assertEquals diff --git a/kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialTest.kt b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialTest.kt similarity index 99% rename from kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialTest.kt rename to kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialTest.kt index d2d417a02..bde1386da 100644 --- a/kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialTest.kt +++ b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialTest.kt @@ -11,15 +11,15 @@ import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.functions.testUtils.IntModuloRing import space.kscience.kmath.functions.testUtils.Rational import space.kscience.kmath.functions.testUtils.RationalField -import space.kscience.kmath.functions.testUtils.o +import space.kscience.kmath.functions.testUtils.iota import space.kscience.kmath.functions.testUtils.m -import kotlin.test.* +import space.kscience.kmath.functions.testUtils.o +import space.kscience.kmath.functions.testUtils.s +import space.kscience.kmath.functions.testUtils.t import space.kscience.kmath.functions.testUtils.x import space.kscience.kmath.functions.testUtils.y import space.kscience.kmath.functions.testUtils.z -import space.kscience.kmath.functions.testUtils.t -import space.kscience.kmath.functions.testUtils.s -import space.kscience.kmath.functions.testUtils.iota +import kotlin.test.* // TODO: Тесты на конвертацию. diff --git a/kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialUtilTest.kt b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialUtilTest.kt similarity index 99% rename from kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialUtilTest.kt rename to kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialUtilTest.kt index 37329a318..88ee1cbb8 100644 --- a/kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialUtilTest.kt +++ b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialUtilTest.kt @@ -6,16 +6,15 @@ package space.kscience.kmath.functions import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.functions.testUtils.Rational import space.kscience.kmath.functions.testUtils.RationalField +import space.kscience.kmath.functions.testUtils.iota +import space.kscience.kmath.functions.testUtils.x +import space.kscience.kmath.functions.testUtils.y +import space.kscience.kmath.misc.UnstableKMathAPI import kotlin.test.Ignore import kotlin.test.Test import kotlin.test.assertEquals -import space.kscience.kmath.functions.testUtils.x -import space.kscience.kmath.functions.testUtils.y -import space.kscience.kmath.functions.testUtils.iota -import space.kscience.kmath.functions.testUtils.assertEquals class LabeledPolynomialUtilTest { @Test diff --git a/kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt similarity index 100% rename from kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt rename to kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt diff --git a/kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt similarity index 100% rename from kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt rename to kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt diff --git a/kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt similarity index 100% rename from kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt rename to kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt diff --git a/settings.gradle.kts b/settings.gradle.kts index 543d08001..bdd83d04e 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -27,8 +27,8 @@ include( ":kmath-coroutines", ":kmath-functions", ":test-utils-functions", - ":kmath-polynomialX", - ":test-utils-polynomialX", + ":kmath-polynomial", + ":test-utils-polynomial", ":kmath-histograms", ":kmath-commons", ":kmath-viktor", diff --git a/test-utils-polynomialX/build.gradle.kts b/test-utils-polynomial/build.gradle.kts similarity index 63% rename from test-utils-polynomialX/build.gradle.kts rename to test-utils-polynomial/build.gradle.kts index f20e1b8bb..e10e1f2b1 100644 --- a/test-utils-polynomialX/build.gradle.kts +++ b/test-utils-polynomial/build.gradle.kts @@ -7,9 +7,7 @@ kotlin.sourceSets { commonMain { dependencies { api(projects.kmathCore) - api(projects.kmathFunctions) - api(projects.testUtilsFunctions) - api(projects.kmathPolynomialX) + api(projects.kmathPolynomial) api(kotlin("test")) } } diff --git a/test-utils-polynomialX/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/BufferUtils.kt b/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/BufferUtils.kt similarity index 100% rename from test-utils-polynomialX/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/BufferUtils.kt rename to test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/BufferUtils.kt diff --git a/test-utils-polynomialX/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt b/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt similarity index 100% rename from test-utils-polynomialX/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt rename to test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt diff --git a/test-utils-polynomialX/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/misc.kt b/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/misc.kt similarity index 100% rename from test-utils-polynomialX/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/misc.kt rename to test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/misc.kt -- 2.34.1 From f726e6d0f17698dd47d6060212c8a6a04257f726 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Mon, 11 Jul 2022 23:32:15 +0300 Subject: [PATCH 103/123] Minimise appearance of new feature, leave only upgrades. --- .../kmath/functions/ListPolynomial.kt | 387 -------- .../kscience/kmath/functions/Piecewise.kt | 22 +- .../kscience/kmath/functions/Polynomial.kt | 629 +++++-------- .../kscience/kmath/functions/algebraicStub.kt | 95 -- .../kmath/functions/listConstructors.kt | 92 -- .../kscience/kmath/functions/listUtil.kt | 255 ------ .../space/kscience/kmath/functions/misc.kt | 22 - .../kmath/functions/polynomialConstructors.kt | 28 + .../kmath/functions/polynomialUtil.kt | 111 +++ .../kmath/functions/AlgebraicStubTest.kt | 460 ---------- .../kmath/functions/ListPolynomialTest.kt | 251 +----- .../kmath/functions/ListPolynomialUtilTest.kt | 850 +----------------- .../functions/testUtils/IntModuloUtils.kt | 13 +- 13 files changed, 376 insertions(+), 2839 deletions(-) delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialConstructors.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt deleted file mode 100644 index 76e1a6bb6..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt +++ /dev/null @@ -1,387 +0,0 @@ -/* - * 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. - */ - -@file:Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress") - -package space.kscience.kmath.functions - -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.ScaleOperations -import space.kscience.kmath.operations.invoke -import kotlin.math.max -import kotlin.math.min - - -/** - * Represents univariate polynomial that stores its coefficients in a [List]. - * - * @param C the type of constants. - */ -public data class ListPolynomial( - /** - * List that contains coefficients of the polynomial. Every monomial `a x^d` is stored as a coefficient `a` placed - * into the list at index `d`. For example, coefficients of a polynomial `5 x^2 - 6` can be represented as - * ``` - * listOf( - * -6, // -6 + - * 0, // 0 x + - * 5, // 5 x^2 - * ) - * ``` - * and also as - * ``` - * listOf( - * -6, // -6 + - * 0, // 0 x + - * 5, // 5 x^2 - * 0, // 0 x^3 - * 0, // 0 x^4 - * ) - * ``` - * It is not prohibited to put extra zeros at end of the list (as for `0x^3` and `0x^4` in the example). But the - * longer the coefficients list the worse performance of arithmetical operations performed on it. Thus, it is - * recommended not to put (or even to remove) extra (or useless) coefficients at the end of the coefficients list. - */ - public val coefficients: List -) : Polynomial { - override fun toString(): String = "ListPolynomial$coefficients" -} - -/** - * Arithmetic context for univariate polynomials with coefficients stored as a [List] constructed with the provided - * [ring] of constants. - * - * @param C the type of constants. Polynomials have them a coefficients in their terms. - * @param A type of provided underlying ring of constants. It's [Ring] of [C]. - * @param ring underlying ring of constants of type [A]. - */ -public open class ListPolynomialSpace>( - public override val ring: A, -) : PolynomialSpaceOverRing, A> { - /** - * Returns sum of the polynomial and the integer represented as a polynomial. - * - * The operation is equivalent to adding [other] copies of unit polynomial to [this]. - */ - public override operator fun ListPolynomial.plus(other: Int): ListPolynomial = - if (other == 0) this - else - ListPolynomial( - coefficients - .toMutableList() - .apply { - val result = getOrElse(0) { constantZero } + other - - if(size == 0) add(result) - else this[0] = result - } - ) - /** - * Returns difference between the polynomial and the integer represented as a polynomial. - * - * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. - */ - public override operator fun ListPolynomial.minus(other: Int): ListPolynomial = - if (other == 0) this - else - ListPolynomial( - coefficients - .toMutableList() - .apply { - val result = getOrElse(0) { constantZero } - other - - if(size == 0) add(result) - else this[0] = result - } - ) - /** - * Returns product of the polynomial and the integer represented as a polynomial. - * - * The operation is equivalent to sum of [other] copies of [this]. - */ - public override operator fun ListPolynomial.times(other: Int): ListPolynomial = - when (other) { - 0 -> zero - 1 -> this - else -> ListPolynomial( - coefficients - .toMutableList() - .apply { - for (deg in indices) this[deg] = this[deg] * other - } - ) - } - - /** - * Returns sum of the integer represented as a polynomial and the polynomial. - * - * The operation is equivalent to adding [this] copies of unit polynomial to [other]. - */ - public override operator fun Int.plus(other: ListPolynomial): ListPolynomial = - if (this == 0) other - else - ListPolynomial( - other.coefficients - .toMutableList() - .apply { - val result = this@plus + getOrElse(0) { constantZero } - - if(size == 0) add(result) - else this[0] = result - } - ) - /** - * Returns difference between the integer represented as a polynomial and the polynomial. - * - * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. - */ - public override operator fun Int.minus(other: ListPolynomial): ListPolynomial = - ListPolynomial( - other.coefficients - .toMutableList() - .apply { - if (this@minus == 0) { - indices.forEach { this[it] = -this[it] } - } else { - (1..lastIndex).forEach { this[it] = -this[it] } - - val result = this@minus - getOrElse(0) { constantZero } - - if (size == 0) add(result) - else this[0] = result - } - } - ) - /** - * Returns product of the integer represented as a polynomial and the polynomial. - * - * The operation is equivalent to sum of [this] copies of [other]. - */ - public override operator fun Int.times(other: ListPolynomial): ListPolynomial = - when (this) { - 0 -> zero - 1 -> other - else -> ListPolynomial( - other.coefficients - .toMutableList() - .apply { - for (deg in indices) this[deg] = this@times * this[deg] - } - ) - } - - /** - * Returns sum of the constant represented as a polynomial and the polynomial. - */ - public override operator fun C.plus(other: ListPolynomial): ListPolynomial = - with(other.coefficients) { - if (isEmpty()) ListPolynomial(listOf(this@plus)) - else ListPolynomial( - toMutableList() - .apply { - val result = if (size == 0) this@plus else this@plus + get(0) - - if(size == 0) add(result) - else this[0] = result - } - ) - } - /** - * Returns difference between the constant represented as a polynomial and the polynomial. - */ - public override operator fun C.minus(other: ListPolynomial): ListPolynomial = - with(other.coefficients) { - if (isEmpty()) ListPolynomial(listOf(this@minus)) - else ListPolynomial( - toMutableList() - .apply { - (1 .. lastIndex).forEach { this[it] = -this[it] } - - val result = if (size == 0) this@minus else this@minus - get(0) - - if(size == 0) add(result) - else this[0] = result - } - ) - } - /** - * Returns product of the constant represented as a polynomial and the polynomial. - */ - public override operator fun C.times(other: ListPolynomial): ListPolynomial = - ListPolynomial( - other.coefficients - .toMutableList() - .apply { - for (deg in indices) this[deg] = this@times * this[deg] - } - ) - - /** - * Returns sum of the constant represented as a polynomial and the polynomial. - */ - public override operator fun ListPolynomial.plus(other: C): ListPolynomial = - with(coefficients) { - if (isEmpty()) ListPolynomial(listOf(other)) - else ListPolynomial( - toMutableList() - .apply { - val result = if (size == 0) other else get(0) + other - - if(size == 0) add(result) - else this[0] = result - } - ) - } - /** - * Returns difference between the constant represented as a polynomial and the polynomial. - */ - public override operator fun ListPolynomial.minus(other: C): ListPolynomial = - with(coefficients) { - if (isEmpty()) ListPolynomial(listOf(-other)) - else ListPolynomial( - toMutableList() - .apply { - val result = if (size == 0) other else get(0) - other - - if(size == 0) add(result) - else this[0] = result - } - ) - } - /** - * Returns product of the constant represented as a polynomial and the polynomial. - */ - public override operator fun ListPolynomial.times(other: C): ListPolynomial = - ListPolynomial( - coefficients - .toMutableList() - .apply { - for (deg in indices) this[deg] = this[deg] * other - } - ) - - /** - * Converts the constant [value] to polynomial. - */ - public override fun number(value: C): ListPolynomial = ListPolynomial(listOf(value)) - - /** - * Returns negation of the polynomial. - */ - public override operator fun ListPolynomial.unaryMinus(): ListPolynomial = - ListPolynomial(coefficients.map { -it }) - /** - * Returns sum of the polynomials. - */ - public override operator fun ListPolynomial.plus(other: ListPolynomial): ListPolynomial { - val thisDegree = degree - val otherDegree = other.degree - return ListPolynomial( - List(max(thisDegree, otherDegree) + 1) { - when { - it > thisDegree -> other.coefficients[it] - it > otherDegree -> coefficients[it] - else -> coefficients[it] + other.coefficients[it] - } - } - ) - } - /** - * Returns difference of the polynomials. - */ - public override operator fun ListPolynomial.minus(other: ListPolynomial): ListPolynomial { - val thisDegree = degree - val otherDegree = other.degree - return ListPolynomial( - List(max(thisDegree, otherDegree) + 1) { - when { - it > thisDegree -> -other.coefficients[it] - it > otherDegree -> coefficients[it] - else -> coefficients[it] - other.coefficients[it] - } - } - ) - } - /** - * Returns product of the polynomials. - */ - public override operator fun ListPolynomial.times(other: ListPolynomial): ListPolynomial { - val thisDegree = degree - val otherDegree = other.degree - return ListPolynomial( - List(thisDegree + otherDegree + 1) { d -> - (max(0, d - otherDegree)..min(thisDegree, d)) - .map { coefficients[it] * other.coefficients[d - it] } - .reduce { acc, rational -> acc + rational } - } - ) - } - /** - * Raises [arg] to the integer power [exponent]. - */ // TODO: To optimize boxing - override fun power(arg: ListPolynomial, exponent: UInt): ListPolynomial = super.power(arg, exponent) - - /** - * Instance of zero polynomial (zero of the polynomial ring). - */ - override val zero: ListPolynomial = ListPolynomial(emptyList()) - /** - * Instance of unit polynomial (unit of the polynomial ring). - */ - override val one: ListPolynomial by lazy { ListPolynomial(listOf(constantOne)) } - - /** - * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is - * zero, degree is -1. - */ - public override val ListPolynomial.degree: Int get() = coefficients.lastIndex - - // TODO: When context receivers will be ready move all of this substitutions and invocations to utilities with - // [ListPolynomialSpace] as a context receiver - /** - * Evaluates value of [this] polynomial on provided [argument]. - */ - public inline fun ListPolynomial.substitute(argument: C): C = substitute(ring, argument) - /** - * Substitutes provided polynomial [argument] into [this] polynomial. - */ - public inline fun ListPolynomial.substitute(argument: ListPolynomial): ListPolynomial = substitute(ring, argument) - - /** - * Represent [this] polynomial as a regular context-less function. - */ - public inline fun ListPolynomial.asFunction(): (C) -> C = asFunctionOver(ring) - /** - * Represent [this] polynomial as a regular context-less function. - */ - public inline fun ListPolynomial.asFunctionOfConstant(): (C) -> C = asFunctionOfConstantOver(ring) - /** - * Represent [this] polynomial as a regular context-less function. - */ - public inline fun ListPolynomial.asFunctionOfPolynomial(): (ListPolynomial) -> ListPolynomial = asFunctionOfPolynomialOver(ring) - - /** - * Evaluates value of [this] polynomial on provided [argument]. - */ - public inline operator fun ListPolynomial.invoke(argument: C): C = substitute(ring, argument) - /** - * Evaluates value of [this] polynomial on provided [argument]. - */ - public inline operator fun ListPolynomial.invoke(argument: ListPolynomial): ListPolynomial = substitute(ring, argument) -} - -/** - * Space of polynomials constructed over ring. - * - * @param C the type of constants. Polynomials have them as a coefficients in their terms. - * @param A type of underlying ring of constants. It's [Ring] of [C]. - * @param ring underlying ring of constants of type [A]. - */ -public class ScalableListPolynomialSpace( - ring: A, -) : ListPolynomialSpace(ring), ScaleOperations> where A : Ring, A : ScaleOperations { - override fun scale(a: ListPolynomial, value: Double): ListPolynomial = - ring { ListPolynomial(a.coefficients.map { scale(it, value) }) } -} diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt index 612b00535..cfd21d552 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt @@ -27,10 +27,10 @@ public fun interface Piecewise { * @property pieces An ordered list of range-polynomial pairs. The list does not in general guarantee that there are no * "holes" in it. */ -public interface PiecewisePolynomial> : Piecewise> { - public val pieces: Collection, ListPolynomial>> +public interface PiecewisePolynomial> : Piecewise> { + public val pieces: Collection, Polynomial>> - override fun findPiece(arg: T): ListPolynomial? + override fun findPiece(arg: T): Polynomial? } /** @@ -38,11 +38,11 @@ public interface PiecewisePolynomial> : Piecewise> PiecewisePolynomial( - pieces: Collection, ListPolynomial>>, + pieces: Collection, Polynomial>>, ): PiecewisePolynomial = object : PiecewisePolynomial { - override val pieces: Collection, ListPolynomial>> = pieces + override val pieces: Collection, Polynomial>> = pieces - override fun findPiece(arg: T): ListPolynomial? = pieces.firstOrNull { arg in it.first }?.second + override fun findPiece(arg: T): Polynomial? = pieces.firstOrNull { arg in it.first }?.second } /** @@ -50,10 +50,10 @@ public fun > PiecewisePolynomial( * The pieces search is logarithmic. */ private class OrderedPiecewisePolynomial>( - override val pieces: List, ListPolynomial>>, + override val pieces: List, Polynomial>>, ) : PiecewisePolynomial { - override fun findPiece(arg: T): ListPolynomial? { + override fun findPiece(arg: T): Polynomial? { val index = pieces.binarySearch { (range, _) -> when { arg >= range.endInclusive -> -1 @@ -74,7 +74,7 @@ private class OrderedPiecewisePolynomial>( */ public class PiecewiseBuilder>(delimiter: T) { private val delimiters: MutableList = arrayListOf(delimiter) - private val pieces: MutableList> = arrayListOf() + private val pieces: MutableList> = arrayListOf() /** * Dynamically adds a piece to the right side (beyond maximum argument value of previous piece) @@ -82,7 +82,7 @@ public class PiecewiseBuilder>(delimiter: T) { * @param right new rightmost position. If is less than current rightmost position, an error is thrown. * @param piece the sub-function. */ - public fun putRight(right: T, piece: ListPolynomial) { + public fun putRight(right: T, piece: Polynomial) { require(right > delimiters.last()) { "New delimiter should be to the right of old one" } delimiters += right pieces += piece @@ -94,7 +94,7 @@ public class PiecewiseBuilder>(delimiter: T) { * @param left the new leftmost position. If is less than current rightmost position, an error is thrown. * @param piece the sub-function. */ - public fun putLeft(left: T, piece: ListPolynomial) { + public fun putLeft(left: T, piece: Polynomial) { require(left < delimiters.first()) { "New delimiter should be to the left of old one" } delimiters.add(0, left) pieces.add(0, piece) 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 61ea5a342..fec4776d9 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 @@ -3,500 +3,299 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ +@file:Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") + package space.kscience.kmath.functions import space.kscience.kmath.operations.Ring +import space.kscience.kmath.operations.ScaleOperations import space.kscience.kmath.operations.invoke -import kotlin.js.JsName -import kotlin.jvm.JvmName +import kotlin.jvm.JvmInline +import kotlin.math.max +import kotlin.math.min /** - * Abstraction of polynomials. - */ -public interface Polynomial - -/** - * Abstraction of ring of polynomials of type [P] over ring of constants of type [C]. + * Represents univariate polynomial that stores its coefficients in a [List]. * - * @param C the type of constants. Polynomials have them as coefficients in their terms. - * @param P the type of polynomials. + * @param C the type of constants. */ -@Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") // FIXME: Waiting for KT-31420 -public interface PolynomialSpace> : Ring

{ +@JvmInline +public value class Polynomial( /** - * Returns sum of the constant and the integer represented as a constant (member of underlying ring). - * - * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. + * List that contains coefficients of the polynomial. Every monomial `a x^d` is stored as a coefficient `a` placed + * into the list at index `d`. For example, coefficients of a polynomial `5 x^2 - 6` can be represented as + * ``` + * listOf( + * -6, // -6 + + * 0, // 0 x + + * 5, // 5 x^2 + * ) + * ``` + * and also as + * ``` + * listOf( + * -6, // -6 + + * 0, // 0 x + + * 5, // 5 x^2 + * 0, // 0 x^3 + * 0, // 0 x^4 + * ) + * ``` + * It is not prohibited to put extra zeros at end of the list (as for `0x^3` and `0x^4` in the example). But the + * longer the coefficients list the worse performance of arithmetical operations performed on it. Thus, it is + * recommended not to put (or even to remove) extra (or useless) coefficients at the end of the coefficients list. */ - public operator fun C.plus(other: Int): C - /** - * Returns difference between the constant and the integer represented as a constant (member of underlying ring). - * - * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. - */ - public operator fun C.minus(other: Int): C - /** - * Returns product of the constant and the integer represented as a constant (member of underlying ring). - * - * The operation is equivalent to sum of [other] copies of [this]. - */ - public operator fun C.times(other: Int): C + public val coefficients: List +) { + override fun toString(): String = "ListPolynomial$coefficients" +} +/** + * Arithmetic context for univariate polynomials with coefficients stored as a [List] constructed with the provided + * [ring] of constants. + * + * @param C the type of constants. Polynomials have them a coefficients in their terms. + * @param A type of provided underlying ring of constants. It's [Ring] of [C]. + * @param ring underlying ring of constants of type [A]. + */ +public open class ListPolynomialSpace>( /** - * Returns sum of the integer represented as a constant (member of underlying ring) and the constant. - * - * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. + * Underlying ring of constants. Its operations on constants are inherited by local operations on constants. */ - public operator fun Int.plus(other: C): C - /** - * Returns difference between the integer represented as a constant (member of underlying ring) and the constant. - * - * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. - */ - public operator fun Int.minus(other: C): C - /** - * Returns product of the integer represented as a constant (member of underlying ring) and the constant. - * - * The operation is equivalent to sum of [this] copies of [other]. - */ - public operator fun Int.times(other: C): C - - /** - * Converts the integer [value] to constant. - */ - public fun constantNumber(value: Int): C = constantOne * value - /** - * Converts the integer to constant. - */ - public fun Int.asConstant(): C = constantNumber(this) - - /** - * Returns sum of the polynomial and the integer represented as a polynomial. - * - * The operation is equivalent to adding [other] copies of unit polynomial to [this]. - */ - public operator fun P.plus(other: Int): P = addMultipliedByDoubling(this, one, other) - /** - * Returns difference between the polynomial and the integer represented as a polynomial. - * - * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. - */ - public operator fun P.minus(other: Int): P = addMultipliedByDoubling(this, one, -other) - /** - * Returns product of the polynomial and the integer represented as a polynomial. - * - * The operation is equivalent to sum of [other] copies of [this]. - */ - public operator fun P.times(other: Int): P = multiplyByDoubling(this, other) - - /** - * Returns sum of the integer represented as a polynomial and the polynomial. - * - * The operation is equivalent to adding [this] copies of unit polynomial to [other]. - */ - public operator fun Int.plus(other: P): P = addMultipliedByDoubling(other, one, this) - /** - * Returns difference between the integer represented as a polynomial and the polynomial. - * - * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. - */ - public operator fun Int.minus(other: P): P = addMultipliedByDoubling(-other, one, this) - /** - * Returns product of the integer represented as a polynomial and the polynomial. - * - * The operation is equivalent to sum of [this] copies of [other]. - */ - public operator fun Int.times(other: P): P = multiplyByDoubling(other, this) - - /** - * Converts the integer [value] to polynomial. - */ - public fun number(value: Int): P = number(constantNumber(value)) - /** - * Converts the integer to polynomial. - */ - public fun Int.asPolynomial(): P = number(this) - - /** - * Returns the same constant. - */ - @JvmName("unaryPlusConstant") - @JsName("unaryPlusConstant") - public operator fun C.unaryPlus(): C = this - /** - * Returns negation of the constant. - */ - @JvmName("unaryMinusConstant") - @JsName("unaryMinusConstant") - public operator fun C.unaryMinus(): C - /** - * Returns sum of the constants. - */ - @JvmName("plusConstantConstant") - @JsName("plusConstantConstant") - public operator fun C.plus(other: C): C - /** - * Returns difference of the constants. - */ - @JvmName("minusConstantConstant") - @JsName("minusConstantConstant") - public operator fun C.minus(other: C): C - /** - * Returns product of the constants. - */ - @JvmName("timesConstantConstant") - @JsName("timesConstantConstant") - public operator fun C.times(other: C): C - /** - * Raises [arg] to the integer power [exponent]. - */ - @JvmName("powerConstant") - @JsName("powerConstant") - public fun power(arg: C, exponent: UInt) : C + public val ring: A, +) : Ring> { /** * Instance of zero constant (zero of the underlying ring). */ - public val constantZero: C + public val constantZero: C get() = ring.zero /** * Instance of unit constant (unit of the underlying ring). */ - public val constantOne: C + public val constantOne: C get() = ring.one /** * Returns sum of the constant represented as a polynomial and the polynomial. */ - public operator fun C.plus(other: P): P + public operator fun C.plus(other: Polynomial): Polynomial = + with(ring) { + with(other.coefficients) { + if (isEmpty()) Polynomial(listOf(this@plus)) + else Polynomial( + toMutableList() + .apply { + val result = if (size == 0) this@plus else this@plus + get(0) + + if (size == 0) add(result) + else this[0] = result + } + ) + } + } /** * Returns difference between the constant represented as a polynomial and the polynomial. */ - public operator fun C.minus(other: P): P + public operator fun C.minus(other: Polynomial): Polynomial = + with(ring) { + with(other.coefficients) { + if (isEmpty()) Polynomial(listOf(this@minus)) + else Polynomial( + toMutableList() + .apply { + (1..lastIndex).forEach { this[it] = -this[it] } + + val result = if (size == 0) this@minus else this@minus - get(0) + + if (size == 0) add(result) + else this[0] = result + } + ) + } + } /** * Returns product of the constant represented as a polynomial and the polynomial. */ - public operator fun C.times(other: P): P + public operator fun C.times(other: Polynomial): Polynomial = + with(ring) { + Polynomial( + other.coefficients + .toMutableList() + .apply { + for (deg in indices) this[deg] = this@times * this[deg] + } + ) + } /** * Returns sum of the constant represented as a polynomial and the polynomial. */ - public operator fun P.plus(other: C): P + public operator fun Polynomial.plus(other: C): Polynomial = + with(ring) { + with(coefficients) { + if (isEmpty()) Polynomial(listOf(other)) + else Polynomial( + toMutableList() + .apply { + val result = if (size == 0) other else get(0) + other + + if (size == 0) add(result) + else this[0] = result + } + ) + } + } /** * Returns difference between the constant represented as a polynomial and the polynomial. */ - public operator fun P.minus(other: C): P + public operator fun Polynomial.minus(other: C): Polynomial = + with(ring) { + with(coefficients) { + if (isEmpty()) Polynomial(listOf(-other)) + else Polynomial( + toMutableList() + .apply { + val result = if (size == 0) other else get(0) - other + + if (size == 0) add(result) + else this[0] = result + } + ) + } + } /** * Returns product of the constant represented as a polynomial and the polynomial. */ - public operator fun P.times(other: C): P + public operator fun Polynomial.times(other: C): Polynomial = + with(ring) { + Polynomial( + coefficients + .toMutableList() + .apply { + for (deg in indices) this[deg] = this[deg] * other + } + ) + } /** * Converts the constant [value] to polynomial. */ - public fun number(value: C): P = one * value + public fun number(value: C): Polynomial = Polynomial(listOf(value)) /** * Converts the constant to polynomial. */ - public fun C.asPolynomial(): P = number(this) + public fun C.asPolynomial(): Polynomial = number(this) - /** - * Returns the same polynomial. - */ - public override operator fun P.unaryPlus(): P = this /** * Returns negation of the polynomial. */ - public override operator fun P.unaryMinus(): P + public override operator fun Polynomial.unaryMinus(): Polynomial = + with(ring) { + Polynomial(coefficients.map { -it }) + } /** * Returns sum of the polynomials. */ - public override operator fun P.plus(other: P): P + public override operator fun Polynomial.plus(other: Polynomial): Polynomial { + with(ring) { + val thisDegree = degree + val otherDegree = other.degree + return Polynomial( + List(max(thisDegree, otherDegree) + 1) { + when { + it > thisDegree -> other.coefficients[it] + it > otherDegree -> coefficients[it] + else -> coefficients[it] + other.coefficients[it] + } + } + ) + } + } /** * Returns difference of the polynomials. */ - public override operator fun P.minus(other: P): P + public override operator fun Polynomial.minus(other: Polynomial): Polynomial { + with(ring) { + val thisDegree = degree + val otherDegree = other.degree + return Polynomial( + List(max(thisDegree, otherDegree) + 1) { + when { + it > thisDegree -> -other.coefficients[it] + it > otherDegree -> coefficients[it] + else -> coefficients[it] - other.coefficients[it] + } + } + ) + } + } /** * Returns product of the polynomials. */ - public override operator fun P.times(other: P): P + public override operator fun Polynomial.times(other: Polynomial): Polynomial { + with(ring) { + val thisDegree = degree + val otherDegree = other.degree + return Polynomial( + List(thisDegree + otherDegree + 1) { d -> + (max(0, d - otherDegree)..min(thisDegree, d)) + .map { coefficients[it] * other.coefficients[d - it] } + .reduce { acc, rational -> acc + rational } + } + ) + } + } /** * Raises [arg] to the integer power [exponent]. - */ - public override fun power(arg: P, exponent: UInt) : P = exponentiateBySquaring(arg, exponent) + */ // TODO: To optimize boxing + override fun power(arg: Polynomial, exponent: UInt): Polynomial = exponentiateBySquaring(arg, exponent) /** * Instance of zero polynomial (zero of the polynomial ring). */ - public override val zero: P + override val zero: Polynomial = Polynomial(emptyList()) /** * Instance of unit polynomial (unit of the polynomial ring). */ - public override val one: P + override val one: Polynomial by lazy { Polynomial(listOf(constantOne)) } /** * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is * zero, degree is -1. */ - public val P.degree: Int + public val Polynomial.degree: Int get() = coefficients.lastIndex - override fun add(left: P, right: P): P = left + right - override fun multiply(left: P, right: P): P = left * right + override fun add(left: Polynomial, right: Polynomial): Polynomial = left + right + override fun multiply(left: Polynomial, right: Polynomial): Polynomial = left * right + + // TODO: When context receivers will be ready move all of this substitutions and invocations to utilities with + // [ListPolynomialSpace] as a context receiver + /** + * Evaluates value of [this] polynomial on provided [argument]. + */ + public inline fun Polynomial.substitute(argument: C): C = substitute(ring, argument) + + /** + * Represent [this] polynomial as a regular context-less function. + */ + public inline fun Polynomial.asFunction(): (C) -> C = asFunctionOver(ring) + + /** + * Evaluates value of [this] polynomial on provided [argument]. + */ + public inline operator fun Polynomial.invoke(argument: C): C = substitute(ring, argument) } /** - * Abstraction of ring of polynomials of type [P] over ring of constants of type [C]. It also assumes that there is - * provided [ring] (of type [A]), that provides constant-wise operations. + * Space of polynomials constructed over ring. * - * @param C the type of constants. Polynomials have them as coefficients in their terms. - * @param P the type of polynomials. - * @param A the type of algebraic structure (precisely, of ring) provided for constants. + * @param C the type of constants. Polynomials have them as a coefficients in their terms. + * @param A type of underlying ring of constants. It's [Ring] of [C]. + * @param ring underlying ring of constants of type [A]. */ -@Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 -public interface PolynomialSpaceOverRing, A: Ring> : PolynomialSpace { - - /** - * Underlying ring of constants. Its operations on constants are inherited by local operations on constants. - */ - public val ring: A - - /** - * Returns sum of the constant and the integer represented as a constant (member of underlying ring). - * - * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. - */ - public override operator fun C.plus(other: Int): C = ring { addMultipliedByDoubling(this@plus, one, other) } - /** - * Returns difference between the constant and the integer represented as a constant (member of underlying ring). - * - * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. - */ - public override operator fun C.minus(other: Int): C = ring { addMultipliedByDoubling(this@minus, one, -other) } - /** - * Returns product of the constant and the integer represented as a constant (member of underlying ring). - * - * The operation is equivalent to sum of [other] copies of [this]. - */ - public override operator fun C.times(other: Int): C = ring { multiplyByDoubling(this@times, other) } - - /** - * Returns sum of the integer represented as a constant (member of underlying ring) and the constant. - * - * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. - */ - public override operator fun Int.plus(other: C): C = ring { addMultipliedByDoubling(other, one, this@plus) } - /** - * Returns difference between the integer represented as a constant (member of underlying ring) and the constant. - * - * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. - */ - public override operator fun Int.minus(other: C): C = ring { addMultipliedByDoubling(-other, one, this@minus) } - /** - * Returns product of the integer represented as a constant (member of underlying ring) and the constant. - * - * The operation is equivalent to sum of [this] copies of [other]. - */ - public override operator fun Int.times(other: C): C = ring { multiplyByDoubling(other, this@times) } - - /** - * Returns negation of the constant. - */ - @JvmName("unaryMinusConstant") - public override operator fun C.unaryMinus(): C = ring { -this@unaryMinus } - /** - * Returns sum of the constants. - */ - @JvmName("plusConstantConstant") - public override operator fun C.plus(other: C): C = ring { this@plus + other } - /** - * Returns difference of the constants. - */ - @JvmName("minusConstantConstant") - public override operator fun C.minus(other: C): C = ring { this@minus - other } - /** - * Returns product of the constants. - */ - @JvmName("timesConstantConstant") - public override operator fun C.times(other: C): C = ring { this@times * other } - /** - * Raises [arg] to the integer power [exponent]. - */ - @JvmName("powerConstant") - override fun power(arg: C, exponent: UInt): C = ring { power(arg, exponent) } - - /** - * Instance of zero constant (zero of the underlying ring). - */ - public override val constantZero: C get() = ring.zero - /** - * Instance of unit constant (unit of the underlying ring). - */ - public override val constantOne: C get() = ring.one +public class ScalableListPolynomialSpace( + ring: A, +) : ListPolynomialSpace(ring), ScaleOperations> where A : Ring, A : ScaleOperations { + override fun scale(a: Polynomial, value: Double): Polynomial = + ring { Polynomial(a.coefficients.map { scale(it, value) }) } } - -/** - * Abstraction of ring of polynomials of type [P] of variables of type [V] and over ring of constants of type [C]. - * - * @param C the type of constants. Polynomials have them as coefficients in their terms. - * @param V the type of variables. Polynomials have them in representations of terms. - * @param P the type of polynomials. - */ -@Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 -public interface MultivariatePolynomialSpace>: PolynomialSpace { - /** - * Returns sum of the variable represented as a monic monomial and the integer represented as a constant polynomial. - */ - @JvmName("plusVariableInt") - public operator fun V.plus(other: Int): P - /** - * Returns difference between the variable represented as a monic monomial and the integer represented as a constant polynomial. - */ - @JvmName("minusVariableInt") - public operator fun V.minus(other: Int): P - /** - * Returns product of the variable represented as a monic monomial and the integer represented as a constant polynomial. - */ - @JvmName("timesVariableInt") - public operator fun V.times(other: Int): P - - /** - * Returns sum of the integer represented as a constant polynomial and the variable represented as a monic monomial. - */ - @JvmName("plusIntVariable") - public operator fun Int.plus(other: V): P - /** - * Returns difference between the integer represented as a constant polynomial and the variable represented as a monic monomial. - */ - @JvmName("minusIntVariable") - public operator fun Int.minus(other: V): P - /** - * Returns product of the integer represented as a constant polynomial and the variable represented as a monic monomial. - */ - @JvmName("timesIntVariable") - public operator fun Int.times(other: V): P - - /** - * Returns sum of the variable represented as a monic monomial and the constant represented as a constant polynomial. - */ - @JvmName("plusVariableConstant") - public operator fun V.plus(other: C): P - /** - * Returns difference between the variable represented as a monic monomial and the constant represented as a constant polynomial. - */ - @JvmName("minusVariableConstant") - public operator fun V.minus(other: C): P - /** - * Returns product of the variable represented as a monic monomial and the constant represented as a constant polynomial. - */ - @JvmName("timesVariableConstant") - public operator fun V.times(other: C): P - - /** - * Returns sum of the constant represented as a constant polynomial and the variable represented as a monic monomial. - */ - @JvmName("plusConstantVariable") - public operator fun C.plus(other: V): P - /** - * Returns difference between the constant represented as a constant polynomial and the variable represented as a monic monomial. - */ - @JvmName("minusConstantVariable") - public operator fun C.minus(other: V): P - /** - * Returns product of the constant represented as a constant polynomial and the variable represented as a monic monomial. - */ - @JvmName("timesConstantVariable") - public operator fun C.times(other: V): P - - /** - * Represents the variable as a monic monomial. - */ - @JvmName("unaryPlusVariable") - public operator fun V.unaryPlus(): P - /** - * Returns negation of representation of the variable as a monic monomial. - */ - @JvmName("unaryMinusVariable") - public operator fun V.unaryMinus(): P - /** - * Returns sum of the variables represented as monic monomials. - */ - @JvmName("plusVariableVariable") - public operator fun V.plus(other: V): P - /** - * Returns difference between the variables represented as monic monomials. - */ - @JvmName("minusVariableVariable") - public operator fun V.minus(other: V): P - /** - * Returns product of the variables represented as monic monomials. - */ - @JvmName("timesVariableVariable") - public operator fun V.times(other: V): P - - /** - * Represents the [variable] as a monic monomial. - */ - @JvmName("numberVariable") - public fun number(variable: V): P = +variable - /** - * Represents the variable as a monic monomial. - */ - @JvmName("asPolynomialVariable") - public fun V.asPolynomial(): P = number(this) - - /** - * Returns sum of the variable represented as a monic monomial and the polynomial. - */ - @JvmName("plusVariablePolynomial") - public operator fun V.plus(other: P): P - /** - * Returns difference between the variable represented as a monic monomial and the polynomial. - */ - @JvmName("minusVariablePolynomial") - public operator fun V.minus(other: P): P - /** - * Returns product of the variable represented as a monic monomial and the polynomial. - */ - @JvmName("timesVariablePolynomial") - public operator fun V.times(other: P): P - - /** - * Returns sum of the polynomial and the variable represented as a monic monomial. - */ - @JvmName("plusPolynomialVariable") - public operator fun P.plus(other: V): P - /** - * Returns difference between the polynomial and the variable represented as a monic monomial. - */ - @JvmName("minusPolynomialVariable") - public operator fun P.minus(other: V): P - /** - * Returns product of the polynomial and the variable represented as a monic monomial. - */ - @JvmName("timesPolynomialVariable") - public operator fun P.times(other: V): P - - /** - * Map that associates variables (that appear in the polynomial in positive exponents) with their most exponents - * in which they are appeared in the polynomial. - * - * As consequence all values in the map are positive integers. Also, if the polynomial is constant, the map is empty. - * And keys of the map is the same as in [variables]. - */ - public val P.degrees: Map - /** - * Counts degree of the polynomial by the specified [variable]. - */ - public fun P.degreeBy(variable: V): UInt = degrees.getOrElse(variable) { 0u } - /** - * Counts degree of the polynomial by the specified [variables]. - */ - public fun P.degreeBy(variables: Collection): UInt - /** - * Set of all variables that appear in the polynomial in positive exponents. - */ - public val P.variables: Set get() = degrees.keys - /** - * Count of all variables that appear in the polynomial in positive exponents. - */ - public val P.countOfVariables: Int get() = variables.size -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt index b40aa4775..5eb1af4dc 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt @@ -9,101 +9,6 @@ import space.kscience.kmath.operations.* // TODO: All of this should be moved to algebraic structures' place for utilities -// FIXME: Move receiver to context receiver -/** - * Returns product of [arg] and integer [multiplier]. - * - * @param arg the multiplicand. - * @param multiplier the integer multiplier. - * @return product of the multiplicand [arg] and the multiplier [multiplier]. - * @author Gleb Minaev - */ -internal fun Group.multiplyByDoubling(arg: C, multiplier: Int): C = - if (multiplier >= 0) multiplyByDoubling(arg, multiplier.toUInt()) - else multiplyByDoubling(-arg, (-multiplier).toUInt()) - -// FIXME: Move receiver to context receiver -/** - * Adds product of [arg] and [multiplier] to [base]. - * - * @param base the augend. - * @param arg the multiplicand. - * @param multiplier the integer multiplier. - * @return sum of the augend [base] and product of the multiplicand [arg] and the multiplier [multiplier]. - * @author Gleb Minaev - */ -internal fun GroupOps.addMultipliedByDoubling(base: C, arg: C, multiplier: Int): C = - if (multiplier >= 0) addMultipliedByDoubling(base, arg, multiplier.toUInt()) - else addMultipliedByDoubling(base, -arg, (-multiplier).toUInt()) - -// FIXME: Move receiver to context receiver -/** - * Returns product of [arg] and integer [multiplier]. - * - * This is implementation of variation of [exponentiation by squaring](https://en.wikipedia.org/wiki/Exponentiation_by_squaring) - * - * @param arg the multiplicand. - * @param multiplier the integer multiplier. - * @return product of the multiplicand [arg] and the multiplier [multiplier]. - * @author Gleb Minaev - */ -internal tailrec fun Group.multiplyByDoubling(arg: C, multiplier: UInt): C = - when { - multiplier == 0u -> zero - multiplier == 1u -> arg - multiplier and 1u == 0u -> multiplyByDoubling(arg + arg, multiplier shr 1) - multiplier and 1u == 1u -> addMultipliedByDoubling(arg, arg + arg, multiplier shr 1) - else -> error("Error in multiplication group instant by unsigned integer: got reminder by division by 2 different from 0 and 1") - } - -// FIXME: Move receiver to context receiver -/** - * Adds product of [arg] and [multiplier] to [base]. - * - * This is implementation of variation of [exponentiation by squaring](https://en.wikipedia.org/wiki/Exponentiation_by_squaring) - * - * @param base the augend. - * @param arg the multiplicand. - * @param multiplier the integer multiplier. - * @return sum of the augend [base] and product of the multiplicand [arg] and the multiplier [multiplier]. - * @author Gleb Minaev - */ -internal tailrec fun GroupOps.addMultipliedByDoubling(base: C, arg: C, multiplier: UInt): C = - when { - multiplier == 0u -> base - multiplier == 1u -> base + arg - multiplier and 1u == 0u -> addMultipliedByDoubling(base, arg + arg, multiplier shr 1) - multiplier and 1u == 1u -> addMultipliedByDoubling(base + arg, arg + arg, multiplier shr 1) - else -> error("Error in multiplication group instant by unsigned integer: got reminder by division by 2 different from 0 and 1") - } - -// FIXME: Move receiver to context receiver -/** - * Raises [arg] to the integer power [exponent]. - * - * @param arg the base of the power. - * @param exponent the exponent of the power. - * @return [arg] raised to the power [exponent]. - * @author Gleb Minaev - */ -internal fun Field.exponentiateBySquaring(arg: C, exponent: Int): C = - if (exponent >= 0) exponentiateBySquaring(arg, exponent.toUInt()) - else exponentiateBySquaring(one / arg, (-exponent).toUInt()) - -// FIXME: Move receiver to context receiver -/** - * Multiplies [base] and [arg] raised to the integer power [exponent]. - * - * @param base the multiplicand. - * @param arg the base of the power. - * @param exponent the exponent of the power. - * @return product of [base] and [arg] raised to the power [exponent]. - * @author Gleb Minaev - */ -internal fun Field.multiplyExponentiatedBySquaring(base: C, arg: C, exponent: Int): C = - if (exponent >= 0) multiplyExponentiatedBySquaring(base, arg, exponent.toUInt()) - else multiplyExponentiatedBySquaring(base, one / arg, (-exponent).toUInt()) - // FIXME: Move receiver to context receiver /** * Raises [arg] to the integer power [exponent]. diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt deleted file mode 100644 index e95361724..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt +++ /dev/null @@ -1,92 +0,0 @@ -/* - * 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.functions - -import space.kscience.kmath.operations.Ring - - -/** - * Constructs a [ListPolynomial] instance with provided [coefficients]. The collection of coefficients will be reversed - * if [reverse] parameter is true. - */ -@Suppress("FunctionName") -public fun ListPolynomial(coefficients: List, reverse: Boolean = false): ListPolynomial = - ListPolynomial(with(coefficients) { if (reverse) reversed() else this }) - -/** - * Constructs a [ListPolynomial] instance with provided [coefficients]. The collection of coefficients will be reversed - * if [reverse] parameter is true. - */ -@Suppress("FunctionName") -public fun ListPolynomial(vararg coefficients: C, reverse: Boolean = false): ListPolynomial = - ListPolynomial(with(coefficients) { if (reverse) reversed() else toList() }) - -/** - * Represents [this] constant as a [ListPolynomial]. - */ -public fun C.asListPolynomial() : ListPolynomial = ListPolynomial(listOf(this)) - - -// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available - -/** - * Constructs [ListRationalFunction] instance with numerator and denominator constructed with provided - * [numeratorCoefficients] and [denominatorCoefficients]. The both collections of coefficients will be reversed if - * [reverse] parameter is true. - */ -@Suppress("FunctionName") -public fun ListRationalFunction(numeratorCoefficients: List, denominatorCoefficients: List, reverse: Boolean = false): ListRationalFunction = - ListRationalFunction( - ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), - ListPolynomial( with(denominatorCoefficients) { if (reverse) reversed() else this } ) - ) -/** - * Constructs [ListRationalFunction] instance with provided [numerator] and unit denominator. - */ -@Suppress("FunctionName") -public fun > A.ListRationalFunction(numerator: ListPolynomial): ListRationalFunction = - ListRationalFunction(numerator, ListPolynomial(listOf(one))) -/** - * Constructs [ListRationalFunction] instance with provided [numerator] and unit denominator. - */ -@Suppress("FunctionName") -public fun > ListRationalFunctionSpace.ListRationalFunction(numerator: ListPolynomial): ListRationalFunction = - ListRationalFunction(numerator, polynomialOne) -/** - * Constructs [ListRationalFunction] instance with numerator constructed with provided [numeratorCoefficients] and unit - * denominator. The collection of numerator coefficients will be reversed if [reverse] parameter is true. - */ -@Suppress("FunctionName") -public fun > A.ListRationalFunction(numeratorCoefficients: List, reverse: Boolean = false): ListRationalFunction = - ListRationalFunction( - ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), - ListPolynomial(listOf(one)) - ) -/** - * Constructs [ListRationalFunction] instance with numerator constructed with provided [numeratorCoefficients] and unit - * denominator. The collection of numerator coefficients will be reversed if [reverse] parameter is true. - */ -@Suppress("FunctionName") -public fun > ListRationalFunctionSpace.ListRationalFunction(numeratorCoefficients: List, reverse: Boolean = false): ListRationalFunction = - ListRationalFunction( - ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), - polynomialOne - ) - -/** - * Represents [this] constant as a rational function. - */ // FIXME: When context receivers will be ready, delete this function and uncomment the following two -public fun > C.asListRationalFunction(ring: A) : ListRationalFunction = ring.ListRationalFunction(asListPolynomial()) -///** -// * Represents [this] constant as a rational function. -// */ -//context(A) -//public fun > C.asListRationalFunction() : ListRationalFunction = ListRationalFunction(asListPolynomial()) -///** -// * Represents [this] constant as a rational function. -// */ -//context(ListRationalFunctionSpace) -//public fun > C.asListRationalFunction() : ListRationalFunction = ListRationalFunction(asListPolynomial()) \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt deleted file mode 100644 index 4f3f6d88e..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt +++ /dev/null @@ -1,255 +0,0 @@ -/* - * 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.functions - -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.* -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract -import kotlin.math.max -import kotlin.math.pow - - -/** - * Creates a [ListPolynomialSpace] over a received ring. - */ -public inline val > A.listPolynomialSpace: ListPolynomialSpace - get() = ListPolynomialSpace(this) - -/** - * Creates a [ListPolynomialSpace]'s scope over a received ring. - */ // TODO: When context will be ready move [ListPolynomialSpace] and add [A] to context receivers of [block] -public inline fun , R> A.listPolynomialSpace(block: ListPolynomialSpace.() -> R): R { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return ListPolynomialSpace(this).block() -} - -/** - * Creates a [ScalableListPolynomialSpace] over a received scalable ring. - */ -public inline val A.scalableListPolynomialSpace: ScalableListPolynomialSpace where A : Ring, A : ScaleOperations - get() = ScalableListPolynomialSpace(this) - -/** - * Creates a [ScalableListPolynomialSpace]'s scope over a received scalable ring. - */ // TODO: When context will be ready move [ListPolynomialSpace] and add [A] to context receivers of [block] -public inline fun A.scalableListPolynomialSpace(block: ScalableListPolynomialSpace.() -> R): R where A : Ring, A : ScaleOperations { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return ScalableListPolynomialSpace(this).block() -} - -/** - * Creates a [ListRationalFunctionSpace] over a received ring. - */ -public inline val > A.listRationalFunctionSpace: ListRationalFunctionSpace - get() = ListRationalFunctionSpace(this) - -/** - * Creates a [ListRationalFunctionSpace]'s scope over a received ring. - */ // TODO: When context will be ready move [ListRationalFunctionSpace] and add [A] to context receivers of [block] -public inline fun , R> A.listRationalFunctionSpace(block: ListRationalFunctionSpace.() -> R): R { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return ListRationalFunctionSpace(this).block() -} - - -/** - * Evaluates value of [this] Double polynomial on provided Double argument. - */ -public fun ListPolynomial.substitute(arg: Double): Double = - coefficients.reduceIndexedOrNull { index, acc, c -> - acc + c * arg.pow(index) - } ?: .0 - -/** - * Evaluates value of [this] polynomial on provided argument. - * - * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). - */ -public fun ListPolynomial.substitute(ring: Ring, arg: C): C = ring { - if (coefficients.isEmpty()) return zero - var result: C = coefficients.last() - for (j in coefficients.size - 2 downTo 0) { - result = (arg * result) + coefficients[j] - } - return result -} - -/** - * Substitutes provided polynomial [arg] into [this] polynomial. - * - * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). - */ // TODO: To optimize boxing -public fun ListPolynomial.substitute(ring: Ring, arg: ListPolynomial) : ListPolynomial = - ring.listPolynomialSpace { - if (coefficients.isEmpty()) return zero - var result: ListPolynomial = coefficients.last().asPolynomial() - for (j in coefficients.size - 2 downTo 0) { - result = (arg * result) + coefficients[j] - } - return result - } - -/** - * Substitutes provided rational function [arg] into [this] polynomial. - * - * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). - */ // TODO: To optimize boxing -public fun ListPolynomial.substitute(ring: Ring, arg: ListRationalFunction) : ListRationalFunction = - ring.listRationalFunctionSpace { - if (coefficients.isEmpty()) return zero - var result: ListRationalFunction = coefficients.last().asRationalFunction() - for (j in coefficients.size - 2 downTo 0) { - result = (arg * result) + coefficients[j] - } - return result - } - -/** - * Evaluates value of [this] Double rational function in provided Double argument. - */ -public fun ListRationalFunction.substitute(arg: Double): Double = - numerator.substitute(arg) / denominator.substitute(arg) - -/** - * Evaluates value of [this] polynomial for provided argument. - * - * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). - */ -public fun ListRationalFunction.substitute(ring: Field, arg: C): C = ring { - numerator.substitute(ring, arg) / denominator.substitute(ring, arg) -} - -/** - * Substitutes provided polynomial [arg] into [this] rational function. - */ // TODO: To optimize boxing -public fun ListRationalFunction.substitute(ring: Ring, arg: ListPolynomial) : ListRationalFunction = - ring.listRationalFunctionSpace { - numerator.substitute(ring, arg) / denominator.substitute(ring, arg) - } - -/** - * Substitutes provided rational function [arg] into [this] rational function. - */ // TODO: To optimize boxing -public fun ListRationalFunction.substitute(ring: Ring, arg: ListRationalFunction) : ListRationalFunction = - ring.listRationalFunctionSpace { - numerator.substitute(ring, arg) / denominator.substitute(ring, arg) - } - -/** - * Represent [this] polynomial as a regular context-less function. - */ -public fun > ListPolynomial.asFunctionOver(ring: A): (C) -> C = { substitute(ring, it) } - -/** - * Represent [this] polynomial as a regular context-less function. - */ -public fun > ListPolynomial.asFunctionOfConstantOver(ring: A): (C) -> C = { substitute(ring, it) } - -/** - * Represent [this] polynomial as a regular context-less function. - */ -public fun > ListPolynomial.asFunctionOfPolynomialOver(ring: A): (ListPolynomial) -> ListPolynomial = { substitute(ring, it) } - -/** - * Represent [this] polynomial as a regular context-less function. - */ -public fun > ListPolynomial.asFunctionOfRationalFunctionOver(ring: A): (ListRationalFunction) -> ListRationalFunction = { substitute(ring, it) } - -/** - * Represent [this] rational function as a regular context-less function. - */ -public fun > ListRationalFunction.asFunctionOver(ring: A): (C) -> C = { substitute(ring, it) } - -/** - * Represent [this] rational function as a regular context-less function. - */ -public fun > ListRationalFunction.asFunctionOfConstantOver(ring: A): (C) -> C = { substitute(ring, it) } - -/** - * Represent [this] rational function as a regular context-less function. - */ -public fun > ListRationalFunction.asFunctionOfPolynomialOver(ring: A): (ListPolynomial) -> ListRationalFunction = { substitute(ring, it) } - -/** - * Represent [this] rational function as a regular context-less function. - */ -public fun > ListRationalFunction.asFunctionOfRationalFunctionOver(ring: A): (ListRationalFunction) -> ListRationalFunction = { substitute(ring, it) } - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun ListPolynomial.derivative( - ring: A, -): ListPolynomial where A : Ring, A : NumericAlgebra = ring { - ListPolynomial( - buildList(max(0, coefficients.size - 1)) { - for (deg in 1 .. coefficients.lastIndex) add(number(deg) * coefficients[deg]) - } - ) -} - -/** - * Returns algebraic derivative of received polynomial of specified [order]. The [order] should be non-negative integer. - */ -@UnstableKMathAPI -public fun ListPolynomial.nthDerivative( - ring: A, - order: Int, -): ListPolynomial where A : Ring, A : NumericAlgebra = ring { - require(order >= 0) { "Order of derivative must be non-negative" } - ListPolynomial( - buildList(max(0, coefficients.size - order)) { - for (deg in order.. coefficients.lastIndex) - add((deg - order + 1 .. deg).fold(coefficients[deg]) { acc, d -> acc * number(d) }) - } - ) -} - -/** - * Returns algebraic antiderivative of received polynomial. - */ -@UnstableKMathAPI -public fun ListPolynomial.antiderivative( - ring: A, -): ListPolynomial where A : Field, A : NumericAlgebra = ring { - ListPolynomial( - buildList(coefficients.size + 1) { - add(zero) - coefficients.mapIndexedTo(this) { index, t -> t / number(index + 1) } - } - ) -} - -/** - * Returns algebraic antiderivative of received polynomial of specified [order]. The [order] should be non-negative integer. - */ -@UnstableKMathAPI -public fun ListPolynomial.nthAntiderivative( - ring: A, - order: Int, -): ListPolynomial where A : Field, A : NumericAlgebra = ring { - require(order >= 0) { "Order of antiderivative must be non-negative" } - ListPolynomial( - buildList(coefficients.size + order) { - repeat(order) { add(zero) } - coefficients.mapIndexedTo(this) { index, c -> (1..order).fold(c) { acc, i -> acc / number(index + i) } } - } - ) -} - -/** - * Computes a definite integral of [this] polynomial in the specified [range]. - */ -@UnstableKMathAPI -public fun > ListPolynomial.integrate( - ring: Field, - range: ClosedRange, -): C = ring { - val antiderivative = antiderivative(ring) - antiderivative.substitute(ring, range.endInclusive) - antiderivative.substitute(ring, range.start) -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt deleted file mode 100644 index 76f1c294e..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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.functions - - -/** - * Marks declarations that give access to internal entities of polynomials delicate structure. Thus, it allows to - * optimize performance a bit by skipping standard steps, but such skips may cause critical errors if something is - * implemented badly. Make sure you fully read and understand documentation and don't break internal contracts. - */ -@RequiresOptIn( - message = "This declaration gives access to delicate internal structure of polynomials. " + - "It allows to optimize performance by skipping unnecessary arguments check. " + - "But at the same time makes it easy to make a mistake " + - "that will cause wrong computation result or even runtime error. " + - "Make sure you fully read and understand documentation.", - level = RequiresOptIn.Level.ERROR -) -public annotation class DelicatePolynomialAPI \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialConstructors.kt new file mode 100644 index 000000000..ff04607a7 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialConstructors.kt @@ -0,0 +1,28 @@ +/* + * 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.functions + + +/** + * Constructs a [Polynomial] instance with provided [coefficients]. The collection of coefficients will be reversed + * if [reverse] parameter is true. + */ +@Suppress("FunctionName") +public fun ListPolynomial(coefficients: List, reverse: Boolean = false): Polynomial = + Polynomial(with(coefficients) { if (reverse) reversed() else this }) + +/** + * Constructs a [Polynomial] instance with provided [coefficients]. The collection of coefficients will be reversed + * if [reverse] parameter is true. + */ +@Suppress("FunctionName") +public fun ListPolynomial(vararg coefficients: C, reverse: Boolean = false): Polynomial = + Polynomial(with(coefficients) { if (reverse) reversed() else toList() }) + +/** + * Represents [this] constant as a [Polynomial]. + */ +public fun C.asListPolynomial() : Polynomial = Polynomial(listOf(this)) \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt new file mode 100644 index 000000000..fc3a728df --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt @@ -0,0 +1,111 @@ +/* + * 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.functions + +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.* +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract +import kotlin.math.max +import kotlin.math.pow + + +/** + * Creates a [ListPolynomialSpace] over a received ring. + */ +public inline val > A.listPolynomialSpace: ListPolynomialSpace + get() = ListPolynomialSpace(this) + +/** + * Creates a [ListPolynomialSpace]'s scope over a received ring. + */ // TODO: When context will be ready move [ListPolynomialSpace] and add [A] to context receivers of [block] +public inline fun , R> A.listPolynomialSpace(block: ListPolynomialSpace.() -> R): R { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return ListPolynomialSpace(this).block() +} + +/** + * Creates a [ScalableListPolynomialSpace] over a received scalable ring. + */ +public inline val A.scalableListPolynomialSpace: ScalableListPolynomialSpace where A : Ring, A : ScaleOperations + get() = ScalableListPolynomialSpace(this) + +/** + * Creates a [ScalableListPolynomialSpace]'s scope over a received scalable ring. + */ // TODO: When context will be ready move [ListPolynomialSpace] and add [A] to context receivers of [block] +public inline fun A.scalableListPolynomialSpace(block: ScalableListPolynomialSpace.() -> R): R where A : Ring, A : ScaleOperations { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return ScalableListPolynomialSpace(this).block() +} + + +/** + * Evaluates value of [this] Double polynomial on provided Double argument. + */ +public fun Polynomial.substitute(arg: Double): Double = + coefficients.reduceIndexedOrNull { index, acc, c -> + acc + c * arg.pow(index) + } ?: .0 + +/** + * Evaluates value of [this] polynomial on provided argument. + * + * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). + */ +public fun Polynomial.substitute(ring: Ring, arg: C): C = ring { + if (coefficients.isEmpty()) return zero + var result: C = coefficients.last() + for (j in coefficients.size - 2 downTo 0) { + result = (arg * result) + coefficients[j] + } + return result +} + +/** + * Represent [this] polynomial as a regular context-less function. + */ +public fun > Polynomial.asFunctionOver(ring: A): (C) -> C = { substitute(ring, it) } + +/** + * Returns algebraic derivative of received polynomial. + */ +@UnstableKMathAPI +public fun Polynomial.derivative( + ring: A, +): Polynomial where A : Ring, A : NumericAlgebra = ring { + Polynomial( + buildList(max(0, coefficients.size - 1)) { + for (deg in 1 .. coefficients.lastIndex) add(number(deg) * coefficients[deg]) + } + ) +} + +/** + * Returns algebraic antiderivative of received polynomial. + */ +@UnstableKMathAPI +public fun Polynomial.antiderivative( + ring: A, +): Polynomial where A : Field, A : NumericAlgebra = ring { + Polynomial( + buildList(coefficients.size + 1) { + add(zero) + coefficients.mapIndexedTo(this) { index, t -> t / number(index + 1) } + } + ) +} + +/** + * Computes a definite integral of [this] polynomial in the specified [range]. + */ +@UnstableKMathAPI +public fun > Polynomial.integrate( + ring: Field, + range: ClosedRange, +): C { + val antiderivative = antiderivative(ring) + return ring { antiderivative.substitute(ring, range.endInclusive) - antiderivative.substitute(ring, range.start) } +} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/AlgebraicStubTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/AlgebraicStubTest.kt index 487cd9ee1..5782292b1 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/AlgebraicStubTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/AlgebraicStubTest.kt @@ -26,286 +26,6 @@ object ExprRing : Field { } class AlgebraicStubTest { - @Test - fun test_addMultipliedBySquaring_for_UInt() { - ExprRing { - assertEquals( - "57", - addMultipliedByDoubling(Expr("57"), Expr("179"), 0u).expr, - "tried addMultipliedBySquaring(57, 179, 0u)" - ) - assertEquals( - "(57 + 179)", - addMultipliedByDoubling(Expr("57"), Expr("179"), 1u).expr, - "tried addMultipliedBySquaring(57, 179, 1u)" - ) - assertEquals( - "(57 + (179 + 179))", - addMultipliedByDoubling(Expr("57"), Expr("179"), 2u).expr, - "tried addMultipliedBySquaring(57, 179, 2u)" - ) - assertEquals( - "((57 + 179) + (179 + 179))", - addMultipliedByDoubling(Expr("57"), Expr("179"), 3u).expr, - "tried addMultipliedBySquaring(57, 179, 3u)" - ) - assertEquals( - "(57 + ((179 + 179) + (179 + 179)))", - addMultipliedByDoubling(Expr("57"), Expr("179"), 4u).expr, - "tried addMultipliedBySquaring(57, 179, 4u)" - ) - assertEquals( - "((57 + 179) + ((179 + 179) + (179 + 179)))", - addMultipliedByDoubling(Expr("57"), Expr("179"), 5u).expr, - "tried addMultipliedBySquaring(57, 179, 5u)" - ) - assertEquals( - "((57 + (179 + 179)) + ((179 + 179) + (179 + 179)))", - addMultipliedByDoubling(Expr("57"), Expr("179"), 6u).expr, - "tried addMultipliedBySquaring(57, 179, 6u)" - ) - assertEquals( - "(((57 + 179) + (179 + 179)) + ((179 + 179) + (179 + 179)))", - addMultipliedByDoubling(Expr("57"), Expr("179"), 7u).expr, - "tried addMultipliedBySquaring(57, 179, 7u)" - ) - assertEquals( - "(57 + (((179 + 179) + (179 + 179)) + ((179 + 179) + (179 + 179))))", - addMultipliedByDoubling(Expr("57"), Expr("179"), 8u).expr, - "tried addMultipliedBySquaring(57, 179, 8u)" - ) - } - } - @Test - fun test_multiplyBySquaring_for_UInt() { - ExprRing { - assertEquals( - "0", - multiplyByDoubling(Expr("57"), 0u).expr, - "tried multiplyBySquaring(57, 0u)" - ) - assertEquals( - "57", - multiplyByDoubling(Expr("57"), 1u).expr, - "tried multiplyBySquaring(57, 1u)" - ) - assertEquals( - "(57 + 57)", - multiplyByDoubling(Expr("57"), 2u).expr, - "tried multiplyBySquaring(57, 2u)" - ) - assertEquals( - "(57 + (57 + 57))", - multiplyByDoubling(Expr("57"), 3u).expr, - "tried multiplyBySquaring(57, 3u)" - ) - assertEquals( - "((57 + 57) + (57 + 57))", - multiplyByDoubling(Expr("57"), 4u).expr, - "tried multiplyBySquaring(57, 4u)" - ) - assertEquals( - "(57 + ((57 + 57) + (57 + 57)))", - multiplyByDoubling(Expr("57"), 5u).expr, - "tried multiplyBySquaring(57, 5u)" - ) - assertEquals( - "((57 + 57) + ((57 + 57) + (57 + 57)))", - multiplyByDoubling(Expr("57"), 6u).expr, - "tried multiplyBySquaring(57, 6u)" - ) - assertEquals( - "((57 + (57 + 57)) + ((57 + 57) + (57 + 57)))", - multiplyByDoubling(Expr("57"), 7u).expr, - "tried multiplyBySquaring(57, 7u)" - ) - assertEquals( - "(((57 + 57) + (57 + 57)) + ((57 + 57) + (57 + 57)))", - multiplyByDoubling(Expr("57"), 8u).expr, - "tried multiplyBySquaring(57, 8u)" - ) - } - } - @Test - fun test_addMultipliedBySquaring_for_Int() { - ExprRing { - assertEquals( - "57", - addMultipliedByDoubling(Expr("57"), Expr("179"), 0).expr, - "tried addMultipliedBySquaring(57, 179, 0)" - ) - assertEquals( - "(57 + 179)", - addMultipliedByDoubling(Expr("57"), Expr("179"), 1).expr, - "tried addMultipliedBySquaring(57, 179, 1)" - ) - assertEquals( - "(57 + -179)", - addMultipliedByDoubling(Expr("57"), Expr("179"), -1).expr, - "tried addMultipliedBySquaring(57, 179, -1)" - ) - assertEquals( - "(57 + (179 + 179))", - addMultipliedByDoubling(Expr("57"), Expr("179"), 2).expr, - "tried addMultipliedBySquaring(57, 179, 2)" - ) - assertEquals( - "(57 + (-179 + -179))", - addMultipliedByDoubling(Expr("57"), Expr("179"), -2).expr, - "tried addMultipliedBySquaring(57, 179, -2)" - ) - assertEquals( - "((57 + 179) + (179 + 179))", - addMultipliedByDoubling(Expr("57"), Expr("179"), 3).expr, - "tried addMultipliedBySquaring(57, 179, 3)" - ) - assertEquals( - "((57 + -179) + (-179 + -179))", - addMultipliedByDoubling(Expr("57"), Expr("179"), -3).expr, - "tried addMultipliedBySquaring(57, 179, -3)" - ) - assertEquals( - "(57 + ((179 + 179) + (179 + 179)))", - addMultipliedByDoubling(Expr("57"), Expr("179"), 4).expr, - "tried addMultipliedBySquaring(57, 179, 4)" - ) - assertEquals( - "(57 + ((-179 + -179) + (-179 + -179)))", - addMultipliedByDoubling(Expr("57"), Expr("179"), -4).expr, - "tried addMultipliedBySquaring(57, 179, -4)" - ) - assertEquals( - "((57 + 179) + ((179 + 179) + (179 + 179)))", - addMultipliedByDoubling(Expr("57"), Expr("179"), 5).expr, - "tried addMultipliedBySquaring(57, 179, 5)" - ) - assertEquals( - "((57 + -179) + ((-179 + -179) + (-179 + -179)))", - addMultipliedByDoubling(Expr("57"), Expr("179"), -5).expr, - "tried addMultipliedBySquaring(57, 179, -5)" - ) - assertEquals( - "((57 + (179 + 179)) + ((179 + 179) + (179 + 179)))", - addMultipliedByDoubling(Expr("57"), Expr("179"), 6).expr, - "tried addMultipliedBySquaring(57, 179, 6)" - ) - assertEquals( - "((57 + (-179 + -179)) + ((-179 + -179) + (-179 + -179)))", - addMultipliedByDoubling(Expr("57"), Expr("179"), -6).expr, - "tried addMultipliedBySquaring(57, 179, -6)" - ) - assertEquals( - "(((57 + 179) + (179 + 179)) + ((179 + 179) + (179 + 179)))", - addMultipliedByDoubling(Expr("57"), Expr("179"), 7).expr, - "tried addMultipliedBySquaring(57, 179, 7)" - ) - assertEquals( - "(((57 + -179) + (-179 + -179)) + ((-179 + -179) + (-179 + -179)))", - addMultipliedByDoubling(Expr("57"), Expr("179"), -7).expr, - "tried addMultipliedBySquaring(57, 179, -7)" - ) - assertEquals( - "(57 + (((179 + 179) + (179 + 179)) + ((179 + 179) + (179 + 179))))", - addMultipliedByDoubling(Expr("57"), Expr("179"), 8).expr, - "tried addMultipliedBySquaring(57, 179, 8)" - ) - assertEquals( - "(57 + (((-179 + -179) + (-179 + -179)) + ((-179 + -179) + (-179 + -179))))", - addMultipliedByDoubling(Expr("57"), Expr("179"), -8).expr, - "tried addMultipliedBySquaring(57, 179, -8)" - ) - } - } - @Test - fun test_multiplyBySquaring_for_Int() { - ExprRing { - assertEquals( - "0", - multiplyByDoubling(Expr("57"), 0).expr, - "tried multiplyBySquaring(57, 0)" - ) - assertEquals( - "57", - multiplyByDoubling(Expr("57"), 1).expr, - "tried multiplyBySquaring(57, 1)" - ) - assertEquals( - "-57", - multiplyByDoubling(Expr("57"), -1).expr, - "tried multiplyBySquaring(57, -1)" - ) - assertEquals( - "(57 + 57)", - multiplyByDoubling(Expr("57"), 2).expr, - "tried multiplyBySquaring(57, 2)" - ) - assertEquals( - "(-57 + -57)", - multiplyByDoubling(Expr("57"), -2).expr, - "tried multiplyBySquaring(57, -2)" - ) - assertEquals( - "(57 + (57 + 57))", - multiplyByDoubling(Expr("57"), 3).expr, - "tried multiplyBySquaring(57, 3)" - ) - assertEquals( - "(-57 + (-57 + -57))", - multiplyByDoubling(Expr("57"), -3).expr, - "tried multiplyBySquaring(57, -3)" - ) - assertEquals( - "((57 + 57) + (57 + 57))", - multiplyByDoubling(Expr("57"), 4).expr, - "tried multiplyBySquaring(57, 4)" - ) - assertEquals( - "((-57 + -57) + (-57 + -57))", - multiplyByDoubling(Expr("57"), -4).expr, - "tried multiplyBySquaring(57, -4)" - ) - assertEquals( - "(57 + ((57 + 57) + (57 + 57)))", - multiplyByDoubling(Expr("57"), 5).expr, - "tried multiplyBySquaring(57, 5)" - ) - assertEquals( - "(-57 + ((-57 + -57) + (-57 + -57)))", - multiplyByDoubling(Expr("57"), -5).expr, - "tried multiplyBySquaring(57, -5)" - ) - assertEquals( - "((57 + 57) + ((57 + 57) + (57 + 57)))", - multiplyByDoubling(Expr("57"), 6).expr, - "tried multiplyBySquaring(57, 6)" - ) - assertEquals( - "((-57 + -57) + ((-57 + -57) + (-57 + -57)))", - multiplyByDoubling(Expr("57"), -6).expr, - "tried multiplyBySquaring(57, -6)" - ) - assertEquals( - "((57 + (57 + 57)) + ((57 + 57) + (57 + 57)))", - multiplyByDoubling(Expr("57"), 7).expr, - "tried multiplyBySquaring(57, 7)" - ) - assertEquals( - "((-57 + (-57 + -57)) + ((-57 + -57) + (-57 + -57)))", - multiplyByDoubling(Expr("57"), -7).expr, - "tried multiplyBySquaring(57, -7)" - ) - assertEquals( - "(((57 + 57) + (57 + 57)) + ((57 + 57) + (57 + 57)))", - multiplyByDoubling(Expr("57"), 8).expr, - "tried multiplyBySquaring(57, 8)" - ) - assertEquals( - "(((-57 + -57) + (-57 + -57)) + ((-57 + -57) + (-57 + -57)))", - multiplyByDoubling(Expr("57"), -8).expr, - "tried multiplyBySquaring(57, -8)" - ) - } - } @Test fun test_multiplyExponentiationBySquaring_for_UInt() { ExprRing { @@ -406,184 +126,4 @@ class AlgebraicStubTest { ) } } - @Test - fun test_multiplyExponentiationBySquaring_for_Int() { - ExprRing { - assertEquals( - "57", - multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 0).expr, - "tried multiplyExponentiationBySquaring(57, 179, 0)" - ) - assertEquals( - "(57 * 179)", - multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 1).expr, - "tried multiplyExponentiationBySquaring(57, 179, 1)" - ) - assertEquals( - "(57 * (1 / 179))", - multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -1).expr, - "tried multiplyExponentiationBySquaring(57, 179, -1)" - ) - assertEquals( - "(57 * (179 * 179))", - multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 2).expr, - "tried multiplyExponentiationBySquaring(57, 179, 2)" - ) - assertEquals( - "(57 * ((1 / 179) * (1 / 179)))", - multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -2).expr, - "tried multiplyExponentiationBySquaring(57, 179, -2)" - ) - assertEquals( - "((57 * 179) * (179 * 179))", - multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 3).expr, - "tried multiplyExponentiationBySquaring(57, 179, 3)" - ) - assertEquals( - "((57 * (1 / 179)) * ((1 / 179) * (1 / 179)))", - multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -3).expr, - "tried multiplyExponentiationBySquaring(57, 179, -3)" - ) - assertEquals( - "(57 * ((179 * 179) * (179 * 179)))", - multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 4).expr, - "tried multiplyExponentiationBySquaring(57, 179, 4)" - ) - assertEquals( - "(57 * (((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179))))", - multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -4).expr, - "tried multiplyExponentiationBySquaring(57, 179, -4)" - ) - assertEquals( - "((57 * 179) * ((179 * 179) * (179 * 179)))", - multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 5).expr, - "tried multiplyExponentiationBySquaring(57, 179, 5)" - ) - assertEquals( - "((57 * (1 / 179)) * (((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179))))", - multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -5).expr, - "tried multiplyExponentiationBySquaring(57, 179, -5)" - ) - assertEquals( - "((57 * (179 * 179)) * ((179 * 179) * (179 * 179)))", - multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 6).expr, - "tried multiplyExponentiationBySquaring(57, 179, 6)" - ) - assertEquals( - "((57 * ((1 / 179) * (1 / 179))) * (((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179))))", - multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -6).expr, - "tried multiplyExponentiationBySquaring(57, 179, -6)" - ) - assertEquals( - "(((57 * 179) * (179 * 179)) * ((179 * 179) * (179 * 179)))", - multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 7).expr, - "tried multiplyExponentiationBySquaring(57, 179, 7)" - ) - assertEquals( - "(((57 * (1 / 179)) * ((1 / 179) * (1 / 179))) * (((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179))))", - multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -7).expr, - "tried multiplyExponentiationBySquaring(57, 179, -7)" - ) - assertEquals( - "(57 * (((179 * 179) * (179 * 179)) * ((179 * 179) * (179 * 179))))", - multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 8).expr, - "tried multiplyExponentiationBySquaring(57, 179, 8)" - ) - assertEquals( - "(57 * ((((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179))) * (((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179)))))", - multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -8).expr, - "tried multiplyExponentiationBySquaring(57, 179, -8)" - ) - } - } - @Test - fun test_exponentiationBySquaring_for_Int() { - ExprRing { - assertEquals( - "0", - exponentiateBySquaring(Expr("57"), 0).expr, - "tried exponentiationBySquaring(57, 0)" - ) - assertEquals( - "57", - exponentiateBySquaring(Expr("57"), 1).expr, - "tried exponentiationBySquaring(57, 1)" - ) - assertEquals( - "(1 / 57)", - exponentiateBySquaring(Expr("57"), -1).expr, - "tried exponentiationBySquaring(57, -1)" - ) - assertEquals( - "(57 * 57)", - exponentiateBySquaring(Expr("57"), 2).expr, - "tried exponentiationBySquaring(57, 2)" - ) - assertEquals( - "((1 / 57) * (1 / 57))", - exponentiateBySquaring(Expr("57"), -2).expr, - "tried exponentiationBySquaring(57, -2)" - ) - assertEquals( - "(57 * (57 * 57))", - exponentiateBySquaring(Expr("57"), 3).expr, - "tried exponentiationBySquaring(57, 3)" - ) - assertEquals( - "((1 / 57) * ((1 / 57) * (1 / 57)))", - exponentiateBySquaring(Expr("57"), -3).expr, - "tried exponentiationBySquaring(57, -3)" - ) - assertEquals( - "((57 * 57) * (57 * 57))", - exponentiateBySquaring(Expr("57"), 4).expr, - "tried exponentiationBySquaring(57, 4)" - ) - assertEquals( - "(((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57)))", - exponentiateBySquaring(Expr("57"), -4).expr, - "tried exponentiationBySquaring(57, -4)" - ) - assertEquals( - "(57 * ((57 * 57) * (57 * 57)))", - exponentiateBySquaring(Expr("57"), 5).expr, - "tried exponentiationBySquaring(57, 5)" - ) - assertEquals( - "((1 / 57) * (((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57))))", - exponentiateBySquaring(Expr("57"), -5).expr, - "tried exponentiationBySquaring(57, -5)" - ) - assertEquals( - "((57 * 57) * ((57 * 57) * (57 * 57)))", - exponentiateBySquaring(Expr("57"), 6).expr, - "tried exponentiationBySquaring(57, 6)" - ) - assertEquals( - "(((1 / 57) * (1 / 57)) * (((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57))))", - exponentiateBySquaring(Expr("57"), -6).expr, - "tried exponentiationBySquaring(57, -6)" - ) - assertEquals( - "((57 * (57 * 57)) * ((57 * 57) * (57 * 57)))", - exponentiateBySquaring(Expr("57"), 7).expr, - "tried exponentiationBySquaring(57, 7)" - ) - assertEquals( - "(((1 / 57) * ((1 / 57) * (1 / 57))) * (((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57))))", - exponentiateBySquaring(Expr("57"), -7).expr, - "tried exponentiationBySquaring(57, -7)" - ) - assertEquals( - "(((57 * 57) * (57 * 57)) * ((57 * 57) * (57 * 57)))", - exponentiateBySquaring(Expr("57"), 8).expr, - "tried exponentiationBySquaring(57, 8)" - ) - assertEquals( - "((((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57))) * (((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57))))", - exponentiateBySquaring(Expr("57"), -8).expr, - "tried exponentiationBySquaring(57, -8)" - ) - } - } } \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt index e7d8dfd8c..117ffb579 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt @@ -7,252 +7,11 @@ package space.kscience.kmath.functions -import space.kscience.kmath.functions.testUtils.IntModuloRing -import space.kscience.kmath.functions.testUtils.ListPolynomial -import space.kscience.kmath.functions.testUtils.Rational -import space.kscience.kmath.functions.testUtils.RationalField +import space.kscience.kmath.functions.testUtils.* import kotlin.test.* class ListPolynomialTest { - @Test - fun test_Polynomial_Int_plus() { - RationalField.listPolynomialSpace { - assertEquals( - ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), - ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + -3, - "test 1" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + 2, - "test 2" - ) - assertEquals( - ListPolynomial(Rational(0)), - ListPolynomial(Rational(-2)) + 2, - "test 3" - ) - val polynomial_4 = ListPolynomial() - assertSame( - polynomial_4, - polynomial_4 + 0, - "test 4" - ) - val polynomial_5 = ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)) - assertSame( - polynomial_5, - polynomial_5 + 0, - "test 5" - ) - assertEquals( - ListPolynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + 1, - "test 6" - ) - assertEquals( - ListPolynomial(Rational(-1)), - ListPolynomial(Rational(-2)) + 1, - "test 7" - ) - assertEquals( - ListPolynomial(Rational(2)), - ListPolynomial() + 2, - "test 8" - ) - } - } - @Test - fun test_Polynomial_Int_minus() { - RationalField.listPolynomialSpace { - assertEquals( - ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), - ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - -3, - "test 1" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), - ListPolynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - 2, - "test 2" - ) - assertEquals( - ListPolynomial(Rational(0)), - ListPolynomial(Rational(2)) - 2, - "test 3" - ) - val polynomial_4 = ListPolynomial() - assertSame( - polynomial_4, - polynomial_4 - 0, - "test 4" - ) - val polynomial_5 = ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)) - assertEquals( - polynomial_5, - polynomial_5 - 0, - "test 5" - ) - assertEquals( - ListPolynomial(Rational(1), Rational(0), Rational(0), Rational(0)), - ListPolynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - 1, - "test 6" - ) - assertEquals( - ListPolynomial(Rational(1)), - ListPolynomial(Rational(2)) - 1, - "test 7" - ) - assertEquals( - ListPolynomial(Rational(-2)), - ListPolynomial() - 2, - "test 8" - ) - } - } - @Test - fun test_Polynomial_Int_times() { - IntModuloRing(35).listPolynomialSpace { - assertEquals( - ListPolynomial(34, 2, 1, 20, 2), - ListPolynomial(22, 26, 13, 15, 26) * 27, - "test 1" - ) - assertEquals( - ListPolynomial(0, 0, 0, 0, 0), - ListPolynomial(7, 0, 49, 21, 14) * 15, - "test 2" - ) - val polynomial = ListPolynomial(22, 26, 13, 15, 26) - assertSame( - zero, - polynomial * 0, - "test 3" - ) - assertSame( - polynomial, - polynomial * 1, - "test 4" - ) - } - } - @Test - fun test_Int_Polynomial_plus() { - RationalField.listPolynomialSpace { - assertEquals( - ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), - -3 + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)), - "test 1" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), - 2 + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 2" - ) - assertEquals( - ListPolynomial(Rational(0)), - 2 + ListPolynomial(Rational(-2)), - "test 3" - ) - val polynomial_4 = ListPolynomial() - assertSame( - polynomial_4, - 0 + polynomial_4, - "test 4" - ) - val polynomial_5 = ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)) - assertSame( - polynomial_5, - 0 + polynomial_5, - "test 5" - ) - assertEquals( - ListPolynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), - 1 + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 6" - ) - assertEquals( - ListPolynomial(Rational(-1)), - 1 + ListPolynomial(Rational(-2)), - "test 7" - ) - assertEquals( - ListPolynomial(Rational(2)), - 2 + ListPolynomial(), - "test 8" - ) - } - } - @Test - fun test_Int_Polynomial_minus() { - RationalField.listPolynomialSpace { - assertEquals( - ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), - 3 - ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), - "test 1" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), - -2 - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 2" - ) - assertEquals( - ListPolynomial(Rational(0)), - -2 - ListPolynomial(Rational(-2)), - "test 3" - ) - assertEquals( - ListPolynomial(Rational(-32, 9), Rational(-8, -9), Rational(8, 7)), - 0 - ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), - "test 4" - ) - assertEquals( - ListPolynomial(), - 0 - ListPolynomial(), - "test 5" - ) - assertEquals( - ListPolynomial(Rational(1), Rational(0), Rational(0), Rational(0)), - -1 - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 6" - ) - assertEquals( - ListPolynomial(Rational(1)), - -1 - ListPolynomial(Rational(-2)), - "test 7" - ) - assertEquals( - ListPolynomial(Rational(-2)), - -2 - ListPolynomial(), - "test 8" - ) - } - } - @Test - fun test_Int_Polynomial_times() { - IntModuloRing(35).listPolynomialSpace { - assertEquals( - ListPolynomial(34, 2, 1, 20, 2), - 27 * ListPolynomial(22, 26, 13, 15, 26), - "test 1" - ) - assertEquals( - ListPolynomial(0, 0, 0, 0, 0), - 15 * ListPolynomial(7, 0, 49, 21, 14), - "test 2" - ) - val polynomial = ListPolynomial(22, 26, 13, 15, 26) - assertSame( - zero, - 0 * polynomial, - "test 3" - ) - assertSame( - polynomial, - 1 * polynomial, - "test 4" - ) - } - } @Test fun test_Polynomial_Constant_plus() { RationalField.listPolynomialSpace { @@ -338,12 +97,12 @@ class ListPolynomialTest { IntModuloRing(35).listPolynomialSpace { assertEquals( ListPolynomial(34, 2, 1, 20, 2), - ListPolynomial(22, 26, 13, 15, 26) * 27.asConstant(), + ListPolynomial(22, 26, 13, 15, 26) * m(27), "test 1" ) assertEquals( ListPolynomial(0, 0, 0, 0, 0), - ListPolynomial(7, 0, 49, 21, 14) * 15.asConstant(), + ListPolynomial(7, 0, 49, 21, 14) * m(15), "test 2" ) } @@ -433,12 +192,12 @@ class ListPolynomialTest { IntModuloRing(35).listPolynomialSpace { assertEquals( ListPolynomial(34, 2, 1, 20, 2), - 27 * ListPolynomial(22, 26, 13, 15, 26), + m(27) * ListPolynomial(22, 26, 13, 15, 26), "test 1" ) assertEquals( ListPolynomial(0, 0, 0, 0, 0), - 15 * ListPolynomial(7, 0, 49, 21, 14), + m(15) * ListPolynomial(7, 0, 49, 21, 14), "test 2" ) } diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt index 339643d02..153b0134b 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt @@ -5,11 +5,9 @@ package space.kscience.kmath.functions -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.functions.testUtils.Rational import space.kscience.kmath.functions.testUtils.RationalField -import space.kscience.kmath.functions.testUtils.assertFailsWithTypeAndMessage -import kotlin.test.Ignore +import space.kscience.kmath.misc.UnstableKMathAPI import kotlin.test.Test import kotlin.test.assertEquals @@ -88,754 +86,6 @@ class ListPolynomialUtilTest { ) } @Test - fun test_Polynomial_substitute_Polynomial() { - assertEquals( - ListPolynomial(Rational(0)), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).substitute(RationalField, ListPolynomial(Rational(1))), - "test 1" - ) - assertEquals( - ListPolynomial(Rational(709, 378), Rational(155, 252), Rational(19, 525), Rational(2, 875)), - ListPolynomial(Rational(1, 7), Rational(9, 4), Rational(1, 3), Rational(2, 7)) - .substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(1, 5))), - "test 2" - ) - assertEquals( - ListPolynomial(Rational(655, 378), Rational(155, 252), Rational(19, 525), Rational(2, 875)), - ListPolynomial(Rational(0), Rational(9, 4), Rational(1, 3), Rational(2, 7)) - .substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(1, 5))), - "test 3" - ) - assertEquals( - ListPolynomial(Rational(677, 378), Rational(97, 180), Rational(1, 75), Rational(0)), - ListPolynomial(Rational(1, 7), Rational(9, 4), Rational(1, 3), Rational(0)) - .substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(1, 5))), - "test 4" - ) - assertEquals( - ListPolynomial(Rational(653, 378), Rational(221, 420), Rational(4, 175), Rational(2, 875)), - ListPolynomial(Rational(1, 7), Rational(9, 4), Rational(0), Rational(2, 7)) - .substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(1, 5))), - "test 5" - ) - assertEquals( - ListPolynomial(Rational(89, 54), Rational(0), Rational(0), Rational(0)), - ListPolynomial(Rational(0), Rational(9, 4), Rational(1, 3), Rational(0)) - .substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(0))), - "test 6" - ) - } - @Test - @Ignore // FIXME: This tests work only for sane realisations of the substitutions. Currently, it is not. - // Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should return denominator r^deg(p), - // not r^(deg(p)(deg(p)+1)/2) as it is now. - fun test_Polynomial_substitute_RationalFunction() { - assertEquals( - ListRationalFunction(ListPolynomial(Rational(0)), ListPolynomial(Rational(1))), - ListPolynomial(Rational(1), Rational(-2), Rational(1)) - .substitute(RationalField, ListRationalFunction(ListPolynomial(Rational(1)), ListPolynomial(Rational(1)))), - "test 1" - ) - assertEquals( - ListRationalFunction( - ListPolynomial( - Rational(66349, 243), - Rational(-17873, 405), - Rational(173533, 3780), - Rational(-91141, 567), - Rational(5773909, 105840), - Rational(-23243, 630), - Rational(1573, 27) - ), - ListPolynomial( - Rational(169, 81), - Rational(-130, 27), - Rational(115, 18), - Rational(-797, 54), - Rational(1985, 144), - Rational(-55, 6), - Rational(121, 9) - ) - ), - ListPolynomial( - Rational(13, 3), - Rational(-9, 5), - Rational(5, 5) - ).substitute(RationalField, - ListRationalFunction( - ListPolynomial( - Rational(15, 1), - Rational(6, 9), - Rational(-3, 7) - ), - ListPolynomial( - Rational(-13, 9), - Rational(10, 6), - Rational(-10, 8), - Rational(11, 3) - ) - ) - ), - "test 2" - ) - assertEquals( - ListRationalFunction( - ListPolynomial( - Rational(0, 1), - Rational(0, 1), - Rational(-14, 9), - Rational(31, 14), - Rational(-5077, 980), - Rational(99, 35) - ), - ListPolynomial( - Rational(0, 1), - Rational(0, 1), - Rational(25, 9), - Rational(-25, 6), - Rational(1985, 144), - Rational(-55, 6), - Rational(121, 9) - ) - ), - ListPolynomial( - Rational(0), - Rational(-9, 5), - Rational(5, 5) - ).substitute(RationalField, - ListRationalFunction( - ListPolynomial( - Rational(0), - Rational(6, 9), - Rational(-3, 7) - ), - ListPolynomial( - Rational(0), - Rational(10, 6), - Rational(-10, 8), - Rational(11, 3) - ) - ) - ), - "test 3" - ) - assertEquals( - ListRationalFunction( - ListPolynomial( - Rational(-898, 27), - Rational(271, 45), - Rational(-65, 12) , - Rational(0), - Rational(0), - Rational(0), - Rational(0) - ), - ListPolynomial( - Rational(-13, 9), - Rational(5, 3), - Rational(-5, 4), - Rational(0), - Rational(0), - Rational(0), - Rational(0) - ) - ), - ListPolynomial( - Rational(13, 3), - Rational(-9, 5), - Rational(0) - ).substitute(RationalField, - ListRationalFunction( - ListPolynomial( - Rational(15, 1), - Rational(6, 9), - Rational(0) - ), - ListPolynomial( - Rational(-13, 9), - Rational(10, 6), - Rational(-10, 8), - Rational(0) - ) - ) - ), - "test 4" - ) - assertEquals( - ListRationalFunction( - ListPolynomial( - Rational(56872, 243), - Rational(0, 1), - Rational(-90, 7), - Rational(-3718, 81), - Rational(9, 49), - Rational(0, 1), - Rational(1573, 27) - ), - ListPolynomial( - Rational(169, 81), - Rational(0, 1), - Rational(0, 1), - Rational(-286, 27), - Rational(0, 1), - Rational(0, 1), - Rational(121, 9) - ) - ), - ListPolynomial( - Rational(13, 3), - Rational(0), - Rational(5, 5) - ).substitute(RationalField, - ListRationalFunction( - ListPolynomial( - Rational(15, 1), - Rational(0), - Rational(-3, 7) - ), - ListPolynomial( - Rational(-13, 9), - Rational(0), - Rational(0), - Rational(11, 3) - ) - ) - ), - "test 5" - ) - } - @Test - fun test_RationalFunction_substitute_Double() { - assertEquals( - 0.0, - ListRationalFunction( - ListPolynomial(1.0, -2.0, 1.0), - ListPolynomial(-6.302012278484357, 5.831971885376948, -9.271604788393432, 5.494387848015814, -3.7187384450880785) - ).substitute(1.0), - 0.001, - "test 1" - ) - assertEquals( - 2.693702616649797, - ListRationalFunction( - ListPolynomial(-5.848840571263625, -1.660411278951134, -3.793740946372443, -9.624569269490076), - ListPolynomial(-2.9680680215311073, -1.862973627119981, 4.776550592888336, -2.7320154512368466) - ).substitute(-7.53452770353279), - 0.001, - "test 2" - ) - assertEquals( - 2.692226268901378, - ListRationalFunction( - ListPolynomial(0.0, -1.660411278951134, -3.793740946372443, -9.624569269490076), - ListPolynomial(0.0, -1.862973627119981, 4.776550592888336, -2.7320154512368466) - ).substitute(-7.53452770353279), - 0.001, - "test 3" - ) - assertEquals( - -0.7394904842099175, - ListRationalFunction( - ListPolynomial(-5.848840571263625, -1.660411278951134, -3.793740946372443, 0.0), - ListPolynomial(-2.9680680215311073, -1.862973627119981, 4.776550592888336, 0.0) - ).substitute(-7.53452770353279), - 0.001, - "test 4" - ) - assertEquals( - 3.526835209398159, - ListRationalFunction( - ListPolynomial(-5.848840571263625, 0.0, 0.0, -9.624569269490076), - ListPolynomial(-2.9680680215311073, 0.0, 0.0, -2.7320154512368466) - ).substitute(-7.53452770353279), - 0.001, - "test 5" - ) - } - @Test - fun test_RationalFunction_substitute_Constant() { - assertEquals( - Rational(0), - ListRationalFunction( - ListPolynomial(Rational(1), Rational(-2), Rational(1)), - ListPolynomial(Rational(1)), - ).substitute(RationalField, Rational(1)), - "test 1" - ) - assertEquals( - Rational(1149615, 61306), - ListRationalFunction( - ListPolynomial(Rational(17, 7), Rational(18, 3), Rational(18, 8), Rational(9, 1)), - ListPolynomial(Rational(11, 9), Rational(-6, 5), Rational(-12, 7), Rational(2, 1)), - ).substitute(RationalField, Rational(-7, 8)), - "test 2" - ) - assertEquals( - Rational(3495, 586), - ListRationalFunction( - ListPolynomial(Rational(0), Rational(18, 3), Rational(18, 8), Rational(9, 1)), - ListPolynomial(Rational(0), Rational(-6, 5), Rational(-12, 7), Rational(2, 1)), - ).substitute(RationalField, Rational(-7, 8)), - "test 3" - ) - assertEquals( - Rational(-88605, 77392), - ListRationalFunction( - ListPolynomial(Rational(17, 7), Rational(18, 3), Rational(18, 8), Rational(0)), - ListPolynomial(Rational(11, 9), Rational(-6, 5), Rational(-12, 7), Rational(0)), - ).substitute(RationalField, Rational(-7, 8)), - "test 4" - ) - assertEquals( - Rational(116145, 3794), - ListRationalFunction( - ListPolynomial(Rational(17, 7), Rational(0), Rational(0), Rational(9, 1)), - ListPolynomial(Rational(11, 9), Rational(0), Rational(0), Rational(2, 1)), - ).substitute(RationalField, Rational(-7, 8)), - "test 5" - ) - } - @Test - fun test_RationalFunction_substitute_Polynomial() { - assertEquals( - ListRationalFunction( - ListPolynomial(Rational(0)), - ListPolynomial(Rational(1)) - ), - ListRationalFunction( - ListPolynomial(Rational(1), Rational(-2), Rational(1)), - ListPolynomial(Rational(1)), - ).substitute(RationalField, ListPolynomial(Rational(1))), - "test 1" - ) - assertEquals( - ListRationalFunction( - ListPolynomial( - Rational(-283303, 36), - Rational(-23593, 24), - Rational(368713, 192), - Rational(1455, 8), - Rational(-272171, 1536), - Rational(-2149, 192), - Rational(469, 64), - Rational(11, 48), - Rational(-11, 96) - ), - ListPolynomial( - Rational(5797, 12), - Rational(595, 16), - Rational(-5285, 72), - Rational(-745, 192), - Rational(1105, 288), - Rational(5, 48), - Rational(-5, 72) - ) - ), - ListRationalFunction( - ListPolynomial( - Rational(2, 9), - Rational(11, 3), - Rational(-9, 4), - Rational(-6, 1), - Rational(-11, 6) - ), - ListPolynomial( - Rational(-2, 3), - Rational(-15, 4), - Rational(5, 9), - Rational(-5, 9) - ) - ).substitute(RationalField, - ListPolynomial( - Rational(-9, 1), - Rational(-1, 4), - Rational(2, 4) - ) - ), - "test 2" - ) - assertEquals( - ListRationalFunction( - ListPolynomial( - Rational(0, 1), - Rational(-11, 12), - Rational(325, 192), - Rational(21, 32), - Rational(-1739, 1536), - Rational(227, 192), - Rational(-59, 64), - Rational(11, 48), - Rational(-11, 96) - ), - ListPolynomial( - Rational(0, 1), - Rational(15, 16), - Rational(-265, 144), - Rational(-25, 192), - Rational(25, 288), - Rational(5, 48), - Rational(-5, 72) - ) - ), - ListRationalFunction( - ListPolynomial( - Rational(0, 9), - Rational(11, 3), - Rational(-9, 4), - Rational(-6, 1), - Rational(-11, 6) - ), - ListPolynomial( - Rational(0, 3), - Rational(-15, 4), - Rational(5, 9), - Rational(-5, 9) - ) - ).substitute(RationalField, - ListPolynomial( - Rational(0, 1), - Rational(-1, 4), - Rational(2, 4) - ) - ), - "test 3" - ) - assertEquals( - ListRationalFunction( - ListPolynomial( - Rational(149723, 36), - Rational(8483, 24), - Rational(639, 64), - Rational(3, 32), - Rational(0), - Rational(0), - Rational(0), - Rational(0), - Rational(0) - ), - ListPolynomial( - Rational(937, 12), - Rational(55, 16), - Rational(5, 144), - Rational(0), - Rational(0), - Rational(0), - Rational(0) - ) - ), - ListRationalFunction( - ListPolynomial( - Rational(2, 9), - Rational(11, 3), - Rational(-9, 4), - Rational(-6, 1), - Rational(0) - ), - ListPolynomial( - Rational(-2, 3), - Rational(-15, 4), - Rational(5, 9), - Rational(0) - ) - ).substitute(RationalField, - ListPolynomial( - Rational(-9, 1), - Rational(-1, 4), - Rational(0) - ) - ), - "test 4" - ) - assertEquals( - ListRationalFunction( - ListPolynomial( - Rational(-216509, 18), - Rational(0, 1), - Rational(2673, 1), - Rational(0, 1), - Rational(-891, 4), - Rational(0, 1), - Rational(33, 4), - Rational(0, 1), - Rational(-11, 96) - ), - ListPolynomial( - Rational(1213, 3), - Rational(0, 1), - Rational(-135, 2), - Rational(0, 1), - Rational(15, 4), - Rational(0, 1), - Rational(-5, 72) - ) - ), - ListRationalFunction( - ListPolynomial( - Rational(2, 9), - Rational(0), - Rational(0), - Rational(0), - Rational(-11, 6) - ), - ListPolynomial( - Rational(-2, 3), - Rational(0), - Rational(0), - Rational(-5, 9) - ) - ).substitute(RationalField, - ListPolynomial( - Rational(-9, 1), - Rational(0), - Rational(2, 4) - ) - ), - "test 5" - ) - } - @Test - @Ignore // FIXME: This tests work only for sane realisations of the substitutions. Currently, it is not. - // Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should return denominator r^deg(p), - // not r^(deg(p)(deg(p)+1)/2) as it is now. - fun test_RationalFunction_substitute_RationalFunction() { - assertEquals( - ListRationalFunction( - ListPolynomial(Rational(0)), - ListPolynomial(Rational(1)) - ), - ListRationalFunction( - ListPolynomial(Rational(1), Rational(-2), Rational(1)), - ListPolynomial(Rational(1)) - ).substitute(RationalField, - ListRationalFunction( - ListPolynomial(Rational(1)), - ListPolynomial(Rational(1)) - ) - ), - "test 1" - ) - assertEquals( - ListRationalFunction( - ListPolynomial( - Rational(130087, 3888), - Rational(-2866333, 65610), - Rational(-5076229, 97200), - Rational(222136997, 3280500), - Rational(754719329, 20995200), - Rational(-12010283, 324000), - Rational(-2011967, 172800), - Rational(18607, 2880), - Rational(4705, 4096) - ), - ListPolynomial( - Rational(-143820355, 3779136), - Rational(73886869, 1574640), - Rational(1440175193, 15746400), - Rational(-5308968857, 52488000), - Rational(-186910083731, 2099520000), - Rational(125043463, 1555200), - Rational(5299123, 388800), - Rational(-213757, 15360), - Rational(1380785, 147456) - ) - ), - ListRationalFunction( - ListPolynomial( - Rational(1, 1), - Rational(-10, 5), - Rational(18, 8), - Rational(-8, 8) - ), - ListPolynomial( - Rational(-14, 8), - Rational(-14, 8), - Rational(-19, 6), - Rational(14, 3), - Rational(8, 9) - ) - ).substitute(RationalField, - ListRationalFunction( - ListPolynomial( - Rational(14, 9), - Rational(-2, 5), - Rational(-14, 7) - ), - ListPolynomial( - Rational(-6, 4), - Rational(5, 9), - Rational(1, 8) - ) - ) - ), - "test 2" - ) - assertEquals( - ListRationalFunction( - ListPolynomial( - Rational(0, 1), - Rational(0, 1), - Rational(0, 1), - Rational(0, 1), - Rational(5173, 18225), - Rational(904291, 364500), - Rational(283127, 43200), - Rational(37189, 5760), - Rational(147, 128) - ), - ListPolynomial( - Rational(0, 1), - Rational(0, 1), - Rational(0, 1), - Rational(0, 1), - Rational(-163589, 911250), - Rational(-881831, 291600), - Rational(-10722229, 777600), - Rational(-640921, 46080), - Rational(86303, 9216) - ) - ), - ListRationalFunction( - ListPolynomial( - Rational(0), - Rational(-10, 5), - Rational(18, 8), - Rational(-8, 8) - ), - ListPolynomial( - Rational(0), - Rational(-14, 8), - Rational(-19, 6), - Rational(14, 3), - Rational(8, 9) - ) - ).substitute(RationalField, - ListRationalFunction( - ListPolynomial( - Rational(0), - Rational(-2, 5), - Rational(-14, 7) - ), - ListPolynomial( - Rational(0), - Rational(5, 9), - Rational(1, 8) - ) - ) - ), - "test 3" - ) - assertEquals( - ListRationalFunction( - ListPolynomial( - Rational(445, 16), - Rational(-2011, 54), - Rational(1359199, 72900), - Rational(-135733, 32805), - Rational(2254, 6561), - Rational(0, 1), - Rational(0, 1), - Rational(0, 1), - Rational(0, 1) - ), - ListPolynomial( - Rational(-2018387, 46656), - Rational(82316437, 1574640), - Rational(-9335047, 393660), - Rational(15765889, 3280500), - Rational(-242089, 656100), - Rational(0, 1), - Rational(0, 1), - Rational(0, 1), - Rational(0, 1) - ) - ), - ListRationalFunction( - ListPolynomial( - Rational(1, 1), - Rational(-10, 5), - Rational(18, 8), - Rational(0) - ), - ListPolynomial( - Rational(-14, 8), - Rational(-14, 8), - Rational(-19, 6), - Rational(14, 3), - Rational(0) - ) - ).substitute(RationalField, - ListRationalFunction( - ListPolynomial( - Rational(14, 9), - Rational(-2, 5), - Rational(0) - ), - ListPolynomial( - Rational(-6, 4), - Rational(5, 9), - Rational(0) - ) - ) - ), - "test 4" - ) - assertEquals( - ListRationalFunction( - ListPolynomial( - Rational(41635, 3888), - Rational(0, 1), - Rational(-279187, 11664), - Rational(0, 1), - Rational(103769, 3456), - Rational(0, 1), - Rational(-11017, 768), - Rational(0, 1), - Rational(4097, 4096) - ), - ListPolynomial( - Rational(-13811791, 3779136), - Rational(0, 1), - Rational(-9999395, 419904), - Rational(0, 1), - Rational(6376601, 124416), - Rational(0, 1), - Rational(-3668315, 82944), - Rational(0, 1), - Rational(2097089, 147456) - ) - ), - ListRationalFunction( - ListPolynomial( - Rational(1, 1), - Rational(0), - Rational(0), - Rational(-8, 8) - ), - ListPolynomial( - Rational(-14, 8), - Rational(0), - Rational(0), - Rational(0), - Rational(8, 9) - ) - ).substitute(RationalField, - ListRationalFunction( - ListPolynomial( - Rational(14, 9), - Rational(0), - Rational(-14, 7) - ), - ListPolynomial( - Rational(-6, 4), - Rational(0), - Rational(1, 8) - ) - ) - ), - "test 5" - ) - } - @Test fun test_Polynomial_derivative() { assertEquals( ListPolynomial(Rational(-2), Rational(2)), @@ -859,55 +109,6 @@ class ListPolynomialUtilTest { ) } @Test - fun test_Polynomial_nthDerivative() { - assertEquals( - ListPolynomial(Rational(-2), Rational(2)), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 1), - "test 1" - ) - assertFailsWithTypeAndMessage( - "Order of derivative must be non-negative", - "test2" - ) { - ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, -1) - } - assertEquals( - ListPolynomial(Rational(1), Rational(-2), Rational(1)), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 0), - "test 3" - ) - assertEquals( - ListPolynomial(Rational(2)), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 2), - "test 4" - ) - assertEquals( - ListPolynomial(), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 3), - "test 5" - ) - assertEquals( - ListPolynomial(), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 4), - "test 6" - ) - assertEquals( - ListPolynomial(Rational(8, 9), Rational(30, 7), Rational(-20, 3)), - ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthDerivative(RationalField, 2), - "test 7" - ) - assertEquals( - ListPolynomial(Rational(8, 9), Rational(30, 7), Rational(-20, 3)), - ListPolynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthDerivative(RationalField, 2), - "test 8" - ) - assertEquals( - ListPolynomial(Rational(8, 9), Rational(30, 7), Rational(0)), - ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).nthDerivative(RationalField, 2), - "test 9" - ) - } - @Test fun test_Polynomial_antiderivative() { assertEquals( ListPolynomial(Rational(0), Rational(1), Rational(-1), Rational(1, 3)), @@ -930,53 +131,4 @@ class ListPolynomialUtilTest { "test 4" ) } - @Test - fun test_Polynomial_nthAntiderivative() { - assertEquals( - ListPolynomial(Rational(0), Rational(1), Rational(-1), Rational(1, 3)), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 1), - "test 1" - ) - assertFailsWithTypeAndMessage( - "Order of antiderivative must be non-negative", - "test2" - ) { - ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, -1) - } - assertEquals( - ListPolynomial(Rational(1), Rational(-2), Rational(1)), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 0), - "test 3" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(1, 2), Rational(-1, 3), Rational(1, 12)), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 2), - "test 4" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(1, 6), Rational(-1, 12), Rational(1, 60)), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 3), - "test 5" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0), Rational(1, 24), Rational(-1, 60), Rational(1, 360)), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 4), - "test 6" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(1, 10), Rational(-4, 9), Rational(1, 27), Rational(1, 28), Rational(-1, 54)), - ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthAntiderivative(RationalField, 2), - "test 7" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0), Rational(1, 27), Rational(1, 28), Rational(-1, 54)), - ListPolynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthAntiderivative(RationalField, 2), - "test 8" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(1, 10), Rational(-4, 9), Rational(1, 27), Rational(1, 28), Rational(0)), - ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).nthAntiderivative(RationalField, 2), - "test 9" - ) - } } \ No newline at end of file diff --git a/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt b/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt index 4b65fbea1..997a966a7 100644 --- a/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt +++ b/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt @@ -5,15 +5,14 @@ package space.kscience.kmath.functions.testUtils -import space.kscience.kmath.functions.ListPolynomial +import space.kscience.kmath.functions.Polynomial import space.kscience.kmath.functions.ListPolynomialSpace -import space.kscience.kmath.functions.PolynomialSpaceOverRing -public fun ListPolynomialSpace.ListPolynomial(vararg coefs: Int): ListPolynomial = - ListPolynomial(coefs.map { IntModulo(it, ring.modulus) }) -public fun IntModuloRing.ListPolynomial(vararg coefs: Int): ListPolynomial = - ListPolynomial(coefs.map { IntModulo(it, modulus) }) +public fun ListPolynomialSpace.ListPolynomial(vararg coefs: Int): Polynomial = + Polynomial(coefs.map { IntModulo(it, ring.modulus) }) +public fun IntModuloRing.ListPolynomial(vararg coefs: Int): Polynomial = + Polynomial(coefs.map { IntModulo(it, modulus) }) public fun IntModuloRing.m(arg: Int): IntModulo = IntModulo(arg, modulus) -public fun PolynomialSpaceOverRing.m(arg: Int): IntModulo = IntModulo(arg, ring.modulus) \ No newline at end of file +public fun ListPolynomialSpace.m(arg: Int): IntModulo = IntModulo(arg, ring.modulus) \ No newline at end of file -- 2.34.1 From 6ff79e28ac0b34e74cbec682866610492425a157 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Tue, 12 Jul 2022 00:57:44 +0300 Subject: [PATCH 104/123] Fix names, references, etc. --- .../kscience/kmath/functions/Polynomial.kt | 6 +- .../kmath/functions/polynomialConstructors.kt | 6 +- .../kmath/functions/polynomialUtil.kt | 24 +- .../kmath/interpolation/LinearInterpolator.kt | 4 +- .../kmath/interpolation/SplineInterpolator.kt | 4 +- .../kmath/functions/ListPolynomialTest.kt | 303 ------------------ .../kmath/functions/ListPolynomialUtilTest.kt | 134 -------- .../kmath/functions/PolynomialTest.kt | 303 ++++++++++++++++++ .../kmath/functions/PolynomialUtilTest.kt | 134 ++++++++ .../kmath/integration/SplineIntegralTest.kt | 4 +- .../functions/LabeledPolynomialUtilTest.kt | 1 + .../functions/testUtils/IntModuloUtils.kt | 8 +- .../kmath/functions/testUtils/IntModulo.kt | 133 ++++++++ .../functions/testUtils/IntModuloUtils.kt | 20 ++ .../kmath/functions/testUtils/NTMisc.kt | 29 ++ .../kmath/functions/testUtils/Rational.kt | 177 ++++++++++ .../kmath/functions/testUtils/assertion.kt | 1 - 17 files changed, 825 insertions(+), 466 deletions(-) delete mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt delete mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt create mode 100644 test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt create mode 100644 test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt create mode 100644 test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/NTMisc.kt create mode 100644 test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt 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 fec4776d9..061f556f6 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 @@ -59,7 +59,7 @@ public value class Polynomial( * @param A type of provided underlying ring of constants. It's [Ring] of [C]. * @param ring underlying ring of constants of type [A]. */ -public open class ListPolynomialSpace>( +public open class PolynomialSpace>( /** * Underlying ring of constants. Its operations on constants are inherited by local operations on constants. */ @@ -293,9 +293,9 @@ public open class ListPolynomialSpace>( * @param A type of underlying ring of constants. It's [Ring] of [C]. * @param ring underlying ring of constants of type [A]. */ -public class ScalableListPolynomialSpace( +public class ScalablePolynomialSpace( ring: A, -) : ListPolynomialSpace(ring), ScaleOperations> where A : Ring, A : ScaleOperations { +) : PolynomialSpace(ring), ScaleOperations> where A : Ring, A : ScaleOperations { override fun scale(a: Polynomial, value: Double): Polynomial = ring { Polynomial(a.coefficients.map { scale(it, value) }) } } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialConstructors.kt index ff04607a7..2da9ea6f5 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialConstructors.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialConstructors.kt @@ -11,7 +11,7 @@ package space.kscience.kmath.functions * if [reverse] parameter is true. */ @Suppress("FunctionName") -public fun ListPolynomial(coefficients: List, reverse: Boolean = false): Polynomial = +public fun Polynomial(coefficients: List, reverse: Boolean = false): Polynomial = Polynomial(with(coefficients) { if (reverse) reversed() else this }) /** @@ -19,10 +19,10 @@ public fun ListPolynomial(coefficients: List, reverse: Boolean = false): * if [reverse] parameter is true. */ @Suppress("FunctionName") -public fun ListPolynomial(vararg coefficients: C, reverse: Boolean = false): Polynomial = +public fun Polynomial(vararg coefficients: C, reverse: Boolean = false): Polynomial = Polynomial(with(coefficients) { if (reverse) reversed() else toList() }) /** * Represents [this] constant as a [Polynomial]. */ -public fun C.asListPolynomial() : Polynomial = Polynomial(listOf(this)) \ No newline at end of file +public fun C.asPolynomial() : Polynomial = Polynomial(listOf(this)) \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt index fc3a728df..0e1259bee 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt @@ -14,31 +14,31 @@ import kotlin.math.pow /** - * Creates a [ListPolynomialSpace] over a received ring. + * Creates a [PolynomialSpace] over a received ring. */ -public inline val > A.listPolynomialSpace: ListPolynomialSpace - get() = ListPolynomialSpace(this) +public inline val > A.polynomialSpace: PolynomialSpace + get() = PolynomialSpace(this) /** - * Creates a [ListPolynomialSpace]'s scope over a received ring. + * Creates a [PolynomialSpace]'s scope over a received ring. */ // TODO: When context will be ready move [ListPolynomialSpace] and add [A] to context receivers of [block] -public inline fun , R> A.listPolynomialSpace(block: ListPolynomialSpace.() -> R): R { +public inline fun , R> A.polynomialSpace(block: PolynomialSpace.() -> R): R { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return ListPolynomialSpace(this).block() + return PolynomialSpace(this).block() } /** - * Creates a [ScalableListPolynomialSpace] over a received scalable ring. + * Creates a [ScalablePolynomialSpace] over a received scalable ring. */ -public inline val A.scalableListPolynomialSpace: ScalableListPolynomialSpace where A : Ring, A : ScaleOperations - get() = ScalableListPolynomialSpace(this) +public inline val A.scalablePolynomialSpace: ScalablePolynomialSpace where A : Ring, A : ScaleOperations + get() = ScalablePolynomialSpace(this) /** - * Creates a [ScalableListPolynomialSpace]'s scope over a received scalable ring. + * Creates a [ScalablePolynomialSpace]'s scope over a received scalable ring. */ // TODO: When context will be ready move [ListPolynomialSpace] and add [A] to context receivers of [block] -public inline fun A.scalableListPolynomialSpace(block: ScalableListPolynomialSpace.() -> R): R where A : Ring, A : ScaleOperations { +public inline fun A.scalablePolynomialSpace(block: ScalablePolynomialSpace.() -> R): R where A : Ring, A : ScaleOperations { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return ScalableListPolynomialSpace(this).block() + return ScalablePolynomialSpace(this).block() } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt index b55f16cf2..34d7bcf41 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt @@ -7,7 +7,7 @@ package space.kscience.kmath.interpolation import space.kscience.kmath.data.XYColumnarData import space.kscience.kmath.functions.PiecewisePolynomial -import space.kscience.kmath.functions.ListPolynomial +import space.kscience.kmath.functions.Polynomial import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.Field import space.kscience.kmath.operations.invoke @@ -32,7 +32,7 @@ public class LinearInterpolator>(override val algebra: Field>( val x02 = x0 * x0 val x03 = x02 * x0 //Shift coefficients to represent absolute polynomial instead of one with an offset - val polynomial = ListPolynomial( + val polynomial = Polynomial( a - b * x0 + c * x02 - d * x03, b - 2 * c * x0 + 3 * d * x02, c - 3 * d * x0, diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt deleted file mode 100644 index 117ffb579..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt +++ /dev/null @@ -1,303 +0,0 @@ -/* - * 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. - */ - -@file:Suppress("LocalVariableName") - -package space.kscience.kmath.functions - -import space.kscience.kmath.functions.testUtils.* -import kotlin.test.* - - -class ListPolynomialTest { - @Test - fun test_Polynomial_Constant_plus() { - RationalField.listPolynomialSpace { - assertEquals( - ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), - ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + Rational(-3), - "test 1" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + Rational(2), - "test 2" - ) - assertEquals( - ListPolynomial(Rational(0)), - ListPolynomial(Rational(-2)) + Rational(2), - "test 3" - ) - assertEquals( - ListPolynomial(Rational(0)), - ListPolynomial() + Rational(0), - "test 4" - ) - assertEquals( - ListPolynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + Rational(1), - "test 5" - ) - assertEquals( - ListPolynomial(Rational(-1)), - ListPolynomial(Rational(-2)) + Rational(1), - "test 6" - ) - assertEquals( - ListPolynomial(Rational(2)), - ListPolynomial() + Rational(2), - "test 7" - ) - } - } - @Test - fun test_Polynomial_Constant_minus() { - RationalField.listPolynomialSpace { - assertEquals( - ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), - ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - Rational(-3), - "test 1" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), - ListPolynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - Rational(2), - "test 2" - ) - assertEquals( - ListPolynomial(Rational(0)), - ListPolynomial(Rational(2)) - Rational(2), - "test 3" - ) - assertEquals( - ListPolynomial(Rational(0)), - ListPolynomial() - Rational(0), - "test 4" - ) - assertEquals( - ListPolynomial(Rational(1), Rational(0), Rational(0), Rational(0)), - ListPolynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - Rational(1), - "test 5" - ) - assertEquals( - ListPolynomial(Rational(1)), - ListPolynomial(Rational(2)) - Rational(1), - "test 6" - ) - assertEquals( - ListPolynomial(Rational(-2)), - ListPolynomial() - Rational(2), - "test 7" - ) - } - } - @Test - fun test_Polynomial_Constant_times() { - IntModuloRing(35).listPolynomialSpace { - assertEquals( - ListPolynomial(34, 2, 1, 20, 2), - ListPolynomial(22, 26, 13, 15, 26) * m(27), - "test 1" - ) - assertEquals( - ListPolynomial(0, 0, 0, 0, 0), - ListPolynomial(7, 0, 49, 21, 14) * m(15), - "test 2" - ) - } - } - @Test - fun test_Constant_Polynomial_plus() { - RationalField.listPolynomialSpace { - assertEquals( - ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), - Rational(-3) + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)), - "test 1" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), - Rational(2) + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 2" - ) - assertEquals( - ListPolynomial(Rational(0)), - Rational(2) + ListPolynomial(Rational(-2)), - "test 3" - ) - assertEquals( - ListPolynomial(Rational(0)), - Rational(0) + ListPolynomial(), - "test 4" - ) - assertEquals( - ListPolynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), - Rational(1) + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 5" - ) - assertEquals( - ListPolynomial(Rational(-1)), - Rational(1) + ListPolynomial(Rational(-2)), - "test 6" - ) - assertEquals( - ListPolynomial(Rational(2)), - Rational(2) + ListPolynomial(), - "test 7" - ) - } - } - @Test - fun test_Constant_Polynomial_minus() { - RationalField.listPolynomialSpace { - assertEquals( - ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), - Rational(3) - ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), - "test 1" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), - Rational(-2) - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 2" - ) - assertEquals( - ListPolynomial(Rational(0)), - Rational(-2) - ListPolynomial(Rational(-2)), - "test 3" - ) - assertEquals( - ListPolynomial(Rational(0)), - Rational(0) - ListPolynomial(), - "test 4" - ) - assertEquals( - ListPolynomial(Rational(1), Rational(0), Rational(0), Rational(0)), - Rational(-1) - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 5" - ) - assertEquals( - ListPolynomial(Rational(1)), - Rational(-1) - ListPolynomial(Rational(-2)), - "test 6" - ) - assertEquals( - ListPolynomial(Rational(-2)), - Rational(-2) - ListPolynomial(), - "test 7" - ) - } - } - @Test - fun test_Constant_Polynomial_times() { - IntModuloRing(35).listPolynomialSpace { - assertEquals( - ListPolynomial(34, 2, 1, 20, 2), - m(27) * ListPolynomial(22, 26, 13, 15, 26), - "test 1" - ) - assertEquals( - ListPolynomial(0, 0, 0, 0, 0), - m(15) * ListPolynomial(7, 0, 49, 21, 14), - "test 2" - ) - } - } - @Test - fun test_Polynomial_unaryMinus() { - RationalField.listPolynomialSpace { - assertEquals( - ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), - -ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)), - "test 1" - ) - assertEquals( - ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7), Rational(0), Rational(0)), - -ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7), Rational(0), Rational(0)), - "test 2" - ) - } - } - @Test - fun test_Polynomial_Polynomial_plus() { - RationalField.listPolynomialSpace { - // (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( - ListPolynomial(Rational(-10, 63), Rational(37, 9), Rational(-29, 56)), - ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + - ListPolynomial(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( - ListPolynomial(Rational(-2, 9), Rational(-5, 12), Rational(2, 4)), - ListPolynomial(Rational(-2, 9), Rational(-8, 3)) + - ListPolynomial(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( - ListPolynomial(Rational(-18, 7), Rational(-23, 6), Rational(2, 3), Rational(0)), - ListPolynomial(Rational(-4, 7), Rational(-2, 6), Rational(0), Rational(0)) + - ListPolynomial(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( - ListPolynomial(Rational(0), Rational(0), Rational(0)), - ListPolynomial(Rational(-2, 4), Rational(-6, 9), Rational(-4, 9)) + - ListPolynomial(Rational(2, 4), Rational(6, 9), Rational(4, 9)), - "test 4" - ) - } - } - @Test - fun test_Polynomial_Polynomial_minus() { - RationalField.listPolynomialSpace { - // (5/9 - 8/9 x - 8/7 x^2) - (-5/7 + 5/1 x + 5/8 x^2) ?= 80/63 - 53/9 x - 99/56 x^2 - assertEquals( - ListPolynomial(Rational(80, 63), Rational(-53, 9), Rational(-99, 56)), - ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - - ListPolynomial(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 - 59/12 x - 2/4 x^2 - assertEquals( - ListPolynomial(Rational(-2, 9), Rational(-59, 12), Rational(-2, 4)), - ListPolynomial(Rational(-2, 9), Rational(-8, 3)) - - ListPolynomial(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) ?= 10/7 + 19/6 x - 2/3 x^2 - assertEquals( - ListPolynomial(Rational(10, 7), Rational(19, 6), Rational(-2, 3), Rational(0)), - ListPolynomial(Rational(-4, 7), Rational(-2, 6), Rational(0), Rational(0)) - - ListPolynomial(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( - ListPolynomial(Rational(0), Rational(0), Rational(0)), - ListPolynomial(Rational(-2, 4), Rational(-6, 9), Rational(-4, 9)) - - ListPolynomial(Rational(-2, 4), Rational(-6, 9), Rational(-4, 9)), - "test 4" - ) - } - } - @Test - fun test_Polynomial_Polynomial_times() { - IntModuloRing(35).listPolynomialSpace { - // (1 + x + x^2) * (1 - x + x^2) ?= 1 + x^2 + x^4 - assertEquals( - ListPolynomial(1, 0, 1, 0, 1), - ListPolynomial(1, -1, 1) * ListPolynomial(1, 1, 1), - "test 1" - ) - // Spoiler: 5 * 7 = 0 - assertEquals( - ListPolynomial(0, 0, 0, 0, 0), - ListPolynomial(5, -25, 10) * ListPolynomial(21, 14, -7), - "test 2" - ) - } - } -} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt deleted file mode 100644 index 153b0134b..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt +++ /dev/null @@ -1,134 +0,0 @@ -/* - * 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.functions - -import space.kscience.kmath.functions.testUtils.Rational -import space.kscience.kmath.functions.testUtils.RationalField -import space.kscience.kmath.misc.UnstableKMathAPI -import kotlin.test.Test -import kotlin.test.assertEquals - - -@OptIn(UnstableKMathAPI::class) -class ListPolynomialUtilTest { - @Test - fun test_Polynomial_substitute_Double() { - assertEquals( - 0.0, - ListPolynomial(1.0, -2.0, 1.0).substitute(1.0), - 0.001, - "test 1" - ) - assertEquals( - 0.0, - ListPolynomial(1.0, -2.0, 1.0).substitute(1.0), - 0.001, - "test 1" - ) - assertEquals( - 1.1931904761904761, - ListPolynomial(0.625, 2.6666666666666665, 0.5714285714285714, 1.5).substitute(0.2), - 0.001, - "test 2" - ) - assertEquals( - 0.5681904761904762, - ListPolynomial(0.0, 2.6666666666666665, 0.5714285714285714, 1.5).substitute(0.2), - 0.001, - "test 3" - ) - assertEquals( - 1.1811904761904761, - ListPolynomial(0.625, 2.6666666666666665, 0.5714285714285714, 0.0).substitute(0.2), - 0.001, - "test 4" - ) - assertEquals( - 1.1703333333333332, - ListPolynomial(0.625, 2.6666666666666665, 0.0, 1.5).substitute(0.2), - 0.001, - "test 5" - ) - } - @Test - fun test_Polynomial_substitute_Constant() { - assertEquals( - Rational(0), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).substitute(RationalField, Rational(1)), - "test 1" - ) - assertEquals( - Rational(25057, 21000), - ListPolynomial(Rational(5, 8), Rational(8, 3), Rational(4, 7), Rational(3, 2)) - .substitute(RationalField, Rational(1, 5)), - "test 2" - ) - assertEquals( - Rational(2983, 5250), - ListPolynomial(Rational(0), Rational(8, 3), Rational(4, 7), Rational(3, 2)) - .substitute(RationalField, Rational(1, 5)), - "test 3" - ) - assertEquals( - Rational(4961, 4200), - ListPolynomial(Rational(5, 8), Rational(8, 3), Rational(4, 7), Rational(0)) - .substitute(RationalField, Rational(1, 5)), - "test 4" - ) - assertEquals( - Rational(3511, 3000), - ListPolynomial(Rational(5, 8), Rational(8, 3), Rational(0), Rational(3, 2)) - .substitute(RationalField, Rational(1, 5)), - "test 5" - ) - } - @Test - fun test_Polynomial_derivative() { - assertEquals( - ListPolynomial(Rational(-2), Rational(2)), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).derivative(RationalField), - "test 1" - ) - assertEquals( - ListPolynomial(Rational(-8, 3), Rational(8, 9), Rational(15, 7), Rational(-20, 9)), - ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).derivative(RationalField), - "test 2" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(8, 9), Rational(15, 7), Rational(-20, 9)), - ListPolynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).derivative(RationalField), - "test 3" - ) - assertEquals( - ListPolynomial(Rational(-8, 3), Rational(8, 9), Rational(15, 7), Rational(0)), - ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).derivative(RationalField), - "test 4" - ) - } - @Test - fun test_Polynomial_antiderivative() { - assertEquals( - ListPolynomial(Rational(0), Rational(1), Rational(-1), Rational(1, 3)), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).antiderivative(RationalField), - "test 1" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(1, 5), Rational(-4, 3), Rational(4, 27), Rational(5, 28), Rational(-1, 9)), - ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).antiderivative(RationalField), - "test 2" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(4, 27), Rational(5, 28), Rational(-1, 9)), - ListPolynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).antiderivative(RationalField), - "test 3" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(1, 5), Rational(-4, 3), Rational(4, 27), Rational(5, 28), Rational(0)), - ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).antiderivative(RationalField), - "test 4" - ) - } -} \ No newline at end of file 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 new file mode 100644 index 000000000..7e0c6cdf2 --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt @@ -0,0 +1,303 @@ +/* + * 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. + */ + +@file:Suppress("LocalVariableName") + +package space.kscience.kmath.functions + +import space.kscience.kmath.functions.testUtils.* +import kotlin.test.* + + +class PolynomialTest { + @Test + fun test_Polynomial_Constant_plus() { + RationalField.polynomialSpace { + assertEquals( + Polynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), + Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + Rational(-3), + "test 1" + ) + assertEquals( + Polynomial(Rational(0), Rational(0), Rational(0), Rational(0)), + Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + Rational(2), + "test 2" + ) + assertEquals( + Polynomial(Rational(0)), + Polynomial(Rational(-2)) + Rational(2), + "test 3" + ) + assertEquals( + Polynomial(Rational(0)), + Polynomial() + Rational(0), + "test 4" + ) + assertEquals( + Polynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), + Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + Rational(1), + "test 5" + ) + assertEquals( + Polynomial(Rational(-1)), + Polynomial(Rational(-2)) + Rational(1), + "test 6" + ) + assertEquals( + Polynomial(Rational(2)), + Polynomial() + Rational(2), + "test 7" + ) + } + } + @Test + fun test_Polynomial_Constant_minus() { + RationalField.polynomialSpace { + assertEquals( + Polynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), + Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - Rational(-3), + "test 1" + ) + assertEquals( + Polynomial(Rational(0), Rational(0), Rational(0), Rational(0)), + Polynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - Rational(2), + "test 2" + ) + assertEquals( + Polynomial(Rational(0)), + Polynomial(Rational(2)) - Rational(2), + "test 3" + ) + assertEquals( + Polynomial(Rational(0)), + Polynomial() - Rational(0), + "test 4" + ) + assertEquals( + Polynomial(Rational(1), Rational(0), Rational(0), Rational(0)), + Polynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - Rational(1), + "test 5" + ) + assertEquals( + Polynomial(Rational(1)), + Polynomial(Rational(2)) - Rational(1), + "test 6" + ) + assertEquals( + Polynomial(Rational(-2)), + Polynomial() - Rational(2), + "test 7" + ) + } + } + @Test + fun test_Polynomial_Constant_times() { + IntModuloRing(35).polynomialSpace { + assertEquals( + Polynomial(34, 2, 1, 20, 2), + Polynomial(22, 26, 13, 15, 26) * m(27), + "test 1" + ) + assertEquals( + Polynomial(0, 0, 0, 0, 0), + Polynomial(7, 0, 49, 21, 14) * m(15), + "test 2" + ) + } + } + @Test + fun test_Constant_Polynomial_plus() { + RationalField.polynomialSpace { + assertEquals( + Polynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), + Rational(-3) + Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)), + "test 1" + ) + assertEquals( + Polynomial(Rational(0), Rational(0), Rational(0), Rational(0)), + Rational(2) + Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), + "test 2" + ) + assertEquals( + Polynomial(Rational(0)), + Rational(2) + Polynomial(Rational(-2)), + "test 3" + ) + assertEquals( + Polynomial(Rational(0)), + Rational(0) + Polynomial(), + "test 4" + ) + assertEquals( + Polynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), + Rational(1) + Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), + "test 5" + ) + assertEquals( + Polynomial(Rational(-1)), + Rational(1) + Polynomial(Rational(-2)), + "test 6" + ) + assertEquals( + Polynomial(Rational(2)), + Rational(2) + Polynomial(), + "test 7" + ) + } + } + @Test + fun test_Constant_Polynomial_minus() { + RationalField.polynomialSpace { + assertEquals( + Polynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), + Rational(3) - Polynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), + "test 1" + ) + assertEquals( + Polynomial(Rational(0), Rational(0), Rational(0), Rational(0)), + Rational(-2) - Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), + "test 2" + ) + assertEquals( + Polynomial(Rational(0)), + Rational(-2) - Polynomial(Rational(-2)), + "test 3" + ) + assertEquals( + Polynomial(Rational(0)), + Rational(0) - Polynomial(), + "test 4" + ) + assertEquals( + Polynomial(Rational(1), Rational(0), Rational(0), Rational(0)), + Rational(-1) - Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), + "test 5" + ) + assertEquals( + Polynomial(Rational(1)), + Rational(-1) - Polynomial(Rational(-2)), + "test 6" + ) + assertEquals( + Polynomial(Rational(-2)), + Rational(-2) - Polynomial(), + "test 7" + ) + } + } + @Test + fun test_Constant_Polynomial_times() { + IntModuloRing(35).polynomialSpace { + assertEquals( + Polynomial(34, 2, 1, 20, 2), + m(27) * Polynomial(22, 26, 13, 15, 26), + "test 1" + ) + assertEquals( + Polynomial(0, 0, 0, 0, 0), + m(15) * Polynomial(7, 0, 49, 21, 14), + "test 2" + ) + } + } + @Test + fun test_Polynomial_unaryMinus() { + RationalField.polynomialSpace { + assertEquals( + Polynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), + -Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)), + "test 1" + ) + assertEquals( + Polynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7), Rational(0), Rational(0)), + -Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7), Rational(0), Rational(0)), + "test 2" + ) + } + } + @Test + fun test_Polynomial_Polynomial_plus() { + RationalField.polynomialSpace { + // (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), Rational(0)), + 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(Rational(0), Rational(0), Rational(0)), + 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.polynomialSpace { + // (5/9 - 8/9 x - 8/7 x^2) - (-5/7 + 5/1 x + 5/8 x^2) ?= 80/63 - 53/9 x - 99/56 x^2 + assertEquals( + Polynomial(Rational(80, 63), Rational(-53, 9), Rational(-99, 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 - 59/12 x - 2/4 x^2 + assertEquals( + Polynomial(Rational(-2, 9), Rational(-59, 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) ?= 10/7 + 19/6 x - 2/3 x^2 + assertEquals( + Polynomial(Rational(10, 7), Rational(19, 6), Rational(-2, 3), Rational(0)), + 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(Rational(0), Rational(0), Rational(0)), + 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_times() { + IntModuloRing(35).polynomialSpace { + // (1 + x + x^2) * (1 - x + x^2) ?= 1 + x^2 + x^4 + assertEquals( + Polynomial(1, 0, 1, 0, 1), + Polynomial(1, -1, 1) * Polynomial(1, 1, 1), + "test 1" + ) + // Spoiler: 5 * 7 = 0 + assertEquals( + Polynomial(0, 0, 0, 0, 0), + Polynomial(5, -25, 10) * Polynomial(21, 14, -7), + "test 2" + ) + } + } +} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt new file mode 100644 index 000000000..820b487b4 --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt @@ -0,0 +1,134 @@ +/* + * 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.functions + +import space.kscience.kmath.functions.testUtils.Rational +import space.kscience.kmath.functions.testUtils.RationalField +import space.kscience.kmath.misc.UnstableKMathAPI +import kotlin.test.Test +import kotlin.test.assertEquals + + +@OptIn(UnstableKMathAPI::class) +class PolynomialUtilTest { + @Test + fun test_Polynomial_substitute_Double() { + assertEquals( + 0.0, + Polynomial(1.0, -2.0, 1.0).substitute(1.0), + 0.001, + "test 1" + ) + assertEquals( + 0.0, + Polynomial(1.0, -2.0, 1.0).substitute(1.0), + 0.001, + "test 1" + ) + assertEquals( + 1.1931904761904761, + Polynomial(0.625, 2.6666666666666665, 0.5714285714285714, 1.5).substitute(0.2), + 0.001, + "test 2" + ) + assertEquals( + 0.5681904761904762, + Polynomial(0.0, 2.6666666666666665, 0.5714285714285714, 1.5).substitute(0.2), + 0.001, + "test 3" + ) + assertEquals( + 1.1811904761904761, + Polynomial(0.625, 2.6666666666666665, 0.5714285714285714, 0.0).substitute(0.2), + 0.001, + "test 4" + ) + assertEquals( + 1.1703333333333332, + Polynomial(0.625, 2.6666666666666665, 0.0, 1.5).substitute(0.2), + 0.001, + "test 5" + ) + } + @Test + fun test_Polynomial_substitute_Constant() { + assertEquals( + Rational(0), + Polynomial(Rational(1), Rational(-2), Rational(1)).substitute(RationalField, Rational(1)), + "test 1" + ) + assertEquals( + Rational(25057, 21000), + Polynomial(Rational(5, 8), Rational(8, 3), Rational(4, 7), Rational(3, 2)) + .substitute(RationalField, Rational(1, 5)), + "test 2" + ) + assertEquals( + Rational(2983, 5250), + Polynomial(Rational(0), Rational(8, 3), Rational(4, 7), Rational(3, 2)) + .substitute(RationalField, Rational(1, 5)), + "test 3" + ) + assertEquals( + Rational(4961, 4200), + Polynomial(Rational(5, 8), Rational(8, 3), Rational(4, 7), Rational(0)) + .substitute(RationalField, Rational(1, 5)), + "test 4" + ) + assertEquals( + Rational(3511, 3000), + Polynomial(Rational(5, 8), Rational(8, 3), Rational(0), Rational(3, 2)) + .substitute(RationalField, Rational(1, 5)), + "test 5" + ) + } + @Test + fun test_Polynomial_derivative() { + assertEquals( + Polynomial(Rational(-2), Rational(2)), + Polynomial(Rational(1), Rational(-2), Rational(1)).derivative(RationalField), + "test 1" + ) + assertEquals( + Polynomial(Rational(-8, 3), Rational(8, 9), Rational(15, 7), Rational(-20, 9)), + Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).derivative(RationalField), + "test 2" + ) + assertEquals( + Polynomial(Rational(0), Rational(8, 9), Rational(15, 7), Rational(-20, 9)), + Polynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).derivative(RationalField), + "test 3" + ) + assertEquals( + Polynomial(Rational(-8, 3), Rational(8, 9), Rational(15, 7), Rational(0)), + Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).derivative(RationalField), + "test 4" + ) + } + @Test + fun test_Polynomial_antiderivative() { + assertEquals( + Polynomial(Rational(0), Rational(1), Rational(-1), Rational(1, 3)), + Polynomial(Rational(1), Rational(-2), Rational(1)).antiderivative(RationalField), + "test 1" + ) + assertEquals( + Polynomial(Rational(0), Rational(1, 5), Rational(-4, 3), Rational(4, 27), Rational(5, 28), Rational(-1, 9)), + Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).antiderivative(RationalField), + "test 2" + ) + assertEquals( + Polynomial(Rational(0), Rational(0), Rational(0), Rational(4, 27), Rational(5, 28), Rational(-1, 9)), + Polynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).antiderivative(RationalField), + "test 3" + ) + assertEquals( + Polynomial(Rational(0), Rational(1, 5), Rational(-4, 3), Rational(4, 27), Rational(5, 28), Rational(0)), + Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).antiderivative(RationalField), + "test 4" + ) + } +} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt index aae0ad017..afeba0be4 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt @@ -5,7 +5,7 @@ package space.kscience.kmath.integration -import space.kscience.kmath.functions.ListPolynomial +import space.kscience.kmath.functions.Polynomial import space.kscience.kmath.functions.integrate import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.DoubleField @@ -19,7 +19,7 @@ class SplineIntegralTest { @Test fun integratePolynomial(){ - val polynomial = ListPolynomial(1.0, 2.0, 3.0) + val polynomial = Polynomial(1.0, 2.0, 3.0) val integral = polynomial.integrate(DoubleField,1.0..2.0) assertEquals(11.0, integral, 0.001) } diff --git a/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialUtilTest.kt b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialUtilTest.kt index 88ee1cbb8..6243818b4 100644 --- a/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialUtilTest.kt +++ b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialUtilTest.kt @@ -6,6 +6,7 @@ package space.kscience.kmath.functions import space.kscience.kmath.expressions.Symbol +import space.kscience.kmath.functions.testUtils.assertEquals import space.kscience.kmath.functions.testUtils.Rational import space.kscience.kmath.functions.testUtils.RationalField import space.kscience.kmath.functions.testUtils.iota diff --git a/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt b/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt index 997a966a7..e534c243e 100644 --- a/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt +++ b/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt @@ -6,13 +6,13 @@ package space.kscience.kmath.functions.testUtils import space.kscience.kmath.functions.Polynomial -import space.kscience.kmath.functions.ListPolynomialSpace +import space.kscience.kmath.functions.PolynomialSpace -public fun ListPolynomialSpace.ListPolynomial(vararg coefs: Int): Polynomial = +public fun PolynomialSpace.Polynomial(vararg coefs: Int): Polynomial = Polynomial(coefs.map { IntModulo(it, ring.modulus) }) -public fun IntModuloRing.ListPolynomial(vararg coefs: Int): Polynomial = +public fun IntModuloRing.Polynomial(vararg coefs: Int): Polynomial = Polynomial(coefs.map { IntModulo(it, modulus) }) public fun IntModuloRing.m(arg: Int): IntModulo = IntModulo(arg, modulus) -public fun ListPolynomialSpace.m(arg: Int): IntModulo = IntModulo(arg, ring.modulus) \ No newline at end of file +public fun PolynomialSpace.m(arg: Int): IntModulo = IntModulo(arg, ring.modulus) \ No newline at end of file diff --git a/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt b/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt new file mode 100644 index 000000000..933c4dc4c --- /dev/null +++ b/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt @@ -0,0 +1,133 @@ +/* + * 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. + */ + +@file:Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress") + +package space.kscience.kmath.functions.testUtils + +import space.kscience.kmath.operations.Ring + + +public class IntModulo { + public val residue: Int + public val modulus: Int + + @PublishedApi + internal constructor(residue: Int, modulus: Int, toCheckInput: Boolean = true) { + if (toCheckInput) { + require(modulus != 0) { "modulus can not be zero" } + this.modulus = if (modulus < 0) -modulus else modulus + this.residue = residue.mod(this.modulus) + } else { + this.residue = residue + this.modulus = modulus + } + } + + public constructor(residue: Int, modulus: Int) : this(residue, modulus, true) + + public operator fun unaryPlus(): IntModulo = this + public operator fun unaryMinus(): IntModulo = + IntModulo( + if (residue == 0) 0 else modulus - residue, + modulus, + toCheckInput = false + ) + public operator fun plus(other: IntModulo): IntModulo { + require(modulus == other.modulus) { "can not add two residue different modulo" } + return IntModulo( + (residue + other.residue) % modulus, + modulus, + toCheckInput = false + ) + } + public operator fun plus(other: Int): IntModulo = + IntModulo( + (residue + other) % modulus, + modulus, + toCheckInput = false + ) + public operator fun minus(other: IntModulo): IntModulo { + require(modulus == other.modulus) { "can not subtract two residue different modulo" } + return IntModulo( + (residue - other.residue) % modulus, + modulus, + toCheckInput = false + ) + } + public operator fun minus(other: Int): IntModulo = + IntModulo( + (residue - other) % modulus, + modulus, + toCheckInput = false + ) + public operator fun times(other: IntModulo): IntModulo { + require(modulus == other.modulus) { "can not multiply two residue different modulo" } + return IntModulo( + (residue * other.residue) % modulus, + modulus, + toCheckInput = false + ) + } + public operator fun times(other: Int): IntModulo = + IntModulo( + (residue * other) % modulus, + modulus, + toCheckInput = false + ) + public operator fun div(other: IntModulo): IntModulo { + require(modulus == other.modulus) { "can not divide two residue different modulo" } + val (reciprocalCandidate, gcdOfOtherResidueAndModulus) = bezoutIdentityWithGCD(other.residue, modulus) + require(gcdOfOtherResidueAndModulus == 1) { "can not divide to residue that has non-trivial GCD with modulo" } + return IntModulo( + (residue * reciprocalCandidate) % modulus, + modulus, + toCheckInput = false + ) + } + public operator fun div(other: Int): IntModulo { + val (reciprocalCandidate, gcdOfOtherResidueAndModulus) = bezoutIdentityWithGCD(other, modulus) + require(gcdOfOtherResidueAndModulus == 1) { "can not divide to residue that has non-trivial GCD with modulo" } + return IntModulo( + (residue * reciprocalCandidate) % modulus, + modulus, + toCheckInput = false + ) + } + override fun equals(other: Any?): Boolean = + when (other) { + is IntModulo -> residue == other.residue && modulus == other.modulus + else -> false + } + + override fun hashCode(): Int = residue.hashCode() + + override fun toString(): String = "$residue mod $modulus" +} + +@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE") +public class IntModuloRing : Ring { + + public val modulus: Int + + public constructor(modulus: Int) { + require(modulus != 0) { "modulus can not be zero" } + this.modulus = if (modulus < 0) -modulus else modulus + } + + override inline val zero: IntModulo get() = IntModulo(0, modulus, toCheckInput = false) + override inline val one: IntModulo get() = IntModulo(1, modulus, toCheckInput = false) + + public fun number(arg: Int): IntModulo = IntModulo(arg, modulus, toCheckInput = false) + + override inline fun add(left: IntModulo, right: IntModulo): IntModulo = left + right + override inline fun multiply(left: IntModulo, right: IntModulo): IntModulo = left * right + + override inline fun IntModulo.unaryMinus(): IntModulo = -this + override inline fun IntModulo.plus(arg: IntModulo): IntModulo = this + arg + override inline fun IntModulo.minus(arg: IntModulo): IntModulo = this - arg + override inline fun IntModulo.times(arg: IntModulo): IntModulo = this * arg + public inline fun IntModulo.div(arg: IntModulo): IntModulo = this / arg +} \ No newline at end of file diff --git a/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt b/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt new file mode 100644 index 000000000..32ca1c3aa --- /dev/null +++ b/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt @@ -0,0 +1,20 @@ +/* + * 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.functions.testUtils + +import space.kscience.kmath.functions.ListPolynomial +import space.kscience.kmath.functions.Polynomial +import space.kscience.kmath.functions.ListPolynomialSpace +import space.kscience.kmath.functions.PolynomialSpaceOverRing + + +public fun ListPolynomialSpace.ListPolynomial(vararg coefs: Int): ListPolynomial = + ListPolynomial(coefs.map { IntModulo(it, ring.modulus) }) +public fun IntModuloRing.ListPolynomial(vararg coefs: Int): ListPolynomial = + ListPolynomial(coefs.map { IntModulo(it, modulus) }) + +public fun IntModuloRing.m(arg: Int): IntModulo = IntModulo(arg, modulus) +public fun PolynomialSpaceOverRing.m(arg: Int): IntModulo = IntModulo(arg, ring.modulus) \ No newline at end of file diff --git a/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/NTMisc.kt b/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/NTMisc.kt new file mode 100644 index 000000000..ff67f19d8 --- /dev/null +++ b/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/NTMisc.kt @@ -0,0 +1,29 @@ +/* + * 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.functions.testUtils + +import kotlin.math.abs + + +internal data class BezoutIdentityWithGCD(val first: T, val second: T, val gcd: T) + +internal tailrec fun gcd(a: Long, b: Long): Long = if (a == 0L) abs(b) else gcd(b % a, a) + +internal fun bezoutIdentityWithGCD(a: Int, b: Int): BezoutIdentityWithGCD = + when { + a < 0 && b < 0 -> with(bezoutIdentityWithGCDInternalLogic(-a, -b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(-first, -second, gcd) } + a < 0 -> with(bezoutIdentityWithGCDInternalLogic(-a, b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(-first, second, gcd) } + b < 0 -> with(bezoutIdentityWithGCDInternalLogic(a, -b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(first, -second, gcd) } + else -> bezoutIdentityWithGCDInternalLogic(a, b, 1, 0, 0, 1) + } + +internal tailrec fun bezoutIdentityWithGCDInternalLogic(a: Int, b: Int, m1: Int, m2: Int, m3: Int, m4: Int): BezoutIdentityWithGCD = + if (b == 0) BezoutIdentityWithGCD(m1, m3, a) + else { + val quotient = a / b + val reminder = a % b + bezoutIdentityWithGCDInternalLogic(b, reminder, m2, m1 - quotient * m2, m4, m3 - quotient * m4) + } \ No newline at end of file diff --git a/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt b/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt new file mode 100644 index 000000000..27b0eb21e --- /dev/null +++ b/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt @@ -0,0 +1,177 @@ +/* + * 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. + */ + +@file:Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress") + +package space.kscience.kmath.functions.testUtils + +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.Field +import space.kscience.kmath.operations.NumbersAddOps + +@Suppress("NAME_SHADOWING") +public class Rational { + public companion object { + public val ZERO: Rational = Rational(0L) + public val ONE: Rational = Rational(1L) + } + + public val numerator: Long + public val denominator: Long + + internal constructor(numerator: Long, denominator: Long, toCheckInput: Boolean = true) { + if (toCheckInput) { + if (denominator == 0L) throw ArithmeticException("/ by zero") + + val greatestCommonDivider = gcd(numerator, denominator).let { if (denominator < 0L) -it else it } + + this.numerator = numerator / greatestCommonDivider + this.denominator = denominator / greatestCommonDivider + } else { + this.numerator = numerator + this.denominator = denominator + } + } + + public constructor(numerator: Int, denominator: Int) : this(numerator.toLong(), denominator.toLong(), true) + public constructor(numerator: Int, denominator: Long) : this(numerator.toLong(), denominator, true) + public constructor(numerator: Long, denominator: Int) : this(numerator, denominator.toLong(), true) + public constructor(numerator: Long, denominator: Long) : this(numerator, denominator, true) + public constructor(numerator: Int) : this(numerator.toLong(), 1L, false) + public constructor(numerator: Long) : this(numerator, 1L, false) + + public operator fun unaryPlus(): Rational = this + public operator fun unaryMinus(): Rational = Rational(-this.numerator, this.denominator) + public operator fun plus(other: Rational): Rational { + val denominatorsGcd = gcd(denominator, other.denominator) + val dividedThisDenominator = denominator / denominatorsGcd + val dividedOtherDenominator = other.denominator / denominatorsGcd + val numeratorCandidate = numerator * dividedOtherDenominator + dividedThisDenominator * other.numerator + val secondGcd = gcd(numeratorCandidate, denominatorsGcd) + return Rational( + numeratorCandidate / secondGcd, + dividedThisDenominator * (other.denominator / secondGcd), + toCheckInput = false + ) + } + public operator fun plus(other: Int): Rational = + Rational( + numerator + denominator * other.toLong(), + denominator, + toCheckInput = false + ) + public operator fun plus(other: Long): Rational = + Rational( + numerator + denominator * other, + denominator, + toCheckInput = false + ) + public operator fun minus(other: Rational): Rational { + val denominatorsGcd = gcd(denominator, other.denominator) + val dividedThisDenominator = denominator / denominatorsGcd + val dividedOtherDenominator = other.denominator / denominatorsGcd + val numeratorCandidate = numerator * dividedOtherDenominator - dividedThisDenominator * other.numerator + val secondGcd = gcd(numeratorCandidate, denominatorsGcd) + return Rational( + numeratorCandidate / secondGcd, + dividedThisDenominator * (other.denominator / secondGcd), + toCheckInput = false + ) + } + public operator fun minus(other: Int): Rational = + Rational( + numerator - denominator * other.toLong(), + denominator, + toCheckInput = false + ) + public operator fun minus(other: Long): Rational = + Rational( + numerator - denominator * other, + denominator, + toCheckInput = false + ) + public operator fun times(other: Rational): Rational { + val thisDenominatorAndOtherNumeratorGcd = gcd(denominator, other.numerator) + val otherDenominatorAndThisNumeratorGcd = gcd(other.denominator, numerator) + return Rational( + (numerator / otherDenominatorAndThisNumeratorGcd) * (other.numerator / thisDenominatorAndOtherNumeratorGcd), + (denominator / thisDenominatorAndOtherNumeratorGcd) * (other.denominator / otherDenominatorAndThisNumeratorGcd), + toCheckInput = false + ) + } + public operator fun times(other: Int): Rational { + val other = other.toLong() + val denominatorAndOtherGcd = gcd(denominator, other) + return Rational( + numerator * (other / denominatorAndOtherGcd), + denominator / denominatorAndOtherGcd, + toCheckInput = false + ) + } + public operator fun times(other: Long): Rational { + val denominatorAndOtherGcd = gcd(denominator, other) + return Rational( + numerator * (other / denominatorAndOtherGcd), + denominator / denominatorAndOtherGcd, + toCheckInput = false + ) + } + public operator fun div(other: Rational): Rational { + val denominatorsGcd = gcd(denominator, other.denominator) + val numeratorsGcd = gcd(numerator, other.numerator) + return Rational( + (numerator / numeratorsGcd) * (other.denominator / denominatorsGcd), + (denominator / denominatorsGcd) * (other.numerator / numeratorsGcd) + ) + } + public operator fun div(other: Int): Rational { + val other = other.toLong() + val numeratorAndOtherGcd = gcd(numerator, other) + return Rational( + numerator / numeratorAndOtherGcd, + denominator * (other / numeratorAndOtherGcd), + toCheckInput = false + ) + } + public operator fun div(other: Long): Rational { + val numeratorAndOtherGcd = gcd(numerator, other) + return Rational( + numerator / numeratorAndOtherGcd, + denominator * (other / numeratorAndOtherGcd), + toCheckInput = false + ) + } + override fun equals(other: Any?): Boolean = + when (other) { + is Rational -> numerator == other.numerator && denominator == other.denominator + is Int -> numerator == other && denominator == 1L + is Long -> numerator == other && denominator == 1L + else -> false + } + + override fun hashCode(): Int = 31 * numerator.hashCode() + denominator.hashCode() + + override fun toString(): String = if (denominator == 1L) "$numerator" else "$numerator/$denominator" +} + +@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_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/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt b/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt index 9ca5f43a3..5d0b77aa8 100644 --- a/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt +++ b/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt @@ -91,7 +91,6 @@ public fun assertEquals( ) } -// FIXME: Don't understand why but the same function from test-utils-functions module can not be used public inline fun assertFailsWithTypeAndMessage( expectedMessage: String? = null, assertionMessage: String? = null, -- 2.34.1 From 5bc627f1d414730c2b2383a179edf290f6e5a47f Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Tue, 12 Jul 2022 01:56:34 +0300 Subject: [PATCH 105/123] Rollback all breaking changes. The only breaking change now is value class. --- .../kscience/kmath/functions/Piecewise.kt | 8 ++-- .../kscience/kmath/functions/Polynomial.kt | 24 +++------- .../kmath/functions/polynomialUtil.kt | 32 ++++--------- .../kmath/integration/SplineIntegrator.kt | 3 +- .../kmath/interpolation/Interpolator.kt | 4 +- .../kmath/functions/PolynomialUtilTest.kt | 46 +++++++++---------- 6 files changed, 45 insertions(+), 72 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt index cfd21d552..16af7f555 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt @@ -117,16 +117,16 @@ public fun > PiecewisePolynomial( * Return a value of polynomial function with given [ring] a given [arg] or null if argument is outside piecewise * definition. */ -public fun , C : Ring> PiecewisePolynomial.substitute(ring: C, arg: T): T? = - findPiece(arg)?.substitute(ring, arg) +public fun , C : Ring> PiecewisePolynomial.value(ring: C, arg: T): T? = + findPiece(arg)?.value(ring, arg) /** * Convert this polynomial to a function returning nullable value (null if argument is outside piecewise range). */ -public fun , C : Ring> PiecewisePolynomial.asFunction(ring: C): (T) -> T? = { substitute(ring, it) } +public fun , C : Ring> PiecewisePolynomial.asFunction(ring: C): (T) -> T? = { value(ring, it) } /** * Convert this polynomial to a function using [defaultValue] for arguments outside the piecewise range. */ public fun , C : Ring> PiecewisePolynomial.asFunction(ring: C, defaultValue: T): (T) -> T = - { substitute(ring, it) ?: defaultValue } + { value(ring, it) ?: defaultValue } 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 061f556f6..bfb378cce 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 @@ -59,12 +59,12 @@ public value class Polynomial( * @param A type of provided underlying ring of constants. It's [Ring] of [C]. * @param ring underlying ring of constants of type [A]. */ -public open class PolynomialSpace>( +public open class PolynomialSpace( /** * Underlying ring of constants. Its operations on constants are inherited by local operations on constants. */ public val ring: A, -) : Ring> { +) : Ring>, ScaleOperations> where A : Ring, A : ScaleOperations { /** * Instance of zero constant (zero of the underlying ring). @@ -267,13 +267,15 @@ public open class PolynomialSpace>( override fun add(left: Polynomial, right: Polynomial): Polynomial = left + right override fun multiply(left: Polynomial, right: Polynomial): Polynomial = left * right + override fun scale(a: Polynomial, value: Double): Polynomial = + ring { Polynomial(a.coefficients.map { scale(it, value) }) } // TODO: When context receivers will be ready move all of this substitutions and invocations to utilities with // [ListPolynomialSpace] as a context receiver /** * Evaluates value of [this] polynomial on provided [argument]. */ - public inline fun Polynomial.substitute(argument: C): C = substitute(ring, argument) + public inline fun Polynomial.substitute(argument: C): C = value(ring, argument) /** * Represent [this] polynomial as a regular context-less function. @@ -283,19 +285,5 @@ public open class PolynomialSpace>( /** * Evaluates value of [this] polynomial on provided [argument]. */ - public inline operator fun Polynomial.invoke(argument: C): C = substitute(ring, argument) -} - -/** - * Space of polynomials constructed over ring. - * - * @param C the type of constants. Polynomials have them as a coefficients in their terms. - * @param A type of underlying ring of constants. It's [Ring] of [C]. - * @param ring underlying ring of constants of type [A]. - */ -public class ScalablePolynomialSpace( - ring: A, -) : PolynomialSpace(ring), ScaleOperations> where A : Ring, A : ScaleOperations { - override fun scale(a: Polynomial, value: Double): Polynomial = - ring { Polynomial(a.coefficients.map { scale(it, value) }) } + public inline operator fun Polynomial.invoke(argument: C): C = value(ring, argument) } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt index 0e1259bee..f745bf6e4 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt @@ -16,36 +16,22 @@ import kotlin.math.pow /** * Creates a [PolynomialSpace] over a received ring. */ -public inline val > A.polynomialSpace: PolynomialSpace +public inline val A.polynomialSpace: PolynomialSpace where A : Ring, A : ScaleOperations get() = PolynomialSpace(this) /** * Creates a [PolynomialSpace]'s scope over a received ring. */ // TODO: When context will be ready move [ListPolynomialSpace] and add [A] to context receivers of [block] -public inline fun , R> A.polynomialSpace(block: PolynomialSpace.() -> R): R { +public inline fun A.polynomialSpace(block: PolynomialSpace.() -> R): R where A : Ring, A : ScaleOperations { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } return PolynomialSpace(this).block() } -/** - * Creates a [ScalablePolynomialSpace] over a received scalable ring. - */ -public inline val A.scalablePolynomialSpace: ScalablePolynomialSpace where A : Ring, A : ScaleOperations - get() = ScalablePolynomialSpace(this) - -/** - * Creates a [ScalablePolynomialSpace]'s scope over a received scalable ring. - */ // TODO: When context will be ready move [ListPolynomialSpace] and add [A] to context receivers of [block] -public inline fun A.scalablePolynomialSpace(block: ScalablePolynomialSpace.() -> R): R where A : Ring, A : ScaleOperations { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return ScalablePolynomialSpace(this).block() -} - /** * Evaluates value of [this] Double polynomial on provided Double argument. */ -public fun Polynomial.substitute(arg: Double): Double = +public fun Polynomial.value(arg: Double): Double = coefficients.reduceIndexedOrNull { index, acc, c -> acc + c * arg.pow(index) } ?: .0 @@ -55,7 +41,7 @@ public fun Polynomial.substitute(arg: Double): Double = * * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). */ -public fun Polynomial.substitute(ring: Ring, arg: C): C = ring { +public fun Polynomial.value(ring: Ring, arg: C): C = ring { if (coefficients.isEmpty()) return zero var result: C = coefficients.last() for (j in coefficients.size - 2 downTo 0) { @@ -67,13 +53,13 @@ public fun Polynomial.substitute(ring: Ring, arg: C): C = ring { /** * Represent [this] polynomial as a regular context-less function. */ -public fun > Polynomial.asFunctionOver(ring: A): (C) -> C = { substitute(ring, it) } +public fun > Polynomial.asFunctionOver(ring: A): (C) -> C = { value(ring, it) } /** * Returns algebraic derivative of received polynomial. */ @UnstableKMathAPI -public fun Polynomial.derivative( +public fun Polynomial.differentiate( ring: A, ): Polynomial where A : Ring, A : NumericAlgebra = ring { Polynomial( @@ -87,7 +73,7 @@ public fun Polynomial.derivative( * Returns algebraic antiderivative of received polynomial. */ @UnstableKMathAPI -public fun Polynomial.antiderivative( +public fun Polynomial.integrate( ring: A, ): Polynomial where A : Field, A : NumericAlgebra = ring { Polynomial( @@ -106,6 +92,6 @@ public fun > Polynomial.integrate( ring: Field, range: ClosedRange, ): C { - val antiderivative = antiderivative(ring) - return ring { antiderivative.substitute(ring, range.endInclusive) - antiderivative.substitute(ring, range.start) } + val antiderivative = integrate(ring) + return ring { antiderivative.value(ring, range.endInclusive) - antiderivative.value(ring, range.start) } } \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt index 0fcd4c6e5..eb88d9ae0 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt @@ -7,7 +7,6 @@ package space.kscience.kmath.integration import space.kscience.kmath.functions.PiecewisePolynomial import space.kscience.kmath.functions.integrate -import space.kscience.kmath.functions.antiderivative import space.kscience.kmath.interpolation.PolynomialInterpolator import space.kscience.kmath.interpolation.SplineInterpolator import space.kscience.kmath.interpolation.interpolatePolynomials @@ -24,7 +23,7 @@ import space.kscience.kmath.structures.MutableBufferFactory @OptIn(PerformancePitfall::class) @UnstableKMathAPI public fun > PiecewisePolynomial.integrate(algebra: Field): PiecewisePolynomial = - PiecewisePolynomial(pieces.map { it.first to it.second.antiderivative(algebra) }) + PiecewisePolynomial(pieces.map { it.first to it.second.integrate(algebra) }) /** * Compute definite integral of given [PiecewisePolynomial] piece by piece in a given [range] diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt index 62819be0c..2266092a3 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt @@ -10,7 +10,7 @@ package space.kscience.kmath.interpolation import space.kscience.kmath.data.XYColumnarData import space.kscience.kmath.functions.PiecewisePolynomial import space.kscience.kmath.functions.asFunction -import space.kscience.kmath.functions.substitute +import space.kscience.kmath.functions.value import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.Ring import space.kscience.kmath.structures.Buffer @@ -34,7 +34,7 @@ public interface PolynomialInterpolator> : Interpolator): PiecewisePolynomial override fun interpolate(points: XYColumnarData): (T) -> T = { x -> - interpolatePolynomials(points).substitute(algebra, x) ?: getDefaultValue() + interpolatePolynomials(points).value(algebra, x) ?: getDefaultValue() } } diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt index 820b487b4..9d0fe4cc3 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt @@ -15,119 +15,119 @@ import kotlin.test.assertEquals @OptIn(UnstableKMathAPI::class) class PolynomialUtilTest { @Test - fun test_Polynomial_substitute_Double() { + fun test_Polynomial_value_Double() { assertEquals( 0.0, - Polynomial(1.0, -2.0, 1.0).substitute(1.0), + Polynomial(1.0, -2.0, 1.0).value(1.0), 0.001, "test 1" ) assertEquals( 0.0, - Polynomial(1.0, -2.0, 1.0).substitute(1.0), + Polynomial(1.0, -2.0, 1.0).value(1.0), 0.001, "test 1" ) assertEquals( 1.1931904761904761, - Polynomial(0.625, 2.6666666666666665, 0.5714285714285714, 1.5).substitute(0.2), + Polynomial(0.625, 2.6666666666666665, 0.5714285714285714, 1.5).value(0.2), 0.001, "test 2" ) assertEquals( 0.5681904761904762, - Polynomial(0.0, 2.6666666666666665, 0.5714285714285714, 1.5).substitute(0.2), + Polynomial(0.0, 2.6666666666666665, 0.5714285714285714, 1.5).value(0.2), 0.001, "test 3" ) assertEquals( 1.1811904761904761, - Polynomial(0.625, 2.6666666666666665, 0.5714285714285714, 0.0).substitute(0.2), + Polynomial(0.625, 2.6666666666666665, 0.5714285714285714, 0.0).value(0.2), 0.001, "test 4" ) assertEquals( 1.1703333333333332, - Polynomial(0.625, 2.6666666666666665, 0.0, 1.5).substitute(0.2), + Polynomial(0.625, 2.6666666666666665, 0.0, 1.5).value(0.2), 0.001, "test 5" ) } @Test - fun test_Polynomial_substitute_Constant() { + fun test_Polynomial_value_Constant() { assertEquals( Rational(0), - Polynomial(Rational(1), Rational(-2), Rational(1)).substitute(RationalField, Rational(1)), + Polynomial(Rational(1), Rational(-2), Rational(1)).value(RationalField, Rational(1)), "test 1" ) assertEquals( Rational(25057, 21000), Polynomial(Rational(5, 8), Rational(8, 3), Rational(4, 7), Rational(3, 2)) - .substitute(RationalField, Rational(1, 5)), + .value(RationalField, Rational(1, 5)), "test 2" ) assertEquals( Rational(2983, 5250), Polynomial(Rational(0), Rational(8, 3), Rational(4, 7), Rational(3, 2)) - .substitute(RationalField, Rational(1, 5)), + .value(RationalField, Rational(1, 5)), "test 3" ) assertEquals( Rational(4961, 4200), Polynomial(Rational(5, 8), Rational(8, 3), Rational(4, 7), Rational(0)) - .substitute(RationalField, Rational(1, 5)), + .value(RationalField, Rational(1, 5)), "test 4" ) assertEquals( Rational(3511, 3000), Polynomial(Rational(5, 8), Rational(8, 3), Rational(0), Rational(3, 2)) - .substitute(RationalField, Rational(1, 5)), + .value(RationalField, Rational(1, 5)), "test 5" ) } @Test - fun test_Polynomial_derivative() { + fun test_Polynomial_differentiate() { assertEquals( Polynomial(Rational(-2), Rational(2)), - Polynomial(Rational(1), Rational(-2), Rational(1)).derivative(RationalField), + Polynomial(Rational(1), Rational(-2), Rational(1)).differentiate(RationalField), "test 1" ) assertEquals( Polynomial(Rational(-8, 3), Rational(8, 9), Rational(15, 7), Rational(-20, 9)), - Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).derivative(RationalField), + Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).differentiate(RationalField), "test 2" ) assertEquals( Polynomial(Rational(0), Rational(8, 9), Rational(15, 7), Rational(-20, 9)), - Polynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).derivative(RationalField), + Polynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).differentiate(RationalField), "test 3" ) assertEquals( Polynomial(Rational(-8, 3), Rational(8, 9), Rational(15, 7), Rational(0)), - Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).derivative(RationalField), + Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).differentiate(RationalField), "test 4" ) } @Test - fun test_Polynomial_antiderivative() { + fun test_Polynomial_integrate() { assertEquals( Polynomial(Rational(0), Rational(1), Rational(-1), Rational(1, 3)), - Polynomial(Rational(1), Rational(-2), Rational(1)).antiderivative(RationalField), + Polynomial(Rational(1), Rational(-2), Rational(1)).integrate(RationalField), "test 1" ) assertEquals( Polynomial(Rational(0), Rational(1, 5), Rational(-4, 3), Rational(4, 27), Rational(5, 28), Rational(-1, 9)), - Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).antiderivative(RationalField), + Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).integrate(RationalField), "test 2" ) assertEquals( Polynomial(Rational(0), Rational(0), Rational(0), Rational(4, 27), Rational(5, 28), Rational(-1, 9)), - Polynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).antiderivative(RationalField), + Polynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).integrate(RationalField), "test 3" ) assertEquals( Polynomial(Rational(0), Rational(1, 5), Rational(-4, 3), Rational(4, 27), Rational(5, 28), Rational(0)), - Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).antiderivative(RationalField), + Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).integrate(RationalField), "test 4" ) } -- 2.34.1 From f7d159bc036d2fa2496906e612db67fa6ce42e06 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Tue, 12 Jul 2022 02:05:29 +0300 Subject: [PATCH 106/123] Made IntModulo implement ScaleOperations. --- .../space/kscience/kmath/functions/testUtils/IntModulo.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt b/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt index 933c4dc4c..21095d858 100644 --- a/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt +++ b/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt @@ -8,6 +8,7 @@ package space.kscience.kmath.functions.testUtils import space.kscience.kmath.operations.Ring +import space.kscience.kmath.operations.ScaleOperations public class IntModulo { @@ -108,7 +109,7 @@ public class IntModulo { } @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE") -public class IntModuloRing : Ring { +public class IntModuloRing : Ring, ScaleOperations { public val modulus: Int @@ -130,4 +131,6 @@ public class IntModuloRing : Ring { override inline fun IntModulo.minus(arg: IntModulo): IntModulo = this - arg override inline fun IntModulo.times(arg: IntModulo): IntModulo = this * arg public inline fun IntModulo.div(arg: IntModulo): IntModulo = this / arg + + override fun scale(a: IntModulo, value: Double): IntModulo = a * value.toInt() } \ No newline at end of file -- 2.34.1 From 87aeda84d9fcbbed2a250695010fb7f254acb276 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Tue, 12 Jul 2022 23:10:38 +0300 Subject: [PATCH 107/123] Added MathJax to docs. --- kmath-functions/build.gradle.kts | 4 ++++ .../space/kscience/kmath/functions/Polynomial.kt | 10 +++++++--- kmath-polynomial/build.gradle.kts | 4 ++++ .../LabeledPolynomial.kt | 13 +++++++++---- .../ListPolynomial.kt | 9 ++++++--- .../NumberedPolynomial.kt | 13 +++++++------ .../labeledConstructors.kt | 14 +++++++++----- .../numberedConstructors.kt | 12 ++++++++---- 8 files changed, 54 insertions(+), 25 deletions(-) diff --git a/kmath-functions/build.gradle.kts b/kmath-functions/build.gradle.kts index 0a8e8a1be..149a8f277 100644 --- a/kmath-functions/build.gradle.kts +++ b/kmath-functions/build.gradle.kts @@ -19,6 +19,10 @@ kotlin.sourceSets { } } +dependencies { + dokkaPlugin("org.jetbrains.dokka:mathjax-plugin:${versionCatalogs.named("npmlibs").findVersion("dokka").get().requiredVersion}") +} + readme { maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) 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 bfb378cce..1e811d3ba 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 @@ -23,8 +23,10 @@ import kotlin.math.min @JvmInline public value class Polynomial( /** - * List that contains coefficients of the polynomial. Every monomial `a x^d` is stored as a coefficient `a` placed - * into the list at index `d`. For example, coefficients of a polynomial `5 x^2 - 6` can be represented as + * List that contains coefficients of the polynomial. + * + * Every monomial \(a x^d\) is stored as a coefficient \(a\) placed + * into the list at index \(d\). For example, coefficients of a polynomial \(5 x^2 - 6\) can be represented as * ``` * listOf( * -6, // -6 + @@ -42,9 +44,11 @@ public value class Polynomial( * 0, // 0 x^4 * ) * ``` - * It is not prohibited to put extra zeros at end of the list (as for `0x^3` and `0x^4` in the example). But the + * It is not prohibited to put extra zeros at end of the list (as for \(0x^3\) and \(0x^4\) in the example). But the * longer the coefficients list the worse performance of arithmetical operations performed on it. Thus, it is * recommended not to put (or even to remove) extra (or useless) coefficients at the end of the coefficients list. + * + * @usesMathJax */ public val coefficients: List ) { diff --git a/kmath-polynomial/build.gradle.kts b/kmath-polynomial/build.gradle.kts index dcfcb1b46..b0f4a095c 100644 --- a/kmath-polynomial/build.gradle.kts +++ b/kmath-polynomial/build.gradle.kts @@ -20,6 +20,10 @@ kotlin.sourceSets { } } +dependencies { + dokkaPlugin("org.jetbrains.dokka:mathjax-plugin:${versionCatalogs.named("npmlibs").findVersion("dokka").get().requiredVersion}") +} + readme { maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledPolynomial.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledPolynomial.kt index 7f107a87f..12bf9f839 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledPolynomial.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledPolynomial.kt @@ -25,9 +25,9 @@ internal constructor( /** * Map that contains coefficients of the polynomial. * - * Every monomial `a x_1^{d_1} ... x_n^{d_n}` is stored as a pair "key-value" in the map, where the value is the - * coefficient `a` and the key is a map that associates variables in the monomial with their degree in the monomial. - * For example, coefficients of a polynomial `5 a^2 c^3 - 6 b` can be represented as + * Every monomial \(a x_1^{d_1} ... x_n^{d_n}\) is stored as a pair "key-value" in the map, where the value is the + * coefficient \(a\) and the key is a map that associates variables in the monomial with their degree in the monomial. + * For example, coefficients of a polynomial \(5 a^2 c^3 - 6 b\) can be represented as * ``` * mapOf( * mapOf( @@ -55,7 +55,12 @@ internal constructor( * ) to 0 * ) * ``` - * where `a`, `b` and `c` are corresponding [Symbol] objects. + * where \(a\), \(b\) and \(c\) are corresponding [Symbol] objects. + * + * It is not prohibited to put extra zero monomials into the map (as for \(0 b c\) in the example). But the + * bigger the coefficients map the worse performance of arithmetical operations performed on it. Thus, it is + * recommended not to put (or even to remove) extra (or useless) monomials in the coefficients map. + * @usesMathJax */ public val coefficients: Map, C> ) : Polynomial { diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/ListPolynomial.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/ListPolynomial.kt index 76e1a6bb6..91b9c7658 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/ListPolynomial.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/ListPolynomial.kt @@ -21,8 +21,10 @@ import kotlin.math.min */ public data class ListPolynomial( /** - * List that contains coefficients of the polynomial. Every monomial `a x^d` is stored as a coefficient `a` placed - * into the list at index `d`. For example, coefficients of a polynomial `5 x^2 - 6` can be represented as + * List that contains coefficients of the polynomial. + * + * Every monomial \(a x^d\) is stored as a coefficient \(a\) placed + * into the list at index \(d\). For example, coefficients of a polynomial \(5 x^2 - 6\) can be represented as * ``` * listOf( * -6, // -6 + @@ -40,9 +42,10 @@ public data class ListPolynomial( * 0, // 0 x^4 * ) * ``` - * It is not prohibited to put extra zeros at end of the list (as for `0x^3` and `0x^4` in the example). But the + * It is not prohibited to put extra zeros at end of the list (as for \(0x^3\) and \(0x^4\) in the example). But the * longer the coefficients list the worse performance of arithmetical operations performed on it. Thus, it is * recommended not to put (or even to remove) extra (or useless) coefficients at the end of the coefficients list. + * @usesMathJax */ public val coefficients: List ) : Polynomial { diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedPolynomial.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedPolynomial.kt index f7dd9d8de..96c96e555 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedPolynomial.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedPolynomial.kt @@ -24,9 +24,9 @@ internal constructor( /** * Map that contains coefficients of the polynomial. * - * Every monomial `a x_1^{d_1} ... x_n^{d_n}` is stored as a pair "key-value" in the map, where the value is the - * coefficient `a` and the key is a list that associates index of every variable in the monomial with their degree - * in the monomial. For example, coefficients of a polynomial `5 x_1^2 x_3^3 - 6 x_2` can be represented as + * Every monomial \(a x_1^{d_1} ... x_n^{d_n}\) is stored as a pair "key-value" in the map, where the value is the + * coefficient \(a\) and the key is a list that associates index of every variable in the monomial with their degree + * in the monomial. For example, coefficients of a polynomial \(5 x_1^2 x_3^3 - 6 x_2\) can be represented as * ``` * mapOf( * listOf(2, 0, 3) to 5, // 5 x_1^2 x_3^3 + @@ -41,9 +41,10 @@ internal constructor( * listOf(0, 1, 1) to 0, // 0 x_2^1 x_3^1 * ) * ``` - * It is not prohibited to put extra zero monomials into the map (as for `0 x_2 x_3` in the example). But the + * It is not prohibited to put extra zero monomials into the map (as for \(0 x_2 x_3\) in the example). But the * bigger the coefficients map the worse performance of arithmetical operations performed on it. Thus, it is * recommended not to put (or even to remove) extra (or useless) monomials in the coefficients map. + * @usesMathJax */ public val coefficients: Map, C> ) : Polynomial { @@ -325,7 +326,7 @@ public class NumberedPolynomialSpace>( /** * Maximal index (ID) of variable occurring in the polynomial with positive power. If there is no such variable, - * the result is `-1`. + * the result is -1. */ public val NumberedPolynomial.lastVariable: Int get() = coefficients.keys.maxOfOrNull { degs -> degs.lastIndex } ?: -1 @@ -365,7 +366,7 @@ public class NumberedPolynomialSpace>( } ?: 0u /** * Count of variables occurring in the polynomial with positive power. If there is no such variable, - * the result is `0`. + * the result is 0. */ public val NumberedPolynomial.countOfVariables: Int get() = diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledConstructors.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledConstructors.kt index 819a36449..d23efc5c2 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledConstructors.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledConstructors.kt @@ -262,7 +262,7 @@ public inline fun C.asLabeledPolynomial() : LabeledPolynomial = LabeledPo /** * Marks DSL that allows to more simply create [LabeledPolynomial]s with good performance. * - * For example, polynomial `5 a^2 c^3 - 6 b` can be described as + * For example, polynomial \(5 a^2 c^3 - 6 b\) can be described as * ``` * Int.algebra { * val numberedPolynomial : NumberedPolynomial = NumberedPolynomial { @@ -271,6 +271,7 @@ public inline fun C.asLabeledPolynomial() : LabeledPolynomial = LabeledPo * } * } * ``` + * @usesMathJax */ @DslMarker @UnstableKMathAPI @@ -385,7 +386,7 @@ public class DSL1LabeledPolynomialBuilder( ///** // * Creates [LabeledPolynomial] with lambda [block] in context of [this] ring of constants. // * -// * For example, polynomial `5 x_1^2 x_3^3 - 6 x_2` can be described as +// * For example, polynomial \(5 x_1^2 x_3^3 - 6 x_2\) can be described as // * ``` // * Int.algebra { // * val LabeledPolynomial : LabeledPolynomial = LabeledPolynomial { @@ -394,6 +395,7 @@ public class DSL1LabeledPolynomialBuilder( // * } // * } // * ``` +// * @usesMathJax // */ // FIXME: For now this fabric does not let next two fabrics work. (See KT-52803.) Possible feature solutions: // 1. `LowPriorityInOverloadResolution` becomes public. Then it should be applied to this function. @@ -404,7 +406,7 @@ public class DSL1LabeledPolynomialBuilder( /** * Creates [LabeledPolynomial] with lambda [block] in context of [this] ring of [LabeledPolynomial]s. * - * For example, polynomial `5 x_1^2 x_3^3 - 6 x_2` can be described as + * For example, polynomial \(5 x_1^2 x_3^3 - 6 x_2\) can be described as * ``` * Int.algebra { * val LabeledPolynomial : LabeledPolynomial = LabeledPolynomial { @@ -413,14 +415,15 @@ public class DSL1LabeledPolynomialBuilder( * } * } * ``` + * @usesMathJax */ @UnstableKMathAPI public inline fun > LabeledPolynomialSpace.LabeledPolynomialDSL1(initialCapacity: Int = 0, block: DSL1LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = DSL1LabeledPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() /** * Creates [LabeledPolynomial] with lambda [block] in context of [this] field of [LabeledRationalFunction]s. * - * For example, polynomial `5 x_1^2 x_3^3 - 6 x_2` can be described as - * ``` + * For example, polynomial \(5 x_1^2 x_3^3 - 6 x_2\) can be described as + * `` * Int.algebra { * val LabeledPolynomial : LabeledPolynomial = LabeledPolynomial { * 5 { 1 inPowerOf 2u; 3 inPowerOf 3u } // 5 x_1^2 x_3^3 + @@ -428,6 +431,7 @@ public inline fun > LabeledPolynomialSpace.LabeledPolynomial * } * } * ``` + * @usesMathJax */ @UnstableKMathAPI public inline fun > LabeledRationalFunctionSpace.LabeledPolynomialDSL1(initialCapacity: Int = 0, block: DSL1LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = DSL1LabeledPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/numberedConstructors.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/numberedConstructors.kt index 8d2c9e617..051019159 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/numberedConstructors.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/numberedConstructors.kt @@ -243,7 +243,7 @@ public inline fun C.asNumberedPolynomial() : NumberedPolynomial = Numbere /** * Marks DSL that allows to more simply create [NumberedPolynomial]s with good performance. * - * For example, polynomial `5 x_1^2 x_3^3 - 6 x_2` can be described as + * For example, polynomial \(5 x_1^2 x_3^3 - 6 x_2\) can be described as * ``` * Int.algebra { * val numberedPolynomial : NumberedPolynomial = NumberedPolynomial { @@ -252,6 +252,7 @@ public inline fun C.asNumberedPolynomial() : NumberedPolynomial = Numbere * } * } * ``` + * @usesMathJax */ @DslMarker @UnstableKMathAPI @@ -372,7 +373,7 @@ public class DSL1NumberedPolynomialBuilder( ///** // * Creates [NumberedPolynomial] with lambda [block] in context of [this] ring of constants. // * -// * For example, polynomial `5 x_1^2 x_3^3 - 6 x_2` can be described as +// * For example, polynomial \(5 x_1^2 x_3^3 - 6 x_2\) can be described as // * ``` // * Int.algebra { // * val numberedPolynomial : NumberedPolynomial = NumberedPolynomial { @@ -381,6 +382,7 @@ public class DSL1NumberedPolynomialBuilder( // * } // * } // * ``` +// * @usesMathJax // */ // FIXME: For now this fabric does not let next two fabrics work. (See KT-52803.) Possible feature solutions: // 1. `LowPriorityInOverloadResolution` becomes public. Then it should be applied to this function. @@ -391,7 +393,7 @@ public class DSL1NumberedPolynomialBuilder( /** * Creates [NumberedPolynomial] with lambda [block] in context of [this] ring of [NumberedPolynomial]s. * - * For example, polynomial `5 x_1^2 x_3^3 - 6 x_2` can be described as + * For example, polynomial \(5 x_1^2 x_3^3 - 6 x_2\) can be described as * ``` * Int.algebra { * val numberedPolynomial : NumberedPolynomial = NumberedPolynomial { @@ -400,13 +402,14 @@ public class DSL1NumberedPolynomialBuilder( * } * } * ``` + * @usesMathJax */ @UnstableKMathAPI public inline fun > NumberedPolynomialSpace.NumberedPolynomialDSL1(initialCapacity: Int = 0, block: DSL1NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = DSL1NumberedPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() /** * Creates [NumberedPolynomial] with lambda [block] in context of [this] field of [NumberedRationalFunction]s. * - * For example, polynomial `5 x_1^2 x_3^3 - 6 x_2` can be described as + * For example, polynomial \(5 x_1^2 x_3^3 - 6 x_2\) can be described as * ``` * Int.algebra { * val numberedPolynomial : NumberedPolynomial = NumberedPolynomial { @@ -415,6 +418,7 @@ public inline fun > NumberedPolynomialSpace.NumberedPolynomi * } * } * ``` + * @usesMathJax */ @UnstableKMathAPI public inline fun > NumberedRationalFunctionSpace.NumberedPolynomialDSL1(initialCapacity: Int = 0, block: DSL1NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = DSL1NumberedPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() -- 2.34.1 From 4ea29c82c5abcc079123bd964f77ac4ea0e307a8 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Wed, 13 Jul 2022 12:05:53 +0300 Subject: [PATCH 108/123] Small fix of DSL1. --- .../kscience/kmath/functions/polynomials.kt | 4 +- .../labeledConstructors.kt | 40 +++++++++---------- .../numberedConstructors.kt | 36 ++++++++--------- 3 files changed, 40 insertions(+), 40 deletions(-) diff --git a/examples/src/main/kotlin/space/kscience/kmath/functions/polynomials.kt b/examples/src/main/kotlin/space/kscience/kmath/functions/polynomials.kt index 4151b0283..c65ca589d 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/functions/polynomials.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/functions/polynomials.kt @@ -107,8 +107,8 @@ fun numberedPolynomialsExample() { // Also there is DSL for constructing NumberedPolynomials: val polynomial5: NumberedPolynomial = NumberedPolynomialDSL1 { 3 {} - 5 { 2 inPowerOf 1u } - -7 with { 1 pow 2u; 3 pow 1u } + 5 { 1 inPowerOf 1u } + -7 with { 0 pow 2u; 2 pow 1u } // `pow` and `inPowerOf` are the same // `with` is omittable } diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledConstructors.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledConstructors.kt index d23efc5c2..aa44660c1 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledConstructors.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledConstructors.kt @@ -265,7 +265,7 @@ public inline fun C.asLabeledPolynomial() : LabeledPolynomial = LabeledPo * For example, polynomial \(5 a^2 c^3 - 6 b\) can be described as * ``` * Int.algebra { - * val numberedPolynomial : NumberedPolynomial = NumberedPolynomial { + * val labeledPolynomial : LabeledPolynomial = LabeledPolynomialDSL1 { * 5 { a inPowerOf 2u; c inPowerOf 3u } // 5 a^2 c^3 + * (-6) { b inPowerOf 1u } // (-6) b^1 * } @@ -339,18 +339,18 @@ public class DSL1LabeledPolynomialBuilder( /** * Initial capacity of coefficients map. */ - initialCapacity: Int = 0 + initialCapacity: Int? = null ) { /** * Coefficients storage. Any declaration of any monomial updates the storage. * Afterward the storage will be used as a resulting coefficients map. */ - private val coefficients: MutableMap, C> = LinkedHashMap(initialCapacity) + private val coefficients: MutableMap, C> = if (initialCapacity != null) LinkedHashMap(initialCapacity) else LinkedHashMap() /** * Builds the resulting coefficients map. * - * In fact, it just returns [coefficients] as regular coefficients map of type `Map, C>`. + * In fact, it just returns [coefficients] as regular coefficients map of type `Map, C>`. */ @PublishedApi internal fun build(): LabeledPolynomial = LabeledPolynomial(coefficients) @@ -386,12 +386,12 @@ public class DSL1LabeledPolynomialBuilder( ///** // * Creates [LabeledPolynomial] with lambda [block] in context of [this] ring of constants. // * -// * For example, polynomial \(5 x_1^2 x_3^3 - 6 x_2\) can be described as +// * For example, polynomial \(5 a^2 c^3 - 6 b\) can be described as // * ``` // * Int.algebra { -// * val LabeledPolynomial : LabeledPolynomial = LabeledPolynomial { -// * 5 { 1 inPowerOf 2u; 3 inPowerOf 3u } // 5 x_1^2 x_3^3 + -// * (-6) { 2 inPowerOf 1u } // (-6) x_2^1 +// * val labeledPolynomial : LabeledPolynomial = LabeledPolynomialDSL1 { +// * 5 { a inPowerOf 2u; c inPowerOf 3u } // 5 a^2 c^3 + +// * (-6) { b inPowerOf 1u } // (-6) b^1 // * } // * } // * ``` @@ -402,39 +402,39 @@ public class DSL1LabeledPolynomialBuilder( // 2. Union types are implemented. Then all three functions should be rewritten // as one with single union type as a (context) receiver. //@UnstableKMathAPI -//public inline fun > A.LabeledPolynomialDSL1(initialCapacity: Int = 0, block: LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = LabeledPolynomialBuilder(::add, initialCapacity).apply(block).build() +//public inline fun > A.LabeledPolynomialDSL1(initialCapacity: Int? = null, block: LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = LabeledPolynomialBuilder(::add, initialCapacity).apply(block).build() /** * Creates [LabeledPolynomial] with lambda [block] in context of [this] ring of [LabeledPolynomial]s. * - * For example, polynomial \(5 x_1^2 x_3^3 - 6 x_2\) can be described as + * For example, polynomial \(5 a^2 c^3 - 6 b\) can be described as * ``` * Int.algebra { - * val LabeledPolynomial : LabeledPolynomial = LabeledPolynomial { - * 5 { 1 inPowerOf 2u; 3 inPowerOf 3u } // 5 x_1^2 x_3^3 + - * (-6) { 2 inPowerOf 1u } // (-6) x_2^1 + * val labeledPolynomial : LabeledPolynomial = LabeledPolynomialDSL1 { + * 5 { a inPowerOf 2u; c inPowerOf 3u } // 5 a^2 c^3 + + * (-6) { b inPowerOf 1u } // (-6) b^1 * } * } * ``` * @usesMathJax */ @UnstableKMathAPI -public inline fun > LabeledPolynomialSpace.LabeledPolynomialDSL1(initialCapacity: Int = 0, block: DSL1LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = DSL1LabeledPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() +public inline fun > LabeledPolynomialSpace.LabeledPolynomialDSL1(initialCapacity: Int? = null, block: DSL1LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = DSL1LabeledPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() /** * Creates [LabeledPolynomial] with lambda [block] in context of [this] field of [LabeledRationalFunction]s. * - * For example, polynomial \(5 x_1^2 x_3^3 - 6 x_2\) can be described as - * `` + * For example, polynomial \(5 a^2 c^3 - 6 b\) can be described as + * ``` * Int.algebra { - * val LabeledPolynomial : LabeledPolynomial = LabeledPolynomial { - * 5 { 1 inPowerOf 2u; 3 inPowerOf 3u } // 5 x_1^2 x_3^3 + - * (-6) { 2 inPowerOf 1u } // (-6) x_2^1 + * val labeledPolynomial : LabeledPolynomial = LabeledPolynomialDSL1 { + * 5 { a inPowerOf 2u; c inPowerOf 3u } // 5 a^2 c^3 + + * (-6) { b inPowerOf 1u } // (-6) b^1 * } * } * ``` * @usesMathJax */ @UnstableKMathAPI -public inline fun > LabeledRationalFunctionSpace.LabeledPolynomialDSL1(initialCapacity: Int = 0, block: DSL1LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = DSL1LabeledPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() +public inline fun > LabeledRationalFunctionSpace.LabeledPolynomialDSL1(initialCapacity: Int? = null, block: DSL1LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = DSL1LabeledPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() // Waiting for context receivers :( FIXME: Replace with context receivers when they will be available diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/numberedConstructors.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/numberedConstructors.kt index 051019159..ce0db3d17 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/numberedConstructors.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/numberedConstructors.kt @@ -243,12 +243,12 @@ public inline fun C.asNumberedPolynomial() : NumberedPolynomial = Numbere /** * Marks DSL that allows to more simply create [NumberedPolynomial]s with good performance. * - * For example, polynomial \(5 x_1^2 x_3^3 - 6 x_2\) can be described as + * For example, polynomial \(5 x_0^2 x_2^3 - 6 x_1\) can be described as * ``` * Int.algebra { * val numberedPolynomial : NumberedPolynomial = NumberedPolynomial { - * 5 { 1 inPowerOf 2u; 3 inPowerOf 3u } // 5 x_1^2 x_3^3 + - * (-6) { 2 inPowerOf 1u } // (-6) x_2^1 + * 5 { 0 inPowerOf 2u; 2 inPowerOf 3u } // 5 x_0^2 x_2^3 + + * (-6) { 1 inPowerOf 1u } // (-6) x_1^1 * } * } * ``` @@ -285,7 +285,7 @@ public class DSL1NumberedPolynomialTermSignatureBuilder { */ public infix fun Int.inPowerOf(deg: UInt) { if (deg == 0u) return - val index = this - 1 + val index = this if (index > signature.lastIndex) { signature.addAll(List(index - signature.lastIndex - 1) { 0u }) signature.add(deg) @@ -326,13 +326,13 @@ public class DSL1NumberedPolynomialBuilder( /** * Initial capacity of coefficients map. */ - initialCapacity: Int = 0 + initialCapacity: Int? = null ) { /** * Coefficients storage. Any declaration of any monomial updates the storage. * Afterward the storage will be used as a resulting coefficients map. */ - private val coefficients: MutableMap, C> = LinkedHashMap(initialCapacity) + private val coefficients: MutableMap, C> = if (initialCapacity != null) LinkedHashMap(initialCapacity) else LinkedHashMap() /** * Builds the resulting coefficients map. @@ -373,12 +373,12 @@ public class DSL1NumberedPolynomialBuilder( ///** // * Creates [NumberedPolynomial] with lambda [block] in context of [this] ring of constants. // * -// * For example, polynomial \(5 x_1^2 x_3^3 - 6 x_2\) can be described as +// * For example, polynomial \(5 x_0^2 x_2^3 - 6 x_1\) can be described as // * ``` // * Int.algebra { // * val numberedPolynomial : NumberedPolynomial = NumberedPolynomial { -// * 5 { 1 inPowerOf 2u; 3 inPowerOf 3u } // 5 x_1^2 x_3^3 + -// * (-6) { 2 inPowerOf 1u } // (-6) x_2^1 +// * 5 { 0 inPowerOf 2u; 2 inPowerOf 3u } // 5 x_0^2 x_2^3 + +// * (-6) { 1 inPowerOf 1u } // (-6) x_1^1 // * } // * } // * ``` @@ -389,39 +389,39 @@ public class DSL1NumberedPolynomialBuilder( // 2. Union types are implemented. Then all three functions should be rewritten // as one with single union type as a (context) receiver. //@UnstableKMathAPI -//public inline fun > A.NumberedPolynomialDSL1(initialCapacity: Int = 0, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder(::add, initialCapacity).apply(block).build() +//public inline fun > A.NumberedPolynomialDSL1(initialCapacity: Int? = null, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder(::add, initialCapacity).apply(block).build() /** * Creates [NumberedPolynomial] with lambda [block] in context of [this] ring of [NumberedPolynomial]s. * - * For example, polynomial \(5 x_1^2 x_3^3 - 6 x_2\) can be described as + * For example, polynomial \(5 x_0^2 x_2^3 - 6 x_1\) can be described as * ``` * Int.algebra { * val numberedPolynomial : NumberedPolynomial = NumberedPolynomial { - * 5 { 1 inPowerOf 2u; 3 inPowerOf 3u } // 5 x_1^2 x_3^3 + - * (-6) { 2 inPowerOf 1u } // (-6) x_2^1 + * 5 { 0 inPowerOf 2u; 2 inPowerOf 3u } // 5 x_0^2 x_2^3 + + * (-6) { 1 inPowerOf 1u } // (-6) x_1^1 * } * } * ``` * @usesMathJax */ @UnstableKMathAPI -public inline fun > NumberedPolynomialSpace.NumberedPolynomialDSL1(initialCapacity: Int = 0, block: DSL1NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = DSL1NumberedPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() +public inline fun > NumberedPolynomialSpace.NumberedPolynomialDSL1(initialCapacity: Int? = null, block: DSL1NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = DSL1NumberedPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() /** * Creates [NumberedPolynomial] with lambda [block] in context of [this] field of [NumberedRationalFunction]s. * - * For example, polynomial \(5 x_1^2 x_3^3 - 6 x_2\) can be described as + * For example, polynomial \(5 x_0^2 x_2^3 - 6 x_1\) can be described as * ``` * Int.algebra { * val numberedPolynomial : NumberedPolynomial = NumberedPolynomial { - * 5 { 1 inPowerOf 2u; 3 inPowerOf 3u } // 5 x_1^2 x_3^3 + - * (-6) { 2 inPowerOf 1u } // (-6) x_2^1 + * 5 { 0 inPowerOf 2u; 2 inPowerOf 3u } // 5 x_0^2 x_2^3 + + * (-6) { 1 inPowerOf 1u } // (-6) x_1^1 * } * } * ``` * @usesMathJax */ @UnstableKMathAPI -public inline fun > NumberedRationalFunctionSpace.NumberedPolynomialDSL1(initialCapacity: Int = 0, block: DSL1NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = DSL1NumberedPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() +public inline fun > NumberedRationalFunctionSpace.NumberedPolynomialDSL1(initialCapacity: Int? = null, block: DSL1NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = DSL1NumberedPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() // Waiting for context receivers :( FIXME: Replace with context receivers when they will be available -- 2.34.1 From 579511a5ee0b598fd0e72863ad69f33456e84996 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sat, 16 Jul 2022 16:07:03 +0300 Subject: [PATCH 109/123] Add utilities for maps. Fix some tests. --- .../LabeledPolynomial.kt | 171 ++---- .../ListPolynomial.kt | 24 +- .../NumberedPolynomial.kt | 80 +-- .../collectionUtils.kt | 500 ++++++++++++++++++ .../labeledConstructors.kt | 50 +- .../labeledUtil.kt | 24 +- .../numberedConstructors.kt | 47 +- .../numberedUtil.kt | 10 +- .../functions/NumberedConstructorsTest.kt | 12 +- 9 files changed, 606 insertions(+), 312 deletions(-) create mode 100644 kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/collectionUtils.kt diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledPolynomial.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledPolynomial.kt index 12bf9f839..b07674a1e 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledPolynomial.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledPolynomial.kt @@ -150,12 +150,7 @@ public class LabeledPolynomialSpace>( else with(coefficients) { if (isEmpty()) other.asPolynomial() else LabeledPolynomialAsIs( - toMutableMap() - .apply { - val degs = emptyMap() - - this[degs] = getOrElse(degs) { constantZero } + other - } + withPutOrChanged(emptyMap(), other.asConstant()) { it -> it + other } ) } /** @@ -168,12 +163,7 @@ public class LabeledPolynomialSpace>( else with(coefficients) { if (isEmpty()) (-other).asPolynomial() else LabeledPolynomialAsIs( - toMutableMap() - .apply { - val degs = emptyMap() - - this[degs] = getOrElse(degs) { constantZero } - other - } + withPutOrChanged(emptyMap(), (-other).asConstant()) { it -> it - other } ) } /** @@ -186,11 +176,7 @@ public class LabeledPolynomialSpace>( 0 -> zero 1 -> this else -> LabeledPolynomialAsIs( - coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this[degs]!! * other - } + coefficients.mapValues { (_, value) -> value * other } ) } @@ -204,12 +190,7 @@ public class LabeledPolynomialSpace>( else with(other.coefficients) { if (isEmpty()) this@plus.asPolynomial() else LabeledPolynomialAsIs( - toMutableMap() - .apply { - val degs = emptyMap() - - this[degs] = this@plus + getOrElse(degs) { constantZero } - } + withPutOrChanged(emptyMap(), this@plus.asConstant()) { it -> this@plus + it } ) } /** @@ -218,18 +199,14 @@ public class LabeledPolynomialSpace>( * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. */ public override operator fun Int.minus(other: LabeledPolynomial): LabeledPolynomial = - if (this == 0) -other - else with(other.coefficients) { - if (isEmpty()) this@minus.asPolynomial() - else LabeledPolynomialAsIs( - toMutableMap() - .apply { - forEach { (key, value) -> if (key.isNotEmpty()) this[key] = -value } - - val degs = emptyMap() - - this[degs] = this@minus - getOrElse(degs) { constantZero } - } + when { + this == 0 -> -other + other.coefficients.isEmpty() -> this@minus.asPolynomial() + else -> LabeledPolynomialAsIs( + buildMap(other.coefficients.size + 1) { + put(emptyMap(), asConstant()) + other.coefficients.copyMapToBy(this, { _, c -> -c }, { currentC, newC -> currentC - newC }) + } ) } /** @@ -242,11 +219,7 @@ public class LabeledPolynomialSpace>( 0 -> zero 1 -> other else -> LabeledPolynomialAsIs( - other.coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this@times * this[degs]!! - } + other.coefficients.mapValues { (_, value) -> this@times * value } ) } @@ -305,41 +278,26 @@ public class LabeledPolynomialSpace>( with(other.coefficients) { if (isEmpty()) this@plus.asLabeledPolynomial() else LabeledPolynomialAsIs( - toMutableMap() - .apply { - val degs = emptyMap() - - this[degs] = this@plus + getOrElse(degs) { constantZero } - } + withPutOrChanged(emptyMap(), this@plus) { it -> this@plus + it } ) } /** * Returns difference between the constant represented as a polynomial and the polynomial. */ override operator fun C.minus(other: LabeledPolynomial): LabeledPolynomial = - with(other.coefficients) { - if (isEmpty()) this@minus.asLabeledPolynomial() - else LabeledPolynomialAsIs( - toMutableMap() - .apply { - forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } - - val degs = emptyMap() - - this[degs] = this@minus - getOrElse(degs) { constantZero } - } - ) - } + if (other.coefficients.isEmpty()) this@minus.asPolynomial() + else LabeledPolynomialAsIs( + buildMap(other.coefficients.size + 1) { + put(emptyMap(), this@minus) + other.coefficients.copyMapToBy(this, { _, c -> -c }, { currentC, newC -> currentC - newC }) + } + ) /** * Returns product of the constant represented as a polynomial and the polynomial. */ override operator fun C.times(other: LabeledPolynomial): LabeledPolynomial = LabeledPolynomialAsIs( - other.coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this@times * this[degs]!! - } + other.coefficients.mapValues { this@times * it.value } ) /** @@ -349,12 +307,7 @@ public class LabeledPolynomialSpace>( with(coefficients) { if (isEmpty()) other.asLabeledPolynomial() else LabeledPolynomialAsIs( - toMutableMap() - .apply { - val degs = emptyMap() - - this[degs] = getOrElse(degs) { constantZero } + other - } + withPutOrChanged(emptyMap(), other) { it -> it + other } ) } /** @@ -364,12 +317,7 @@ public class LabeledPolynomialSpace>( with(coefficients) { if (isEmpty()) other.asLabeledPolynomial() else LabeledPolynomialAsIs( - toMutableMap() - .apply { - val degs = emptyMap() - - this[degs] = getOrElse(degs) { constantZero } - other - } + withPutOrChanged(emptyMap(), -other) { it -> it - other } ) } /** @@ -377,11 +325,7 @@ public class LabeledPolynomialSpace>( */ override operator fun LabeledPolynomial.times(other: C): LabeledPolynomial = LabeledPolynomialAsIs( - coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this[degs]!! * other - } + coefficients.mapValues { it.value * other } ) /** @@ -441,38 +385,27 @@ public class LabeledPolynomialSpace>( with(other.coefficients) { if (isEmpty()) this@plus.asPolynomial() else LabeledPolynomialAsIs( - toMutableMap() - .apply { - val degs = mapOf(this@plus to 1U) - - this[degs] = constantOne + getOrElse(degs) { constantZero } - } + withPutOrChanged(mapOf(this@plus to 1U), constantOne) { it -> constantOne + it } ) } /** * Returns difference between the variable represented as a monic monomial and the polynomial. */ public override operator fun Symbol.minus(other: LabeledPolynomial): LabeledPolynomial = - with(other.coefficients) { - if (isEmpty()) this@minus.asPolynomial() - else LabeledPolynomialAsIs( - toMutableMap() - .apply { - val theVariableDegs = mapOf(this@minus to 1U) - - forEach { (degs, c) -> if(degs != theVariableDegs) this[degs] = -c } - - this[theVariableDegs] = constantOne - getOrElse(theVariableDegs) { constantZero } - } - ) - } + if (other.coefficients.isEmpty()) this@minus.asPolynomial() + else LabeledPolynomialAsIs( + buildMap(other.coefficients.size + 1) { + put(mapOf(this@minus to 1U), constantOne) + other.coefficients.copyMapToBy(this, { _, c -> -c }) { currentC, newC -> currentC - newC } + } + ) /** * Returns product of the variable represented as a monic monomial and the polynomial. */ public override operator fun Symbol.times(other: LabeledPolynomial): LabeledPolynomial = LabeledPolynomialAsIs( other.coefficients - .mapKeys { (degs, _) -> degs.toMutableMap().also{ it[this] = if (this in it) it[this]!! + 1U else 1U } } + .mapKeys { (degs, _) -> degs.withPutOrChanged(this, 1u) { it -> it + 1u } } ) /** @@ -482,12 +415,7 @@ public class LabeledPolynomialSpace>( with(coefficients) { if (isEmpty()) other.asPolynomial() else LabeledPolynomialAsIs( - toMutableMap() - .apply { - val degs = mapOf(other to 1U) - - this[degs] = constantOne + getOrElse(degs) { constantZero } - } + withPutOrChanged(mapOf(other to 1U), constantOne) { it -> it + constantOne } ) } /** @@ -497,12 +425,7 @@ public class LabeledPolynomialSpace>( with(coefficients) { if (isEmpty()) other.asPolynomial() else LabeledPolynomialAsIs( - toMutableMap() - .apply { - val degs = mapOf(other to 1U) - - this[degs] = getOrElse(degs) { constantZero } - constantOne - } + withPutOrChanged(mapOf(other to 1U), -constantOne) { it -> it - constantOne } ) } /** @@ -511,7 +434,7 @@ public class LabeledPolynomialSpace>( public override operator fun LabeledPolynomial.times(other: Symbol): LabeledPolynomial = LabeledPolynomialAsIs( coefficients - .mapKeys { (degs, _) -> degs.toMutableMap().also{ it[other] = if (other in it) it[other]!! + 1U else 1U } } + .mapKeys { (degs, _) -> degs.withPutOrChanged(other, 1u) { it -> it + 1u } } ) /** @@ -526,10 +449,7 @@ public class LabeledPolynomialSpace>( */ override operator fun LabeledPolynomial.plus(other: LabeledPolynomial): LabeledPolynomial = LabeledPolynomialAsIs( - buildMap(coefficients.size + other.coefficients.size) { - coefficients.mapValuesTo(this) { it.value } - other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! + value else value } - } + mergeBy(coefficients, other.coefficients) { c1, c2 -> c1 + c2 } ) /** * Returns difference of the polynomials. @@ -537,8 +457,8 @@ public class LabeledPolynomialSpace>( override operator fun LabeledPolynomial.minus(other: LabeledPolynomial): LabeledPolynomial = LabeledPolynomialAsIs( buildMap(coefficients.size + other.coefficients.size) { - coefficients.mapValuesTo(this) { it.value } - other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! - value else -value } + coefficients.copyTo(this) + other.coefficients.copyMapToBy(this, { _, c -> -c }, { currentC, newC -> currentC - newC }) } ) /** @@ -548,10 +468,9 @@ public class LabeledPolynomialSpace>( LabeledPolynomialAsIs( buildMap(coefficients.size * other.coefficients.size) { for ((degs1, c1) in coefficients) for ((degs2, c2) in other.coefficients) { - val degs = degs1.toMutableMap() - degs2.mapValuesTo(degs) { (variable, deg) -> degs.getOrElse(variable) { 0u } + deg } + val degs = mergeBy(degs1, degs2) { deg1, deg2 -> deg1 + deg2 } val c = c1 * c2 - this[degs] = if (degs in this) this[degs]!! + c else c + this.putOrChange(degs, c) { it -> it + c } } } ) @@ -581,10 +500,8 @@ public class LabeledPolynomialSpace>( public override val LabeledPolynomial.degrees: Map get() = buildMap { - coefficients.entries.forEach { (degs, _) -> - degs.mapValuesTo(this) { (variable, deg) -> - max(getOrElse(variable) { 0u }, deg) - } + coefficients.keys.forEach { degs -> + degs.copyToBy(this, ::max) } } /** diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/ListPolynomial.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/ListPolynomial.kt index 91b9c7658..17c42ac8c 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/ListPolynomial.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/ListPolynomial.kt @@ -109,11 +109,7 @@ public open class ListPolynomialSpace>( 0 -> zero 1 -> this else -> ListPolynomial( - coefficients - .toMutableList() - .apply { - for (deg in indices) this[deg] = this[deg] * other - } + coefficients.map { it * other } ) } @@ -167,11 +163,7 @@ public open class ListPolynomialSpace>( 0 -> zero 1 -> other else -> ListPolynomial( - other.coefficients - .toMutableList() - .apply { - for (deg in indices) this[deg] = this@times * this[deg] - } + other.coefficients.map { this@times * it } ) } @@ -214,11 +206,7 @@ public open class ListPolynomialSpace>( */ public override operator fun C.times(other: ListPolynomial): ListPolynomial = ListPolynomial( - other.coefficients - .toMutableList() - .apply { - for (deg in indices) this[deg] = this@times * this[deg] - } + other.coefficients.map { this@times * it } ) /** @@ -258,11 +246,7 @@ public open class ListPolynomialSpace>( */ public override operator fun ListPolynomial.times(other: C): ListPolynomial = ListPolynomial( - coefficients - .toMutableList() - .apply { - for (deg in indices) this[deg] = this[deg] * other - } + coefficients.map { it * other } ) /** diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedPolynomial.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedPolynomial.kt index 96c96e555..14c03ff7c 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedPolynomial.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedPolynomial.kt @@ -71,13 +71,7 @@ public class NumberedPolynomialSpace>( if (other == 0) this else NumberedPolynomialAsIs( - coefficients - .toMutableMap() - .apply { - val degs = emptyList() - - this[degs] = getOrElse(degs) { constantZero } + other - } + coefficients.withPutOrChanged(emptyList(), other.asConstant()) { it -> it + other } ) /** * Returns difference between the polynomial and the integer represented as a polynomial. @@ -88,13 +82,7 @@ public class NumberedPolynomialSpace>( if (other == 0) this else NumberedPolynomialAsIs( - coefficients - .toMutableMap() - .apply { - val degs = emptyList() - - this[degs] = getOrElse(degs) { constantZero } - other - } + coefficients.withPutOrChanged(emptyList(), (-other).asConstant()) { it -> it - other } ) /** * Returns product of the polynomial and the integer represented as a polynomial. @@ -106,11 +94,7 @@ public class NumberedPolynomialSpace>( 0 -> zero 1 -> this else -> NumberedPolynomialAsIs( - coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this[degs]!! * other - } + coefficients.mapValues { it.value * other } ) } @@ -123,13 +107,7 @@ public class NumberedPolynomialSpace>( if (this == 0) other else NumberedPolynomialAsIs( - other.coefficients - .toMutableMap() - .apply { - val degs = emptyList() - - this[degs] = this@plus + getOrElse(degs) { constantZero } - } + other.coefficients.withPutOrChanged(emptyList(), this@plus.asConstant()) { it -> this@plus + it } ) /** * Returns difference between the integer represented as a polynomial and the polynomial. @@ -162,11 +140,7 @@ public class NumberedPolynomialSpace>( 0 -> zero 1 -> other else -> NumberedPolynomialAsIs( - other.coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this@times * this[degs]!! - } + other.coefficients.mapValues { this@times * it.value } ) } @@ -177,12 +151,7 @@ public class NumberedPolynomialSpace>( with(other.coefficients) { if (isEmpty()) NumberedPolynomialAsIs(mapOf(emptyList() to this@plus)) else NumberedPolynomialAsIs( - toMutableMap() - .apply { - val degs = emptyList() - - this[degs] = this@plus + getOrElse(degs) { constantZero } - } + withPutOrChanged(emptyList(), this@plus) { it -> this@plus + it } ) } /** @@ -207,11 +176,7 @@ public class NumberedPolynomialSpace>( */ override operator fun C.times(other: NumberedPolynomial): NumberedPolynomial = NumberedPolynomialAsIs( - other.coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this@times * this[degs]!! - } + other.coefficients.mapValues { this@times * it.value } ) /** @@ -221,12 +186,7 @@ public class NumberedPolynomialSpace>( with(coefficients) { if (isEmpty()) NumberedPolynomialAsIs(mapOf(emptyList() to other)) else NumberedPolynomialAsIs( - toMutableMap() - .apply { - val degs = emptyList() - - this[degs] = getOrElse(degs) { constantZero } + other - } + withPutOrChanged(emptyList(), other) { it -> it + other } ) } /** @@ -236,12 +196,7 @@ public class NumberedPolynomialSpace>( with(coefficients) { if (isEmpty()) NumberedPolynomialAsIs(mapOf(emptyList() to other)) else NumberedPolynomialAsIs( - toMutableMap() - .apply { - val degs = emptyList() - - this[degs] = getOrElse(degs) { constantZero } - other - } + withPutOrChanged(emptyList(), -other) { it -> it - other } ) } /** @@ -249,11 +204,7 @@ public class NumberedPolynomialSpace>( */ override operator fun NumberedPolynomial.times(other: C): NumberedPolynomial = NumberedPolynomialAsIs( - coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this[degs]!! * other - } + coefficients.mapValues { it.value * other } ) /** @@ -274,10 +225,7 @@ public class NumberedPolynomialSpace>( */ override operator fun NumberedPolynomial.plus(other: NumberedPolynomial): NumberedPolynomial = NumberedPolynomialAsIs( - buildMap(coefficients.size + other.coefficients.size) { - coefficients.mapValuesTo(this) { it.value } - other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! + value else value } - } + mergeBy(coefficients, other.coefficients) { c1, c2 -> c1 + c2 } ) /** * Returns difference of the polynomials. @@ -285,8 +233,8 @@ public class NumberedPolynomialSpace>( override operator fun NumberedPolynomial.minus(other: NumberedPolynomial): NumberedPolynomial = NumberedPolynomialAsIs( buildMap(coefficients.size + other.coefficients.size) { - coefficients.mapValuesTo(this) { it.value } - other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! - value else -value } + coefficients.copyTo(this) + other.coefficients.copyMapToBy(this, { _, c -> -c }, { currentC, newC -> currentC - newC }) } ) /** @@ -300,7 +248,7 @@ public class NumberedPolynomialSpace>( (0..max(degs1.lastIndex, degs2.lastIndex)) .map { degs1.getOrElse(it) { 0U } + degs2.getOrElse(it) { 0U } } val c = c1 * c2 - this[degs] = if (degs in this) this[degs]!! + c else c + putOrChange(degs, c) { it -> it + c } } } ) diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/collectionUtils.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/collectionUtils.kt new file mode 100644 index 000000000..1d3da4c8b --- /dev/null +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/collectionUtils.kt @@ -0,0 +1,500 @@ +/* + * 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.functions + +import kotlin.contracts.InvocationKind.* +import kotlin.contracts.contract + + +/** + * Applies the [transformation][transform] to the value corresponding to the given [key] or null instead if it's not + * present. + * + * @param key key to check. + * @param transform transformation to apply. + * @return result of the transformation + */ +internal inline fun MutableMap.applyToKey(key: K, transform: (currentValue: V?) -> V): V { + contract { + callsInPlace(transform, EXACTLY_ONCE) + } + return transform(get(key)).also { this[key] = it } +} + +/** + * Depending on presence of value corresponding to the given [key] either puts new value calculated by [valueOnPut] or + * changes the present value with [transformOnChange]. + * + * @param key key to check. + * @param valueOnPut lazily calculated value to put in case of absence of the [key]. + * @param transformOnChange transform to apply to current value corresponding to the [key] in case of its presence. Uses + * current value as a parameter. + * @return result value corresponding to the [key]. + */ +internal inline fun MutableMap.putOrChange(key: K, valueOnPut: () -> V, transformOnChange: (currentValue: V) -> V): V { + contract { + callsInPlace(valueOnPut, AT_MOST_ONCE) + callsInPlace(transformOnChange, AT_MOST_ONCE) + } + @Suppress("UNCHECKED_CAST") + return (if (key !in this) valueOnPut() else transformOnChange(get(key) as V)).also { this[key] = it } +} + +/** + * Depending on presence of value corresponding to the given [key] either puts new value [valueOnPut] or + * changes the present value with [transformOnChange]. + * + * @param key key to check. + * @param valueOnPut value to put in case of absence of the [key]. + * @param transformOnChange transform to apply to current value corresponding to the [key] in case of its presence. Uses + * current value as a parameter. + * @return result value corresponding to the [key]. + */ +internal inline fun MutableMap.putOrChange(key: K, valueOnPut: V, transformOnChange: (currentValue: V) -> V): V { + contract { + callsInPlace(transformOnChange, AT_MOST_ONCE) + } + return putOrChange(key, { valueOnPut }, transformOnChange) +} + +/** + * Depending on presence of value corresponding to the given [key] either puts new value [valueOnPut] or + * changes the present value with [transformOnChange]. + * + * @param key key to check. + * @param valueOnPut value to put in case of absence of the [key]. + * @param transformOnChange transform to apply to current value corresponding to the [key] in case of its presence. Uses + * current value and new value as parameters. + * @return result value corresponding to the [key]. + */ +internal inline fun MutableMap.putOrChange(key: K, valueOnPut: V, transformOnChange: (currentValue: V, newValue: V) -> V): V { + contract { + callsInPlace(transformOnChange, AT_MOST_ONCE) + } + return putOrChange(key, { valueOnPut }, { transformOnChange(it, valueOnPut) }) +} + +/** + * Depending on presence of value corresponding to the given [key] either puts new value [valueOnPut] or + * changes the present value with [transformOnChange]. + * + * @param key key to check. + * @param valueOnPut value to put in case of absence of the [key]. + * @param transformOnChange transform to apply to current value corresponding to the [key] in case of its presence. Uses + * the [key], current value, and new value as parameters. + * @return result value corresponding to the [key]. + */ +internal inline fun MutableMap.putOrChange(key: K, valueOnPut: V, transformOnChange: (key: K, currentValue: V, newValue: V) -> V): V { + contract { + callsInPlace(transformOnChange, AT_MOST_ONCE) + } + return putOrChange(key, { valueOnPut }, { transformOnChange(key, it, valueOnPut) }) +} + +/** + * Creates copy of [the map][this] and applies the [transformation][transform] to the value corresponding to the given + * [key] in the copy or null instead if it's not present. + * + * @param key key to check. + * @param transform transformation to apply. + * @return the copy of [the map][this]. + */ +internal inline fun Map.withAppliedToKey(key: K, transform: (currentValue: V?) -> V): Map { + contract { + callsInPlace(transform, EXACTLY_ONCE) + } + return buildMap(size) { + putAll(this) + applyToKey(key, transform) + } +} + +/** + * Creates copy of [the map][this] and depending on presence of value corresponding to the given [key] either puts new + * value calculated by [valueOnPut] or changes the present value with [transformOnChange]. + * + * @param key key to check. + * @param valueOnPut lazily calculated value to put in case of absence of the [key]. + * @param transformOnChange transform to apply to current value corresponding to the [key] in case of its presence. Uses + * current value as a parameter. + * @return the copy of [the map][this]. + */ +internal inline fun Map.withPutOrChanged(key: K, valueOnPut: () -> V, transformOnChange: (currentValue: V) -> V): Map { + contract { + callsInPlace(valueOnPut, AT_MOST_ONCE) + callsInPlace(transformOnChange, AT_MOST_ONCE) + } + return buildMap(size + 1) { + putAll(this@withPutOrChanged) + putOrChange(key, valueOnPut, transformOnChange) + } +} + +/** + * Creates copy of [the map][this] and depending on presence of value corresponding to the given [key] either puts new + * value [valueOnPut] or changes the present value with [transformOnChange]. + * + * @param key key to check. + * @param valueOnPut value to put in case of absence of the [key]. + * @param transformOnChange transform to apply to current value corresponding to the [key] in case of its presence. Uses + * current value as a parameter. + * @return the copy of [the map][this]. + */ +internal inline fun Map.withPutOrChanged(key: K, valueOnPut: V, transformOnChange: (currentValue: V) -> V): Map { + contract { + callsInPlace(transformOnChange, AT_MOST_ONCE) + } + return withPutOrChanged(key, { valueOnPut }, transformOnChange) +} + +/** + * Creates copy of [the map][this] and depending on presence of value corresponding to the given [key] either puts new + * value [valueOnPut] or changes the present value with [transformOnChange]. + * + * @param key key to check. + * @param valueOnPut value to put in case of absence of the [key]. + * @param transformOnChange transform to apply to current value corresponding to the [key] in case of its presence. Uses + * current value and new value as parameters. + * @return the copy of [the map][this]. + */ +internal inline fun Map.withPutOrChanged(key: K, valueOnPut: V, transformOnChange: (currentValue: V, newValue: V) -> V): Map { + contract { + callsInPlace(transformOnChange, AT_MOST_ONCE) + } + return withPutOrChanged(key, { valueOnPut }, { transformOnChange(it, valueOnPut) }) +} + +/** + * Creates copy of [the map][this] and depending on presence of value corresponding to the given [key] either puts new + * value [valueOnPut] or changes the present value with [transformOnChange]. + * + * @param key key to check. + * @param valueOnPut value to put in case of absence of the [key]. + * @param transformOnChange transform to apply to current value corresponding to the [key] in case of its presence. Uses + * the [key], current value, and new value as parameters. + * @return the copy of [the map][this]. + */ +internal inline fun Map.withPutOrChanged(key: K, valueOnPut: V, transformOnChange: (key: K, currentValue: V, newValue: V) -> V): Map { + contract { + callsInPlace(transformOnChange, AT_MOST_ONCE) + } + return withPutOrChanged(key, { valueOnPut }, { transformOnChange(key, it, valueOnPut) }) +} + +/** + * Copies entries of [this map][this] to the [destination] map overriding present ones if needed. + * + * @receiver map to be copied. + * @param destination map to receive copies. + * @return the [destination]. + */ +internal fun > Map.copyTo(destination: D): D { + for ((key, value) in this) { + destination[key] = value + } + return destination +} + +/** + * Copies entries of [this map][this] to the [destination] map merging present entries with new ones using [resolve] + * lambda. + * + * @receiver map to be copied. + * @param destination map to receive copies. + * @param resolve lambda function that resolves overriding. It takes a key, current value corresponding to the key, and + * a new one and returns value to associate to the key. + * @return the [destination]. + */ +internal inline fun > Map.copyToBy(destination: D, resolve: (key: K, currentValue: W, newValue: V) -> W): D { + for ((key, value) in this) { + destination.putOrChange(key, value) { it -> resolve(key, it, value) } + } + return destination +} + +/** + * Copies entries of [this map][this] to the [destination] map merging present entries with new ones using [resolve] + * lambda. + * + * @receiver map to be copied. + * @param destination map to receive copies. + * @param resolve lambda function that resolves overriding. It takes current value corresponding to some key, and + * a new one and returns value to associate to the key. + * @return the [destination]. + */ +internal inline fun > Map.copyToBy(destination: D, resolve: (currentValue: W, newValue: V) -> W): D = + copyToBy(destination) { _, currentValue, newValue -> resolve(currentValue, newValue) } + +/** + * Transforms values of entries of [this map][this] with [the given transformation][transform] and copies resulting + * entries to the [destination] map overriding present ones if needed. Is equivalent to + * ```kotlin + * this.mapValues(transform).copyTo(destination) + * ``` + * + * @receiver map to be transformed and copied. + * @param destination map to receive copies. + * @param transform generates value of transformed entry using initial entry as an argument. Key of transformed entry is + * the same as initial entry. + * @return the [destination]. + */ +internal inline fun > Map.copyMapTo(destination: D, transform: (Map.Entry) -> W): D { + for (entry in this) { + destination[entry.key] = transform(entry) + } + return destination +} + +/** + * Transforms values of entries of [this map][this] with [the given transformation][transform] and copies resulting + * entries to the [destination] map overriding present ones if needed. Is equivalent to + * ```kotlin + * this.mapValues(transform).copyTo(destination) + * ``` + * + * @receiver map to be transformed and copied. + * @param destination map to receive copies. + * @param transform generates value of transformed entry using initial entry as an argument. Key of transformed entry is + * the same as initial entry. + * @return the [destination]. + */ +internal inline fun > Map.copyMapTo(destination: D, transform: (key: K, value: V) -> W): D = + copyMapTo(destination) { (key, value) -> transform(key, value) } + +/** + * Transforms values of entries of [this map][this] with [the given transformation][transform] and copies resulting + * entries to the [destination] map merging present entries with new ones using [resolve] lambda. Is equivalent to + * ```kotlin + * this.mapValues(transform).copyToBy(destination, resolve) + * ``` + * + * @receiver map to be transformed and copied. + * @param destination map to receive copies. + * @param transform generates value of transformed entry using initial entry as an argument. Key of transformed entry is + * the same as initial entry. + * @param resolve lambda function that resolves overriding. It takes a key, current value corresponding to the key, and + * a new one and returns value to associate to the key. + * @return the [destination]. + */ +internal inline fun > Map.copyMapToBy(destination: D, transform: (Map.Entry) -> W, resolve: (key: K, currentValue: W, newValue: V) -> W): D { + for (entry in this) { + val (key, value) = entry + destination.putOrChange(key, transform(entry)) { it -> resolve(key, it, value) } + } + return destination +} + +/** + * Transforms values of entries of [this map][this] with [the given transformation][transform] and copies resulting + * entries to the [destination] map merging present entries with new ones using [resolve] lambda. Is equivalent to + * ```kotlin + * this.mapValues(transform).copyToBy(destination, resolve) + * ``` + * + * @receiver map to be transformed and copied. + * @param destination map to receive copies. + * @param transform generates value of transformed entry using initial entry as an argument. Key of transformed entry is + * the same as initial entry. + * @param resolve lambda function that resolves overriding. It takes a key, current value corresponding to the key, and + * a new one and returns value to associate to the key. + * @return the [destination]. + */ +internal inline fun > Map.copyMapToBy(destination: D, transform: (key: K, value: V) -> W, resolve: (key: K, currentValue: W, newValue: V) -> W): D = + copyMapToBy(destination, { (key, value) -> transform(key, value) }, resolve) + +/** + * Transforms values of entries of [this map][this] with [the given transformation][transform] and copies resulting + * entries to the [destination] map merging present entries with new ones using [resolve] lambda. Is equivalent to + * ```kotlin + * this.mapValues(transform).copyToBy(destination, resolve) + * ``` + * + * @receiver map to be transformed and copied. + * @param destination map to receive copies. + * @param transform generates value of transformed entry using initial entry as an argument. Key of transformed entry is + * the same as initial entry. + * @param resolve lambda function that resolves overriding. It takes current value corresponding to some key, and + * a new one and returns value to associate to the key. + * @return the [destination]. + */ +internal inline fun > Map.copyMapToBy(destination: D, transform: (Map.Entry) -> W, resolve: (currentValue: W, newValue: V) -> W): D = + copyMapToBy(destination, transform, { _, currentValue, newValue -> resolve(currentValue, newValue) }) + +/** + * Transforms values of entries of [this map][this] with [the given transformation][transform] and copies resulting + * entries to the [destination] map merging present entries with new ones using [resolve] lambda. Is equivalent to + * ```kotlin + * this.mapValues(transform).copyToBy(destination, resolve) + * ``` + * + * @receiver map to be transformed and copied. + * @param destination map to receive copies. + * @param transform generates value of transformed entry using initial entry as an argument. Key of transformed entry is + * the same as initial entry. + * @param resolve lambda function that resolves overriding. It takes current value corresponding to some key, and + * a new one and returns value to associate to the key. + * @return the [destination]. + */ +internal inline fun > Map.copyMapToBy(destination: D, transform: (key: K, value: V) -> W, resolve: (currentValue: W, newValue: V) -> W): D = + copyMapToBy(destination, { (key, value) -> transform(key, value) }, { _, currentValue, newValue -> resolve(currentValue, newValue) }) + +// TODO: Docs +internal fun > mergeTo(map1: Map, map2: Map, destination: D): D { + for ((key, value) in map1) { + destination.put(key, value) + } + for ((key, value) in map2) { + destination.put(key, value) + } + return destination +} + +// TODO: Docs +internal inline fun > mergeToBy(map1: Map, map2: Map, destination: D, resolve: (key: K, value1: V1, value2: V2) -> W): D { + for (key in map2.keys) { + destination.remove(key) + } + for ((key, value) in map1) { + destination.put(key, value) + } + for ((key, value) in map2) { + @Suppress("UNCHECKED_CAST") + destination.putOrChange(key, value) { it -> resolve(key, it as V1, value) } + } + return destination +} + +// TODO: Docs +internal inline fun > mergeToBy(map1: Map, map2: Map, destination: D, resolve: (value1: V1, value2: V2) -> W): D = + mergeToBy(map1, map2, destination) { _, value1, value2 -> resolve(value1, value2) } + +// TODO: Docs +internal fun merge(map1: Map, map2: Map): Map { + val result = LinkedHashMap(map1.size + map2.size) + return mergeTo(map1, map2, result) +} + +// TODO: Docs +internal inline fun mergeBy(map1: Map, map2: Map, transform: (key: K, value1: V1, value2: V2) -> W): Map { + val result = LinkedHashMap(map1.size + map2.size) + return mergeToBy(map1, map2, result, transform) +} + +// TODO: Docs +internal inline fun mergeBy(map1: Map, map2: Map, transform: (value1: V1, value2: V2) -> W): Map = + mergeBy(map1, map2) { _, value1, value2 -> transform(value1, value2) } + +// TODO: Docs +internal inline fun > Iterable.associateTo(destination: D, transform: (T) -> Pair, resolve: (key: K, currentValue: V, newValue: V) -> V): D { + for (element in this) { + val (key, value) = transform(element) + destination.putOrChange(key, value, resolve) + } + return destination +} + +// TODO: Docs +internal inline fun > Iterable.associateByTo(destination: D, keySelector: (T) -> K, valueTransform: (T) -> V, resolve: (key: K, currentValue: V, newValue: V) -> V): D { + for (element in this) { + val key = keySelector(element) + val value = valueTransform(element) + destination.putOrChange(key, value, resolve) + } + return destination +} + +// TODO: Docs +internal inline fun > Iterable.associateByTo(destination: D, keySelector: (T) -> K, resolve: (key: K, currentValue: T, newValue: T) -> T): D { + for (element in this) { + val key = keySelector(element) + destination.putOrChange(key, element, resolve) + } + return destination +} + +// TODO: Docs +internal inline fun > Iterable.associateTo(destination: D, transform: (T) -> Pair, resolve: (currentValue: V, newValue: V) -> V): D = + associateTo(destination, transform) { _, currentValue, newValue -> resolve(currentValue, newValue) } + +// TODO: Docs +internal inline fun > Iterable.associateByTo(destination: D, keySelector: (T) -> K, valueTransform: (T) -> V, resolve: (currentValue: V, newValue: V) -> V): D = + associateByTo(destination, keySelector, valueTransform) { _, currentValue, newValue -> resolve(currentValue, newValue) } + +// TODO: Docs +internal inline fun > Iterable.associateByTo(destination: D, keySelector: (T) -> K, resolve: (currentValue: T, newValue: T) -> T): D = + associateByTo(destination, keySelector) { _, currentValue, newValue -> resolve(currentValue, newValue) } + +// TODO: Docs +internal inline fun Iterable.associate(transform: (T) -> Pair, resolve: (key: K, currentValue: V, newValue: V) -> V): Map = + associateTo(LinkedHashMap(), transform, resolve) + +// TODO: Docs +internal inline fun Iterable.associateBy(keySelector: (T) -> K, valueTransform: (T) -> V, resolve: (key: K, currentValue: V, newValue: V) -> V): Map = + associateByTo(LinkedHashMap(), keySelector, valueTransform, resolve) + +// TODO: Docs +internal inline fun Iterable.associateBy(keySelector: (T) -> K, resolve: (key: K, currentValue: T, newValue: T) -> T): Map = + associateByTo(LinkedHashMap(), keySelector, resolve) + +// TODO: Docs +internal inline fun Iterable.associate(transform: (T) -> Pair, resolve: (currentValue: V, newValue: V) -> V): Map = + associateTo(LinkedHashMap(), transform, resolve) + +// TODO: Docs +internal inline fun Iterable.associateBy(keySelector: (T) -> K, valueTransform: (T) -> V, resolve: (currentValue: V, newValue: V) -> V): Map = + associateByTo(LinkedHashMap(), keySelector, valueTransform, resolve) + +// TODO: Docs +internal inline fun Iterable.associateBy(keySelector: (T) -> K, resolve: (currentValue: T, newValue: T) -> T): Map = + associateByTo(LinkedHashMap(), keySelector, resolve) + +// TODO: Docs +internal inline fun > Map.mapValuesTo(destination: D, transform: (Map.Entry) -> W, resolve: (key: K, currentValue: W, newValue: W) -> W): D = + entries.associateByTo(destination, { it.key }, transform, resolve) + +// TODO: Docs +internal inline fun > Map.mapValuesTo(destination: D, transform: (key: K, value: V) -> W, resolve: (key: K, currentValue: W, newValue: W) -> W): D = + entries.associateByTo(destination, { it.key }, { (key, value) -> transform(key, value) }, resolve) + +// TODO: Docs +internal inline fun > Map.mapValuesTo(destination: D, transform: (Map.Entry) -> W, resolve: (currentValue: W, newValue: W) -> W): D = + entries.associateByTo(destination, { it.key }, transform, resolve) + +// TODO: Docs +internal inline fun > Map.mapValuesTo(destination: D, transform: (key: K, value: V) -> W, resolve: (currentValue: W, newValue: W) -> W): D = + entries.associateByTo(destination, { it.key }, { (key, value) -> transform(key, value) }, resolve) + +// TODO: Docs +internal inline fun > Map.mapKeysTo(destination: D, transform: (Map.Entry) -> L, resolve: (key: L, currentValue: V, newValue: V) -> V): D = + entries.associateByTo(destination, transform, { it.value }, resolve) + +// TODO: Docs +internal inline fun > Map.mapKeysTo(destination: D, transform: (key: K, value: V) -> L, resolve: (key: L, currentValue: V, newValue: V) -> V): D = + entries.associateByTo(destination, { (key, value) -> transform(key, value) }, { it.value }, resolve) + +// TODO: Docs +internal inline fun > Map.mapKeysTo(destination: D, transform: (Map.Entry) -> L, resolve: (currentValue: V, newValue: V) -> V): D = + entries.associateByTo(destination, transform, { it.value }, resolve) + +// TODO: Docs +internal inline fun > Map.mapKeysTo(destination: D, transform: (key: K, value: V) -> L, resolve: (currentValue: V, newValue: V) -> V): D = + entries.associateByTo(destination, { (key, value) -> transform(key, value) }, { it.value }, resolve) + +// TODO: Docs +internal inline fun Map.mapKeys(transform: (Map.Entry) -> L, resolve: (key: L, currentValue: V, newValue: V) -> V): Map = + mapKeysTo(LinkedHashMap(size), transform, resolve) + +// TODO: Docs +internal inline fun Map.mapKeys(transform: (key: K, value: V) -> L, resolve: (key: L, currentValue: V, newValue: V) -> V): Map = + mapKeysTo(LinkedHashMap(size), transform, resolve) + +// TODO: Docs +internal inline fun Map.mapKeys(transform: (Map.Entry) -> L, resolve: (currentValue: V, newValue: V) -> V): Map = + mapKeysTo(LinkedHashMap(size), transform, resolve) + +// TODO: Docs +internal inline fun Map.mapKeys(transform: (key: K, value: V) -> L, resolve: (currentValue: V, newValue: V) -> V): Map = + mapKeysTo(LinkedHashMap(size), transform, resolve) \ No newline at end of file diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledConstructors.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledConstructors.kt index aa44660c1..43048089e 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledConstructors.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledConstructors.kt @@ -10,6 +10,7 @@ package space.kscience.kmath.functions import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.Ring +import space.kscience.kmath.operations.invoke /** @@ -76,17 +77,10 @@ public inline fun LabeledPolynomialWithoutCheck(vararg pairs: Pair LabeledPolynomial(coefs: Map, C>, add: (C, C) -> C) : LabeledPolynomial { - val fixedCoefs = mutableMapOf, C>() - - for (entry in coefs) { - val key = entry.key.cleanUp() - val value = entry.value - fixedCoefs[key] = if (key in fixedCoefs) add(fixedCoefs[key]!!, value) else value - } - - return LabeledPolynomial(fixedCoefs) -} +public fun LabeledPolynomial(coefs: Map, C>, add: (C, C) -> C) : LabeledPolynomial = + LabeledPolynomialAsIs( + coefs.mapKeys({ key, _ -> key.cleanUp() }, add) + ) /** * Constructs [LabeledPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient". @@ -98,17 +92,10 @@ public fun LabeledPolynomial(coefs: Map, C>, add: (C, C) - * * @see LabeledPolynomialWithoutCheck */ -public fun LabeledPolynomial(pairs: Collection, C>>, add: (C, C) -> C) : LabeledPolynomial { - val fixedCoefs = mutableMapOf, C>() - - for (entry in pairs) { - val key = entry.first.cleanUp() - val value = entry.second - fixedCoefs[key] = if (key in fixedCoefs) add(fixedCoefs[key]!!, value) else value - } - - return LabeledPolynomial(fixedCoefs) -} +public fun LabeledPolynomial(pairs: Collection, C>>, add: (C, C) -> C) : LabeledPolynomial = + LabeledPolynomialAsIs( + pairs.associateBy({ it.first.cleanUp() }, { it.second }, add) + ) /** * Constructs [LabeledPolynomial] with provided array [pairs] of pairs "term's signature — term's coefficient". @@ -120,17 +107,10 @@ public fun LabeledPolynomial(pairs: Collection, C>>, * * @see LabeledPolynomialWithoutCheck */ -public fun LabeledPolynomial(vararg pairs: Pair, C>, add: (C, C) -> C) : LabeledPolynomial { - val fixedCoefs = mutableMapOf, C>() - - for (entry in pairs) { - val key = entry.first.cleanUp() - val value = entry.second - fixedCoefs[key] = if (key in fixedCoefs) add(fixedCoefs[key]!!, value) else value - } - - return LabeledPolynomial(fixedCoefs) -} +public fun LabeledPolynomial(vararg pairs: Pair, C>, add: (C, C) -> C) : LabeledPolynomial = + LabeledPolynomialAsIs( + pairs.asIterable().associateBy({ it.first.cleanUp() }, { it.second }, add) + ) // Waiting for context receivers :( FIXME: Replace with context receivers when they will be available @@ -304,7 +284,7 @@ public class DSL1LabeledPolynomialTermSignatureBuilder { */ public infix fun Symbol.inPowerOf(deg: UInt) { if (deg == 0u) return - signature[this] = signature.getOrElse(this) { 0u } + deg + signature.putOrChange(this, deg) { it -> it + deg } } /** * Declares power of [this] variable of degree [deg]. @@ -362,7 +342,7 @@ public class DSL1LabeledPolynomialBuilder( * coefficients is zero at any moment the monomial won't be removed but will be left as it is. */ public infix fun C.with(signature: Map) { - coefficients[signature] = if (signature in coefficients) add(coefficients[signature]!!, this@with) else this@with + coefficients.putOrChange(signature, this@with, add) } /** * Declares monomial with [this] coefficient and signature constructed by [block]. diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledUtil.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledUtil.kt index e3b35facc..a37a1fe39 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledUtil.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledUtil.kt @@ -7,10 +7,7 @@ package space.kscience.kmath.functions import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.Field -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.algebra -import space.kscience.kmath.operations.invoke +import space.kscience.kmath.operations.* import kotlin.contracts.InvocationKind import kotlin.contracts.contract import kotlin.jvm.JvmName @@ -56,7 +53,7 @@ public fun LabeledPolynomial.substitute(args: Map): Labe val deg = degs.getOrElse(variable) { 0u } if (deg == 0u) product else product * power(substitution, deg) } - this[newDegs] = if (newDegs in this) this[newDegs]!! + newC else newC + putOrChange(newDegs, newC, ::add) } } ) @@ -75,7 +72,7 @@ public fun LabeledPolynomial.substitute(ring: Ring, args: Map> LabeledPolynomial.antiderivativeWithRespectTo( buildMap(coefficients.size) { coefficients .forEach { (degs, c) -> - val newDegs = buildMap(degs.size + 1) { - put(variable, 1u) - for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) - } + val newDegs = degs.withPutOrChanged(variable, 1u) { it -> it + 1u } put( newDegs, c / multiplyByDoubling(one, newDegs[variable]!!) @@ -284,10 +278,7 @@ public fun > LabeledPolynomial.nthAntiderivativeWithRespectTo buildMap(coefficients.size) { coefficients .forEach { (degs, c) -> - val newDegs = buildMap(degs.size + 1) { - put(variable, order) - for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) - } + val newDegs = degs.withPutOrChanged(variable, order) { it -> it + order } put( newDegs, newDegs[variable]!!.let { deg -> @@ -314,10 +305,7 @@ public fun > LabeledPolynomial.nthAntiderivativeWithRespectTo buildMap(coefficients.size) { coefficients .forEach { (degs, c) -> - val newDegs = buildMap(degs.size + 1) { - for ((variable, order) in filteredVariablesAndOrders) put(variable, order) - for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) - } + val newDegs = mergeBy(degs, filteredVariablesAndOrders) { deg, order -> deg + order } put( newDegs, filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/numberedConstructors.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/numberedConstructors.kt index ce0db3d17..ce49088ae 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/numberedConstructors.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/numberedConstructors.kt @@ -75,17 +75,10 @@ public inline fun NumberedPolynomialWithoutCheck(vararg pairs: Pair NumberedPolynomial(coefs: Map, C>, add: (C, C) -> C) : NumberedPolynomial { - val fixedCoefs = mutableMapOf, C>() - - for (entry in coefs) { - val key = entry.key.cleanUp() - val value = entry.value - fixedCoefs[key] = if (key in fixedCoefs) add(fixedCoefs[key]!!, value) else value - } - - return NumberedPolynomial(fixedCoefs) -} +public fun NumberedPolynomial(coefs: Map, C>, add: (C, C) -> C) : NumberedPolynomial = + NumberedPolynomialAsIs( + coefs.mapKeys({ key, _ -> key.cleanUp() }, add) + ) /** * Constructs [NumberedPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient". @@ -97,17 +90,10 @@ public fun NumberedPolynomial(coefs: Map, C>, add: (C, C) -> C) : * * @see NumberedPolynomialWithoutCheck */ -public fun NumberedPolynomial(pairs: Collection, C>>, add: (C, C) -> C) : NumberedPolynomial { - val fixedCoefs = mutableMapOf, C>() - - for (entry in pairs) { - val key = entry.first.cleanUp() - val value = entry.second - fixedCoefs[key] = if (key in fixedCoefs) add(fixedCoefs[key]!!, value) else value - } - - return NumberedPolynomial(fixedCoefs) -} +public fun NumberedPolynomial(pairs: Collection, C>>, add: (C, C) -> C) : NumberedPolynomial = + NumberedPolynomialAsIs( + pairs.associateBy({ it.first.cleanUp() }, { it.second }, add) + ) /** * Constructs [NumberedPolynomial] with provided array [pairs] of pairs "term's signature — term's coefficient". @@ -119,17 +105,10 @@ public fun NumberedPolynomial(pairs: Collection, C>>, add: ( * * @see NumberedPolynomialWithoutCheck */ -public fun NumberedPolynomial(vararg pairs: Pair, C>, add: (C, C) -> C) : NumberedPolynomial { - val fixedCoefs = mutableMapOf, C>() - - for (entry in pairs) { - val key = entry.first.cleanUp() - val value = entry.second - fixedCoefs[key] = if (key in fixedCoefs) add(fixedCoefs[key]!!, value) else value - } - - return NumberedPolynomial(fixedCoefs) -} +public fun NumberedPolynomial(vararg pairs: Pair, C>, add: (C, C) -> C) : NumberedPolynomial = + NumberedPolynomialAsIs( + pairs.asIterable().associateBy({ it.first.cleanUp() }, { it.second }, add) + ) // Waiting for context receivers :( FIXME: Replace with context receivers when they will be available @@ -349,7 +328,7 @@ public class DSL1NumberedPolynomialBuilder( * coefficients is zero at any moment the monomial won't be removed but will be left as it is. */ public infix fun C.with(signature: List) { - coefficients[signature] = if (signature in coefficients) add(coefficients[signature]!!, this@with) else this@with + coefficients.putOrChange(signature, this@with, add) } /** * Declares monomial with [this] coefficient and signature constructed by [block]. diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/numberedUtil.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/numberedUtil.kt index 9d88cd648..9f29cf31a 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/numberedUtil.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/numberedUtil.kt @@ -58,7 +58,7 @@ public fun NumberedPolynomial.substitute(args: Map): Number val deg = degs.getOrElse(variable) { 0u } if (deg == 0u) product else product * substitution.pow(deg.toInt()) } - this[newDegs] = if (newDegs !in this) newC else this[newDegs]!! + newC + putOrChange(newDegs, newC) { it -> it + newC } } } ) @@ -76,7 +76,7 @@ public fun NumberedPolynomial.substitute(ring: Ring, args: Map val deg = degs.getOrElse(variable) { 0u } if (deg == 0u) product else product * power(substitution, deg) } - this[newDegs] = if (newDegs !in this) newC else this[newDegs]!! + newC + putOrChange(newDegs, newC) { it -> it + newC } } } ) @@ -158,8 +158,7 @@ public fun NumberedPolynomial.substitute(args: Buffer): Numbered val deg = degs[variable] if (deg == 0u) product else product * args[variable].pow(deg.toInt()) } - if (newDegs !in this) this[newDegs] = newC - else this[newDegs] = this[newDegs]!! + newC + putOrChange(newDegs, newC) { it -> it + newC } } } ) @@ -183,8 +182,7 @@ public fun NumberedPolynomial.substitute(ring: Ring, args: Buffer): val deg = degs[variable] if (deg == 0u) product else product * power(args[variable], deg) } - if (newDegs !in this) this[newDegs] = newC - else this[newDegs] = this[newDegs]!! + newC + putOrChange(newDegs, newC) { it -> it + newC } } } ) diff --git a/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt index f9a5a041b..1815749ce 100644 --- a/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt +++ b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt @@ -23,8 +23,8 @@ class NumberedConstructorsTest { ), Int.algebra.numberedPolynomialSpace { NumberedPolynomialDSL1 { - 5 { 1 pow 2u; 3 pow 3u } - (-6) { 2 pow 1u } + 5 { 0 pow 2u; 2 pow 3u } + (-6) { 1 pow 1u } } }, "test 1" @@ -47,8 +47,8 @@ class NumberedConstructorsTest { ), Int.algebra.numberedPolynomialSpace { NumberedPolynomialDSL1 { - 5 { 1 pow 1u; 1 pow 1u } - (-6) { 1 pow 2u } + 5 { 0 pow 1u; 0 pow 1u } + (-6) { 0 pow 2u } } }, "test 3" @@ -59,8 +59,8 @@ class NumberedConstructorsTest { ), Int.algebra.numberedPolynomialSpace { NumberedPolynomialDSL1 { - 5 { 1 pow 1u; 1 pow 1u } - (-6) { 1 pow 2u; 3 pow 0u } + 5 { 0 pow 1u; 0 pow 1u } + (-6) { 0 pow 2u; 2 pow 0u } } }, "test 3" -- 2.34.1 From a1a2c41846b5a720cb05ec4bee9c5136c74b55c9 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sat, 16 Jul 2022 17:13:05 +0300 Subject: [PATCH 110/123] Add a bit more utilities for maps and refactor polynomials' code. --- .../LabeledPolynomial.kt | 100 ++++++++---------- .../NumberedPolynomial.kt | 100 +++++++----------- .../collectionUtils.kt | 39 ++++++- 3 files changed, 117 insertions(+), 122 deletions(-) diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledPolynomial.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledPolynomial.kt index b07674a1e..7df51930e 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledPolynomial.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledPolynomial.kt @@ -87,7 +87,7 @@ public class LabeledPolynomialSpace>( ) else LabeledPolynomialAsIs( mapOf(this@plus to 1U) to constantOne, - emptyMap() to constantOne * other, + emptyMap() to other.asConstant(), ) /** * Returns difference between the variable represented as a monic monomial and the integer represented as a constant polynomial. @@ -98,7 +98,7 @@ public class LabeledPolynomialSpace>( ) else LabeledPolynomialAsIs( mapOf(this@minus to 1U) to constantOne, - emptyMap() to constantOne * -other, + emptyMap() to (-other).asConstant(), ) /** * Returns product of the variable represented as a monic monomial and the integer represented as a constant polynomial. @@ -106,7 +106,7 @@ public class LabeledPolynomialSpace>( public override operator fun Symbol.times(other: Int): LabeledPolynomial = if (other == 0) zero else LabeledPolynomialAsIs( - mapOf(this to 1U) to constantOne * other, + mapOf(this to 1U) to other.asConstant(), ) /** @@ -118,7 +118,7 @@ public class LabeledPolynomialSpace>( ) else LabeledPolynomialAsIs( mapOf(other to 1U) to constantOne, - emptyMap() to constantOne * this@plus, + emptyMap() to this@plus.asConstant(), ) /** * Returns difference between the integer represented as a constant polynomial and the variable represented as a monic monomial. @@ -137,7 +137,7 @@ public class LabeledPolynomialSpace>( public override operator fun Int.times(other: Symbol): LabeledPolynomial = if (this == 0) zero else LabeledPolynomialAsIs( - mapOf(other to 1U) to constantOne * this@times, + mapOf(other to 1U) to this@times.asConstant(), ) /** @@ -146,11 +146,11 @@ public class LabeledPolynomialSpace>( * The operation is equivalent to adding [other] copies of unit polynomial to [this]. */ public override operator fun LabeledPolynomial.plus(other: Int): LabeledPolynomial = - if (other == 0) this - else with(coefficients) { - if (isEmpty()) other.asPolynomial() - else LabeledPolynomialAsIs( - withPutOrChanged(emptyMap(), other.asConstant()) { it -> it + other } + when { + other == 0 -> this + coefficients.isEmpty() -> other.asPolynomial() + else -> LabeledPolynomialAsIs( + coefficients.withPutOrChanged(emptyMap(), other.asConstant()) { it -> it + other } ) } /** @@ -159,11 +159,11 @@ public class LabeledPolynomialSpace>( * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. */ public override operator fun LabeledPolynomial.minus(other: Int): LabeledPolynomial = - if (other == 0) this - else with(coefficients) { - if (isEmpty()) (-other).asPolynomial() - else LabeledPolynomialAsIs( - withPutOrChanged(emptyMap(), (-other).asConstant()) { it -> it - other } + when { + other == 0 -> this + coefficients.isEmpty() -> other.asPolynomial() + else -> LabeledPolynomialAsIs( + coefficients.withPutOrChanged(emptyMap(), (-other).asConstant()) { it -> it - other } ) } /** @@ -186,11 +186,11 @@ public class LabeledPolynomialSpace>( * The operation is equivalent to adding [this] copies of unit polynomial to [other]. */ public override operator fun Int.plus(other: LabeledPolynomial): LabeledPolynomial = - if (this == 0) other - else with(other.coefficients) { - if (isEmpty()) this@plus.asPolynomial() - else LabeledPolynomialAsIs( - withPutOrChanged(emptyMap(), this@plus.asConstant()) { it -> this@plus + it } + when { + this == 0 -> other + other.coefficients.isEmpty() -> this@plus.asPolynomial() + else -> LabeledPolynomialAsIs( + other.coefficients.withPutOrChanged(emptyMap(), this@plus.asConstant()) { it -> this@plus + it } ) } /** @@ -275,12 +275,10 @@ public class LabeledPolynomialSpace>( * Returns sum of the constant represented as a polynomial and the polynomial. */ override operator fun C.plus(other: LabeledPolynomial): LabeledPolynomial = - with(other.coefficients) { - if (isEmpty()) this@plus.asLabeledPolynomial() - else LabeledPolynomialAsIs( - withPutOrChanged(emptyMap(), this@plus) { it -> this@plus + it } - ) - } + if (other.coefficients.isEmpty()) this@plus.asLabeledPolynomial() + else LabeledPolynomialAsIs( + other.coefficients.withPutOrChanged(emptyMap(), this@plus) { it -> this@plus + it } + ) /** * Returns difference between the constant represented as a polynomial and the polynomial. */ @@ -304,22 +302,18 @@ public class LabeledPolynomialSpace>( * Returns sum of the constant represented as a polynomial and the polynomial. */ override operator fun LabeledPolynomial.plus(other: C): LabeledPolynomial = - with(coefficients) { - if (isEmpty()) other.asLabeledPolynomial() - else LabeledPolynomialAsIs( - withPutOrChanged(emptyMap(), other) { it -> it + other } - ) - } + if (coefficients.isEmpty()) other.asLabeledPolynomial() + else LabeledPolynomialAsIs( + coefficients.withPutOrChanged(emptyMap(), other) { it -> it + other } + ) /** * Returns difference between the constant represented as a polynomial and the polynomial. */ override operator fun LabeledPolynomial.minus(other: C): LabeledPolynomial = - with(coefficients) { - if (isEmpty()) other.asLabeledPolynomial() - else LabeledPolynomialAsIs( - withPutOrChanged(emptyMap(), -other) { it -> it - other } - ) - } + if (coefficients.isEmpty()) other.asLabeledPolynomial() + else LabeledPolynomialAsIs( + coefficients.withPutOrChanged(emptyMap(), -other) { it -> it - other } + ) /** * Returns product of the constant represented as a polynomial and the polynomial. */ @@ -382,12 +376,10 @@ public class LabeledPolynomialSpace>( * Returns sum of the variable represented as a monic monomial and the polynomial. */ public override operator fun Symbol.plus(other: LabeledPolynomial): LabeledPolynomial = - with(other.coefficients) { - if (isEmpty()) this@plus.asPolynomial() - else LabeledPolynomialAsIs( - withPutOrChanged(mapOf(this@plus to 1U), constantOne) { it -> constantOne + it } - ) - } + if (other.coefficients.isEmpty()) this@plus.asPolynomial() + else LabeledPolynomialAsIs( + other.coefficients.withPutOrChanged(mapOf(this@plus to 1U), constantOne) { it -> constantOne + it } + ) /** * Returns difference between the variable represented as a monic monomial and the polynomial. */ @@ -412,22 +404,18 @@ public class LabeledPolynomialSpace>( * Returns sum of the polynomial and the variable represented as a monic monomial. */ public override operator fun LabeledPolynomial.plus(other: Symbol): LabeledPolynomial = - with(coefficients) { - if (isEmpty()) other.asPolynomial() - else LabeledPolynomialAsIs( - withPutOrChanged(mapOf(other to 1U), constantOne) { it -> it + constantOne } - ) - } + if (coefficients.isEmpty()) other.asPolynomial() + else LabeledPolynomialAsIs( + coefficients.withPutOrChanged(mapOf(other to 1U), constantOne) { it -> it + constantOne } + ) /** * Returns difference between the polynomial and the variable represented as a monic monomial. */ public override operator fun LabeledPolynomial.minus(other: Symbol): LabeledPolynomial = - with(coefficients) { - if (isEmpty()) other.asPolynomial() - else LabeledPolynomialAsIs( - withPutOrChanged(mapOf(other to 1U), -constantOne) { it -> it - constantOne } - ) - } + if (coefficients.isEmpty()) other.asPolynomial() + else LabeledPolynomialAsIs( + coefficients.withPutOrChanged(mapOf(other to 1U), -constantOne) { it -> it - constantOne } + ) /** * Returns product of the polynomial and the variable represented as a monic monomial. */ diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedPolynomial.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedPolynomial.kt index 14c03ff7c..037419cfc 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedPolynomial.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedPolynomial.kt @@ -69,10 +69,9 @@ public class NumberedPolynomialSpace>( */ public override operator fun NumberedPolynomial.plus(other: Int): NumberedPolynomial = if (other == 0) this - else - NumberedPolynomialAsIs( - coefficients.withPutOrChanged(emptyList(), other.asConstant()) { it -> it + other } - ) + else NumberedPolynomialAsIs( + coefficients.withPutOrChanged(emptyList(), other.asConstant()) { it -> it + other } + ) /** * Returns difference between the polynomial and the integer represented as a polynomial. * @@ -80,10 +79,9 @@ public class NumberedPolynomialSpace>( */ public override operator fun NumberedPolynomial.minus(other: Int): NumberedPolynomial = if (other == 0) this - else - NumberedPolynomialAsIs( - coefficients.withPutOrChanged(emptyList(), (-other).asConstant()) { it -> it - other } - ) + else NumberedPolynomialAsIs( + coefficients.withPutOrChanged(emptyList(), (-other).asConstant()) { it -> it - other } + ) /** * Returns product of the polynomial and the integer represented as a polynomial. * @@ -105,31 +103,25 @@ public class NumberedPolynomialSpace>( */ public override operator fun Int.plus(other: NumberedPolynomial): NumberedPolynomial = if (this == 0) other - else - NumberedPolynomialAsIs( - other.coefficients.withPutOrChanged(emptyList(), this@plus.asConstant()) { it -> this@plus + it } - ) + else NumberedPolynomialAsIs( + other.coefficients.withPutOrChanged(emptyList(), this@plus.asConstant()) { it -> this@plus + it } + ) /** * Returns difference between the integer represented as a polynomial and the polynomial. * * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. */ public override operator fun Int.minus(other: NumberedPolynomial): NumberedPolynomial = - NumberedPolynomialAsIs( - other.coefficients - .toMutableMap() - .apply { - if (this@minus == 0) { - forEach { (key, value) -> this[key] = -value } - } else { - forEach { (key, value) -> if (key.isNotEmpty()) this[key] = -value } - - val degs = emptyList() - - this[degs] = this@minus - getOrElse(degs) { constantZero } - } + when { + this == 0 -> -other + other.coefficients.isEmpty() -> this.asPolynomial() + else -> NumberedPolynomialAsIs( + buildMap(other.coefficients.size + 1) { + put(emptyList(), other.coefficients.computeOnOrElse(emptyList(), { this@minus.asConstant() }, { it -> this@minus - it})) + other.coefficients.copyMapToBy(this, { _, c -> -c }) { currentC, _ -> currentC } } ) + } /** * Returns product of the integer represented as a polynomial and the polynomial. * @@ -148,29 +140,21 @@ public class NumberedPolynomialSpace>( * Returns sum of the constant represented as a polynomial and the polynomial. */ override operator fun C.plus(other: NumberedPolynomial): NumberedPolynomial = - with(other.coefficients) { - if (isEmpty()) NumberedPolynomialAsIs(mapOf(emptyList() to this@plus)) - else NumberedPolynomialAsIs( - withPutOrChanged(emptyList(), this@plus) { it -> this@plus + it } - ) - } + if (other.coefficients.isEmpty()) this@plus.asPolynomial() + else NumberedPolynomialAsIs( + other.coefficients.withPutOrChanged(emptyList(), this@plus) { it -> this@plus + it } + ) /** * Returns difference between the constant represented as a polynomial and the polynomial. */ override operator fun C.minus(other: NumberedPolynomial): NumberedPolynomial = - with(other.coefficients) { - if (isEmpty()) NumberedPolynomialAsIs(mapOf(emptyList() to this@minus)) - else NumberedPolynomialAsIs( - toMutableMap() - .apply { - forEach { (degs, c) -> if (degs.isNotEmpty()) this[degs] = -c } - - val degs = emptyList() - - this[degs] = this@minus - getOrElse(degs) { constantZero } - } - ) - } + if (other.coefficients.isEmpty()) this@minus.asPolynomial() + else NumberedPolynomialAsIs( + buildMap(other.coefficients.size) { + put(emptyList(), other.coefficients.computeOnOrElse(emptyList(), this@minus) { it -> this@minus - it }) + other.coefficients.copyMapToBy(this, { _, c -> -c }, { currentC, _ -> currentC }) + } + ) /** * Returns product of the constant represented as a polynomial and the polynomial. */ @@ -183,22 +167,18 @@ public class NumberedPolynomialSpace>( * Returns sum of the constant represented as a polynomial and the polynomial. */ override operator fun NumberedPolynomial.plus(other: C): NumberedPolynomial = - with(coefficients) { - if (isEmpty()) NumberedPolynomialAsIs(mapOf(emptyList() to other)) - else NumberedPolynomialAsIs( - withPutOrChanged(emptyList(), other) { it -> it + other } - ) - } + if (coefficients.isEmpty()) other.asPolynomial() + else NumberedPolynomialAsIs( + coefficients.withPutOrChanged(emptyList(), other) { it -> it + other } + ) /** * Returns difference between the constant represented as a polynomial and the polynomial. */ override operator fun NumberedPolynomial.minus(other: C): NumberedPolynomial = - with(coefficients) { - if (isEmpty()) NumberedPolynomialAsIs(mapOf(emptyList() to other)) - else NumberedPolynomialAsIs( - withPutOrChanged(emptyList(), -other) { it -> it - other } - ) - } + if (coefficients.isEmpty()) other.asPolynomial() + else NumberedPolynomialAsIs( + coefficients.withPutOrChanged(emptyList(), -other) { it -> it - other } + ) /** * Returns product of the constant represented as a polynomial and the polynomial. */ @@ -264,13 +244,7 @@ public class NumberedPolynomialSpace>( /** * Instance of unit polynomial (unit of the polynomial ring). */ - override val one: NumberedPolynomial by lazy { - NumberedPolynomialAsIs( - mapOf( - emptyList() to constantOne // 1 * x_1^0 * x_2^0 * ... - ) - ) - } + override val one: NumberedPolynomial by lazy { NumberedPolynomialAsIs(mapOf(emptyList() to constantOne)) } /** * Maximal index (ID) of variable occurring in the polynomial with positive power. If there is no such variable, diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/collectionUtils.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/collectionUtils.kt index 1d3da4c8b..ee32aa9a7 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/collectionUtils.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/collectionUtils.kt @@ -9,6 +9,40 @@ import kotlin.contracts.InvocationKind.* import kotlin.contracts.contract +// TODO: Docs +internal inline fun Map.computeOn(key: K, compute: (V?) -> R): R { + contract { + callsInPlace(compute, EXACTLY_ONCE) + } + return compute(get(key)) +} + +// TODO: Docs +internal inline fun Map.computeOnOrElse(key: K, defaultResult: () -> R, compute: (value: V) -> R): R { + contract { + callsInPlace(defaultResult, AT_MOST_ONCE) + callsInPlace(compute, AT_MOST_ONCE) + } + @Suppress("UNCHECKED_CAST") + return (if (key !in this) defaultResult() else compute(get(key) as V)) +} + +// TODO: Docs +internal inline fun Map.computeOnOrElse(key: K, defaultResult: R, compute: (value: V) -> R): R { + contract { + callsInPlace(compute, AT_MOST_ONCE) + } + return computeOnOrElse(key, { defaultResult }, compute) +} + +// TODO: Docs +internal inline fun Map.computeOnOrElse(key: K, defaultResult: R, compute: (key: K, value: V) -> R): R { + contract { + callsInPlace(compute, AT_MOST_ONCE) + } + return computeOnOrElse(key, { defaultResult }, { it -> compute(key, it) }) +} + /** * Applies the [transformation][transform] to the value corresponding to the given [key] or null instead if it's not * present. @@ -21,7 +55,7 @@ internal inline fun MutableMap.applyToKey(key: K, transform: (cu contract { callsInPlace(transform, EXACTLY_ONCE) } - return transform(get(key)).also { this[key] = it } + return computeOn(key, transform).also { this[key] = it } } /** @@ -39,8 +73,7 @@ internal inline fun MutableMap.putOrChange(key: K, valueOnPut: () - callsInPlace(valueOnPut, AT_MOST_ONCE) callsInPlace(transformOnChange, AT_MOST_ONCE) } - @Suppress("UNCHECKED_CAST") - return (if (key !in this) valueOnPut() else transformOnChange(get(key) as V)).also { this[key] = it } + return computeOnOrElse(key, valueOnPut, transformOnChange).also { this[key] = it } } /** -- 2.34.1 From 3a91cb2579862e7ef9d617a46d6c8b44c8e61438 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sat, 16 Jul 2022 18:46:40 +0300 Subject: [PATCH 111/123] Draft another DSL for labeled polynomials. Add variance. --- .../LabeledPolynomial.kt | 2 +- .../ListPolynomial.kt | 4 +- .../NumberedPolynomial.kt | 2 +- .../Polynomial.kt | 2 +- .../RationalFunction.kt | 6 +- .../labeledConstructors.kt | 255 ++++++++++++++++++ 6 files changed, 263 insertions(+), 8 deletions(-) diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledPolynomial.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledPolynomial.kt index 7df51930e..e2320114b 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledPolynomial.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledPolynomial.kt @@ -75,7 +75,7 @@ internal constructor( * @param A type of provided underlying ring of constants. It's [Ring] of [C]. * @param ring underlying ring of constants of type [A]. */ -public class LabeledPolynomialSpace>( +public class LabeledPolynomialSpace>( public override val ring: A, ) : MultivariatePolynomialSpace>, PolynomialSpaceOverRing, A> { /** diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/ListPolynomial.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/ListPolynomial.kt index 17c42ac8c..d0e58c0d6 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/ListPolynomial.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/ListPolynomial.kt @@ -60,7 +60,7 @@ public data class ListPolynomial( * @param A type of provided underlying ring of constants. It's [Ring] of [C]. * @param ring underlying ring of constants of type [A]. */ -public open class ListPolynomialSpace>( +public open class ListPolynomialSpace>( public override val ring: A, ) : PolynomialSpaceOverRing, A> { /** @@ -366,7 +366,7 @@ public open class ListPolynomialSpace>( * @param A type of underlying ring of constants. It's [Ring] of [C]. * @param ring underlying ring of constants of type [A]. */ -public class ScalableListPolynomialSpace( +public class ScalableListPolynomialSpace( ring: A, ) : ListPolynomialSpace(ring), ScaleOperations> where A : Ring, A : ScaleOperations { override fun scale(a: ListPolynomial, value: Double): ListPolynomial = diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedPolynomial.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedPolynomial.kt index 037419cfc..d2fc5ffa1 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedPolynomial.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedPolynomial.kt @@ -59,7 +59,7 @@ internal constructor( * @param A type of provided underlying ring of constants. It's [Ring] of [C]. * @param ring underlying ring of constants of type [A]. */ -public class NumberedPolynomialSpace>( +public class NumberedPolynomialSpace>( public override val ring: A, ) : PolynomialSpaceOverRing, A> { /** diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/Polynomial.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/Polynomial.kt index 61ea5a342..66308a7bc 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/Polynomial.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/Polynomial.kt @@ -252,7 +252,7 @@ public interface PolynomialSpace> : Ring

{ * @param A the type of algebraic structure (precisely, of ring) provided for constants. */ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 -public interface PolynomialSpaceOverRing, A: Ring> : PolynomialSpace { +public interface PolynomialSpaceOverRing, out A: Ring> : PolynomialSpace { /** * Underlying ring of constants. Its operations on constants are inherited by local operations on constants. diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/RationalFunction.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/RationalFunction.kt index f664ae9db..da91c8d61 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/RationalFunction.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/RationalFunction.kt @@ -464,7 +464,7 @@ public interface RationalFunctionSpaceOverRing< C, P: Polynomial, R: RationalFunction, - A: Ring + out A: Ring > : RationalFunctionSpace { /** @@ -566,7 +566,7 @@ public interface RationalFunctionSpaceOverPolynomialSpace< C, P: Polynomial, R: RationalFunction, - AP: PolynomialSpace, + out AP: PolynomialSpace, > : RationalFunctionSpace { /** @@ -1341,7 +1341,7 @@ public interface MultivariateRationalFunctionSpaceOverMultivariatePolynomialSpac V, P: Polynomial, R: RationalFunction, - AP: MultivariatePolynomialSpace, + out AP: MultivariatePolynomialSpace, > : RationalFunctionSpaceOverPolynomialSpace, MultivariateRationalFunctionSpace { /** * Returns sum of the variable represented as a monic monomial and the integer represented as a constant polynomial. diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledConstructors.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledConstructors.kt index 43048089e..d74c0e1fb 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledConstructors.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledConstructors.kt @@ -416,6 +416,261 @@ public inline fun > LabeledPolynomialSpace.LabeledPolynomial @UnstableKMathAPI public inline fun > LabeledRationalFunctionSpace.LabeledPolynomialDSL1(initialCapacity: Int? = null, block: DSL1LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = DSL1LabeledPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() +/** + * Marks DSL that allows to more simply create [LabeledPolynomial]s with good performance. + * + * For example, polynomial \(5 a^2 c^3 - 6 b\) can be described as + * ``` + * Int.algebra { + * val numberedPolynomial : NumberedPolynomial = NumberedPolynomial { + * 5 { a inPowerOf 2u; c inPowerOf 3u } // 5 a^2 c^3 + + * (-6) { b inPowerOf 1u } // (-6) b^1 + * } + * } + * ``` + * @usesMathJax + */ +@DslMarker +@UnstableKMathAPI +internal annotation class LabeledPolynomialBuilderDSL2 + +/** + * Builder of [LabeledPolynomial]. It should be used as an implicit context for lambdas that describe [LabeledPolynomial]. + */ +@UnstableKMathAPI +@LabeledPolynomialBuilderDSL2 +public class DSL2LabeledPolynomialBuilder( + private val ring: Ring, + /** + * Initial capacity of coefficients map. + */ + initialCapacity: Int? = null +) { + /** + * Coefficients storage. Any declaration of any monomial updates the storage. + * Afterward the storage will be used as a resulting coefficients map. + */ + private val coefficients: MutableMap, C> = if (initialCapacity != null) LinkedHashMap(initialCapacity) else LinkedHashMap() + + /** + * Builds the resulting coefficients map. + * + * In fact, it just returns [coefficients] as regular coefficients map of type `Map, C>`. + */ + @PublishedApi + internal fun build(): LabeledPolynomial = LabeledPolynomial(coefficients) + + public inner class Term internal constructor( + internal val signature: Map = HashMap(), + internal val coefficient: C + ) + + private inline fun submit(signature: Map, onPut: Ring.() -> C, onChange: Ring.(C) -> C) { + coefficients.putOrChange<_, C>(signature, { ring.onPut() }, { ring.onChange(it) }) + } + + private inline fun submit(signature: Map, lazyCoefficient: Ring.() -> C) { + submit(signature, lazyCoefficient, { it + lazyCoefficient() }) + } + + private fun submit(signature: Map, coefficient: C) { + submit(signature) { coefficient } + } + + // TODO: `@submit` will be resolved differently. Change it to `@C`. + private fun C.submit() = submit(emptyMap(), { this@submit }) + + private fun Symbol.submit() = submit(mapOf(this to 1u), { one }) + + private fun Term.submit(): Submit { + submit(signature, coefficient) + return Submit + } + + public object Submit + + public operator fun C.unaryPlus(): Submit { + submit() + return Submit + } + + public operator fun C.unaryMinus(): Submit { + submit(emptyMap(), { -this@unaryMinus }, { it - this@unaryMinus }) + return Submit + } + + public operator fun C.plus(other: C): Submit { + submit(emptyMap(), { this@plus + other }) + return Submit + } + + public operator fun C.minus(other: C): Submit { + submit(emptyMap(), { this@minus - other }) + return Submit + } + + public operator fun C.times(other: C): C = ring { this@times * other } + + public operator fun C.plus(other: Symbol): Submit { + submit(emptyMap(), this) + submit(mapOf(other to 1u), ring.one) + return Submit + } + + public operator fun C.minus(other: Symbol): Submit { + submit(emptyMap(), this) + submit(mapOf(other to 1u), { -one }, { it - one }) + return Submit + } + + public operator fun C.times(other: Symbol): Term = Term(mapOf(other to 1u), this) + + public operator fun C.plus(other: Term): Submit { + submit(emptyMap(), this) + other.submit() + return Submit + } + + public operator fun C.minus(other: Term): Submit { + submit(emptyMap(), this) + submit(other.signature, { -other.coefficient }, { it - other.coefficient }) + return Submit + } + + public operator fun C.times(other: Term): Term = Term(other.signature, ring { this@times * other.coefficient }) + + public operator fun Symbol.plus(other: C): Submit { + this.submit() + other.submit() + return Submit + } + + public operator fun Symbol.minus(other: C): Submit { + this.submit() + submit(emptyMap(), { -other }, { it - other }) + return Submit + } + + public operator fun Symbol.times(other: C): Term = Term(mapOf(this to 1u), other) + + public operator fun Symbol.unaryPlus(): Submit { + this.submit() + return Submit + } + + public operator fun Symbol.unaryMinus(): Submit { + submit(mapOf(this to 1u), { -one }, { it - one }) + return Submit + } + + public operator fun Symbol.plus(other: Symbol): Submit { + this.submit() + other.submit() + return Submit + } + + public operator fun Symbol.minus(other: Symbol): Submit { + this.submit() + submit(mapOf(other to 1u), { -one }, { it - one }) + return Submit + } + + public operator fun Symbol.times(other: Symbol): Term = + if (this == other) Term(mapOf(this to 2u), ring.one) + else Term(mapOf(this to 1u, other to 1u), ring.one) + + public operator fun Symbol.plus(other: Term): Submit { + this.submit() + other.submit() + return Submit + } + + public operator fun Symbol.minus(other: Term): Submit { + this.submit() + submit(other.signature, { -other.coefficient }, { it - other.coefficient }) + return Submit + } + + public operator fun Symbol.times(other: Term): Term = + Term( + other.signature.withPutOrChanged(this, 1u) { it -> it + 1u }, + other.coefficient + ) + + public operator fun Term.plus(other: C): Submit { + this.submit() + other.submit() + return Submit + } + + public operator fun Term.minus(other: C): Submit { + this.submit() + submit(emptyMap(), { -other }, { it - other }) + return Submit + } + + public operator fun Term.times(other: C): Term = + Term( + signature, + ring { coefficient * other } + ) + + public operator fun Term.plus(other: Symbol): Submit { + this.submit() + other.submit() + return Submit + } + + public operator fun Term.minus(other: Symbol): Submit { + this.submit() + submit(mapOf(other to 1u), { -one }, { it - one }) + return Submit + } + + public operator fun Term.times(other: Symbol): Term = + Term( + signature.withPutOrChanged(other, 1u) { it -> it + 1u }, + coefficient + ) + + public operator fun Term.unaryPlus(): Submit { + this.submit() + return Submit + } + + public operator fun Term.unaryMinus(): Submit { + submit(signature, { -coefficient }, { it - coefficient }) + return Submit + } + + public operator fun Term.plus(other: Term): Submit { + this.submit() + other.submit() + return Submit + } + + public operator fun Term.minus(other: Term): Submit { + this.submit() + submit(other.signature, { -other.coefficient }, { it - other.coefficient }) + return Submit + } + + public operator fun Term.times(other: Term): Term = + Term( + mergeBy(signature, other.signature) { deg1, deg2 -> deg1 + deg2 }, + ring { coefficient * other.coefficient } + ) +} + +//@UnstableKMathAPI +//public fun Ring.LabeledPolynomialDSL2(initialCapacity: Int? = null, block: DSL2LabeledPolynomialBuilder.() -> Unit): LabeledPolynomial = DSL2LabeledPolynomialBuilder(this, initialCapacity).apply(block).build() + +@UnstableKMathAPI +public fun > LabeledPolynomialSpace.LabeledPolynomialDSL2(initialCapacity: Int? = null, block: DSL2LabeledPolynomialBuilder.() -> Unit): LabeledPolynomial = DSL2LabeledPolynomialBuilder(ring, initialCapacity).apply(block).build() + +@UnstableKMathAPI +public fun > LabeledRationalFunctionSpace.LabeledPolynomialDSL2(initialCapacity: Int? = null, block: DSL2LabeledPolynomialBuilder.() -> Unit): LabeledPolynomial = DSL2LabeledPolynomialBuilder(ring, initialCapacity).apply(block).build() + // Waiting for context receivers :( FIXME: Replace with context receivers when they will be available /** -- 2.34.1 From 58d7015782bc24c12e11ff2c84d0fe2c631a3c59 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sat, 16 Jul 2022 20:15:30 +0300 Subject: [PATCH 112/123] Remove utils modules. Revive suddenly lost tests. --- kmath-functions/build.gradle.kts | 5 - .../kmath/functions/testUtils/IntModulo.kt | 38 +- .../functions/testUtils/IntModuloUtils.kt | 8 +- .../kmath/functions/testUtils/Rational.kt | 54 +- .../kmath/functions/testUtils/misc.kt | 0 kmath-polynomial/build.gradle.kts | 6 - .../kmath/functions/AlgebraicStubTest.kt | 589 +++++++++++ .../kmath/functions/ListPolynomialTest.kt | 544 ++++++++++ .../kmath/functions/ListPolynomialUtilTest.kt | 982 ++++++++++++++++++ .../kmath/functions/testUtils/BufferUtils.kt | 2 +- .../kmath/functions/testUtils/IntModulo.kt | 38 +- .../functions/testUtils/IntModuloUtils.kt | 9 +- .../kmath/functions/testUtils/NTMisc.kt | 0 .../kmath/functions/testUtils/Rational.kt | 54 +- .../kmath/functions/testUtils/assertion.kt | 12 +- .../kmath/functions/testUtils/misc.kt | 14 +- settings.gradle.kts | 2 - test-utils-functions/build.gradle.kts | 14 - .../kmath/functions/testUtils/assertion.kt | 22 - test-utils-polynomial/build.gradle.kts | 14 - 20 files changed, 2229 insertions(+), 178 deletions(-) rename {test-utils-functions/src/commonMain => kmath-functions/src/commonTest}/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt (80%) rename {test-utils-functions/src/commonMain => kmath-functions/src/commonTest}/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt (54%) rename {test-utils-polynomial/src/commonMain => kmath-functions/src/commonTest}/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt (78%) rename {test-utils-functions/src/commonMain => kmath-functions/src/commonTest}/kotlin/space/kscience/kmath/functions/testUtils/misc.kt (100%) create mode 100644 kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/AlgebraicStubTest.kt create mode 100644 kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt create mode 100644 kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt rename {test-utils-polynomial/src/commonMain => kmath-polynomial/src/commonTest}/kotlin/space/kscience/kmath/functions/testUtils/BufferUtils.kt (80%) rename {test-utils-polynomial/src/commonMain => kmath-polynomial/src/commonTest}/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt (79%) rename {test-utils-polynomial/src/commonMain => kmath-polynomial/src/commonTest}/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt (53%) rename {test-utils-polynomial/src/commonMain => kmath-polynomial/src/commonTest}/kotlin/space/kscience/kmath/functions/testUtils/NTMisc.kt (100%) rename {test-utils-functions/src/commonMain => kmath-polynomial/src/commonTest}/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt (78%) rename {test-utils-polynomial/src/commonMain => kmath-polynomial/src/commonTest}/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt (92%) rename {test-utils-polynomial/src/commonMain => kmath-polynomial/src/commonTest}/kotlin/space/kscience/kmath/functions/testUtils/misc.kt (58%) delete mode 100644 test-utils-functions/build.gradle.kts delete mode 100644 test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt delete mode 100644 test-utils-polynomial/build.gradle.kts diff --git a/kmath-functions/build.gradle.kts b/kmath-functions/build.gradle.kts index 149a8f277..eec17e82b 100644 --- a/kmath-functions/build.gradle.kts +++ b/kmath-functions/build.gradle.kts @@ -12,11 +12,6 @@ kotlin.sourceSets { api(project(":kmath-core")) } } - commonTest { - dependencies { - api(projects.testUtilsFunctions) - } - } } dependencies { diff --git a/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt similarity index 80% rename from test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt rename to kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt index 21095d858..ef601c941 100644 --- a/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt @@ -11,9 +11,9 @@ import space.kscience.kmath.operations.Ring import space.kscience.kmath.operations.ScaleOperations -public class IntModulo { - public val residue: Int - public val modulus: Int +class IntModulo { + val residue: Int + val modulus: Int @PublishedApi internal constructor(residue: Int, modulus: Int, toCheckInput: Boolean = true) { @@ -27,16 +27,16 @@ public class IntModulo { } } - public constructor(residue: Int, modulus: Int) : this(residue, modulus, true) + constructor(residue: Int, modulus: Int) : this(residue, modulus, true) - public operator fun unaryPlus(): IntModulo = this - public operator fun unaryMinus(): IntModulo = + operator fun unaryPlus(): IntModulo = this + operator fun unaryMinus(): IntModulo = IntModulo( if (residue == 0) 0 else modulus - residue, modulus, toCheckInput = false ) - public operator fun plus(other: IntModulo): IntModulo { + operator fun plus(other: IntModulo): IntModulo { require(modulus == other.modulus) { "can not add two residue different modulo" } return IntModulo( (residue + other.residue) % modulus, @@ -44,13 +44,13 @@ public class IntModulo { toCheckInput = false ) } - public operator fun plus(other: Int): IntModulo = + operator fun plus(other: Int): IntModulo = IntModulo( (residue + other) % modulus, modulus, toCheckInput = false ) - public operator fun minus(other: IntModulo): IntModulo { + operator fun minus(other: IntModulo): IntModulo { require(modulus == other.modulus) { "can not subtract two residue different modulo" } return IntModulo( (residue - other.residue) % modulus, @@ -58,13 +58,13 @@ public class IntModulo { toCheckInput = false ) } - public operator fun minus(other: Int): IntModulo = + operator fun minus(other: Int): IntModulo = IntModulo( (residue - other) % modulus, modulus, toCheckInput = false ) - public operator fun times(other: IntModulo): IntModulo { + operator fun times(other: IntModulo): IntModulo { require(modulus == other.modulus) { "can not multiply two residue different modulo" } return IntModulo( (residue * other.residue) % modulus, @@ -72,13 +72,13 @@ public class IntModulo { toCheckInput = false ) } - public operator fun times(other: Int): IntModulo = + operator fun times(other: Int): IntModulo = IntModulo( (residue * other) % modulus, modulus, toCheckInput = false ) - public operator fun div(other: IntModulo): IntModulo { + operator fun div(other: IntModulo): IntModulo { require(modulus == other.modulus) { "can not divide two residue different modulo" } val (reciprocalCandidate, gcdOfOtherResidueAndModulus) = bezoutIdentityWithGCD(other.residue, modulus) require(gcdOfOtherResidueAndModulus == 1) { "can not divide to residue that has non-trivial GCD with modulo" } @@ -88,7 +88,7 @@ public class IntModulo { toCheckInput = false ) } - public operator fun div(other: Int): IntModulo { + operator fun div(other: Int): IntModulo { val (reciprocalCandidate, gcdOfOtherResidueAndModulus) = bezoutIdentityWithGCD(other, modulus) require(gcdOfOtherResidueAndModulus == 1) { "can not divide to residue that has non-trivial GCD with modulo" } return IntModulo( @@ -109,11 +109,11 @@ public class IntModulo { } @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE") -public class IntModuloRing : Ring, ScaleOperations { +class IntModuloRing : Ring, ScaleOperations { - public val modulus: Int + val modulus: Int - public constructor(modulus: Int) { + constructor(modulus: Int) { require(modulus != 0) { "modulus can not be zero" } this.modulus = if (modulus < 0) -modulus else modulus } @@ -121,7 +121,7 @@ public class IntModuloRing : Ring, ScaleOperations { override inline val zero: IntModulo get() = IntModulo(0, modulus, toCheckInput = false) override inline val one: IntModulo get() = IntModulo(1, modulus, toCheckInput = false) - public fun number(arg: Int): IntModulo = IntModulo(arg, modulus, toCheckInput = false) + fun number(arg: Int): IntModulo = IntModulo(arg, modulus, toCheckInput = false) override inline fun add(left: IntModulo, right: IntModulo): IntModulo = left + right override inline fun multiply(left: IntModulo, right: IntModulo): IntModulo = left * right @@ -130,7 +130,7 @@ public class IntModuloRing : Ring, ScaleOperations { override inline fun IntModulo.plus(arg: IntModulo): IntModulo = this + arg override inline fun IntModulo.minus(arg: IntModulo): IntModulo = this - arg override inline fun IntModulo.times(arg: IntModulo): IntModulo = this * arg - public inline fun IntModulo.div(arg: IntModulo): IntModulo = this / arg + inline fun IntModulo.div(arg: IntModulo): IntModulo = this / arg override fun scale(a: IntModulo, value: Double): IntModulo = a * value.toInt() } \ No newline at end of file diff --git a/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt similarity index 54% rename from test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt rename to kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt index e534c243e..730a455bf 100644 --- a/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt @@ -9,10 +9,10 @@ import space.kscience.kmath.functions.Polynomial import space.kscience.kmath.functions.PolynomialSpace -public fun PolynomialSpace.Polynomial(vararg coefs: Int): Polynomial = +fun PolynomialSpace.Polynomial(vararg coefs: Int): Polynomial = Polynomial(coefs.map { IntModulo(it, ring.modulus) }) -public fun IntModuloRing.Polynomial(vararg coefs: Int): Polynomial = +fun IntModuloRing.Polynomial(vararg coefs: Int): Polynomial = Polynomial(coefs.map { IntModulo(it, modulus) }) -public fun IntModuloRing.m(arg: Int): IntModulo = IntModulo(arg, modulus) -public fun PolynomialSpace.m(arg: Int): IntModulo = IntModulo(arg, ring.modulus) \ No newline at end of file +fun IntModuloRing.m(arg: Int): IntModulo = IntModulo(arg, modulus) +fun PolynomialSpace.m(arg: Int): IntModulo = IntModulo(arg, ring.modulus) \ No newline at end of file diff --git a/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt similarity index 78% rename from test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt rename to kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt index 27b0eb21e..19cb77df5 100644 --- a/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt @@ -12,14 +12,14 @@ import space.kscience.kmath.operations.Field import space.kscience.kmath.operations.NumbersAddOps @Suppress("NAME_SHADOWING") -public class Rational { - public companion object { - public val ZERO: Rational = Rational(0L) - public val ONE: Rational = Rational(1L) +class Rational { + companion object { + val ZERO: Rational = Rational(0L) + val ONE: Rational = Rational(1L) } - public val numerator: Long - public val denominator: Long + val numerator: Long + val denominator: Long internal constructor(numerator: Long, denominator: Long, toCheckInput: Boolean = true) { if (toCheckInput) { @@ -35,16 +35,16 @@ public class Rational { } } - public constructor(numerator: Int, denominator: Int) : this(numerator.toLong(), denominator.toLong(), true) - public constructor(numerator: Int, denominator: Long) : this(numerator.toLong(), denominator, true) - public constructor(numerator: Long, denominator: Int) : this(numerator, denominator.toLong(), true) - public constructor(numerator: Long, denominator: Long) : this(numerator, denominator, true) - public constructor(numerator: Int) : this(numerator.toLong(), 1L, false) - public constructor(numerator: Long) : this(numerator, 1L, false) + constructor(numerator: Int, denominator: Int) : this(numerator.toLong(), denominator.toLong(), true) + constructor(numerator: Int, denominator: Long) : this(numerator.toLong(), denominator, true) + constructor(numerator: Long, denominator: Int) : this(numerator, denominator.toLong(), true) + constructor(numerator: Long, denominator: Long) : this(numerator, denominator, true) + constructor(numerator: Int) : this(numerator.toLong(), 1L, false) + constructor(numerator: Long) : this(numerator, 1L, false) - public operator fun unaryPlus(): Rational = this - public operator fun unaryMinus(): Rational = Rational(-this.numerator, this.denominator) - public operator fun plus(other: Rational): Rational { + operator fun unaryPlus(): Rational = this + operator fun unaryMinus(): Rational = Rational(-this.numerator, this.denominator) + operator fun plus(other: Rational): Rational { val denominatorsGcd = gcd(denominator, other.denominator) val dividedThisDenominator = denominator / denominatorsGcd val dividedOtherDenominator = other.denominator / denominatorsGcd @@ -56,19 +56,19 @@ public class Rational { toCheckInput = false ) } - public operator fun plus(other: Int): Rational = + operator fun plus(other: Int): Rational = Rational( numerator + denominator * other.toLong(), denominator, toCheckInput = false ) - public operator fun plus(other: Long): Rational = + operator fun plus(other: Long): Rational = Rational( numerator + denominator * other, denominator, toCheckInput = false ) - public operator fun minus(other: Rational): Rational { + operator fun minus(other: Rational): Rational { val denominatorsGcd = gcd(denominator, other.denominator) val dividedThisDenominator = denominator / denominatorsGcd val dividedOtherDenominator = other.denominator / denominatorsGcd @@ -80,19 +80,19 @@ public class Rational { toCheckInput = false ) } - public operator fun minus(other: Int): Rational = + operator fun minus(other: Int): Rational = Rational( numerator - denominator * other.toLong(), denominator, toCheckInput = false ) - public operator fun minus(other: Long): Rational = + operator fun minus(other: Long): Rational = Rational( numerator - denominator * other, denominator, toCheckInput = false ) - public operator fun times(other: Rational): Rational { + operator fun times(other: Rational): Rational { val thisDenominatorAndOtherNumeratorGcd = gcd(denominator, other.numerator) val otherDenominatorAndThisNumeratorGcd = gcd(other.denominator, numerator) return Rational( @@ -101,7 +101,7 @@ public class Rational { toCheckInput = false ) } - public operator fun times(other: Int): Rational { + operator fun times(other: Int): Rational { val other = other.toLong() val denominatorAndOtherGcd = gcd(denominator, other) return Rational( @@ -110,7 +110,7 @@ public class Rational { toCheckInput = false ) } - public operator fun times(other: Long): Rational { + operator fun times(other: Long): Rational { val denominatorAndOtherGcd = gcd(denominator, other) return Rational( numerator * (other / denominatorAndOtherGcd), @@ -118,7 +118,7 @@ public class Rational { toCheckInput = false ) } - public operator fun div(other: Rational): Rational { + operator fun div(other: Rational): Rational { val denominatorsGcd = gcd(denominator, other.denominator) val numeratorsGcd = gcd(numerator, other.numerator) return Rational( @@ -126,7 +126,7 @@ public class Rational { (denominator / denominatorsGcd) * (other.numerator / numeratorsGcd) ) } - public operator fun div(other: Int): Rational { + operator fun div(other: Int): Rational { val other = other.toLong() val numeratorAndOtherGcd = gcd(numerator, other) return Rational( @@ -135,7 +135,7 @@ public class Rational { toCheckInput = false ) } - public operator fun div(other: Long): Rational { + operator fun div(other: Long): Rational { val numeratorAndOtherGcd = gcd(numerator, other) return Rational( numerator / numeratorAndOtherGcd, @@ -158,7 +158,7 @@ public class Rational { @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE") @OptIn(UnstableKMathAPI::class) -public object RationalField : Field, NumbersAddOps { +object RationalField : Field, NumbersAddOps { override inline val zero: Rational get() = Rational.ZERO override inline val one: Rational get() = Rational.ONE diff --git a/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/misc.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/misc.kt similarity index 100% rename from test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/misc.kt rename to kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/misc.kt diff --git a/kmath-polynomial/build.gradle.kts b/kmath-polynomial/build.gradle.kts index b0f4a095c..85b87fb34 100644 --- a/kmath-polynomial/build.gradle.kts +++ b/kmath-polynomial/build.gradle.kts @@ -12,12 +12,6 @@ kotlin.sourceSets { api(projects.kmathCore) } } - commonTest { - dependencies { - api(projects.testUtilsPolynomial) - api(kotlin("test")) - } - } } dependencies { diff --git a/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/AlgebraicStubTest.kt b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/AlgebraicStubTest.kt new file mode 100644 index 000000000..487cd9ee1 --- /dev/null +++ b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/AlgebraicStubTest.kt @@ -0,0 +1,589 @@ +/* + * 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.functions + + +import space.kscience.kmath.operations.invoke +import space.kscience.kmath.operations.Field +import kotlin.jvm.JvmInline +import kotlin.test.Test +import kotlin.test.assertEquals + +@JvmInline +value class Expr(val expr: String) + +object ExprRing : Field { + override fun Expr.unaryMinus(): Expr = Expr("-${expr}") + override fun add(left: Expr, right: Expr): Expr = Expr("(${left.expr} + ${right.expr})") + override fun multiply(left: Expr, right: Expr): Expr = Expr("(${left.expr} * ${right.expr})") + override val zero: Expr = Expr("0") + override val one: Expr = Expr("1") + override fun divide(left: Expr, right: Expr): Expr = Expr("(${left.expr} / ${right.expr})") + override fun scale(a: Expr, value: Double): Expr = Expr("(${a.expr} / $value)") +} + +class AlgebraicStubTest { + @Test + fun test_addMultipliedBySquaring_for_UInt() { + ExprRing { + assertEquals( + "57", + addMultipliedByDoubling(Expr("57"), Expr("179"), 0u).expr, + "tried addMultipliedBySquaring(57, 179, 0u)" + ) + assertEquals( + "(57 + 179)", + addMultipliedByDoubling(Expr("57"), Expr("179"), 1u).expr, + "tried addMultipliedBySquaring(57, 179, 1u)" + ) + assertEquals( + "(57 + (179 + 179))", + addMultipliedByDoubling(Expr("57"), Expr("179"), 2u).expr, + "tried addMultipliedBySquaring(57, 179, 2u)" + ) + assertEquals( + "((57 + 179) + (179 + 179))", + addMultipliedByDoubling(Expr("57"), Expr("179"), 3u).expr, + "tried addMultipliedBySquaring(57, 179, 3u)" + ) + assertEquals( + "(57 + ((179 + 179) + (179 + 179)))", + addMultipliedByDoubling(Expr("57"), Expr("179"), 4u).expr, + "tried addMultipliedBySquaring(57, 179, 4u)" + ) + assertEquals( + "((57 + 179) + ((179 + 179) + (179 + 179)))", + addMultipliedByDoubling(Expr("57"), Expr("179"), 5u).expr, + "tried addMultipliedBySquaring(57, 179, 5u)" + ) + assertEquals( + "((57 + (179 + 179)) + ((179 + 179) + (179 + 179)))", + addMultipliedByDoubling(Expr("57"), Expr("179"), 6u).expr, + "tried addMultipliedBySquaring(57, 179, 6u)" + ) + assertEquals( + "(((57 + 179) + (179 + 179)) + ((179 + 179) + (179 + 179)))", + addMultipliedByDoubling(Expr("57"), Expr("179"), 7u).expr, + "tried addMultipliedBySquaring(57, 179, 7u)" + ) + assertEquals( + "(57 + (((179 + 179) + (179 + 179)) + ((179 + 179) + (179 + 179))))", + addMultipliedByDoubling(Expr("57"), Expr("179"), 8u).expr, + "tried addMultipliedBySquaring(57, 179, 8u)" + ) + } + } + @Test + fun test_multiplyBySquaring_for_UInt() { + ExprRing { + assertEquals( + "0", + multiplyByDoubling(Expr("57"), 0u).expr, + "tried multiplyBySquaring(57, 0u)" + ) + assertEquals( + "57", + multiplyByDoubling(Expr("57"), 1u).expr, + "tried multiplyBySquaring(57, 1u)" + ) + assertEquals( + "(57 + 57)", + multiplyByDoubling(Expr("57"), 2u).expr, + "tried multiplyBySquaring(57, 2u)" + ) + assertEquals( + "(57 + (57 + 57))", + multiplyByDoubling(Expr("57"), 3u).expr, + "tried multiplyBySquaring(57, 3u)" + ) + assertEquals( + "((57 + 57) + (57 + 57))", + multiplyByDoubling(Expr("57"), 4u).expr, + "tried multiplyBySquaring(57, 4u)" + ) + assertEquals( + "(57 + ((57 + 57) + (57 + 57)))", + multiplyByDoubling(Expr("57"), 5u).expr, + "tried multiplyBySquaring(57, 5u)" + ) + assertEquals( + "((57 + 57) + ((57 + 57) + (57 + 57)))", + multiplyByDoubling(Expr("57"), 6u).expr, + "tried multiplyBySquaring(57, 6u)" + ) + assertEquals( + "((57 + (57 + 57)) + ((57 + 57) + (57 + 57)))", + multiplyByDoubling(Expr("57"), 7u).expr, + "tried multiplyBySquaring(57, 7u)" + ) + assertEquals( + "(((57 + 57) + (57 + 57)) + ((57 + 57) + (57 + 57)))", + multiplyByDoubling(Expr("57"), 8u).expr, + "tried multiplyBySquaring(57, 8u)" + ) + } + } + @Test + fun test_addMultipliedBySquaring_for_Int() { + ExprRing { + assertEquals( + "57", + addMultipliedByDoubling(Expr("57"), Expr("179"), 0).expr, + "tried addMultipliedBySquaring(57, 179, 0)" + ) + assertEquals( + "(57 + 179)", + addMultipliedByDoubling(Expr("57"), Expr("179"), 1).expr, + "tried addMultipliedBySquaring(57, 179, 1)" + ) + assertEquals( + "(57 + -179)", + addMultipliedByDoubling(Expr("57"), Expr("179"), -1).expr, + "tried addMultipliedBySquaring(57, 179, -1)" + ) + assertEquals( + "(57 + (179 + 179))", + addMultipliedByDoubling(Expr("57"), Expr("179"), 2).expr, + "tried addMultipliedBySquaring(57, 179, 2)" + ) + assertEquals( + "(57 + (-179 + -179))", + addMultipliedByDoubling(Expr("57"), Expr("179"), -2).expr, + "tried addMultipliedBySquaring(57, 179, -2)" + ) + assertEquals( + "((57 + 179) + (179 + 179))", + addMultipliedByDoubling(Expr("57"), Expr("179"), 3).expr, + "tried addMultipliedBySquaring(57, 179, 3)" + ) + assertEquals( + "((57 + -179) + (-179 + -179))", + addMultipliedByDoubling(Expr("57"), Expr("179"), -3).expr, + "tried addMultipliedBySquaring(57, 179, -3)" + ) + assertEquals( + "(57 + ((179 + 179) + (179 + 179)))", + addMultipliedByDoubling(Expr("57"), Expr("179"), 4).expr, + "tried addMultipliedBySquaring(57, 179, 4)" + ) + assertEquals( + "(57 + ((-179 + -179) + (-179 + -179)))", + addMultipliedByDoubling(Expr("57"), Expr("179"), -4).expr, + "tried addMultipliedBySquaring(57, 179, -4)" + ) + assertEquals( + "((57 + 179) + ((179 + 179) + (179 + 179)))", + addMultipliedByDoubling(Expr("57"), Expr("179"), 5).expr, + "tried addMultipliedBySquaring(57, 179, 5)" + ) + assertEquals( + "((57 + -179) + ((-179 + -179) + (-179 + -179)))", + addMultipliedByDoubling(Expr("57"), Expr("179"), -5).expr, + "tried addMultipliedBySquaring(57, 179, -5)" + ) + assertEquals( + "((57 + (179 + 179)) + ((179 + 179) + (179 + 179)))", + addMultipliedByDoubling(Expr("57"), Expr("179"), 6).expr, + "tried addMultipliedBySquaring(57, 179, 6)" + ) + assertEquals( + "((57 + (-179 + -179)) + ((-179 + -179) + (-179 + -179)))", + addMultipliedByDoubling(Expr("57"), Expr("179"), -6).expr, + "tried addMultipliedBySquaring(57, 179, -6)" + ) + assertEquals( + "(((57 + 179) + (179 + 179)) + ((179 + 179) + (179 + 179)))", + addMultipliedByDoubling(Expr("57"), Expr("179"), 7).expr, + "tried addMultipliedBySquaring(57, 179, 7)" + ) + assertEquals( + "(((57 + -179) + (-179 + -179)) + ((-179 + -179) + (-179 + -179)))", + addMultipliedByDoubling(Expr("57"), Expr("179"), -7).expr, + "tried addMultipliedBySquaring(57, 179, -7)" + ) + assertEquals( + "(57 + (((179 + 179) + (179 + 179)) + ((179 + 179) + (179 + 179))))", + addMultipliedByDoubling(Expr("57"), Expr("179"), 8).expr, + "tried addMultipliedBySquaring(57, 179, 8)" + ) + assertEquals( + "(57 + (((-179 + -179) + (-179 + -179)) + ((-179 + -179) + (-179 + -179))))", + addMultipliedByDoubling(Expr("57"), Expr("179"), -8).expr, + "tried addMultipliedBySquaring(57, 179, -8)" + ) + } + } + @Test + fun test_multiplyBySquaring_for_Int() { + ExprRing { + assertEquals( + "0", + multiplyByDoubling(Expr("57"), 0).expr, + "tried multiplyBySquaring(57, 0)" + ) + assertEquals( + "57", + multiplyByDoubling(Expr("57"), 1).expr, + "tried multiplyBySquaring(57, 1)" + ) + assertEquals( + "-57", + multiplyByDoubling(Expr("57"), -1).expr, + "tried multiplyBySquaring(57, -1)" + ) + assertEquals( + "(57 + 57)", + multiplyByDoubling(Expr("57"), 2).expr, + "tried multiplyBySquaring(57, 2)" + ) + assertEquals( + "(-57 + -57)", + multiplyByDoubling(Expr("57"), -2).expr, + "tried multiplyBySquaring(57, -2)" + ) + assertEquals( + "(57 + (57 + 57))", + multiplyByDoubling(Expr("57"), 3).expr, + "tried multiplyBySquaring(57, 3)" + ) + assertEquals( + "(-57 + (-57 + -57))", + multiplyByDoubling(Expr("57"), -3).expr, + "tried multiplyBySquaring(57, -3)" + ) + assertEquals( + "((57 + 57) + (57 + 57))", + multiplyByDoubling(Expr("57"), 4).expr, + "tried multiplyBySquaring(57, 4)" + ) + assertEquals( + "((-57 + -57) + (-57 + -57))", + multiplyByDoubling(Expr("57"), -4).expr, + "tried multiplyBySquaring(57, -4)" + ) + assertEquals( + "(57 + ((57 + 57) + (57 + 57)))", + multiplyByDoubling(Expr("57"), 5).expr, + "tried multiplyBySquaring(57, 5)" + ) + assertEquals( + "(-57 + ((-57 + -57) + (-57 + -57)))", + multiplyByDoubling(Expr("57"), -5).expr, + "tried multiplyBySquaring(57, -5)" + ) + assertEquals( + "((57 + 57) + ((57 + 57) + (57 + 57)))", + multiplyByDoubling(Expr("57"), 6).expr, + "tried multiplyBySquaring(57, 6)" + ) + assertEquals( + "((-57 + -57) + ((-57 + -57) + (-57 + -57)))", + multiplyByDoubling(Expr("57"), -6).expr, + "tried multiplyBySquaring(57, -6)" + ) + assertEquals( + "((57 + (57 + 57)) + ((57 + 57) + (57 + 57)))", + multiplyByDoubling(Expr("57"), 7).expr, + "tried multiplyBySquaring(57, 7)" + ) + assertEquals( + "((-57 + (-57 + -57)) + ((-57 + -57) + (-57 + -57)))", + multiplyByDoubling(Expr("57"), -7).expr, + "tried multiplyBySquaring(57, -7)" + ) + assertEquals( + "(((57 + 57) + (57 + 57)) + ((57 + 57) + (57 + 57)))", + multiplyByDoubling(Expr("57"), 8).expr, + "tried multiplyBySquaring(57, 8)" + ) + assertEquals( + "(((-57 + -57) + (-57 + -57)) + ((-57 + -57) + (-57 + -57)))", + multiplyByDoubling(Expr("57"), -8).expr, + "tried multiplyBySquaring(57, -8)" + ) + } + } + @Test + fun test_multiplyExponentiationBySquaring_for_UInt() { + ExprRing { + assertEquals( + "57", + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 0u).expr, + "tried multiplyExponentiationBySquaring(57, 179, 0u)" + ) + assertEquals( + "(57 * 179)", + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 1u).expr, + "tried multiplyExponentiationBySquaring(57, 179, 1u)" + ) + assertEquals( + "(57 * (179 * 179))", + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 2u).expr, + "tried multiplyExponentiationBySquaring(57, 179, 2u)" + ) + assertEquals( + "((57 * 179) * (179 * 179))", + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 3u).expr, + "tried multiplyExponentiationBySquaring(57, 179, 3u)" + ) + assertEquals( + "(57 * ((179 * 179) * (179 * 179)))", + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 4u).expr, + "tried multiplyExponentiationBySquaring(57, 179, 4u)" + ) + assertEquals( + "((57 * 179) * ((179 * 179) * (179 * 179)))", + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 5u).expr, + "tried multiplyExponentiationBySquaring(57, 179, 5u)" + ) + assertEquals( + "((57 * (179 * 179)) * ((179 * 179) * (179 * 179)))", + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 6u).expr, + "tried multiplyExponentiationBySquaring(57, 179, 6u)" + ) + assertEquals( + "(((57 * 179) * (179 * 179)) * ((179 * 179) * (179 * 179)))", + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 7u).expr, + "tried multiplyExponentiationBySquaring(57, 179, 7u)" + ) + assertEquals( + "(57 * (((179 * 179) * (179 * 179)) * ((179 * 179) * (179 * 179))))", + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 8u).expr, + "tried multiplyExponentiationBySquaring(57, 179, 8u)" + ) + } + } + @Test + fun test_exponentiationBySquaring_for_UInt() { + ExprRing { + assertEquals( + "0", + exponentiateBySquaring(Expr("57"), 0u).expr, + "tried exponentiationBySquaring(57, 0u)" + ) + assertEquals( + "57", + exponentiateBySquaring(Expr("57"), 1u).expr, + "tried exponentiationBySquaring(57, 1u)" + ) + assertEquals( + "(57 * 57)", + exponentiateBySquaring(Expr("57"), 2u).expr, + "tried exponentiationBySquaring(57, 2u)" + ) + assertEquals( + "(57 * (57 * 57))", + exponentiateBySquaring(Expr("57"), 3u).expr, + "tried exponentiationBySquaring(57, 3u)" + ) + assertEquals( + "((57 * 57) * (57 * 57))", + exponentiateBySquaring(Expr("57"), 4u).expr, + "tried exponentiationBySquaring(57, 4u)" + ) + assertEquals( + "(57 * ((57 * 57) * (57 * 57)))", + exponentiateBySquaring(Expr("57"), 5u).expr, + "tried exponentiationBySquaring(57, 5u)" + ) + assertEquals( + "((57 * 57) * ((57 * 57) * (57 * 57)))", + exponentiateBySquaring(Expr("57"), 6u).expr, + "tried exponentiationBySquaring(57, 6u)" + ) + assertEquals( + "((57 * (57 * 57)) * ((57 * 57) * (57 * 57)))", + exponentiateBySquaring(Expr("57"), 7u).expr, + "tried exponentiationBySquaring(57, 7u)" + ) + assertEquals( + "(((57 * 57) * (57 * 57)) * ((57 * 57) * (57 * 57)))", + exponentiateBySquaring(Expr("57"), 8u).expr, + "tried exponentiationBySquaring(57, 8u)" + ) + } + } + @Test + fun test_multiplyExponentiationBySquaring_for_Int() { + ExprRing { + assertEquals( + "57", + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 0).expr, + "tried multiplyExponentiationBySquaring(57, 179, 0)" + ) + assertEquals( + "(57 * 179)", + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 1).expr, + "tried multiplyExponentiationBySquaring(57, 179, 1)" + ) + assertEquals( + "(57 * (1 / 179))", + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -1).expr, + "tried multiplyExponentiationBySquaring(57, 179, -1)" + ) + assertEquals( + "(57 * (179 * 179))", + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 2).expr, + "tried multiplyExponentiationBySquaring(57, 179, 2)" + ) + assertEquals( + "(57 * ((1 / 179) * (1 / 179)))", + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -2).expr, + "tried multiplyExponentiationBySquaring(57, 179, -2)" + ) + assertEquals( + "((57 * 179) * (179 * 179))", + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 3).expr, + "tried multiplyExponentiationBySquaring(57, 179, 3)" + ) + assertEquals( + "((57 * (1 / 179)) * ((1 / 179) * (1 / 179)))", + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -3).expr, + "tried multiplyExponentiationBySquaring(57, 179, -3)" + ) + assertEquals( + "(57 * ((179 * 179) * (179 * 179)))", + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 4).expr, + "tried multiplyExponentiationBySquaring(57, 179, 4)" + ) + assertEquals( + "(57 * (((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179))))", + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -4).expr, + "tried multiplyExponentiationBySquaring(57, 179, -4)" + ) + assertEquals( + "((57 * 179) * ((179 * 179) * (179 * 179)))", + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 5).expr, + "tried multiplyExponentiationBySquaring(57, 179, 5)" + ) + assertEquals( + "((57 * (1 / 179)) * (((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179))))", + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -5).expr, + "tried multiplyExponentiationBySquaring(57, 179, -5)" + ) + assertEquals( + "((57 * (179 * 179)) * ((179 * 179) * (179 * 179)))", + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 6).expr, + "tried multiplyExponentiationBySquaring(57, 179, 6)" + ) + assertEquals( + "((57 * ((1 / 179) * (1 / 179))) * (((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179))))", + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -6).expr, + "tried multiplyExponentiationBySquaring(57, 179, -6)" + ) + assertEquals( + "(((57 * 179) * (179 * 179)) * ((179 * 179) * (179 * 179)))", + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 7).expr, + "tried multiplyExponentiationBySquaring(57, 179, 7)" + ) + assertEquals( + "(((57 * (1 / 179)) * ((1 / 179) * (1 / 179))) * (((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179))))", + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -7).expr, + "tried multiplyExponentiationBySquaring(57, 179, -7)" + ) + assertEquals( + "(57 * (((179 * 179) * (179 * 179)) * ((179 * 179) * (179 * 179))))", + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 8).expr, + "tried multiplyExponentiationBySquaring(57, 179, 8)" + ) + assertEquals( + "(57 * ((((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179))) * (((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179)))))", + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -8).expr, + "tried multiplyExponentiationBySquaring(57, 179, -8)" + ) + } + } + @Test + fun test_exponentiationBySquaring_for_Int() { + ExprRing { + assertEquals( + "0", + exponentiateBySquaring(Expr("57"), 0).expr, + "tried exponentiationBySquaring(57, 0)" + ) + assertEquals( + "57", + exponentiateBySquaring(Expr("57"), 1).expr, + "tried exponentiationBySquaring(57, 1)" + ) + assertEquals( + "(1 / 57)", + exponentiateBySquaring(Expr("57"), -1).expr, + "tried exponentiationBySquaring(57, -1)" + ) + assertEquals( + "(57 * 57)", + exponentiateBySquaring(Expr("57"), 2).expr, + "tried exponentiationBySquaring(57, 2)" + ) + assertEquals( + "((1 / 57) * (1 / 57))", + exponentiateBySquaring(Expr("57"), -2).expr, + "tried exponentiationBySquaring(57, -2)" + ) + assertEquals( + "(57 * (57 * 57))", + exponentiateBySquaring(Expr("57"), 3).expr, + "tried exponentiationBySquaring(57, 3)" + ) + assertEquals( + "((1 / 57) * ((1 / 57) * (1 / 57)))", + exponentiateBySquaring(Expr("57"), -3).expr, + "tried exponentiationBySquaring(57, -3)" + ) + assertEquals( + "((57 * 57) * (57 * 57))", + exponentiateBySquaring(Expr("57"), 4).expr, + "tried exponentiationBySquaring(57, 4)" + ) + assertEquals( + "(((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57)))", + exponentiateBySquaring(Expr("57"), -4).expr, + "tried exponentiationBySquaring(57, -4)" + ) + assertEquals( + "(57 * ((57 * 57) * (57 * 57)))", + exponentiateBySquaring(Expr("57"), 5).expr, + "tried exponentiationBySquaring(57, 5)" + ) + assertEquals( + "((1 / 57) * (((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57))))", + exponentiateBySquaring(Expr("57"), -5).expr, + "tried exponentiationBySquaring(57, -5)" + ) + assertEquals( + "((57 * 57) * ((57 * 57) * (57 * 57)))", + exponentiateBySquaring(Expr("57"), 6).expr, + "tried exponentiationBySquaring(57, 6)" + ) + assertEquals( + "(((1 / 57) * (1 / 57)) * (((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57))))", + exponentiateBySquaring(Expr("57"), -6).expr, + "tried exponentiationBySquaring(57, -6)" + ) + assertEquals( + "((57 * (57 * 57)) * ((57 * 57) * (57 * 57)))", + exponentiateBySquaring(Expr("57"), 7).expr, + "tried exponentiationBySquaring(57, 7)" + ) + assertEquals( + "(((1 / 57) * ((1 / 57) * (1 / 57))) * (((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57))))", + exponentiateBySquaring(Expr("57"), -7).expr, + "tried exponentiationBySquaring(57, -7)" + ) + assertEquals( + "(((57 * 57) * (57 * 57)) * ((57 * 57) * (57 * 57)))", + exponentiateBySquaring(Expr("57"), 8).expr, + "tried exponentiationBySquaring(57, 8)" + ) + assertEquals( + "((((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57))) * (((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57))))", + exponentiateBySquaring(Expr("57"), -8).expr, + "tried exponentiationBySquaring(57, -8)" + ) + } + } +} \ No newline at end of file diff --git a/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt new file mode 100644 index 000000000..e7d8dfd8c --- /dev/null +++ b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt @@ -0,0 +1,544 @@ +/* + * 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. + */ + +@file:Suppress("LocalVariableName") + +package space.kscience.kmath.functions + +import space.kscience.kmath.functions.testUtils.IntModuloRing +import space.kscience.kmath.functions.testUtils.ListPolynomial +import space.kscience.kmath.functions.testUtils.Rational +import space.kscience.kmath.functions.testUtils.RationalField +import kotlin.test.* + + +class ListPolynomialTest { + @Test + fun test_Polynomial_Int_plus() { + RationalField.listPolynomialSpace { + assertEquals( + ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + -3, + "test 1" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + 2, + "test 2" + ) + assertEquals( + ListPolynomial(Rational(0)), + ListPolynomial(Rational(-2)) + 2, + "test 3" + ) + val polynomial_4 = ListPolynomial() + assertSame( + polynomial_4, + polynomial_4 + 0, + "test 4" + ) + val polynomial_5 = ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)) + assertSame( + polynomial_5, + polynomial_5 + 0, + "test 5" + ) + assertEquals( + ListPolynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + 1, + "test 6" + ) + assertEquals( + ListPolynomial(Rational(-1)), + ListPolynomial(Rational(-2)) + 1, + "test 7" + ) + assertEquals( + ListPolynomial(Rational(2)), + ListPolynomial() + 2, + "test 8" + ) + } + } + @Test + fun test_Polynomial_Int_minus() { + RationalField.listPolynomialSpace { + assertEquals( + ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - -3, + "test 1" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), + ListPolynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - 2, + "test 2" + ) + assertEquals( + ListPolynomial(Rational(0)), + ListPolynomial(Rational(2)) - 2, + "test 3" + ) + val polynomial_4 = ListPolynomial() + assertSame( + polynomial_4, + polynomial_4 - 0, + "test 4" + ) + val polynomial_5 = ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)) + assertEquals( + polynomial_5, + polynomial_5 - 0, + "test 5" + ) + assertEquals( + ListPolynomial(Rational(1), Rational(0), Rational(0), Rational(0)), + ListPolynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - 1, + "test 6" + ) + assertEquals( + ListPolynomial(Rational(1)), + ListPolynomial(Rational(2)) - 1, + "test 7" + ) + assertEquals( + ListPolynomial(Rational(-2)), + ListPolynomial() - 2, + "test 8" + ) + } + } + @Test + fun test_Polynomial_Int_times() { + IntModuloRing(35).listPolynomialSpace { + assertEquals( + ListPolynomial(34, 2, 1, 20, 2), + ListPolynomial(22, 26, 13, 15, 26) * 27, + "test 1" + ) + assertEquals( + ListPolynomial(0, 0, 0, 0, 0), + ListPolynomial(7, 0, 49, 21, 14) * 15, + "test 2" + ) + val polynomial = ListPolynomial(22, 26, 13, 15, 26) + assertSame( + zero, + polynomial * 0, + "test 3" + ) + assertSame( + polynomial, + polynomial * 1, + "test 4" + ) + } + } + @Test + fun test_Int_Polynomial_plus() { + RationalField.listPolynomialSpace { + assertEquals( + ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), + -3 + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)), + "test 1" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), + 2 + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), + "test 2" + ) + assertEquals( + ListPolynomial(Rational(0)), + 2 + ListPolynomial(Rational(-2)), + "test 3" + ) + val polynomial_4 = ListPolynomial() + assertSame( + polynomial_4, + 0 + polynomial_4, + "test 4" + ) + val polynomial_5 = ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)) + assertSame( + polynomial_5, + 0 + polynomial_5, + "test 5" + ) + assertEquals( + ListPolynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), + 1 + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), + "test 6" + ) + assertEquals( + ListPolynomial(Rational(-1)), + 1 + ListPolynomial(Rational(-2)), + "test 7" + ) + assertEquals( + ListPolynomial(Rational(2)), + 2 + ListPolynomial(), + "test 8" + ) + } + } + @Test + fun test_Int_Polynomial_minus() { + RationalField.listPolynomialSpace { + assertEquals( + ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), + 3 - ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), + "test 1" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), + -2 - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), + "test 2" + ) + assertEquals( + ListPolynomial(Rational(0)), + -2 - ListPolynomial(Rational(-2)), + "test 3" + ) + assertEquals( + ListPolynomial(Rational(-32, 9), Rational(-8, -9), Rational(8, 7)), + 0 - ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), + "test 4" + ) + assertEquals( + ListPolynomial(), + 0 - ListPolynomial(), + "test 5" + ) + assertEquals( + ListPolynomial(Rational(1), Rational(0), Rational(0), Rational(0)), + -1 - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), + "test 6" + ) + assertEquals( + ListPolynomial(Rational(1)), + -1 - ListPolynomial(Rational(-2)), + "test 7" + ) + assertEquals( + ListPolynomial(Rational(-2)), + -2 - ListPolynomial(), + "test 8" + ) + } + } + @Test + fun test_Int_Polynomial_times() { + IntModuloRing(35).listPolynomialSpace { + assertEquals( + ListPolynomial(34, 2, 1, 20, 2), + 27 * ListPolynomial(22, 26, 13, 15, 26), + "test 1" + ) + assertEquals( + ListPolynomial(0, 0, 0, 0, 0), + 15 * ListPolynomial(7, 0, 49, 21, 14), + "test 2" + ) + val polynomial = ListPolynomial(22, 26, 13, 15, 26) + assertSame( + zero, + 0 * polynomial, + "test 3" + ) + assertSame( + polynomial, + 1 * polynomial, + "test 4" + ) + } + } + @Test + fun test_Polynomial_Constant_plus() { + RationalField.listPolynomialSpace { + assertEquals( + ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + Rational(-3), + "test 1" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + Rational(2), + "test 2" + ) + assertEquals( + ListPolynomial(Rational(0)), + ListPolynomial(Rational(-2)) + Rational(2), + "test 3" + ) + assertEquals( + ListPolynomial(Rational(0)), + ListPolynomial() + Rational(0), + "test 4" + ) + assertEquals( + ListPolynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + Rational(1), + "test 5" + ) + assertEquals( + ListPolynomial(Rational(-1)), + ListPolynomial(Rational(-2)) + Rational(1), + "test 6" + ) + assertEquals( + ListPolynomial(Rational(2)), + ListPolynomial() + Rational(2), + "test 7" + ) + } + } + @Test + fun test_Polynomial_Constant_minus() { + RationalField.listPolynomialSpace { + assertEquals( + ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - Rational(-3), + "test 1" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), + ListPolynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - Rational(2), + "test 2" + ) + assertEquals( + ListPolynomial(Rational(0)), + ListPolynomial(Rational(2)) - Rational(2), + "test 3" + ) + assertEquals( + ListPolynomial(Rational(0)), + ListPolynomial() - Rational(0), + "test 4" + ) + assertEquals( + ListPolynomial(Rational(1), Rational(0), Rational(0), Rational(0)), + ListPolynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - Rational(1), + "test 5" + ) + assertEquals( + ListPolynomial(Rational(1)), + ListPolynomial(Rational(2)) - Rational(1), + "test 6" + ) + assertEquals( + ListPolynomial(Rational(-2)), + ListPolynomial() - Rational(2), + "test 7" + ) + } + } + @Test + fun test_Polynomial_Constant_times() { + IntModuloRing(35).listPolynomialSpace { + assertEquals( + ListPolynomial(34, 2, 1, 20, 2), + ListPolynomial(22, 26, 13, 15, 26) * 27.asConstant(), + "test 1" + ) + assertEquals( + ListPolynomial(0, 0, 0, 0, 0), + ListPolynomial(7, 0, 49, 21, 14) * 15.asConstant(), + "test 2" + ) + } + } + @Test + fun test_Constant_Polynomial_plus() { + RationalField.listPolynomialSpace { + assertEquals( + ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), + Rational(-3) + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)), + "test 1" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), + Rational(2) + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), + "test 2" + ) + assertEquals( + ListPolynomial(Rational(0)), + Rational(2) + ListPolynomial(Rational(-2)), + "test 3" + ) + assertEquals( + ListPolynomial(Rational(0)), + Rational(0) + ListPolynomial(), + "test 4" + ) + assertEquals( + ListPolynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), + Rational(1) + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), + "test 5" + ) + assertEquals( + ListPolynomial(Rational(-1)), + Rational(1) + ListPolynomial(Rational(-2)), + "test 6" + ) + assertEquals( + ListPolynomial(Rational(2)), + Rational(2) + ListPolynomial(), + "test 7" + ) + } + } + @Test + fun test_Constant_Polynomial_minus() { + RationalField.listPolynomialSpace { + assertEquals( + ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), + Rational(3) - ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), + "test 1" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), + Rational(-2) - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), + "test 2" + ) + assertEquals( + ListPolynomial(Rational(0)), + Rational(-2) - ListPolynomial(Rational(-2)), + "test 3" + ) + assertEquals( + ListPolynomial(Rational(0)), + Rational(0) - ListPolynomial(), + "test 4" + ) + assertEquals( + ListPolynomial(Rational(1), Rational(0), Rational(0), Rational(0)), + Rational(-1) - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), + "test 5" + ) + assertEquals( + ListPolynomial(Rational(1)), + Rational(-1) - ListPolynomial(Rational(-2)), + "test 6" + ) + assertEquals( + ListPolynomial(Rational(-2)), + Rational(-2) - ListPolynomial(), + "test 7" + ) + } + } + @Test + fun test_Constant_Polynomial_times() { + IntModuloRing(35).listPolynomialSpace { + assertEquals( + ListPolynomial(34, 2, 1, 20, 2), + 27 * ListPolynomial(22, 26, 13, 15, 26), + "test 1" + ) + assertEquals( + ListPolynomial(0, 0, 0, 0, 0), + 15 * ListPolynomial(7, 0, 49, 21, 14), + "test 2" + ) + } + } + @Test + fun test_Polynomial_unaryMinus() { + RationalField.listPolynomialSpace { + assertEquals( + ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), + -ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)), + "test 1" + ) + assertEquals( + ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7), Rational(0), Rational(0)), + -ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7), Rational(0), Rational(0)), + "test 2" + ) + } + } + @Test + fun test_Polynomial_Polynomial_plus() { + RationalField.listPolynomialSpace { + // (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( + ListPolynomial(Rational(-10, 63), Rational(37, 9), Rational(-29, 56)), + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + + ListPolynomial(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( + ListPolynomial(Rational(-2, 9), Rational(-5, 12), Rational(2, 4)), + ListPolynomial(Rational(-2, 9), Rational(-8, 3)) + + ListPolynomial(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( + ListPolynomial(Rational(-18, 7), Rational(-23, 6), Rational(2, 3), Rational(0)), + ListPolynomial(Rational(-4, 7), Rational(-2, 6), Rational(0), Rational(0)) + + ListPolynomial(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( + ListPolynomial(Rational(0), Rational(0), Rational(0)), + ListPolynomial(Rational(-2, 4), Rational(-6, 9), Rational(-4, 9)) + + ListPolynomial(Rational(2, 4), Rational(6, 9), Rational(4, 9)), + "test 4" + ) + } + } + @Test + fun test_Polynomial_Polynomial_minus() { + RationalField.listPolynomialSpace { + // (5/9 - 8/9 x - 8/7 x^2) - (-5/7 + 5/1 x + 5/8 x^2) ?= 80/63 - 53/9 x - 99/56 x^2 + assertEquals( + ListPolynomial(Rational(80, 63), Rational(-53, 9), Rational(-99, 56)), + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - + ListPolynomial(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 - 59/12 x - 2/4 x^2 + assertEquals( + ListPolynomial(Rational(-2, 9), Rational(-59, 12), Rational(-2, 4)), + ListPolynomial(Rational(-2, 9), Rational(-8, 3)) - + ListPolynomial(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) ?= 10/7 + 19/6 x - 2/3 x^2 + assertEquals( + ListPolynomial(Rational(10, 7), Rational(19, 6), Rational(-2, 3), Rational(0)), + ListPolynomial(Rational(-4, 7), Rational(-2, 6), Rational(0), Rational(0)) - + ListPolynomial(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( + ListPolynomial(Rational(0), Rational(0), Rational(0)), + ListPolynomial(Rational(-2, 4), Rational(-6, 9), Rational(-4, 9)) - + ListPolynomial(Rational(-2, 4), Rational(-6, 9), Rational(-4, 9)), + "test 4" + ) + } + } + @Test + fun test_Polynomial_Polynomial_times() { + IntModuloRing(35).listPolynomialSpace { + // (1 + x + x^2) * (1 - x + x^2) ?= 1 + x^2 + x^4 + assertEquals( + ListPolynomial(1, 0, 1, 0, 1), + ListPolynomial(1, -1, 1) * ListPolynomial(1, 1, 1), + "test 1" + ) + // Spoiler: 5 * 7 = 0 + assertEquals( + ListPolynomial(0, 0, 0, 0, 0), + ListPolynomial(5, -25, 10) * ListPolynomial(21, 14, -7), + "test 2" + ) + } + } +} \ No newline at end of file diff --git a/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt new file mode 100644 index 000000000..339643d02 --- /dev/null +++ b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt @@ -0,0 +1,982 @@ +/* + * 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.functions + +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.functions.testUtils.Rational +import space.kscience.kmath.functions.testUtils.RationalField +import space.kscience.kmath.functions.testUtils.assertFailsWithTypeAndMessage +import kotlin.test.Ignore +import kotlin.test.Test +import kotlin.test.assertEquals + + +@OptIn(UnstableKMathAPI::class) +class ListPolynomialUtilTest { + @Test + fun test_Polynomial_substitute_Double() { + assertEquals( + 0.0, + ListPolynomial(1.0, -2.0, 1.0).substitute(1.0), + 0.001, + "test 1" + ) + assertEquals( + 0.0, + ListPolynomial(1.0, -2.0, 1.0).substitute(1.0), + 0.001, + "test 1" + ) + assertEquals( + 1.1931904761904761, + ListPolynomial(0.625, 2.6666666666666665, 0.5714285714285714, 1.5).substitute(0.2), + 0.001, + "test 2" + ) + assertEquals( + 0.5681904761904762, + ListPolynomial(0.0, 2.6666666666666665, 0.5714285714285714, 1.5).substitute(0.2), + 0.001, + "test 3" + ) + assertEquals( + 1.1811904761904761, + ListPolynomial(0.625, 2.6666666666666665, 0.5714285714285714, 0.0).substitute(0.2), + 0.001, + "test 4" + ) + assertEquals( + 1.1703333333333332, + ListPolynomial(0.625, 2.6666666666666665, 0.0, 1.5).substitute(0.2), + 0.001, + "test 5" + ) + } + @Test + fun test_Polynomial_substitute_Constant() { + assertEquals( + Rational(0), + ListPolynomial(Rational(1), Rational(-2), Rational(1)).substitute(RationalField, Rational(1)), + "test 1" + ) + assertEquals( + Rational(25057, 21000), + ListPolynomial(Rational(5, 8), Rational(8, 3), Rational(4, 7), Rational(3, 2)) + .substitute(RationalField, Rational(1, 5)), + "test 2" + ) + assertEquals( + Rational(2983, 5250), + ListPolynomial(Rational(0), Rational(8, 3), Rational(4, 7), Rational(3, 2)) + .substitute(RationalField, Rational(1, 5)), + "test 3" + ) + assertEquals( + Rational(4961, 4200), + ListPolynomial(Rational(5, 8), Rational(8, 3), Rational(4, 7), Rational(0)) + .substitute(RationalField, Rational(1, 5)), + "test 4" + ) + assertEquals( + Rational(3511, 3000), + ListPolynomial(Rational(5, 8), Rational(8, 3), Rational(0), Rational(3, 2)) + .substitute(RationalField, Rational(1, 5)), + "test 5" + ) + } + @Test + fun test_Polynomial_substitute_Polynomial() { + assertEquals( + ListPolynomial(Rational(0)), + ListPolynomial(Rational(1), Rational(-2), Rational(1)).substitute(RationalField, ListPolynomial(Rational(1))), + "test 1" + ) + assertEquals( + ListPolynomial(Rational(709, 378), Rational(155, 252), Rational(19, 525), Rational(2, 875)), + ListPolynomial(Rational(1, 7), Rational(9, 4), Rational(1, 3), Rational(2, 7)) + .substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(1, 5))), + "test 2" + ) + assertEquals( + ListPolynomial(Rational(655, 378), Rational(155, 252), Rational(19, 525), Rational(2, 875)), + ListPolynomial(Rational(0), Rational(9, 4), Rational(1, 3), Rational(2, 7)) + .substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(1, 5))), + "test 3" + ) + assertEquals( + ListPolynomial(Rational(677, 378), Rational(97, 180), Rational(1, 75), Rational(0)), + ListPolynomial(Rational(1, 7), Rational(9, 4), Rational(1, 3), Rational(0)) + .substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(1, 5))), + "test 4" + ) + assertEquals( + ListPolynomial(Rational(653, 378), Rational(221, 420), Rational(4, 175), Rational(2, 875)), + ListPolynomial(Rational(1, 7), Rational(9, 4), Rational(0), Rational(2, 7)) + .substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(1, 5))), + "test 5" + ) + assertEquals( + ListPolynomial(Rational(89, 54), Rational(0), Rational(0), Rational(0)), + ListPolynomial(Rational(0), Rational(9, 4), Rational(1, 3), Rational(0)) + .substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(0))), + "test 6" + ) + } + @Test + @Ignore // FIXME: This tests work only for sane realisations of the substitutions. Currently, it is not. + // Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should return denominator r^deg(p), + // not r^(deg(p)(deg(p)+1)/2) as it is now. + fun test_Polynomial_substitute_RationalFunction() { + assertEquals( + ListRationalFunction(ListPolynomial(Rational(0)), ListPolynomial(Rational(1))), + ListPolynomial(Rational(1), Rational(-2), Rational(1)) + .substitute(RationalField, ListRationalFunction(ListPolynomial(Rational(1)), ListPolynomial(Rational(1)))), + "test 1" + ) + assertEquals( + ListRationalFunction( + ListPolynomial( + Rational(66349, 243), + Rational(-17873, 405), + Rational(173533, 3780), + Rational(-91141, 567), + Rational(5773909, 105840), + Rational(-23243, 630), + Rational(1573, 27) + ), + ListPolynomial( + Rational(169, 81), + Rational(-130, 27), + Rational(115, 18), + Rational(-797, 54), + Rational(1985, 144), + Rational(-55, 6), + Rational(121, 9) + ) + ), + ListPolynomial( + Rational(13, 3), + Rational(-9, 5), + Rational(5, 5) + ).substitute(RationalField, + ListRationalFunction( + ListPolynomial( + Rational(15, 1), + Rational(6, 9), + Rational(-3, 7) + ), + ListPolynomial( + Rational(-13, 9), + Rational(10, 6), + Rational(-10, 8), + Rational(11, 3) + ) + ) + ), + "test 2" + ) + assertEquals( + ListRationalFunction( + ListPolynomial( + Rational(0, 1), + Rational(0, 1), + Rational(-14, 9), + Rational(31, 14), + Rational(-5077, 980), + Rational(99, 35) + ), + ListPolynomial( + Rational(0, 1), + Rational(0, 1), + Rational(25, 9), + Rational(-25, 6), + Rational(1985, 144), + Rational(-55, 6), + Rational(121, 9) + ) + ), + ListPolynomial( + Rational(0), + Rational(-9, 5), + Rational(5, 5) + ).substitute(RationalField, + ListRationalFunction( + ListPolynomial( + Rational(0), + Rational(6, 9), + Rational(-3, 7) + ), + ListPolynomial( + Rational(0), + Rational(10, 6), + Rational(-10, 8), + Rational(11, 3) + ) + ) + ), + "test 3" + ) + assertEquals( + ListRationalFunction( + ListPolynomial( + Rational(-898, 27), + Rational(271, 45), + Rational(-65, 12) , + Rational(0), + Rational(0), + Rational(0), + Rational(0) + ), + ListPolynomial( + Rational(-13, 9), + Rational(5, 3), + Rational(-5, 4), + Rational(0), + Rational(0), + Rational(0), + Rational(0) + ) + ), + ListPolynomial( + Rational(13, 3), + Rational(-9, 5), + Rational(0) + ).substitute(RationalField, + ListRationalFunction( + ListPolynomial( + Rational(15, 1), + Rational(6, 9), + Rational(0) + ), + ListPolynomial( + Rational(-13, 9), + Rational(10, 6), + Rational(-10, 8), + Rational(0) + ) + ) + ), + "test 4" + ) + assertEquals( + ListRationalFunction( + ListPolynomial( + Rational(56872, 243), + Rational(0, 1), + Rational(-90, 7), + Rational(-3718, 81), + Rational(9, 49), + Rational(0, 1), + Rational(1573, 27) + ), + ListPolynomial( + Rational(169, 81), + Rational(0, 1), + Rational(0, 1), + Rational(-286, 27), + Rational(0, 1), + Rational(0, 1), + Rational(121, 9) + ) + ), + ListPolynomial( + Rational(13, 3), + Rational(0), + Rational(5, 5) + ).substitute(RationalField, + ListRationalFunction( + ListPolynomial( + Rational(15, 1), + Rational(0), + Rational(-3, 7) + ), + ListPolynomial( + Rational(-13, 9), + Rational(0), + Rational(0), + Rational(11, 3) + ) + ) + ), + "test 5" + ) + } + @Test + fun test_RationalFunction_substitute_Double() { + assertEquals( + 0.0, + ListRationalFunction( + ListPolynomial(1.0, -2.0, 1.0), + ListPolynomial(-6.302012278484357, 5.831971885376948, -9.271604788393432, 5.494387848015814, -3.7187384450880785) + ).substitute(1.0), + 0.001, + "test 1" + ) + assertEquals( + 2.693702616649797, + ListRationalFunction( + ListPolynomial(-5.848840571263625, -1.660411278951134, -3.793740946372443, -9.624569269490076), + ListPolynomial(-2.9680680215311073, -1.862973627119981, 4.776550592888336, -2.7320154512368466) + ).substitute(-7.53452770353279), + 0.001, + "test 2" + ) + assertEquals( + 2.692226268901378, + ListRationalFunction( + ListPolynomial(0.0, -1.660411278951134, -3.793740946372443, -9.624569269490076), + ListPolynomial(0.0, -1.862973627119981, 4.776550592888336, -2.7320154512368466) + ).substitute(-7.53452770353279), + 0.001, + "test 3" + ) + assertEquals( + -0.7394904842099175, + ListRationalFunction( + ListPolynomial(-5.848840571263625, -1.660411278951134, -3.793740946372443, 0.0), + ListPolynomial(-2.9680680215311073, -1.862973627119981, 4.776550592888336, 0.0) + ).substitute(-7.53452770353279), + 0.001, + "test 4" + ) + assertEquals( + 3.526835209398159, + ListRationalFunction( + ListPolynomial(-5.848840571263625, 0.0, 0.0, -9.624569269490076), + ListPolynomial(-2.9680680215311073, 0.0, 0.0, -2.7320154512368466) + ).substitute(-7.53452770353279), + 0.001, + "test 5" + ) + } + @Test + fun test_RationalFunction_substitute_Constant() { + assertEquals( + Rational(0), + ListRationalFunction( + ListPolynomial(Rational(1), Rational(-2), Rational(1)), + ListPolynomial(Rational(1)), + ).substitute(RationalField, Rational(1)), + "test 1" + ) + assertEquals( + Rational(1149615, 61306), + ListRationalFunction( + ListPolynomial(Rational(17, 7), Rational(18, 3), Rational(18, 8), Rational(9, 1)), + ListPolynomial(Rational(11, 9), Rational(-6, 5), Rational(-12, 7), Rational(2, 1)), + ).substitute(RationalField, Rational(-7, 8)), + "test 2" + ) + assertEquals( + Rational(3495, 586), + ListRationalFunction( + ListPolynomial(Rational(0), Rational(18, 3), Rational(18, 8), Rational(9, 1)), + ListPolynomial(Rational(0), Rational(-6, 5), Rational(-12, 7), Rational(2, 1)), + ).substitute(RationalField, Rational(-7, 8)), + "test 3" + ) + assertEquals( + Rational(-88605, 77392), + ListRationalFunction( + ListPolynomial(Rational(17, 7), Rational(18, 3), Rational(18, 8), Rational(0)), + ListPolynomial(Rational(11, 9), Rational(-6, 5), Rational(-12, 7), Rational(0)), + ).substitute(RationalField, Rational(-7, 8)), + "test 4" + ) + assertEquals( + Rational(116145, 3794), + ListRationalFunction( + ListPolynomial(Rational(17, 7), Rational(0), Rational(0), Rational(9, 1)), + ListPolynomial(Rational(11, 9), Rational(0), Rational(0), Rational(2, 1)), + ).substitute(RationalField, Rational(-7, 8)), + "test 5" + ) + } + @Test + fun test_RationalFunction_substitute_Polynomial() { + assertEquals( + ListRationalFunction( + ListPolynomial(Rational(0)), + ListPolynomial(Rational(1)) + ), + ListRationalFunction( + ListPolynomial(Rational(1), Rational(-2), Rational(1)), + ListPolynomial(Rational(1)), + ).substitute(RationalField, ListPolynomial(Rational(1))), + "test 1" + ) + assertEquals( + ListRationalFunction( + ListPolynomial( + Rational(-283303, 36), + Rational(-23593, 24), + Rational(368713, 192), + Rational(1455, 8), + Rational(-272171, 1536), + Rational(-2149, 192), + Rational(469, 64), + Rational(11, 48), + Rational(-11, 96) + ), + ListPolynomial( + Rational(5797, 12), + Rational(595, 16), + Rational(-5285, 72), + Rational(-745, 192), + Rational(1105, 288), + Rational(5, 48), + Rational(-5, 72) + ) + ), + ListRationalFunction( + ListPolynomial( + Rational(2, 9), + Rational(11, 3), + Rational(-9, 4), + Rational(-6, 1), + Rational(-11, 6) + ), + ListPolynomial( + Rational(-2, 3), + Rational(-15, 4), + Rational(5, 9), + Rational(-5, 9) + ) + ).substitute(RationalField, + ListPolynomial( + Rational(-9, 1), + Rational(-1, 4), + Rational(2, 4) + ) + ), + "test 2" + ) + assertEquals( + ListRationalFunction( + ListPolynomial( + Rational(0, 1), + Rational(-11, 12), + Rational(325, 192), + Rational(21, 32), + Rational(-1739, 1536), + Rational(227, 192), + Rational(-59, 64), + Rational(11, 48), + Rational(-11, 96) + ), + ListPolynomial( + Rational(0, 1), + Rational(15, 16), + Rational(-265, 144), + Rational(-25, 192), + Rational(25, 288), + Rational(5, 48), + Rational(-5, 72) + ) + ), + ListRationalFunction( + ListPolynomial( + Rational(0, 9), + Rational(11, 3), + Rational(-9, 4), + Rational(-6, 1), + Rational(-11, 6) + ), + ListPolynomial( + Rational(0, 3), + Rational(-15, 4), + Rational(5, 9), + Rational(-5, 9) + ) + ).substitute(RationalField, + ListPolynomial( + Rational(0, 1), + Rational(-1, 4), + Rational(2, 4) + ) + ), + "test 3" + ) + assertEquals( + ListRationalFunction( + ListPolynomial( + Rational(149723, 36), + Rational(8483, 24), + Rational(639, 64), + Rational(3, 32), + Rational(0), + Rational(0), + Rational(0), + Rational(0), + Rational(0) + ), + ListPolynomial( + Rational(937, 12), + Rational(55, 16), + Rational(5, 144), + Rational(0), + Rational(0), + Rational(0), + Rational(0) + ) + ), + ListRationalFunction( + ListPolynomial( + Rational(2, 9), + Rational(11, 3), + Rational(-9, 4), + Rational(-6, 1), + Rational(0) + ), + ListPolynomial( + Rational(-2, 3), + Rational(-15, 4), + Rational(5, 9), + Rational(0) + ) + ).substitute(RationalField, + ListPolynomial( + Rational(-9, 1), + Rational(-1, 4), + Rational(0) + ) + ), + "test 4" + ) + assertEquals( + ListRationalFunction( + ListPolynomial( + Rational(-216509, 18), + Rational(0, 1), + Rational(2673, 1), + Rational(0, 1), + Rational(-891, 4), + Rational(0, 1), + Rational(33, 4), + Rational(0, 1), + Rational(-11, 96) + ), + ListPolynomial( + Rational(1213, 3), + Rational(0, 1), + Rational(-135, 2), + Rational(0, 1), + Rational(15, 4), + Rational(0, 1), + Rational(-5, 72) + ) + ), + ListRationalFunction( + ListPolynomial( + Rational(2, 9), + Rational(0), + Rational(0), + Rational(0), + Rational(-11, 6) + ), + ListPolynomial( + Rational(-2, 3), + Rational(0), + Rational(0), + Rational(-5, 9) + ) + ).substitute(RationalField, + ListPolynomial( + Rational(-9, 1), + Rational(0), + Rational(2, 4) + ) + ), + "test 5" + ) + } + @Test + @Ignore // FIXME: This tests work only for sane realisations of the substitutions. Currently, it is not. + // Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should return denominator r^deg(p), + // not r^(deg(p)(deg(p)+1)/2) as it is now. + fun test_RationalFunction_substitute_RationalFunction() { + assertEquals( + ListRationalFunction( + ListPolynomial(Rational(0)), + ListPolynomial(Rational(1)) + ), + ListRationalFunction( + ListPolynomial(Rational(1), Rational(-2), Rational(1)), + ListPolynomial(Rational(1)) + ).substitute(RationalField, + ListRationalFunction( + ListPolynomial(Rational(1)), + ListPolynomial(Rational(1)) + ) + ), + "test 1" + ) + assertEquals( + ListRationalFunction( + ListPolynomial( + Rational(130087, 3888), + Rational(-2866333, 65610), + Rational(-5076229, 97200), + Rational(222136997, 3280500), + Rational(754719329, 20995200), + Rational(-12010283, 324000), + Rational(-2011967, 172800), + Rational(18607, 2880), + Rational(4705, 4096) + ), + ListPolynomial( + Rational(-143820355, 3779136), + Rational(73886869, 1574640), + Rational(1440175193, 15746400), + Rational(-5308968857, 52488000), + Rational(-186910083731, 2099520000), + Rational(125043463, 1555200), + Rational(5299123, 388800), + Rational(-213757, 15360), + Rational(1380785, 147456) + ) + ), + ListRationalFunction( + ListPolynomial( + Rational(1, 1), + Rational(-10, 5), + Rational(18, 8), + Rational(-8, 8) + ), + ListPolynomial( + Rational(-14, 8), + Rational(-14, 8), + Rational(-19, 6), + Rational(14, 3), + Rational(8, 9) + ) + ).substitute(RationalField, + ListRationalFunction( + ListPolynomial( + Rational(14, 9), + Rational(-2, 5), + Rational(-14, 7) + ), + ListPolynomial( + Rational(-6, 4), + Rational(5, 9), + Rational(1, 8) + ) + ) + ), + "test 2" + ) + assertEquals( + ListRationalFunction( + ListPolynomial( + Rational(0, 1), + Rational(0, 1), + Rational(0, 1), + Rational(0, 1), + Rational(5173, 18225), + Rational(904291, 364500), + Rational(283127, 43200), + Rational(37189, 5760), + Rational(147, 128) + ), + ListPolynomial( + Rational(0, 1), + Rational(0, 1), + Rational(0, 1), + Rational(0, 1), + Rational(-163589, 911250), + Rational(-881831, 291600), + Rational(-10722229, 777600), + Rational(-640921, 46080), + Rational(86303, 9216) + ) + ), + ListRationalFunction( + ListPolynomial( + Rational(0), + Rational(-10, 5), + Rational(18, 8), + Rational(-8, 8) + ), + ListPolynomial( + Rational(0), + Rational(-14, 8), + Rational(-19, 6), + Rational(14, 3), + Rational(8, 9) + ) + ).substitute(RationalField, + ListRationalFunction( + ListPolynomial( + Rational(0), + Rational(-2, 5), + Rational(-14, 7) + ), + ListPolynomial( + Rational(0), + Rational(5, 9), + Rational(1, 8) + ) + ) + ), + "test 3" + ) + assertEquals( + ListRationalFunction( + ListPolynomial( + Rational(445, 16), + Rational(-2011, 54), + Rational(1359199, 72900), + Rational(-135733, 32805), + Rational(2254, 6561), + Rational(0, 1), + Rational(0, 1), + Rational(0, 1), + Rational(0, 1) + ), + ListPolynomial( + Rational(-2018387, 46656), + Rational(82316437, 1574640), + Rational(-9335047, 393660), + Rational(15765889, 3280500), + Rational(-242089, 656100), + Rational(0, 1), + Rational(0, 1), + Rational(0, 1), + Rational(0, 1) + ) + ), + ListRationalFunction( + ListPolynomial( + Rational(1, 1), + Rational(-10, 5), + Rational(18, 8), + Rational(0) + ), + ListPolynomial( + Rational(-14, 8), + Rational(-14, 8), + Rational(-19, 6), + Rational(14, 3), + Rational(0) + ) + ).substitute(RationalField, + ListRationalFunction( + ListPolynomial( + Rational(14, 9), + Rational(-2, 5), + Rational(0) + ), + ListPolynomial( + Rational(-6, 4), + Rational(5, 9), + Rational(0) + ) + ) + ), + "test 4" + ) + assertEquals( + ListRationalFunction( + ListPolynomial( + Rational(41635, 3888), + Rational(0, 1), + Rational(-279187, 11664), + Rational(0, 1), + Rational(103769, 3456), + Rational(0, 1), + Rational(-11017, 768), + Rational(0, 1), + Rational(4097, 4096) + ), + ListPolynomial( + Rational(-13811791, 3779136), + Rational(0, 1), + Rational(-9999395, 419904), + Rational(0, 1), + Rational(6376601, 124416), + Rational(0, 1), + Rational(-3668315, 82944), + Rational(0, 1), + Rational(2097089, 147456) + ) + ), + ListRationalFunction( + ListPolynomial( + Rational(1, 1), + Rational(0), + Rational(0), + Rational(-8, 8) + ), + ListPolynomial( + Rational(-14, 8), + Rational(0), + Rational(0), + Rational(0), + Rational(8, 9) + ) + ).substitute(RationalField, + ListRationalFunction( + ListPolynomial( + Rational(14, 9), + Rational(0), + Rational(-14, 7) + ), + ListPolynomial( + Rational(-6, 4), + Rational(0), + Rational(1, 8) + ) + ) + ), + "test 5" + ) + } + @Test + fun test_Polynomial_derivative() { + assertEquals( + ListPolynomial(Rational(-2), Rational(2)), + ListPolynomial(Rational(1), Rational(-2), Rational(1)).derivative(RationalField), + "test 1" + ) + assertEquals( + ListPolynomial(Rational(-8, 3), Rational(8, 9), Rational(15, 7), Rational(-20, 9)), + ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).derivative(RationalField), + "test 2" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(8, 9), Rational(15, 7), Rational(-20, 9)), + ListPolynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).derivative(RationalField), + "test 3" + ) + assertEquals( + ListPolynomial(Rational(-8, 3), Rational(8, 9), Rational(15, 7), Rational(0)), + ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).derivative(RationalField), + "test 4" + ) + } + @Test + fun test_Polynomial_nthDerivative() { + assertEquals( + ListPolynomial(Rational(-2), Rational(2)), + ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 1), + "test 1" + ) + assertFailsWithTypeAndMessage( + "Order of derivative must be non-negative", + "test2" + ) { + ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, -1) + } + assertEquals( + ListPolynomial(Rational(1), Rational(-2), Rational(1)), + ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 0), + "test 3" + ) + assertEquals( + ListPolynomial(Rational(2)), + ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 2), + "test 4" + ) + assertEquals( + ListPolynomial(), + ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 3), + "test 5" + ) + assertEquals( + ListPolynomial(), + ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 4), + "test 6" + ) + assertEquals( + ListPolynomial(Rational(8, 9), Rational(30, 7), Rational(-20, 3)), + ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthDerivative(RationalField, 2), + "test 7" + ) + assertEquals( + ListPolynomial(Rational(8, 9), Rational(30, 7), Rational(-20, 3)), + ListPolynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthDerivative(RationalField, 2), + "test 8" + ) + assertEquals( + ListPolynomial(Rational(8, 9), Rational(30, 7), Rational(0)), + ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).nthDerivative(RationalField, 2), + "test 9" + ) + } + @Test + fun test_Polynomial_antiderivative() { + assertEquals( + ListPolynomial(Rational(0), Rational(1), Rational(-1), Rational(1, 3)), + ListPolynomial(Rational(1), Rational(-2), Rational(1)).antiderivative(RationalField), + "test 1" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(1, 5), Rational(-4, 3), Rational(4, 27), Rational(5, 28), Rational(-1, 9)), + ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).antiderivative(RationalField), + "test 2" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(4, 27), Rational(5, 28), Rational(-1, 9)), + ListPolynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).antiderivative(RationalField), + "test 3" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(1, 5), Rational(-4, 3), Rational(4, 27), Rational(5, 28), Rational(0)), + ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).antiderivative(RationalField), + "test 4" + ) + } + @Test + fun test_Polynomial_nthAntiderivative() { + assertEquals( + ListPolynomial(Rational(0), Rational(1), Rational(-1), Rational(1, 3)), + ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 1), + "test 1" + ) + assertFailsWithTypeAndMessage( + "Order of antiderivative must be non-negative", + "test2" + ) { + ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, -1) + } + assertEquals( + ListPolynomial(Rational(1), Rational(-2), Rational(1)), + ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 0), + "test 3" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(1, 2), Rational(-1, 3), Rational(1, 12)), + ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 2), + "test 4" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(1, 6), Rational(-1, 12), Rational(1, 60)), + ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 3), + "test 5" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0), Rational(1, 24), Rational(-1, 60), Rational(1, 360)), + ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 4), + "test 6" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(1, 10), Rational(-4, 9), Rational(1, 27), Rational(1, 28), Rational(-1, 54)), + ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthAntiderivative(RationalField, 2), + "test 7" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0), Rational(1, 27), Rational(1, 28), Rational(-1, 54)), + ListPolynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthAntiderivative(RationalField, 2), + "test 8" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(1, 10), Rational(-4, 9), Rational(1, 27), Rational(1, 28), Rational(0)), + ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).nthAntiderivative(RationalField, 2), + "test 9" + ) + } +} \ No newline at end of file diff --git a/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/BufferUtils.kt b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/BufferUtils.kt similarity index 80% rename from test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/BufferUtils.kt rename to kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/BufferUtils.kt index afd26dd36..3297733b1 100644 --- a/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/BufferUtils.kt +++ b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/BufferUtils.kt @@ -9,4 +9,4 @@ import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.asBuffer -public fun bufferOf(vararg elements: T): Buffer = elements.asBuffer() \ No newline at end of file +fun bufferOf(vararg elements: T): Buffer = elements.asBuffer() \ No newline at end of file diff --git a/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt similarity index 79% rename from test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt rename to kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt index 933c4dc4c..5bac4cd73 100644 --- a/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt +++ b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt @@ -10,9 +10,9 @@ package space.kscience.kmath.functions.testUtils import space.kscience.kmath.operations.Ring -public class IntModulo { - public val residue: Int - public val modulus: Int +class IntModulo { + val residue: Int + val modulus: Int @PublishedApi internal constructor(residue: Int, modulus: Int, toCheckInput: Boolean = true) { @@ -26,16 +26,16 @@ public class IntModulo { } } - public constructor(residue: Int, modulus: Int) : this(residue, modulus, true) + constructor(residue: Int, modulus: Int) : this(residue, modulus, true) - public operator fun unaryPlus(): IntModulo = this - public operator fun unaryMinus(): IntModulo = + operator fun unaryPlus(): IntModulo = this + operator fun unaryMinus(): IntModulo = IntModulo( if (residue == 0) 0 else modulus - residue, modulus, toCheckInput = false ) - public operator fun plus(other: IntModulo): IntModulo { + operator fun plus(other: IntModulo): IntModulo { require(modulus == other.modulus) { "can not add two residue different modulo" } return IntModulo( (residue + other.residue) % modulus, @@ -43,13 +43,13 @@ public class IntModulo { toCheckInput = false ) } - public operator fun plus(other: Int): IntModulo = + operator fun plus(other: Int): IntModulo = IntModulo( (residue + other) % modulus, modulus, toCheckInput = false ) - public operator fun minus(other: IntModulo): IntModulo { + operator fun minus(other: IntModulo): IntModulo { require(modulus == other.modulus) { "can not subtract two residue different modulo" } return IntModulo( (residue - other.residue) % modulus, @@ -57,13 +57,13 @@ public class IntModulo { toCheckInput = false ) } - public operator fun minus(other: Int): IntModulo = + operator fun minus(other: Int): IntModulo = IntModulo( (residue - other) % modulus, modulus, toCheckInput = false ) - public operator fun times(other: IntModulo): IntModulo { + operator fun times(other: IntModulo): IntModulo { require(modulus == other.modulus) { "can not multiply two residue different modulo" } return IntModulo( (residue * other.residue) % modulus, @@ -71,13 +71,13 @@ public class IntModulo { toCheckInput = false ) } - public operator fun times(other: Int): IntModulo = + operator fun times(other: Int): IntModulo = IntModulo( (residue * other) % modulus, modulus, toCheckInput = false ) - public operator fun div(other: IntModulo): IntModulo { + operator fun div(other: IntModulo): IntModulo { require(modulus == other.modulus) { "can not divide two residue different modulo" } val (reciprocalCandidate, gcdOfOtherResidueAndModulus) = bezoutIdentityWithGCD(other.residue, modulus) require(gcdOfOtherResidueAndModulus == 1) { "can not divide to residue that has non-trivial GCD with modulo" } @@ -87,7 +87,7 @@ public class IntModulo { toCheckInput = false ) } - public operator fun div(other: Int): IntModulo { + operator fun div(other: Int): IntModulo { val (reciprocalCandidate, gcdOfOtherResidueAndModulus) = bezoutIdentityWithGCD(other, modulus) require(gcdOfOtherResidueAndModulus == 1) { "can not divide to residue that has non-trivial GCD with modulo" } return IntModulo( @@ -108,11 +108,11 @@ public class IntModulo { } @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE") -public class IntModuloRing : Ring { +class IntModuloRing : Ring { - public val modulus: Int + val modulus: Int - public constructor(modulus: Int) { + constructor(modulus: Int) { require(modulus != 0) { "modulus can not be zero" } this.modulus = if (modulus < 0) -modulus else modulus } @@ -120,7 +120,7 @@ public class IntModuloRing : Ring { override inline val zero: IntModulo get() = IntModulo(0, modulus, toCheckInput = false) override inline val one: IntModulo get() = IntModulo(1, modulus, toCheckInput = false) - public fun number(arg: Int): IntModulo = IntModulo(arg, modulus, toCheckInput = false) + fun number(arg: Int): IntModulo = IntModulo(arg, modulus, toCheckInput = false) override inline fun add(left: IntModulo, right: IntModulo): IntModulo = left + right override inline fun multiply(left: IntModulo, right: IntModulo): IntModulo = left * right @@ -129,5 +129,5 @@ public class IntModuloRing : Ring { override inline fun IntModulo.plus(arg: IntModulo): IntModulo = this + arg override inline fun IntModulo.minus(arg: IntModulo): IntModulo = this - arg override inline fun IntModulo.times(arg: IntModulo): IntModulo = this * arg - public inline fun IntModulo.div(arg: IntModulo): IntModulo = this / arg + inline fun IntModulo.div(arg: IntModulo): IntModulo = this / arg } \ No newline at end of file diff --git a/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt similarity index 53% rename from test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt rename to kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt index 32ca1c3aa..33fd03aa0 100644 --- a/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt +++ b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt @@ -6,15 +6,14 @@ package space.kscience.kmath.functions.testUtils import space.kscience.kmath.functions.ListPolynomial -import space.kscience.kmath.functions.Polynomial import space.kscience.kmath.functions.ListPolynomialSpace import space.kscience.kmath.functions.PolynomialSpaceOverRing -public fun ListPolynomialSpace.ListPolynomial(vararg coefs: Int): ListPolynomial = +fun ListPolynomialSpace.ListPolynomial(vararg coefs: Int): ListPolynomial = ListPolynomial(coefs.map { IntModulo(it, ring.modulus) }) -public fun IntModuloRing.ListPolynomial(vararg coefs: Int): ListPolynomial = +fun IntModuloRing.ListPolynomial(vararg coefs: Int): ListPolynomial = ListPolynomial(coefs.map { IntModulo(it, modulus) }) -public fun IntModuloRing.m(arg: Int): IntModulo = IntModulo(arg, modulus) -public fun PolynomialSpaceOverRing.m(arg: Int): IntModulo = IntModulo(arg, ring.modulus) \ No newline at end of file +fun IntModuloRing.m(arg: Int): IntModulo = IntModulo(arg, modulus) +fun PolynomialSpaceOverRing.m(arg: Int): IntModulo = IntModulo(arg, ring.modulus) \ No newline at end of file diff --git a/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/NTMisc.kt b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/NTMisc.kt similarity index 100% rename from test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/NTMisc.kt rename to kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/NTMisc.kt diff --git a/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt similarity index 78% rename from test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt rename to kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt index 27b0eb21e..19cb77df5 100644 --- a/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt +++ b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt @@ -12,14 +12,14 @@ import space.kscience.kmath.operations.Field import space.kscience.kmath.operations.NumbersAddOps @Suppress("NAME_SHADOWING") -public class Rational { - public companion object { - public val ZERO: Rational = Rational(0L) - public val ONE: Rational = Rational(1L) +class Rational { + companion object { + val ZERO: Rational = Rational(0L) + val ONE: Rational = Rational(1L) } - public val numerator: Long - public val denominator: Long + val numerator: Long + val denominator: Long internal constructor(numerator: Long, denominator: Long, toCheckInput: Boolean = true) { if (toCheckInput) { @@ -35,16 +35,16 @@ public class Rational { } } - public constructor(numerator: Int, denominator: Int) : this(numerator.toLong(), denominator.toLong(), true) - public constructor(numerator: Int, denominator: Long) : this(numerator.toLong(), denominator, true) - public constructor(numerator: Long, denominator: Int) : this(numerator, denominator.toLong(), true) - public constructor(numerator: Long, denominator: Long) : this(numerator, denominator, true) - public constructor(numerator: Int) : this(numerator.toLong(), 1L, false) - public constructor(numerator: Long) : this(numerator, 1L, false) + constructor(numerator: Int, denominator: Int) : this(numerator.toLong(), denominator.toLong(), true) + constructor(numerator: Int, denominator: Long) : this(numerator.toLong(), denominator, true) + constructor(numerator: Long, denominator: Int) : this(numerator, denominator.toLong(), true) + constructor(numerator: Long, denominator: Long) : this(numerator, denominator, true) + constructor(numerator: Int) : this(numerator.toLong(), 1L, false) + constructor(numerator: Long) : this(numerator, 1L, false) - public operator fun unaryPlus(): Rational = this - public operator fun unaryMinus(): Rational = Rational(-this.numerator, this.denominator) - public operator fun plus(other: Rational): Rational { + operator fun unaryPlus(): Rational = this + operator fun unaryMinus(): Rational = Rational(-this.numerator, this.denominator) + operator fun plus(other: Rational): Rational { val denominatorsGcd = gcd(denominator, other.denominator) val dividedThisDenominator = denominator / denominatorsGcd val dividedOtherDenominator = other.denominator / denominatorsGcd @@ -56,19 +56,19 @@ public class Rational { toCheckInput = false ) } - public operator fun plus(other: Int): Rational = + operator fun plus(other: Int): Rational = Rational( numerator + denominator * other.toLong(), denominator, toCheckInput = false ) - public operator fun plus(other: Long): Rational = + operator fun plus(other: Long): Rational = Rational( numerator + denominator * other, denominator, toCheckInput = false ) - public operator fun minus(other: Rational): Rational { + operator fun minus(other: Rational): Rational { val denominatorsGcd = gcd(denominator, other.denominator) val dividedThisDenominator = denominator / denominatorsGcd val dividedOtherDenominator = other.denominator / denominatorsGcd @@ -80,19 +80,19 @@ public class Rational { toCheckInput = false ) } - public operator fun minus(other: Int): Rational = + operator fun minus(other: Int): Rational = Rational( numerator - denominator * other.toLong(), denominator, toCheckInput = false ) - public operator fun minus(other: Long): Rational = + operator fun minus(other: Long): Rational = Rational( numerator - denominator * other, denominator, toCheckInput = false ) - public operator fun times(other: Rational): Rational { + operator fun times(other: Rational): Rational { val thisDenominatorAndOtherNumeratorGcd = gcd(denominator, other.numerator) val otherDenominatorAndThisNumeratorGcd = gcd(other.denominator, numerator) return Rational( @@ -101,7 +101,7 @@ public class Rational { toCheckInput = false ) } - public operator fun times(other: Int): Rational { + operator fun times(other: Int): Rational { val other = other.toLong() val denominatorAndOtherGcd = gcd(denominator, other) return Rational( @@ -110,7 +110,7 @@ public class Rational { toCheckInput = false ) } - public operator fun times(other: Long): Rational { + operator fun times(other: Long): Rational { val denominatorAndOtherGcd = gcd(denominator, other) return Rational( numerator * (other / denominatorAndOtherGcd), @@ -118,7 +118,7 @@ public class Rational { toCheckInput = false ) } - public operator fun div(other: Rational): Rational { + operator fun div(other: Rational): Rational { val denominatorsGcd = gcd(denominator, other.denominator) val numeratorsGcd = gcd(numerator, other.numerator) return Rational( @@ -126,7 +126,7 @@ public class Rational { (denominator / denominatorsGcd) * (other.numerator / numeratorsGcd) ) } - public operator fun div(other: Int): Rational { + operator fun div(other: Int): Rational { val other = other.toLong() val numeratorAndOtherGcd = gcd(numerator, other) return Rational( @@ -135,7 +135,7 @@ public class Rational { toCheckInput = false ) } - public operator fun div(other: Long): Rational { + operator fun div(other: Long): Rational { val numeratorAndOtherGcd = gcd(numerator, other) return Rational( numerator / numeratorAndOtherGcd, @@ -158,7 +158,7 @@ public class Rational { @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE") @OptIn(UnstableKMathAPI::class) -public object RationalField : Field, NumbersAddOps { +object RationalField : Field, NumbersAddOps { override inline val zero: Rational get() = Rational.ZERO override inline val one: Rational get() = Rational.ONE diff --git a/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt similarity index 92% rename from test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt rename to kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt index 5d0b77aa8..4ef87f736 100644 --- a/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt +++ b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt @@ -13,7 +13,7 @@ import kotlin.test.assertEquals import kotlin.test.assertFailsWith -public fun assertContentEquals( +fun assertContentEquals( expected: Map, actual: Map, absoluteTolerance: Double, @@ -23,7 +23,7 @@ public fun assertContentEquals( for ((key, expectedValue) in expected) assertEquals(expectedValue, actual[key]!!, absoluteTolerance, message) } -public fun assertEquals( +fun assertEquals( expected: NumberedPolynomial, actual: NumberedPolynomial, absoluteTolerance: Double, @@ -37,7 +37,7 @@ public fun assertEquals( ) } -public fun assertEquals( +fun assertEquals( expected: LabeledPolynomial, actual: LabeledPolynomial, absoluteTolerance: Double, @@ -51,7 +51,7 @@ public fun assertEquals( ) } -public fun assertEquals( +fun assertEquals( expected: NumberedRationalFunction, actual: NumberedRationalFunction, absoluteTolerance: Double, @@ -71,7 +71,7 @@ public fun assertEquals( ) } -public fun assertEquals( +fun assertEquals( expected: LabeledRationalFunction, actual: LabeledRationalFunction, absoluteTolerance: Double, @@ -91,7 +91,7 @@ public fun assertEquals( ) } -public inline fun assertFailsWithTypeAndMessage( +inline fun assertFailsWithTypeAndMessage( expectedMessage: String? = null, assertionMessage: String? = null, block: () -> Unit diff --git a/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/misc.kt b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/misc.kt similarity index 58% rename from test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/misc.kt rename to kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/misc.kt index 051fc0f37..93c3f8ea5 100644 --- a/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/misc.kt +++ b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/misc.kt @@ -9,11 +9,11 @@ import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.expressions.symbol -public val o: Rational = Rational(0) +val o: Rational = Rational(0) -public val x: Symbol by symbol -public val y: Symbol by symbol -public val z: Symbol by symbol -public val t: Symbol by symbol -public val s: Symbol by symbol -public val iota: Symbol by symbol \ No newline at end of file +val x: Symbol by symbol +val y: Symbol by symbol +val z: Symbol by symbol +val t: Symbol by symbol +val s: Symbol by symbol +val iota: Symbol by symbol \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index bdd83d04e..336e1c36b 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -26,9 +26,7 @@ include( ":kmath-core", ":kmath-coroutines", ":kmath-functions", - ":test-utils-functions", ":kmath-polynomial", - ":test-utils-polynomial", ":kmath-histograms", ":kmath-commons", ":kmath-viktor", diff --git a/test-utils-functions/build.gradle.kts b/test-utils-functions/build.gradle.kts deleted file mode 100644 index 8476abecc..000000000 --- a/test-utils-functions/build.gradle.kts +++ /dev/null @@ -1,14 +0,0 @@ -plugins { - id("ru.mipt.npm.gradle.mpp") - id("ru.mipt.npm.gradle.native") -} - -kotlin.sourceSets { - commonMain { - dependencies { - api(projects.kmathCore) - api(projects.kmathFunctions) - api(kotlin("test")) - } - } -} diff --git a/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt b/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt deleted file mode 100644 index 5cf82996f..000000000 --- a/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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.functions.testUtils - -import kotlin.test.assertEquals -import kotlin.test.assertFailsWith - - -public inline fun assertFailsWithTypeAndMessage( - expectedMessage: String? = null, - assertionMessage: String? = null, - block: () -> Unit -) { - assertEquals( - expectedMessage, - assertFailsWith(T::class, assertionMessage, block).message, - assertionMessage - ) -} \ No newline at end of file diff --git a/test-utils-polynomial/build.gradle.kts b/test-utils-polynomial/build.gradle.kts deleted file mode 100644 index e10e1f2b1..000000000 --- a/test-utils-polynomial/build.gradle.kts +++ /dev/null @@ -1,14 +0,0 @@ -plugins { - id("ru.mipt.npm.gradle.mpp") - id("ru.mipt.npm.gradle.native") -} - -kotlin.sourceSets { - commonMain { - dependencies { - api(projects.kmathCore) - api(projects.kmathPolynomial) - api(kotlin("test")) - } - } -} -- 2.34.1 From 99c7174802e263d1961322a658d85b5e0da9d0a4 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sat, 16 Jul 2022 20:55:10 +0300 Subject: [PATCH 113/123] Turn Polynomial data class back. --- .../kotlin/space/kscience/kmath/functions/Polynomial.kt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) 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 1e811d3ba..b57697dd9 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 @@ -10,7 +10,6 @@ package space.kscience.kmath.functions import space.kscience.kmath.operations.Ring import space.kscience.kmath.operations.ScaleOperations import space.kscience.kmath.operations.invoke -import kotlin.jvm.JvmInline import kotlin.math.max import kotlin.math.min @@ -20,8 +19,7 @@ import kotlin.math.min * * @param C the type of constants. */ -@JvmInline -public value class Polynomial( +public data class Polynomial( /** * List that contains coefficients of the polynomial. * -- 2.34.1 From 2d86cf1cc7e6294185038b2b34fc08c7bd17b040 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sat, 16 Jul 2022 21:55:35 +0300 Subject: [PATCH 114/123] Remove power overriding and algebraic stub. --- .../kscience/kmath/functions/Polynomial.kt | 4 - .../kscience/kmath/functions/algebraicStub.kt | 51 ------- .../kmath/functions/AlgebraicStubTest.kt | 129 ------------------ 3 files changed, 184 deletions(-) delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt delete mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/AlgebraicStubTest.kt 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 b57697dd9..9275ff8eb 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 @@ -247,10 +247,6 @@ public open class PolynomialSpace( ) } } - /** - * Raises [arg] to the integer power [exponent]. - */ // TODO: To optimize boxing - override fun power(arg: Polynomial, exponent: UInt): Polynomial = exponentiateBySquaring(arg, exponent) /** * Instance of zero polynomial (zero of the polynomial ring). diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt deleted file mode 100644 index 5eb1af4dc..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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.functions - -import space.kscience.kmath.operations.* - - -// TODO: All of this should be moved to algebraic structures' place for utilities -// FIXME: Move receiver to context receiver -/** - * Raises [arg] to the integer power [exponent]. - * - * This is implementation of variation of [exponentiation by squaring](https://en.wikipedia.org/wiki/Exponentiation_by_squaring) - * - * @param arg the base of the power. - * @param exponent the exponent of the power. - * @return [arg] raised to the power [exponent]. - * @author Gleb Minaev - */ -internal tailrec fun Ring.exponentiateBySquaring(arg: C, exponent: UInt): C = - when { - exponent == 0u -> zero - exponent == 1u -> arg - exponent and 1u == 0u -> exponentiateBySquaring(arg * arg, exponent shr 1) - exponent and 1u == 1u -> multiplyExponentiatedBySquaring(arg, arg * arg, exponent shr 1) - else -> error("Error in multiplication group instant by unsigned integer: got reminder by division by 2 different from 0 and 1") - } - -// FIXME: Move receiver to context receiver -/** - * Multiplies [base] and [arg] raised to the integer power [exponent]. - * - * This is implementation of variation of [exponentiation by squaring](https://en.wikipedia.org/wiki/Exponentiation_by_squaring) - * - * @param base the multiplicand. - * @param arg the base of the power. - * @param exponent the exponent of the power. - * @return product of [base] and [arg] raised to the power [exponent]. - * @author Gleb Minaev - */ -internal tailrec fun RingOps.multiplyExponentiatedBySquaring(base: C, arg: C, exponent: UInt): C = - when { - exponent == 0u -> base - exponent == 1u -> base * arg - exponent and 1u == 0u -> multiplyExponentiatedBySquaring(base, arg * arg, exponent shr 1) - exponent and 1u == 1u -> multiplyExponentiatedBySquaring(base * arg, arg * arg, exponent shr 1) - else -> error("Error in multiplication group instant by unsigned integer: got reminder by division by 2 different from 0 and 1") - } \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/AlgebraicStubTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/AlgebraicStubTest.kt deleted file mode 100644 index 5782292b1..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/AlgebraicStubTest.kt +++ /dev/null @@ -1,129 +0,0 @@ -/* - * 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.functions - - -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.operations.Field -import kotlin.jvm.JvmInline -import kotlin.test.Test -import kotlin.test.assertEquals - -@JvmInline -value class Expr(val expr: String) - -object ExprRing : Field { - override fun Expr.unaryMinus(): Expr = Expr("-${expr}") - override fun add(left: Expr, right: Expr): Expr = Expr("(${left.expr} + ${right.expr})") - override fun multiply(left: Expr, right: Expr): Expr = Expr("(${left.expr} * ${right.expr})") - override val zero: Expr = Expr("0") - override val one: Expr = Expr("1") - override fun divide(left: Expr, right: Expr): Expr = Expr("(${left.expr} / ${right.expr})") - override fun scale(a: Expr, value: Double): Expr = Expr("(${a.expr} / $value)") -} - -class AlgebraicStubTest { - @Test - fun test_multiplyExponentiationBySquaring_for_UInt() { - ExprRing { - assertEquals( - "57", - multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 0u).expr, - "tried multiplyExponentiationBySquaring(57, 179, 0u)" - ) - assertEquals( - "(57 * 179)", - multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 1u).expr, - "tried multiplyExponentiationBySquaring(57, 179, 1u)" - ) - assertEquals( - "(57 * (179 * 179))", - multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 2u).expr, - "tried multiplyExponentiationBySquaring(57, 179, 2u)" - ) - assertEquals( - "((57 * 179) * (179 * 179))", - multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 3u).expr, - "tried multiplyExponentiationBySquaring(57, 179, 3u)" - ) - assertEquals( - "(57 * ((179 * 179) * (179 * 179)))", - multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 4u).expr, - "tried multiplyExponentiationBySquaring(57, 179, 4u)" - ) - assertEquals( - "((57 * 179) * ((179 * 179) * (179 * 179)))", - multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 5u).expr, - "tried multiplyExponentiationBySquaring(57, 179, 5u)" - ) - assertEquals( - "((57 * (179 * 179)) * ((179 * 179) * (179 * 179)))", - multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 6u).expr, - "tried multiplyExponentiationBySquaring(57, 179, 6u)" - ) - assertEquals( - "(((57 * 179) * (179 * 179)) * ((179 * 179) * (179 * 179)))", - multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 7u).expr, - "tried multiplyExponentiationBySquaring(57, 179, 7u)" - ) - assertEquals( - "(57 * (((179 * 179) * (179 * 179)) * ((179 * 179) * (179 * 179))))", - multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 8u).expr, - "tried multiplyExponentiationBySquaring(57, 179, 8u)" - ) - } - } - @Test - fun test_exponentiationBySquaring_for_UInt() { - ExprRing { - assertEquals( - "0", - exponentiateBySquaring(Expr("57"), 0u).expr, - "tried exponentiationBySquaring(57, 0u)" - ) - assertEquals( - "57", - exponentiateBySquaring(Expr("57"), 1u).expr, - "tried exponentiationBySquaring(57, 1u)" - ) - assertEquals( - "(57 * 57)", - exponentiateBySquaring(Expr("57"), 2u).expr, - "tried exponentiationBySquaring(57, 2u)" - ) - assertEquals( - "(57 * (57 * 57))", - exponentiateBySquaring(Expr("57"), 3u).expr, - "tried exponentiationBySquaring(57, 3u)" - ) - assertEquals( - "((57 * 57) * (57 * 57))", - exponentiateBySquaring(Expr("57"), 4u).expr, - "tried exponentiationBySquaring(57, 4u)" - ) - assertEquals( - "(57 * ((57 * 57) * (57 * 57)))", - exponentiateBySquaring(Expr("57"), 5u).expr, - "tried exponentiationBySquaring(57, 5u)" - ) - assertEquals( - "((57 * 57) * ((57 * 57) * (57 * 57)))", - exponentiateBySquaring(Expr("57"), 6u).expr, - "tried exponentiationBySquaring(57, 6u)" - ) - assertEquals( - "((57 * (57 * 57)) * ((57 * 57) * (57 * 57)))", - exponentiateBySquaring(Expr("57"), 7u).expr, - "tried exponentiationBySquaring(57, 7u)" - ) - assertEquals( - "(((57 * 57) * (57 * 57)) * ((57 * 57) * (57 * 57)))", - exponentiateBySquaring(Expr("57"), 8u).expr, - "tried exponentiationBySquaring(57, 8u)" - ) - } - } -} \ No newline at end of file -- 2.34.1 From f48e4483cc282730f6d7b6e9bddbb47046360682 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sat, 16 Jul 2022 22:21:13 +0300 Subject: [PATCH 115/123] Last cosmetic changes. --- .../kscience/kmath/functions/Polynomial.kt | 81 +++++++++---------- .../kmath/functions/polynomialUtil.kt | 4 +- 2 files changed, 39 insertions(+), 46 deletions(-) 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 9275ff8eb..1f9bab52c 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 @@ -50,7 +50,7 @@ public data class Polynomial( */ public val coefficients: List ) { - override fun toString(): String = "ListPolynomial$coefficients" + override fun toString(): String = "Polynomial$coefficients" } /** @@ -63,7 +63,7 @@ public data class Polynomial( */ public open class PolynomialSpace( /** - * Underlying ring of constants. Its operations on constants are inherited by local operations on constants. + * Underlying ring of constants. Its operations on constants are used by local operations on constants and polynomials. */ public val ring: A, ) : Ring>, ScaleOperations> where A : Ring, A : ScaleOperations { @@ -191,61 +191,54 @@ public open class PolynomialSpace( /** * Returns negation of the polynomial. */ - public override operator fun Polynomial.unaryMinus(): Polynomial = - with(ring) { - Polynomial(coefficients.map { -it }) - } + public override operator fun Polynomial.unaryMinus(): Polynomial = ring { + Polynomial(coefficients.map { -it }) + } /** * Returns sum of the polynomials. */ - public override operator fun Polynomial.plus(other: Polynomial): Polynomial { - with(ring) { - val thisDegree = degree - val otherDegree = other.degree - return Polynomial( - List(max(thisDegree, otherDegree) + 1) { - when { - it > thisDegree -> other.coefficients[it] - it > otherDegree -> coefficients[it] - else -> coefficients[it] + other.coefficients[it] - } + public override operator fun Polynomial.plus(other: Polynomial): Polynomial = ring { + val thisDegree = degree + val otherDegree = other.degree + return Polynomial( + List(max(thisDegree, otherDegree) + 1) { + when { + it > thisDegree -> other.coefficients[it] + it > otherDegree -> coefficients[it] + else -> coefficients[it] + other.coefficients[it] } - ) - } + } + ) } /** * Returns difference of the polynomials. */ - public override operator fun Polynomial.minus(other: Polynomial): Polynomial { - with(ring) { - val thisDegree = degree - val otherDegree = other.degree - return Polynomial( - List(max(thisDegree, otherDegree) + 1) { - when { - it > thisDegree -> -other.coefficients[it] - it > otherDegree -> coefficients[it] - else -> coefficients[it] - other.coefficients[it] - } + public override operator fun Polynomial.minus(other: Polynomial): Polynomial = ring { + val thisDegree = degree + val otherDegree = other.degree + return Polynomial( + List(max(thisDegree, otherDegree) + 1) { + when { + it > thisDegree -> -other.coefficients[it] + it > otherDegree -> coefficients[it] + else -> coefficients[it] - other.coefficients[it] } - ) - } + } + ) } /** * Returns product of the polynomials. */ - public override operator fun Polynomial.times(other: Polynomial): Polynomial { - with(ring) { - val thisDegree = degree - val otherDegree = other.degree - return Polynomial( - List(thisDegree + otherDegree + 1) { d -> - (max(0, d - otherDegree)..min(thisDegree, d)) - .map { coefficients[it] * other.coefficients[d - it] } - .reduce { acc, rational -> acc + rational } - } - ) - } + public override operator fun Polynomial.times(other: Polynomial): Polynomial = ring { + val thisDegree = degree + val otherDegree = other.degree + return Polynomial( + List(thisDegree + otherDegree + 1) { d -> + (max(0, d - otherDegree)..min(thisDegree, d)) + .map { coefficients[it] * other.coefficients[d - it] } + .reduce { acc, rational -> acc + rational } + } + ) } /** diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt index f745bf6e4..c9377a6c1 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt @@ -91,7 +91,7 @@ public fun Polynomial.integrate( public fun > Polynomial.integrate( ring: Field, range: ClosedRange, -): C { +): C = ring { val antiderivative = integrate(ring) - return ring { antiderivative.value(ring, range.endInclusive) - antiderivative.value(ring, range.start) } + return antiderivative.value(ring, range.endInclusive) - antiderivative.value(ring, range.start) } \ No newline at end of file -- 2.34.1 From 9d4df5d8e03a1aadb85109e3fabb2d25694b1695 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Wed, 20 Jul 2022 08:22:41 +0300 Subject: [PATCH 116/123] Add and regenerate READMEs. Fix files' directory. --- README.md | 31 +++++++++++- kmath-ast/README.md | 6 +-- kmath-commons/README.md | 6 +-- kmath-complex/README.md | 10 ++-- kmath-core/README.md | 6 +-- kmath-coroutines/README.md | 6 +-- kmath-dimensions/README.md | 6 +-- kmath-ejml/README.md | 6 +-- kmath-for-real/README.md | 6 +-- kmath-functions/README.md | 6 +-- kmath-geometry/README.md | 6 +-- kmath-histograms/README.md | 6 +-- kmath-jafama/README.md | 6 +-- kmath-jupyter/README.md | 6 +-- kmath-kotlingrad/README.md | 6 +-- kmath-memory/README.md | 6 +-- kmath-multik/README.md | 6 +-- kmath-nd4j/README.md | 6 +-- kmath-optimization/README.md | 6 +-- kmath-polynomial/README.md | 50 +++++++++++++++++++ kmath-polynomial/build.gradle.kts | 43 +++++++++++++++- .../kmath/functions}/LabeledPolynomial.kt | 0 .../functions}/LabeledRationalFunction.kt | 0 .../kmath/functions}/ListPolynomial.kt | 0 .../kmath/functions}/ListRationalFunction.kt | 0 .../kmath/functions}/NumberedPolynomial.kt | 0 .../functions}/NumberedRationalFunction.kt | 0 .../kscience/kmath/functions}/Polynomial.kt | 0 .../kmath/functions}/RationalFunction.kt | 0 .../kmath/functions}/algebraicStub.kt | 0 .../kmath/functions}/collectionUtils.kt | 0 .../kmath/functions}/labeledConstructors.kt | 0 .../kscience/kmath/functions}/labeledUtil.kt | 0 .../kmath/functions}/listConstructors.kt | 0 .../kscience/kmath/functions}/listUtil.kt | 0 .../kscience/kmath/functions}/misc.kt | 0 .../kmath/functions}/numberedConstructors.kt | 0 .../kscience/kmath/functions}/numberedUtil.kt | 0 kmath-stat/README.md | 6 +-- kmath-symja/README.md | 6 +-- kmath-tensorflow/README.md | 6 +-- kmath-tensors/README.md | 6 +-- kmath-viktor/README.md | 6 +-- 43 files changed, 192 insertions(+), 74 deletions(-) create mode 100644 kmath-polynomial/README.md rename kmath-polynomial/src/commonMain/kotlin/{space.kscience.kmath.functions => space/kscience/kmath/functions}/LabeledPolynomial.kt (100%) rename kmath-polynomial/src/commonMain/kotlin/{space.kscience.kmath.functions => space/kscience/kmath/functions}/LabeledRationalFunction.kt (100%) rename kmath-polynomial/src/commonMain/kotlin/{space.kscience.kmath.functions => space/kscience/kmath/functions}/ListPolynomial.kt (100%) rename kmath-polynomial/src/commonMain/kotlin/{space.kscience.kmath.functions => space/kscience/kmath/functions}/ListRationalFunction.kt (100%) rename kmath-polynomial/src/commonMain/kotlin/{space.kscience.kmath.functions => space/kscience/kmath/functions}/NumberedPolynomial.kt (100%) rename kmath-polynomial/src/commonMain/kotlin/{space.kscience.kmath.functions => space/kscience/kmath/functions}/NumberedRationalFunction.kt (100%) rename kmath-polynomial/src/commonMain/kotlin/{space.kscience.kmath.functions => space/kscience/kmath/functions}/Polynomial.kt (100%) rename kmath-polynomial/src/commonMain/kotlin/{space.kscience.kmath.functions => space/kscience/kmath/functions}/RationalFunction.kt (100%) rename kmath-polynomial/src/commonMain/kotlin/{space.kscience.kmath.functions => space/kscience/kmath/functions}/algebraicStub.kt (100%) rename kmath-polynomial/src/commonMain/kotlin/{space.kscience.kmath.functions => space/kscience/kmath/functions}/collectionUtils.kt (100%) rename kmath-polynomial/src/commonMain/kotlin/{space.kscience.kmath.functions => space/kscience/kmath/functions}/labeledConstructors.kt (100%) rename kmath-polynomial/src/commonMain/kotlin/{space.kscience.kmath.functions => space/kscience/kmath/functions}/labeledUtil.kt (100%) rename kmath-polynomial/src/commonMain/kotlin/{space.kscience.kmath.functions => space/kscience/kmath/functions}/listConstructors.kt (100%) rename kmath-polynomial/src/commonMain/kotlin/{space.kscience.kmath.functions => space/kscience/kmath/functions}/listUtil.kt (100%) rename kmath-polynomial/src/commonMain/kotlin/{space.kscience.kmath.functions => space/kscience/kmath/functions}/misc.kt (100%) rename kmath-polynomial/src/commonMain/kotlin/{space.kscience.kmath.functions => space/kscience/kmath/functions}/numberedConstructors.kt (100%) rename kmath-polynomial/src/commonMain/kotlin/{space.kscience.kmath.functions => space/kscience/kmath/functions}/numberedUtil.kt (100%) diff --git a/README.md b/README.md index 8353d341b..39cbf19c9 100644 --- a/README.md +++ b/README.md @@ -86,8 +86,8 @@ module definitions below. The module stability could have the following levels: > **Maturity**: PROTOTYPE > > **Features:** -> - [complex](kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt) : Complex Numbers -> - [quaternion](kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt) : Quaternions +> - [complex](kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt) : Complex numbers operations +> - [quaternion](kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt) : Quaternions and their composition ### [kmath-core](kmath-core) @@ -214,6 +214,28 @@ One can still use generic algebras though. > > **Maturity**: EXPERIMENTAL +### [kmath-polynomial](kmath-polynomial) +> +> +> **Maturity**: PROTOTYPE +> +> **Features:** +> - [polynomial abstraction](kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt) : Abstraction for polynomial spaces. +> - [rational function abstraction](kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt) : Abstraction for rational functions spaces. +> - ["list" polynomials](kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt) : List implementation of univariate polynomials. +> - ["list" rational functions](kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt) : List implementation of univariate rational functions. +> - ["list" polynomials and rational functions constructors](kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt) : Constructors for list polynomials and rational functions. +> - ["list" polynomials and rational functions utilities](kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt) : Utilities for list polynomials and rational functions. +> - ["numbered" polynomials](kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt) : Numbered implementation of multivariate polynomials. +> - ["numbered" rational functions](kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt) : Numbered implementation of multivariate rational functions. +> - ["numbered" polynomials and rational functions constructors](kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt) : Constructors for numbered polynomials and rational functions. +> - ["numbered" polynomials and rational functions utilities](kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt) : Utilities for numbered polynomials and rational functions. +> - ["labeled" polynomials](kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt) : Labeled implementation of multivariate polynomials. +> - ["labeled" rational functions](kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt) : Labeled implementation of multivariate rational functions. +> - ["labeled" polynomials and rational functions constructors](kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt) : Constructors for labeled polynomials and rational functions. +> - ["labeled" polynomials and rational functions utilities](kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/labeledUtil.kt) : Utilities for labeled polynomials and rational functions. + + ### [kmath-stat](kmath-stat) > > @@ -245,6 +267,11 @@ One can still use generic algebras though. > > **Maturity**: DEVELOPMENT +### [test-utils](test-utils) +> +> +> **Maturity**: EXPERIMENTAL + ## Multi-platform support diff --git a/kmath-ast/README.md b/kmath-ast/README.md index 553c60bb3..c6da64982 100644 --- a/kmath-ast/README.md +++ b/kmath-ast/README.md @@ -10,7 +10,7 @@ Extensions to MST API: transformations, dynamic compilation and visualization. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-ast:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-ast:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -20,7 +20,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-ast:0.3.0' + implementation 'space.kscience:kmath-ast:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -31,7 +31,7 @@ repositories { } dependencies { - implementation("space.kscience:kmath-ast:0.3.0") + implementation("space.kscience:kmath-ast:0.3.1-dev-1") } ``` diff --git a/kmath-commons/README.md b/kmath-commons/README.md index 7195e6fb1..89f1f6c9f 100644 --- a/kmath-commons/README.md +++ b/kmath-commons/README.md @@ -6,7 +6,7 @@ Commons math binding for kmath ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-commons:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-commons:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -16,7 +16,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-commons:0.3.0' + implementation 'space.kscience:kmath-commons:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -27,6 +27,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-commons:0.3.0") + implementation("space.kscience:kmath-commons:0.3.1-dev-1") } ``` diff --git a/kmath-complex/README.md b/kmath-complex/README.md index 4646c6a80..f00952065 100644 --- a/kmath-complex/README.md +++ b/kmath-complex/README.md @@ -2,13 +2,13 @@ Complex and hypercomplex number systems in KMath. - - [complex](src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt) : Complex Numbers - - [quaternion](src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt) : Quaternions + - [complex](src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt) : Complex numbers operations + - [quaternion](src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt) : Quaternions and their composition ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-complex:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-complex:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -18,7 +18,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-complex:0.3.0' + implementation 'space.kscience:kmath-complex:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -29,6 +29,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-complex:0.3.0") + implementation("space.kscience:kmath-complex:0.3.1-dev-1") } ``` diff --git a/kmath-core/README.md b/kmath-core/README.md index 4fddd327c..e84ca38d7 100644 --- a/kmath-core/README.md +++ b/kmath-core/README.md @@ -15,7 +15,7 @@ performance calculations to code generation. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-core:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-core:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -25,7 +25,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-core:0.3.0' + implementation 'space.kscience:kmath-core:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -36,6 +36,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-core:0.3.0") + implementation("space.kscience:kmath-core:0.3.1-dev-1") } ``` diff --git a/kmath-coroutines/README.md b/kmath-coroutines/README.md index d0fef6e0f..337d8e037 100644 --- a/kmath-coroutines/README.md +++ b/kmath-coroutines/README.md @@ -6,7 +6,7 @@ ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-coroutines:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-coroutines:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -16,7 +16,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-coroutines:0.3.0' + implementation 'space.kscience:kmath-coroutines:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -27,6 +27,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-coroutines:0.3.0") + implementation("space.kscience:kmath-coroutines:0.3.1-dev-1") } ``` diff --git a/kmath-dimensions/README.md b/kmath-dimensions/README.md index 650bcafde..12aa2a7fa 100644 --- a/kmath-dimensions/README.md +++ b/kmath-dimensions/README.md @@ -6,7 +6,7 @@ A proof of concept module for adding type-safe dimensions to structures ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-dimensions:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-dimensions:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -16,7 +16,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-dimensions:0.3.0' + implementation 'space.kscience:kmath-dimensions:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -27,6 +27,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-dimensions:0.3.0") + implementation("space.kscience:kmath-dimensions:0.3.1-dev-1") } ``` diff --git a/kmath-ejml/README.md b/kmath-ejml/README.md index eaa90120f..2d6c661e4 100644 --- a/kmath-ejml/README.md +++ b/kmath-ejml/README.md @@ -9,7 +9,7 @@ EJML based linear algebra implementation. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-ejml:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-ejml:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -19,7 +19,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-ejml:0.3.0' + implementation 'space.kscience:kmath-ejml:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -30,6 +30,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-ejml:0.3.0") + implementation("space.kscience:kmath-ejml:0.3.1-dev-1") } ``` diff --git a/kmath-for-real/README.md b/kmath-for-real/README.md index 9e8f95a16..5a8376976 100644 --- a/kmath-for-real/README.md +++ b/kmath-for-real/README.md @@ -9,7 +9,7 @@ Specialization of KMath APIs for Double numbers. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-for-real:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-for-real:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -19,7 +19,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-for-real:0.3.0' + implementation 'space.kscience:kmath-for-real:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -30,6 +30,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-for-real:0.3.0") + implementation("space.kscience:kmath-for-real:0.3.1-dev-1") } ``` diff --git a/kmath-functions/README.md b/kmath-functions/README.md index 3f44bd3f9..1292424b5 100644 --- a/kmath-functions/README.md +++ b/kmath-functions/README.md @@ -11,7 +11,7 @@ Functions and interpolations. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-functions:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-functions:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -21,7 +21,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-functions:0.3.0' + implementation 'space.kscience:kmath-functions:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -32,6 +32,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-functions:0.3.0") + implementation("space.kscience:kmath-functions:0.3.1-dev-1") } ``` diff --git a/kmath-geometry/README.md b/kmath-geometry/README.md index 6602f5510..72d275697 100644 --- a/kmath-geometry/README.md +++ b/kmath-geometry/README.md @@ -6,7 +6,7 @@ ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-geometry:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-geometry:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -16,7 +16,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-geometry:0.3.0' + implementation 'space.kscience:kmath-geometry:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -27,6 +27,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-geometry:0.3.0") + implementation("space.kscience:kmath-geometry:0.3.1-dev-1") } ``` diff --git a/kmath-histograms/README.md b/kmath-histograms/README.md index 27f1b43ec..5fd91ee0c 100644 --- a/kmath-histograms/README.md +++ b/kmath-histograms/README.md @@ -6,7 +6,7 @@ ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-histograms:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-histograms:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -16,7 +16,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-histograms:0.3.0' + implementation 'space.kscience:kmath-histograms:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -27,6 +27,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-histograms:0.3.0") + implementation("space.kscience:kmath-histograms:0.3.1-dev-1") } ``` diff --git a/kmath-jafama/README.md b/kmath-jafama/README.md index fe6afb835..c008c76ca 100644 --- a/kmath-jafama/README.md +++ b/kmath-jafama/README.md @@ -7,7 +7,7 @@ Integration with [Jafama](https://github.com/jeffhain/jafama). ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-jafama:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-jafama:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -17,7 +17,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-jafama:0.3.0' + implementation 'space.kscience:kmath-jafama:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -28,7 +28,7 @@ repositories { } dependencies { - implementation("space.kscience:kmath-jafama:0.3.0") + implementation("space.kscience:kmath-jafama:0.3.1-dev-1") } ``` diff --git a/kmath-jupyter/README.md b/kmath-jupyter/README.md index db58ad840..3c9832625 100644 --- a/kmath-jupyter/README.md +++ b/kmath-jupyter/README.md @@ -6,7 +6,7 @@ ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-jupyter:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-jupyter:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -16,7 +16,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-jupyter:0.3.0' + implementation 'space.kscience:kmath-jupyter:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -27,6 +27,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-jupyter:0.3.0") + implementation("space.kscience:kmath-jupyter:0.3.1-dev-1") } ``` diff --git a/kmath-kotlingrad/README.md b/kmath-kotlingrad/README.md index 52e8b3116..457652aaf 100644 --- a/kmath-kotlingrad/README.md +++ b/kmath-kotlingrad/README.md @@ -8,7 +8,7 @@ ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-kotlingrad:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-kotlingrad:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -18,7 +18,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-kotlingrad:0.3.0' + implementation 'space.kscience:kmath-kotlingrad:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -29,6 +29,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-kotlingrad:0.3.0") + implementation("space.kscience:kmath-kotlingrad:0.3.1-dev-1") } ``` diff --git a/kmath-memory/README.md b/kmath-memory/README.md index 9f4520bd8..536d7f145 100644 --- a/kmath-memory/README.md +++ b/kmath-memory/README.md @@ -6,7 +6,7 @@ ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-memory:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-memory:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -16,7 +16,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-memory:0.3.0' + implementation 'space.kscience:kmath-memory:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -27,6 +27,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-memory:0.3.0") + implementation("space.kscience:kmath-memory:0.3.1-dev-1") } ``` diff --git a/kmath-multik/README.md b/kmath-multik/README.md index edfce6f79..0f5b65b4c 100644 --- a/kmath-multik/README.md +++ b/kmath-multik/README.md @@ -6,7 +6,7 @@ JetBrains Multik connector ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-multik:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-multik:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -16,7 +16,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-multik:0.3.0' + implementation 'space.kscience:kmath-multik:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -27,6 +27,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-multik:0.3.0") + implementation("space.kscience:kmath-multik:0.3.1-dev-1") } ``` diff --git a/kmath-nd4j/README.md b/kmath-nd4j/README.md index 0bcae138e..bb065a300 100644 --- a/kmath-nd4j/README.md +++ b/kmath-nd4j/README.md @@ -9,7 +9,7 @@ ND4J based implementations of KMath abstractions. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-nd4j:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-nd4j:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -19,7 +19,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-nd4j:0.3.0' + implementation 'space.kscience:kmath-nd4j:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -30,7 +30,7 @@ repositories { } dependencies { - implementation("space.kscience:kmath-nd4j:0.3.0") + implementation("space.kscience:kmath-nd4j:0.3.1-dev-1") } ``` diff --git a/kmath-optimization/README.md b/kmath-optimization/README.md index 63e0f43e3..d7441ebd1 100644 --- a/kmath-optimization/README.md +++ b/kmath-optimization/README.md @@ -6,7 +6,7 @@ ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-optimization:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-optimization:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -16,7 +16,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-optimization:0.3.0' + implementation 'space.kscience:kmath-optimization:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -27,6 +27,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-optimization:0.3.0") + implementation("space.kscience:kmath-optimization:0.3.1-dev-1") } ``` diff --git a/kmath-polynomial/README.md b/kmath-polynomial/README.md new file mode 100644 index 000000000..640ea8876 --- /dev/null +++ b/kmath-polynomial/README.md @@ -0,0 +1,50 @@ +# Module kmath-polynomial + +Polynomial extra utilities and rational functions + +## Features + + - [polynomial abstraction](src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt) : Abstraction for polynomial spaces. + - [rational function abstraction](src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt) : Abstraction for rational functions spaces. + - ["list" polynomials](src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt) : List implementation of univariate polynomials. + - ["list" rational functions](src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt) : List implementation of univariate rational functions. + - ["list" polynomials and rational functions constructors](src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt) : Constructors for list polynomials and rational functions. + - ["list" polynomials and rational functions utilities](src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt) : Utilities for list polynomials and rational functions. + - ["numbered" polynomials](src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt) : Numbered implementation of multivariate polynomials. + - ["numbered" rational functions](src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt) : Numbered implementation of multivariate rational functions. + - ["numbered" polynomials and rational functions constructors](src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt) : Constructors for numbered polynomials and rational functions. + - ["numbered" polynomials and rational functions utilities](src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt) : Utilities for numbered polynomials and rational functions. + - ["labeled" polynomials](src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt) : Labeled implementation of multivariate polynomials. + - ["labeled" rational functions](src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt) : Labeled implementation of multivariate rational functions. + - ["labeled" polynomials and rational functions constructors](src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt) : Constructors for labeled polynomials and rational functions. + - ["labeled" polynomials and rational functions utilities](src/commonMain/kotlin/space/kscience/kmath/functions/labeledUtil.kt) : Utilities for labeled polynomials and rational functions. + + +## Usage + +## Artifact: + +The Maven coordinates of this project are `space.kscience:kmath-polynomial:0.3.1-dev-1`. + +**Gradle Groovy:** +```groovy +repositories { + maven { url 'https://repo.kotlin.link' } + mavenCentral() +} + +dependencies { + implementation 'space.kscience:kmath-polynomial:0.3.1-dev-1' +} +``` +**Gradle Kotlin DSL:** +```kotlin +repositories { + maven("https://repo.kotlin.link") + mavenCentral() +} + +dependencies { + implementation("space.kscience:kmath-polynomial:0.3.1-dev-1") +} +``` diff --git a/kmath-polynomial/build.gradle.kts b/kmath-polynomial/build.gradle.kts index 85b87fb34..dd0d9e77d 100644 --- a/kmath-polynomial/build.gradle.kts +++ b/kmath-polynomial/build.gradle.kts @@ -22,5 +22,46 @@ readme { maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) -// feature("TODO") { "TODO" } + feature("polynomial abstraction", "src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt") { + "Abstraction for polynomial spaces." + } + feature("rational function abstraction", "src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt") { + "Abstraction for rational functions spaces." + } + feature("\"list\" polynomials", "src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt") { + "List implementation of univariate polynomials." + } + feature("\"list\" rational functions", "src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt") { + "List implementation of univariate rational functions." + } + feature("\"list\" polynomials and rational functions constructors", "src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt") { + "Constructors for list polynomials and rational functions." + } + feature("\"list\" polynomials and rational functions utilities", "src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt") { + "Utilities for list polynomials and rational functions." + } + feature("\"numbered\" polynomials", "src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt") { + "Numbered implementation of multivariate polynomials." + } + feature("\"numbered\" rational functions", "src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt") { + "Numbered implementation of multivariate rational functions." + } + feature("\"numbered\" polynomials and rational functions constructors", "src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt") { + "Constructors for numbered polynomials and rational functions." + } + feature("\"numbered\" polynomials and rational functions utilities", "src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt") { + "Utilities for numbered polynomials and rational functions." + } + feature("\"labeled\" polynomials", "src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt") { + "Labeled implementation of multivariate polynomials." + } + feature("\"labeled\" rational functions", "src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt") { + "Labeled implementation of multivariate rational functions." + } + feature("\"labeled\" polynomials and rational functions constructors", "src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt") { + "Constructors for labeled polynomials and rational functions." + } + feature("\"labeled\" polynomials and rational functions utilities", "src/commonMain/kotlin/space/kscience/kmath/functions/labeledUtil.kt") { + "Utilities for labeled polynomials and rational functions." + } } diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledPolynomial.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt similarity index 100% rename from kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledPolynomial.kt rename to kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledRationalFunction.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt similarity index 100% rename from kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledRationalFunction.kt rename to kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/ListPolynomial.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt similarity index 100% rename from kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/ListPolynomial.kt rename to kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/ListRationalFunction.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt similarity index 100% rename from kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/ListRationalFunction.kt rename to kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedPolynomial.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt similarity index 100% rename from kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedPolynomial.kt rename to kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedRationalFunction.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt similarity index 100% rename from kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedRationalFunction.kt rename to kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/Polynomial.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt similarity index 100% rename from kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/Polynomial.kt rename to kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/RationalFunction.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt similarity index 100% rename from kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/RationalFunction.kt rename to kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/algebraicStub.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt similarity index 100% rename from kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/algebraicStub.kt rename to kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/collectionUtils.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/collectionUtils.kt similarity index 100% rename from kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/collectionUtils.kt rename to kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/collectionUtils.kt diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledConstructors.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt similarity index 100% rename from kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledConstructors.kt rename to kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledUtil.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/labeledUtil.kt similarity index 100% rename from kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledUtil.kt rename to kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/labeledUtil.kt diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/listConstructors.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt similarity index 100% rename from kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/listConstructors.kt rename to kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/listUtil.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt similarity index 100% rename from kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/listUtil.kt rename to kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/misc.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt similarity index 100% rename from kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/misc.kt rename to kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/numberedConstructors.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt similarity index 100% rename from kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/numberedConstructors.kt rename to kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/numberedUtil.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt similarity index 100% rename from kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/numberedUtil.kt rename to kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt diff --git a/kmath-stat/README.md b/kmath-stat/README.md index 80c6e0fcd..7ed20fcf4 100644 --- a/kmath-stat/README.md +++ b/kmath-stat/README.md @@ -6,7 +6,7 @@ ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-stat:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-stat:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -16,7 +16,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-stat:0.3.0' + implementation 'space.kscience:kmath-stat:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -27,6 +27,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-stat:0.3.0") + implementation("space.kscience:kmath-stat:0.3.1-dev-1") } ``` diff --git a/kmath-symja/README.md b/kmath-symja/README.md index ea2d5d68f..a96b0e835 100644 --- a/kmath-symja/README.md +++ b/kmath-symja/README.md @@ -6,7 +6,7 @@ Symja integration module ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-symja:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-symja:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -16,7 +16,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-symja:0.3.0' + implementation 'space.kscience:kmath-symja:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -27,6 +27,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-symja:0.3.0") + implementation("space.kscience:kmath-symja:0.3.1-dev-1") } ``` diff --git a/kmath-tensorflow/README.md b/kmath-tensorflow/README.md index 7852c07be..83f2eb315 100644 --- a/kmath-tensorflow/README.md +++ b/kmath-tensorflow/README.md @@ -6,7 +6,7 @@ Google tensorflow connector ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-tensorflow:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-tensorflow:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -16,7 +16,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-tensorflow:0.3.0' + implementation 'space.kscience:kmath-tensorflow:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -27,6 +27,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-tensorflow:0.3.0") + implementation("space.kscience:kmath-tensorflow:0.3.1-dev-1") } ``` diff --git a/kmath-tensors/README.md b/kmath-tensors/README.md index 44ee47675..4208cd83d 100644 --- a/kmath-tensors/README.md +++ b/kmath-tensors/README.md @@ -9,7 +9,7 @@ Common linear algebra operations on tensors. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-tensors:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-tensors:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -19,7 +19,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-tensors:0.3.0' + implementation 'space.kscience:kmath-tensors:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -30,6 +30,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-tensors:0.3.0") + implementation("space.kscience:kmath-tensors:0.3.1-dev-1") } ``` diff --git a/kmath-viktor/README.md b/kmath-viktor/README.md index 5d7c2dea1..abff20427 100644 --- a/kmath-viktor/README.md +++ b/kmath-viktor/README.md @@ -6,7 +6,7 @@ Binding for https://github.com/JetBrains-Research/viktor ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-viktor:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-viktor:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -16,7 +16,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-viktor:0.3.0' + implementation 'space.kscience:kmath-viktor:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -27,6 +27,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-viktor:0.3.0") + implementation("space.kscience:kmath-viktor:0.3.1-dev-1") } ``` -- 2.34.1 From 163a7c717a922b8f670475ad489184dd28716c11 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Wed, 20 Jul 2022 08:28:47 +0300 Subject: [PATCH 117/123] Fix description. --- kmath-polynomial/README.md | 2 +- kmath-polynomial/build.gradle.kts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kmath-polynomial/README.md b/kmath-polynomial/README.md index 640ea8876..a5078a7e0 100644 --- a/kmath-polynomial/README.md +++ b/kmath-polynomial/README.md @@ -1,6 +1,6 @@ # Module kmath-polynomial -Polynomial extra utilities and rational functions +Polynomials, rational functions, and utilities ## Features diff --git a/kmath-polynomial/build.gradle.kts b/kmath-polynomial/build.gradle.kts index dd0d9e77d..9c5083d2d 100644 --- a/kmath-polynomial/build.gradle.kts +++ b/kmath-polynomial/build.gradle.kts @@ -4,7 +4,7 @@ plugins { id("ru.mipt.npm.gradle.native") } -description = "Polynomial extra utilities and rational functions" +description = "Polynomials, rational functions, and utilities" kotlin.sourceSets { commonMain { -- 2.34.1 From fe4eb96daed13a30d9c7f328fa49d2daefe9a2f5 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Wed, 20 Jul 2022 19:09:20 +0300 Subject: [PATCH 118/123] Add docs. --- .../kmath/functions/collectionUtils.kt | 451 ++++++++++++++++-- 1 file changed, 412 insertions(+), 39 deletions(-) diff --git a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/collectionUtils.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/collectionUtils.kt index ee32aa9a7..0d2ea3653 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/collectionUtils.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/collectionUtils.kt @@ -9,7 +9,13 @@ import kotlin.contracts.InvocationKind.* import kotlin.contracts.contract -// TODO: Docs +/** + * Computes the given lambda [compute] on value corresponding to the provided [key] or `null` if the key is not present. + * + * @param key key which corresponding value will be used if it's present. + * @param compute lambda that is computed on the received value. + * @return result of the computation of the lambda. + */ internal inline fun Map.computeOn(key: K, compute: (V?) -> R): R { contract { callsInPlace(compute, EXACTLY_ONCE) @@ -17,7 +23,15 @@ internal inline fun Map.computeOn(key: K, compute: (V?) -> R) return compute(get(key)) } -// TODO: Docs +/** + * Computes the given lambda [compute] on value corresponding to the provided [key] or computes the given lambda + * [defaultResult] if the key is not present. + * + * @param key key which corresponding value will be used if it's present. + * @param compute lambda that is computed on the value corresponding to the [key]. + * @param defaultResult lambda that is computed if the [key] is not present. + * @return result of [compute] lambda if the [key] is present or result of [defaultResult] otherwise. + */ internal inline fun Map.computeOnOrElse(key: K, defaultResult: () -> R, compute: (value: V) -> R): R { contract { callsInPlace(defaultResult, AT_MOST_ONCE) @@ -27,7 +41,15 @@ internal inline fun Map.computeOnOrElse(key: K, defaultResult: ( return (if (key !in this) defaultResult() else compute(get(key) as V)) } -// TODO: Docs +/** + * Computes the given lambda [compute] on value corresponding to the provided [key] or computes the given lambda + * [defaultResult] if the key is not present. + * + * @param key key which corresponding value will be used if it's present. + * @param compute lambda that is computed on the value corresponding to the [key]. + * @param defaultResult default result that is returned in case of the [key]'s absence. + * @return result of [compute] lambda if the [key] is present or [defaultResult] otherwise. + */ internal inline fun Map.computeOnOrElse(key: K, defaultResult: R, compute: (value: V) -> R): R { contract { callsInPlace(compute, AT_MOST_ONCE) @@ -35,7 +57,15 @@ internal inline fun Map.computeOnOrElse(key: K, defaultResult: R return computeOnOrElse(key, { defaultResult }, compute) } -// TODO: Docs +/** + * Computes the given lambda [compute] on value corresponding to the provided [key] or computes the given lambda + * [defaultResult] if the key is not present. + * + * @param key key which corresponding value will be used if it's present. + * @param compute lambda that is computed on the value corresponding to the [key]. + * @param defaultResult default result that is returned in case of the [key]'s absence. + * @return result of [compute] lambda if the [key] is present or [defaultResult] otherwise. + */ internal inline fun Map.computeOnOrElse(key: K, defaultResult: R, compute: (key: K, value: V) -> R): R { contract { callsInPlace(compute, AT_MOST_ONCE) @@ -374,8 +404,20 @@ internal inline fun > Map.copyMapToBy(des internal inline fun > Map.copyMapToBy(destination: D, transform: (key: K, value: V) -> W, resolve: (currentValue: W, newValue: V) -> W): D = copyMapToBy(destination, { (key, value) -> transform(key, value) }, { _, currentValue, newValue -> resolve(currentValue, newValue) }) -// TODO: Docs -internal fun > mergeTo(map1: Map, map2: Map, destination: D): D { +/** + * Merges [the first map][map1] and [the second map][map2] prioritising the second one, puts result to the [destination] + * and returns the [destination]. + * + * Precisely, corresponding keys and values of the received maps are put into the destination overriding existing values + * in the [destination] if needed. For every key appearing in both maps corresponding value from the second map is + * chosen. + * + * @param map1 the first (less prioritised) map to merge. + * @param map2 the second (more prioritised) map to merge. + * @param destination the map where result of the merge is put. + * @return the destination. + */ +internal fun > mergeTo(map1: Map, map2: Map, destination: D): D { for ((key, value) in map1) { destination.put(key, value) } @@ -385,7 +427,20 @@ internal fun > mergeTo(map1: Map, map2: Map< return destination } -// TODO: Docs +/** + * Merges [the first map][map1] and [the second map][map2] resolving conflicts with [resolve] lambda, puts result to the + * [destination] and returns the [destination]. + * + * Precisely, corresponding keys and values of the received maps are put into the destination overriding existing values + * in the [destination] if needed. For every key appearing in both maps corresponding value is a result of the [resolve] + * lambda calculated on the key and its corresponding values from the merged maps. + * + * @param map1 the first (less prioritised) map to merge. + * @param map2 the second (more prioritised) map to merge. + * @param resolve lambda function that resolves merge conflicts. + * @param destination the map where result of the merge is put. + * @return the destination. + */ internal inline fun > mergeToBy(map1: Map, map2: Map, destination: D, resolve: (key: K, value1: V1, value2: V2) -> W): D { for (key in map2.keys) { destination.remove(key) @@ -400,27 +455,82 @@ internal inline fun > mergeToBy(map1: Ma return destination } -// TODO: Docs +/** + * Merges [the first map][map1] and [the second map][map2] resolving conflicts with [resolve] lambda, puts result to the + * [destination] and returns the [destination]. + * + * Precisely, corresponding keys and values of the received maps are put into the destination overriding existing values + * in the [destination] if needed. For every key appearing in both maps corresponding value is a result of the [resolve] + * lambda calculated on the key's corresponding values from the merged maps. + * + * @param map1 the first (less prioritised) map to merge. + * @param map2 the second (more prioritised) map to merge. + * @param resolve lambda function that resolves merge conflicts. + * @param destination the map where result of the merge is put. + * @return the destination. + */ internal inline fun > mergeToBy(map1: Map, map2: Map, destination: D, resolve: (value1: V1, value2: V2) -> W): D = mergeToBy(map1, map2, destination) { _, value1, value2 -> resolve(value1, value2) } -// TODO: Docs +/** + * Merges [the first map][map1] and [the second map][map2] prioritising the second one. + * + * Precisely, corresponding keys and values of the received maps are put into a new empty map which is returned after + * afterwards. For every key appearing in both maps corresponding value from the second map is chosen. + * + * @param map1 the first (less prioritised) map to merge. + * @param map2 the second (more prioritised) map to merge. + * @return the result of the merge. + */ internal fun merge(map1: Map, map2: Map): Map { val result = LinkedHashMap(map1.size + map2.size) return mergeTo(map1, map2, result) } -// TODO: Docs -internal inline fun mergeBy(map1: Map, map2: Map, transform: (key: K, value1: V1, value2: V2) -> W): Map { +/** + * Merges [the first map][map1] and [the second map][map2] resolving conflicts with [resolve] lambda. + * + * Precisely, corresponding keys and values of the received maps are put into a new empty map which is returned after + * afterwards. For every key appearing in both maps corresponding value is a result of the [resolve] lambda calculated + * on the key and its corresponding values from the merged maps. + * + * @param map1 the first (less prioritised) map to merge. + * @param map2 the second (more prioritised) map to merge. + * @param resolve lambda function that resolves merge conflicts. + * @return the result of the merge. + */ +internal inline fun mergeBy(map1: Map, map2: Map, resolve: (key: K, value1: V1, value2: V2) -> W): Map { val result = LinkedHashMap(map1.size + map2.size) - return mergeToBy(map1, map2, result, transform) + return mergeToBy(map1, map2, result, resolve) } -// TODO: Docs -internal inline fun mergeBy(map1: Map, map2: Map, transform: (value1: V1, value2: V2) -> W): Map = - mergeBy(map1, map2) { _, value1, value2 -> transform(value1, value2) } +/** + * Merges [the first map][map1] and [the second map][map2] resolving conflicts with [resolve] lambda. + * + * Precisely, corresponding keys and values of the received maps are put into a new empty map which is returned after + * afterwards. For every key appearing in both maps corresponding value is a result of the [resolve] lambda calculated + * on the key's corresponding values from the merged maps. + * + * @param map1 the first (less prioritised) map to merge. + * @param map2 the second (more prioritised) map to merge. + * @param resolve lambda function that resolves merge conflicts. + * @return the result of the merge. + */ +internal inline fun mergeBy(map1: Map, map2: Map, resolve: (value1: V1, value2: V2) -> W): Map = + mergeBy(map1, map2) { _, value1, value2 -> resolve(value1, value2) } -// TODO: Docs +/** + * Populates the [destination] map with key-value pairs provided by [transform] function applied to each element of the + * given collection resolving conflicts with [resolve] function and returns the [destination]. + * + * All pairs are added and resolved in order of iteration. + * + * @param destination the destination of the generated key-value pairs. + * @param transform function which transforms each element to key-value. + * @param resolve lambda function that resolves merge conflicts which receives some key, its current, and new + * corresponding values. + * @return the [destination]. + */ internal inline fun > Iterable.associateTo(destination: D, transform: (T) -> Pair, resolve: (key: K, currentValue: V, newValue: V) -> V): D { for (element in this) { val (key, value) = transform(element) @@ -429,7 +539,20 @@ internal inline fun > Iterable.associateTo(dest return destination } -// TODO: Docs +/** + * Populates the [destination] map with key-value pairs, where key is provided by [keySelector] function and value is + * provided by [valueTransform] applied to each element of the given collection, resolving conflicts with [resolve] + * function and returns the [destination]. + * + * All pairs are added and resolved in order of iteration. + * + * @param destination the destination of the generated key-value pairs. + * @param keySelector lambda functions that generates keys for the key-value pairs. + * @param valueTransform lambda functions that generates value for the key-value pairs. + * @param resolve lambda function that resolves merge conflicts which receives some key, its current, and new + * corresponding values. + * @return the [destination]. + */ internal inline fun > Iterable.associateByTo(destination: D, keySelector: (T) -> K, valueTransform: (T) -> V, resolve: (key: K, currentValue: V, newValue: V) -> V): D { for (element in this) { val key = keySelector(element) @@ -439,7 +562,19 @@ internal inline fun > Iterable.associateByTo(de return destination } -// TODO: Docs +/** + * Populates the [destination] map with key-value pairs, where key is provided by [keySelector] function applied to each + * element of the given collection and value is the element itself, resolving conflicts with [resolve] function and + * returns the [destination]. + * + * All pairs are added and resolved in order of iteration. + * + * @param destination the destination of the generated key-value pairs. + * @param keySelector lambda functions that generates keys for the key-value pairs. + * @param resolve lambda function that resolves merge conflicts which receives some key, its current, and new + * corresponding values. + * @return the [destination]. + */ internal inline fun > Iterable.associateByTo(destination: D, keySelector: (T) -> K, resolve: (key: K, currentValue: T, newValue: T) -> T): D { for (element in this) { val key = keySelector(element) @@ -448,86 +583,324 @@ internal inline fun > Iterable.associateByTo(desti return destination } -// TODO: Docs +/** + * Populates the [destination] map with key-value pairs provided by [transform] function applied to each element of the + * given collection resolving conflicts with [resolve] function and returns the [destination]. + * + * All pairs are added and resolved in order of iteration. + * + * @param destination the destination of the generated key-value pairs. + * @param transform function which transforms each element to key-value pair. + * @param resolve lambda function that resolves merge conflicts which receives some key, its current, and new + * corresponding values. + * @return the [destination]. + */ internal inline fun > Iterable.associateTo(destination: D, transform: (T) -> Pair, resolve: (currentValue: V, newValue: V) -> V): D = associateTo(destination, transform) { _, currentValue, newValue -> resolve(currentValue, newValue) } -// TODO: Docs +/** + * Populates the [destination] map with key-value pairs, where key is provided by [keySelector] function and value is + * provided by [valueTransform] applied to each element of the given collection, resolving conflicts with [resolve] + * function and returns the [destination]. + * + * All pairs are added and resolved in order of iteration. + * + * @param destination the destination of the generated key-value pairs. + * @param keySelector lambda functions that generates keys for the key-value pairs. + * @param valueTransform lambda functions that generates value for the key-value pairs. + * @param resolve lambda function that resolves merge conflicts which receives some key, its current, and new + * corresponding values. + * @return the [destination]. + */ internal inline fun > Iterable.associateByTo(destination: D, keySelector: (T) -> K, valueTransform: (T) -> V, resolve: (currentValue: V, newValue: V) -> V): D = associateByTo(destination, keySelector, valueTransform) { _, currentValue, newValue -> resolve(currentValue, newValue) } -// TODO: Docs +/** + * Populates the [destination] map with key-value pairs, where key is provided by [keySelector] function applied to each + * element of the given collection and value is the element itself, resolving conflicts with [resolve] function and + * returns the [destination]. + * + * All pairs are added and resolved in order of iteration. + * + * @param destination the destination of the generated key-value pairs. + * @param keySelector lambda functions that generates keys for the key-value pairs. + * @param resolve lambda function that resolves merge conflicts which receives some key, its current, and new + * corresponding values. + * @return the [destination]. + */ internal inline fun > Iterable.associateByTo(destination: D, keySelector: (T) -> K, resolve: (currentValue: T, newValue: T) -> T): D = associateByTo(destination, keySelector) { _, currentValue, newValue -> resolve(currentValue, newValue) } -// TODO: Docs +/** + * Returns a map containing key-value pairs provided by [transform] function applied to elements of the given collection. + * + * All pairs are added in order of iteration. If some key is already added to the map, adding new key-value pair with the + * key is resolved with [resolve] function which takes the key, current value corresponding to the key, and new value + * from the pair. + * + * @param transform function which transforms each element to key-value pair. + * @param resolve lambda function that resolves merge conflicts which receives some key, its current, and new + * corresponding values. + * @return the result map. + */ internal inline fun Iterable.associate(transform: (T) -> Pair, resolve: (key: K, currentValue: V, newValue: V) -> V): Map = associateTo(LinkedHashMap(), transform, resolve) -// TODO: Docs +/** + * Returns a map containing the values provided by [valueTransform] and indexed by [keySelector] functions applied to + * elements of the given collection. + * + * All pairs are added in order of iteration. If some key is already added to the map, adding new key-value pair with + * the key is resolved with [resolve] function which takes the key, current value corresponding to the key, and new + * value from the pair. + * + * @param keySelector lambda functions that generates keys for the key-value pairs. + * @param valueTransform lambda functions that generates value for the key-value pairs. + * @param resolve lambda function that resolves merge conflicts which receives some key, its current, and new + * corresponding values. + * @return the result map. + */ internal inline fun Iterable.associateBy(keySelector: (T) -> K, valueTransform: (T) -> V, resolve: (key: K, currentValue: V, newValue: V) -> V): Map = associateByTo(LinkedHashMap(), keySelector, valueTransform, resolve) -// TODO: Docs +/** + * Returns a map containing the elements from the given collection indexed by the key returned from [keySelector] + * function applied to each element. + * + * All pairs are added in order of iteration. If some key is already added to the map, adding new key-value pair with + * the key is resolved with [resolve] function which takes the key, current value corresponding to the key, and new + * value from the pair. + * + * @param keySelector lambda functions that generates keys for the key-value pairs. + * @param resolve lambda function that resolves merge conflicts which receives some key, its current, and new + * corresponding values. + * @return the result map. + */ internal inline fun Iterable.associateBy(keySelector: (T) -> K, resolve: (key: K, currentValue: T, newValue: T) -> T): Map = associateByTo(LinkedHashMap(), keySelector, resolve) -// TODO: Docs +/** + * Returns a map containing key-value pairs provided by [transform] function applied to elements of the given collection. + * + * All pairs are added in order of iteration. If some key is already added to the map, adding new key-value pair with + * the key is resolved with [resolve] function which takes current value corresponding to the key and new value from the + * pair. + * + * @param transform function which transforms each element to key-value pair. + * @param resolve lambda function that resolves merge conflicts which receives some key, its current, and new + * corresponding values. + * @return the result map. + */ internal inline fun Iterable.associate(transform: (T) -> Pair, resolve: (currentValue: V, newValue: V) -> V): Map = associateTo(LinkedHashMap(), transform, resolve) -// TODO: Docs +/** + * Returns a map containing the values provided by [valueTransform] and indexed by [keySelector] functions applied to + * elements of the given collection. + * + * All pairs are added in order of iteration. If some key is already added to the map, adding new key-value pair with + * the key is resolved with [resolve] function which takes current value corresponding to the key and new value from the + * pair. + * + * @param keySelector lambda functions that generates keys for the key-value pairs. + * @param valueTransform lambda functions that generates value for the key-value pairs. + * @param resolve lambda function that resolves merge conflicts which receives some key, its current, and new + * corresponding values. + * @return the result map. + */ internal inline fun Iterable.associateBy(keySelector: (T) -> K, valueTransform: (T) -> V, resolve: (currentValue: V, newValue: V) -> V): Map = associateByTo(LinkedHashMap(), keySelector, valueTransform, resolve) -// TODO: Docs +/** + * Returns a map containing the elements from the given collection indexed by the key returned from [keySelector] + * function applied to each element. + * + * All pairs are added in order of iteration. If some key is already added to the map, adding new key-value pair with + * the key is resolved with [resolve] function which takes current value corresponding to the key and new value from the + * pair. + * + * @param keySelector lambda functions that generates keys for the key-value pairs. + * @param resolve lambda function that resolves merge conflicts which receives some key, its current, and new + * corresponding values. + * @return the result map. + */ internal inline fun Iterable.associateBy(keySelector: (T) -> K, resolve: (currentValue: T, newValue: T) -> T): Map = associateByTo(LinkedHashMap(), keySelector, resolve) -// TODO: Docs +/** + * Populates the given [destination] map with entries having the keys of this map and the values obtained + * by applying the [transform] function to each entry in this map resolving conflicts with [resolve] function and + * returns the [destination]. + * + * All pairs are added and resolved in order of iteration. + * + * @param destination the destination of the generated key-value pairs. + * @param transform function which transforms each key-value pair to new value. + * @param resolve lambda function that resolves merge conflicts which receives some key, its current, and new + * corresponding values. + * @return the [destination]. + */ internal inline fun > Map.mapValuesTo(destination: D, transform: (Map.Entry) -> W, resolve: (key: K, currentValue: W, newValue: W) -> W): D = entries.associateByTo(destination, { it.key }, transform, resolve) -// TODO: Docs +/** + * Populates the given [destination] map with entries having the keys of this map and the values obtained + * by applying the [transform] function to each entry in this map resolving conflicts with [resolve] function and + * returns the [destination]. + * + * All pairs are added and resolved in order of iteration. + * + * @param destination the destination of the generated key-value pairs. + * @param transform function which transforms each key-value pair to new value. + * @param resolve lambda function that resolves merge conflicts which receives some key, its current, and new + * corresponding values. + * @return the [destination]. + */ internal inline fun > Map.mapValuesTo(destination: D, transform: (key: K, value: V) -> W, resolve: (key: K, currentValue: W, newValue: W) -> W): D = entries.associateByTo(destination, { it.key }, { (key, value) -> transform(key, value) }, resolve) -// TODO: Docs +/** + * Populates the given [destination] map with entries having the keys of this map and the values obtained + * by applying the [transform] function to each entry in this map resolving conflicts with [resolve] function and + * returns the [destination]. + * + * All pairs are added and resolved in order of iteration. + * + * @param destination the destination of the generated key-value pairs. + * @param transform function which transforms each key-value pair to new value. + * @param resolve lambda function that resolves merge conflicts which current and new values corresponding to some key. + * @return the [destination]. + */ internal inline fun > Map.mapValuesTo(destination: D, transform: (Map.Entry) -> W, resolve: (currentValue: W, newValue: W) -> W): D = entries.associateByTo(destination, { it.key }, transform, resolve) -// TODO: Docs +/** + * Populates the given [destination] map with entries having the keys of this map and the values obtained + * by applying the [transform] function to each entry in this map resolving conflicts with [resolve] function and + * returns the [destination]. + * + * All pairs are added and resolved in order of iteration. + * + * @param destination the destination of the generated key-value pairs. + * @param transform function which transforms each key-value pair to new value. + * @param resolve lambda function that resolves merge conflicts which current and new values corresponding to some key. + * @return the [destination]. + */ internal inline fun > Map.mapValuesTo(destination: D, transform: (key: K, value: V) -> W, resolve: (currentValue: W, newValue: W) -> W): D = entries.associateByTo(destination, { it.key }, { (key, value) -> transform(key, value) }, resolve) -// TODO: Docs +/** + * Populates the given [destination] map with entries having the keys obtained by applying the [transform] function to + * each entry in this map and the values of this map, resolving conflicts with [resolve] function and returns the + * [destination]. + * + * All pairs are added and resolved in order of iteration. + * + * @param destination the destination of the generated key-value pairs. + * @param transform function which transforms each key-value pair to new key. + * @param resolve lambda function that resolves merge conflicts which receives some key, its current, and new + * corresponding values. + * @return the [destination]. + */ internal inline fun > Map.mapKeysTo(destination: D, transform: (Map.Entry) -> L, resolve: (key: L, currentValue: V, newValue: V) -> V): D = entries.associateByTo(destination, transform, { it.value }, resolve) -// TODO: Docs +/** + * Populates the given [destination] map with entries having the keys obtained by applying the [transform] function to + * each entry in this map and the values of this map, resolving conflicts with [resolve] function and returns the + * [destination]. + * + * All pairs are added and resolved in order of iteration. + * + * @param destination the destination of the generated key-value pairs. + * @param transform function which transforms each key-value pair to new key. + * @param resolve lambda function that resolves merge conflicts which receives some key, its current, and new + * corresponding values. + * @return the [destination]. + */ internal inline fun > Map.mapKeysTo(destination: D, transform: (key: K, value: V) -> L, resolve: (key: L, currentValue: V, newValue: V) -> V): D = entries.associateByTo(destination, { (key, value) -> transform(key, value) }, { it.value }, resolve) -// TODO: Docs +/** + * Populates the given [destination] map with entries having the keys obtained by applying the [transform] function to + * each entry in this map and the values of this map, resolving conflicts with [resolve] function and returns the + * [destination]. + * + * All pairs are added and resolved in order of iteration. + * + * @param destination the destination of the generated key-value pairs. + * @param transform function which transforms each key-value pair to new key. + * @param resolve lambda function that resolves merge conflicts which current and new values corresponding to some key. + * @return the [destination]. + */ internal inline fun > Map.mapKeysTo(destination: D, transform: (Map.Entry) -> L, resolve: (currentValue: V, newValue: V) -> V): D = entries.associateByTo(destination, transform, { it.value }, resolve) -// TODO: Docs +/** + * Populates the given [destination] map with entries having the keys obtained by applying the [transform] function to + * each entry in this map and the values of this map, resolving conflicts with [resolve] function and returns the + * [destination]. + * + * All pairs are added and resolved in order of iteration. + * + * @param destination the destination of the generated key-value pairs. + * @param transform function which transforms each key-value pair to new key. + * @param resolve lambda function that resolves merge conflicts which current and new values corresponding to some key. + * @return the [destination]. + */ internal inline fun > Map.mapKeysTo(destination: D, transform: (key: K, value: V) -> L, resolve: (currentValue: V, newValue: V) -> V): D = entries.associateByTo(destination, { (key, value) -> transform(key, value) }, { it.value }, resolve) -// TODO: Docs +/** + * Returns a new map with entries having the keys obtained by applying the [transform] function to each entry in this + * map and the values of this map and resolving conflicts with [resolve] function. + * + * All pairs are added and resolved in order of iteration. + * + * @param transform function which transforms each key-value pair to new key. + * @param resolve lambda function that resolves merge conflicts which receives some key, its current, and new + * corresponding values. + * @return the result map. + */ internal inline fun Map.mapKeys(transform: (Map.Entry) -> L, resolve: (key: L, currentValue: V, newValue: V) -> V): Map = mapKeysTo(LinkedHashMap(size), transform, resolve) -// TODO: Docs +/** + * Returns a new map with entries having the keys obtained by applying the [transform] function to each entry in this + * map and the values of this map and resolving conflicts with [resolve] function. + * + * All pairs are added and resolved in order of iteration. + * + * @param transform function which transforms each key-value pair to new key. + * @param resolve lambda function that resolves merge conflicts which receives some key, its current, and new + * corresponding values. + * @return the result map. + */ internal inline fun Map.mapKeys(transform: (key: K, value: V) -> L, resolve: (key: L, currentValue: V, newValue: V) -> V): Map = mapKeysTo(LinkedHashMap(size), transform, resolve) -// TODO: Docs +/** + * Returns a new map with entries having the keys obtained by applying the [transform] function to each entry in this + * map and the values of this map and resolving conflicts with [resolve] function. + * + * All pairs are added and resolved in order of iteration. + * + * @param transform function which transforms each key-value pair to new key. + * @param resolve lambda function that resolves merge conflicts which current and new values corresponding to some key. + * @return the result map. + */ internal inline fun Map.mapKeys(transform: (Map.Entry) -> L, resolve: (currentValue: V, newValue: V) -> V): Map = mapKeysTo(LinkedHashMap(size), transform, resolve) -// TODO: Docs +/** + * Returns a new map with entries having the keys obtained by applying the [transform] function to each entry in this + * map and the values of this map and resolving conflicts with [resolve] function.. + * + * All pairs are added and resolved in order of iteration. + * + * @param transform function which transforms each key-value pair to new key. + * @param resolve lambda function that resolves merge conflicts which current and new values corresponding to some key. + * @return the result map. + */ internal inline fun Map.mapKeys(transform: (key: K, value: V) -> L, resolve: (currentValue: V, newValue: V) -> V): Map = mapKeysTo(LinkedHashMap(size), transform, resolve) \ No newline at end of file -- 2.34.1 From e1b8fcdbbf78d13a04aa0602e2f341d420f8b103 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Wed, 20 Jul 2022 19:10:35 +0300 Subject: [PATCH 119/123] Two consecutive dots... --- .../kotlin/space/kscience/kmath/functions/collectionUtils.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/collectionUtils.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/collectionUtils.kt index 0d2ea3653..c9146a493 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/collectionUtils.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/collectionUtils.kt @@ -894,7 +894,7 @@ internal inline fun Map.mapKeys(transform: (Map.Entry) /** * Returns a new map with entries having the keys obtained by applying the [transform] function to each entry in this - * map and the values of this map and resolving conflicts with [resolve] function.. + * map and the values of this map and resolving conflicts with [resolve] function. * * All pairs are added and resolved in order of iteration. * -- 2.34.1 From 0c6ad35c13ecf6bff31170092685e71ce016f1b5 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sat, 23 Jul 2022 10:24:52 +0300 Subject: [PATCH 120/123] Simplify the version catalog usage. --- kmath-functions/build.gradle.kts | 2 +- kmath-polynomial/build.gradle.kts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kmath-functions/build.gradle.kts b/kmath-functions/build.gradle.kts index eec17e82b..337875ba4 100644 --- a/kmath-functions/build.gradle.kts +++ b/kmath-functions/build.gradle.kts @@ -15,7 +15,7 @@ kotlin.sourceSets { } dependencies { - dokkaPlugin("org.jetbrains.dokka:mathjax-plugin:${versionCatalogs.named("npmlibs").findVersion("dokka").get().requiredVersion}") + dokkaPlugin("org.jetbrains.dokka:mathjax-plugin:${npmlibs.versions.dokka.get()}") } readme { diff --git a/kmath-polynomial/build.gradle.kts b/kmath-polynomial/build.gradle.kts index 9c5083d2d..5e66f83ec 100644 --- a/kmath-polynomial/build.gradle.kts +++ b/kmath-polynomial/build.gradle.kts @@ -15,7 +15,7 @@ kotlin.sourceSets { } dependencies { - dokkaPlugin("org.jetbrains.dokka:mathjax-plugin:${versionCatalogs.named("npmlibs").findVersion("dokka").get().requiredVersion}") + dokkaPlugin("org.jetbrains.dokka:mathjax-plugin:${npmlibs.versions.dokka.get()}") } readme { -- 2.34.1 From 323e8b6872137eb6da1b8c91aff1ce8b4e8d31d7 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Tue, 26 Jul 2022 09:19:04 +0300 Subject: [PATCH 121/123] Code simplification for Dubins path --- .../space/kscience/kmath/geometry/Circle2D.kt | 18 ++++ .../space/kscience/kmath/geometry/Line.kt | 4 + .../kmath/trajectory/dubins/DubinsPath.kt | 82 +++++++++-------- ...oryFunctions.kt => trajectoryFunctions.kt} | 41 +++++---- .../kscience/kmath/trajectory/segments/Arc.kt | 59 ------------ .../kmath/trajectory/segments/Pose2D.kt | 21 +++++ .../kmath/trajectory/segments/Segment.kt | 5 -- .../kmath/trajectory/segments/Straight.kt | 18 ---- .../kmath/trajectory/segments/Trajectory.kt | 89 +++++++++++++++++++ .../trajectory/segments/components/Circle.kt | 11 --- .../trajectory/segments/components/Pose2D.kt | 13 --- .../space/kscience/kmath/trajectory/Math.kt | 10 +-- .../kmath/trajectory/dubins/DubinsTests.kt | 16 ++-- .../kmath/trajectory/segments/ArcTests.kt | 7 +- .../segments/{components => }/CircleTests.kt | 6 +- .../kmath/trajectory/segments/LineTests.kt | 12 +-- 16 files changed, 225 insertions(+), 187 deletions(-) create mode 100644 kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Circle2D.kt rename kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/{TrajectoryFunctions.kt => trajectoryFunctions.kt} (51%) delete mode 100644 kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Arc.kt create mode 100644 kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Pose2D.kt delete mode 100644 kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Segment.kt delete mode 100644 kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Straight.kt create mode 100644 kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Trajectory.kt delete mode 100644 kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/components/Circle.kt delete mode 100644 kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/components/Pose2D.kt rename kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/{components => }/CircleTests.kt (74%) diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Circle2D.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Circle2D.kt new file mode 100644 index 000000000..8623335b9 --- /dev/null +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Circle2D.kt @@ -0,0 +1,18 @@ +/* + * 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.geometry + +import kotlin.math.PI + +/** + * A circle in 2D space + */ +public class Circle2D( + public val center: Vector2D, + public val radius: Double +) + +public val Circle2D.circumference: Double get() = radius * 2 * PI diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Line.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Line.kt index 8c6ccb55e..85bfcdd8f 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Line.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Line.kt @@ -5,6 +5,10 @@ package space.kscience.kmath.geometry +/** + * A line formed by [base] vector of start and a [direction] vector. Direction vector is not necessarily normalized, + * but its length does not affect line properties + */ public data class Line(val base: V, val direction: V) public typealias Line2D = Line diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/DubinsPath.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/DubinsPath.kt index ee4f38662..f510e3572 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/DubinsPath.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/DubinsPath.kt @@ -5,91 +5,95 @@ package space.kscience.kmath.trajectory.dubins +import space.kscience.kmath.geometry.Circle2D import space.kscience.kmath.geometry.Euclidean2DSpace.distanceTo import space.kscience.kmath.geometry.Vector2D -import space.kscience.kmath.trajectory.segments.Arc -import space.kscience.kmath.trajectory.segments.Segment -import space.kscience.kmath.trajectory.segments.Straight -import space.kscience.kmath.trajectory.segments.components.Circle -import space.kscience.kmath.trajectory.segments.components.Pose2D +import space.kscience.kmath.trajectory.segments.ArcSegment +import space.kscience.kmath.trajectory.segments.Pose2D +import space.kscience.kmath.trajectory.segments.StraightSegment +import space.kscience.kmath.trajectory.segments.Trajectory import kotlin.math.acos import kotlin.math.cos import kotlin.math.sin public class DubinsPath( - public val a: Arc, - public val b: Segment, - public val c: Arc, -) { + public val a: ArcSegment, + public val b: Trajectory, + public val c: ArcSegment, +) : Trajectory { public val type: TYPE = TYPE.valueOf( arrayOf( a.direction.name[0], - if (b is Arc) b.direction.name[0] else 'S', + if (b is ArcSegment) b.direction.name[0] else 'S', c.direction.name[0] ).toCharArray().concatToString() ) - public val length: Double = a.length + b.length + c.length + override val length: Double get() = a.length + b.length + c.length public enum class TYPE { RLR, LRL, RSR, LSL, RSL, LSR } public companion object { - public fun all(start: Pose2D, end: Pose2D, turningRadius: Double): List = - listOfNotNull( - rlr(start, end, turningRadius), - lrl(start, end, turningRadius), - rsr(start, end, turningRadius), - lsl(start, end, turningRadius), - rsl(start, end, turningRadius), - lsr(start, end, turningRadius) - ) + public fun all( + start: Pose2D, + end: Pose2D, + turningRadius: Double, + ): List = listOfNotNull( + rlr(start, end, turningRadius), + lrl(start, end, turningRadius), + rsr(start, end, turningRadius), + lsl(start, end, turningRadius), + rsl(start, end, turningRadius), + lsr(start, end, turningRadius) + ) + public fun shortest(start: Pose2D, end: Pose2D, turningRadius: Double): DubinsPath = - all(start, end, turningRadius).minByOrNull { it.length }!! + all(start, end, turningRadius).minBy { it.length } public fun rlr(start: Pose2D, end: Pose2D, turningRadius: Double): DubinsPath? { val c1 = start.getRightCircle(turningRadius) val c2 = end.getRightCircle(turningRadius) - val centers = Straight(c1.center, c2.center) + val centers = StraightSegment(c1.center, c2.center) if (centers.length > turningRadius * 4) return null var theta = theta(centers.theta - acos(centers.length / (turningRadius * 4))) var dX = turningRadius * sin(theta) var dY = turningRadius * cos(theta) val p = Vector2D(c1.center.x + dX * 2, c1.center.y + dY * 2) - val e = Circle(p, turningRadius) + val e = Circle2D(p, turningRadius) val p1 = Vector2D(c1.center.x + dX, c1.center.y + dY) theta = theta(centers.theta + acos(centers.length / (turningRadius * 4))) dX = turningRadius * sin(theta) dY = turningRadius * cos(theta) val p2 = Vector2D(e.center.x + dX, e.center.y + dY) - val a1 = Arc.of(c1.center, start, p1, Arc.Direction.RIGHT) - val a2 = Arc.of(e.center, p1, p2, Arc.Direction.LEFT) - val a3 = Arc.of(c2.center, p2, end, Arc.Direction.RIGHT) + val a1 = ArcSegment.of(c1.center, start, p1, ArcSegment.Direction.RIGHT) + val a2 = ArcSegment.of(e.center, p1, p2, ArcSegment.Direction.LEFT) + val a3 = ArcSegment.of(c2.center, p2, end, ArcSegment.Direction.RIGHT) return DubinsPath(a1, a2, a3) } public fun lrl(start: Pose2D, end: Pose2D, turningRadius: Double): DubinsPath? { val c1 = start.getLeftCircle(turningRadius) val c2 = end.getLeftCircle(turningRadius) - val centers = Straight(c1.center, c2.center) + val centers = StraightSegment(c1.center, c2.center) if (centers.length > turningRadius * 4) return null var theta = theta(centers.theta + acos(centers.length / (turningRadius * 4))) var dX = turningRadius * sin(theta) var dY = turningRadius * cos(theta) val p = Vector2D(c1.center.x + dX * 2, c1.center.y + dY * 2) - val e = Circle(p, turningRadius) + val e = Circle2D(p, turningRadius) val p1 = Vector2D(c1.center.x + dX, c1.center.y + dY) theta = theta(centers.theta - acos(centers.length / (turningRadius * 4))) dX = turningRadius * sin(theta) dY = turningRadius * cos(theta) val p2 = Vector2D(e.center.x + dX, e.center.y + dY) - val a1 = Arc.of(c1.center, start, p1, Arc.Direction.LEFT) - val a2 = Arc.of(e.center, p1, p2, Arc.Direction.RIGHT) - val a3 = Arc.of(c2.center, p2, end, Arc.Direction.LEFT) + val a1 = ArcSegment.of(c1.center, start, p1, ArcSegment.Direction.LEFT) + val a2 = ArcSegment.of(e.center, p1, p2, ArcSegment.Direction.RIGHT) + val a3 = ArcSegment.of(c2.center, p2, end, ArcSegment.Direction.LEFT) return DubinsPath(a1, a2, a3) } @@ -97,8 +101,8 @@ public class DubinsPath( val c1 = start.getRightCircle(turningRadius) val c2 = end.getRightCircle(turningRadius) val s = leftOuterTangent(c1, c2) - val a1 = Arc.of(c1.center, start, s.start, Arc.Direction.RIGHT) - val a3 = Arc.of(c2.center, s.end, end, Arc.Direction.RIGHT) + val a1 = ArcSegment.of(c1.center, start, s.start, ArcSegment.Direction.RIGHT) + val a3 = ArcSegment.of(c2.center, s.end, end, ArcSegment.Direction.RIGHT) return DubinsPath(a1, s, a3) } @@ -106,8 +110,8 @@ public class DubinsPath( val c1 = start.getLeftCircle(turningRadius) val c2 = end.getLeftCircle(turningRadius) val s = rightOuterTangent(c1, c2) - val a1 = Arc.of(c1.center, start, s.start, Arc.Direction.LEFT) - val a3 = Arc.of(c2.center, s.end, end, Arc.Direction.LEFT) + val a1 = ArcSegment.of(c1.center, start, s.start, ArcSegment.Direction.LEFT) + val a3 = ArcSegment.of(c2.center, s.end, end, ArcSegment.Direction.LEFT) return DubinsPath(a1, s, a3) } @@ -117,8 +121,8 @@ public class DubinsPath( val s = rightInnerTangent(c1, c2) if (c1.center.distanceTo(c2.center) < turningRadius * 2 || s == null) return null - val a1 = Arc.of(c1.center, start, s.start, Arc.Direction.RIGHT) - val a3 = Arc.of(c2.center, s.end, end, Arc.Direction.LEFT) + val a1 = ArcSegment.of(c1.center, start, s.start, ArcSegment.Direction.RIGHT) + val a3 = ArcSegment.of(c2.center, s.end, end, ArcSegment.Direction.LEFT) return DubinsPath(a1, s, a3) } @@ -128,8 +132,8 @@ public class DubinsPath( val s = leftInnerTangent(c1, c2) if (c1.center.distanceTo(c2.center) < turningRadius * 2 || s == null) return null - val a1 = Arc.of(c1.center, start, s.start, Arc.Direction.LEFT) - val a3 = Arc.of(c2.center, s.end, end, Arc.Direction.RIGHT) + val a1 = ArcSegment.of(c1.center, start, s.start, ArcSegment.Direction.LEFT) + val a3 = ArcSegment.of(c2.center, s.end, end, ArcSegment.Direction.RIGHT) return DubinsPath(a1, s, a3) } } diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/TrajectoryFunctions.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/trajectoryFunctions.kt similarity index 51% rename from kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/TrajectoryFunctions.kt rename to kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/trajectoryFunctions.kt index 547cb99fc..18384d349 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/TrajectoryFunctions.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/trajectoryFunctions.kt @@ -5,10 +5,10 @@ package space.kscience.kmath.trajectory.dubins +import space.kscience.kmath.geometry.Circle2D import space.kscience.kmath.geometry.Vector2D -import space.kscience.kmath.trajectory.segments.Straight -import space.kscience.kmath.trajectory.segments.components.Circle -import space.kscience.kmath.trajectory.segments.components.Pose2D +import space.kscience.kmath.trajectory.segments.Pose2D +import space.kscience.kmath.trajectory.segments.StraightSegment import kotlin.math.PI import kotlin.math.acos import kotlin.math.cos @@ -18,18 +18,19 @@ private enum class SIDE { LEFT, RIGHT } -internal fun Pose2D.getLeftCircle(radius: Double): Circle = getTangentCircles(radius).first -internal fun Pose2D.getRightCircle(radius: Double): Circle = getTangentCircles(radius).second -internal fun Pose2D.getTangentCircles(radius: Double): Pair { +internal fun Pose2D.getLeftCircle(radius: Double): Circle2D = getTangentCircles(radius).first +internal fun Pose2D.getRightCircle(radius: Double): Circle2D = getTangentCircles(radius).second +internal fun Pose2D.getTangentCircles(radius: Double): Pair { val dX = radius * cos(theta) val dY = radius * sin(theta) - return Circle(Vector2D(x - dX, y + dY), radius) to Circle(Vector2D(x + dX, y - dY), radius) + return Circle2D(Vector2D(x - dX, y + dY), radius) to Circle2D(Vector2D(x + dX, y - dY), radius) } -internal fun leftOuterTangent(a: Circle, b: Circle) = outerTangent(a, b, SIDE.LEFT) -internal fun rightOuterTangent(a: Circle, b: Circle) = outerTangent(a, b, SIDE.RIGHT) -private fun outerTangent(a: Circle, b: Circle, side: SIDE): Straight { - val centers = Straight(a.center, b.center) +internal fun leftOuterTangent(a: Circle2D, b: Circle2D): StraightSegment = outerTangent(a, b, SIDE.LEFT) +internal fun rightOuterTangent(a: Circle2D, b: Circle2D): StraightSegment = outerTangent(a, b, SIDE.RIGHT) + +private fun outerTangent(a: Circle2D, b: Circle2D, side: SIDE): StraightSegment { + val centers = StraightSegment(a.center, b.center) val p1 = when (side) { SIDE.LEFT -> Vector2D( a.center.x - a.radius * cos(centers.theta), @@ -40,16 +41,20 @@ private fun outerTangent(a: Circle, b: Circle, side: SIDE): Straight { a.center.y - a.radius * sin(centers.theta) ) } - return Straight( + return StraightSegment( p1, Vector2D(p1.x + (centers.end.x - centers.start.x), p1.y + (centers.end.y - centers.start.y)) ) } -internal fun leftInnerTangent(base: Circle, direction: Circle) = innerTangent(base, direction, SIDE.LEFT) -internal fun rightInnerTangent(base: Circle, direction: Circle) = innerTangent(base, direction, SIDE.RIGHT) -private fun innerTangent(base: Circle, direction: Circle, side: SIDE): Straight? { - val centers = Straight(base.center, direction.center) +internal fun leftInnerTangent(base: Circle2D, direction: Circle2D): StraightSegment? = + innerTangent(base, direction, SIDE.LEFT) + +internal fun rightInnerTangent(base: Circle2D, direction: Circle2D): StraightSegment? = + innerTangent(base, direction, SIDE.RIGHT) + +private fun innerTangent(base: Circle2D, direction: Circle2D, side: SIDE): StraightSegment? { + val centers = StraightSegment(base.center, direction.center) if (centers.length < base.radius * 2) return null val angle = theta( when (side) { @@ -61,7 +66,7 @@ private fun innerTangent(base: Circle, direction: Circle, side: SIDE): Straight? val dY = base.radius * cos(angle) val p1 = Vector2D(base.center.x + dX, base.center.y + dY) val p2 = Vector2D(direction.center.x - dX, direction.center.y - dY) - return Straight(p1, p2) + return StraightSegment(p1, p2) } -internal fun theta(theta: Double) = (theta + (2 * PI)) % (2 * PI) +internal fun theta(theta: Double): Double = (theta + (2 * PI)) % (2 * PI) diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Arc.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Arc.kt deleted file mode 100644 index 1c02dd952..000000000 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Arc.kt +++ /dev/null @@ -1,59 +0,0 @@ -package space.kscience.kmath.trajectory.segments - -import space.kscience.kmath.geometry.Vector2D -import space.kscience.kmath.trajectory.dubins.theta -import space.kscience.kmath.trajectory.segments.components.Circle -import space.kscience.kmath.trajectory.segments.components.Pose2D -import kotlin.math.PI - -public data class Arc( - public val circle: Circle, - public val start: Pose2D, - public val end: Pose2D -) : Segment { - - internal companion object { - fun of(center: Vector2D, start: Vector2D, end: Vector2D, direction: Direction): Arc { - val s1 = Straight(center, start) - val s2 = Straight(center, end) - val pose1 = calculatePose(start, s1.theta, direction) - val pose2 = calculatePose(end, s2.theta, direction) - return Arc(Circle(center, s1.length), pose1, pose2) - } - - private fun calculatePose(vector: Vector2D, theta: Double, direction: Direction): Pose2D = - Pose2D.of( - vector, - when (direction) { - Direction.LEFT -> theta(theta - PI / 2) - Direction.RIGHT -> theta(theta + PI / 2) - } - ) - } - - internal enum class Direction { - LEFT, RIGHT - } - - override val length: Double - get() { - val angle: Double = - theta(if (direction == Direction.LEFT) start.theta - end.theta else end.theta - start.theta) - val proportion = angle / (2 * PI) - return circle.circumference * proportion - } - - internal val direction: Direction - get() = if (start.y < circle.center.y) { - if (start.theta > PI) Direction.RIGHT else Direction.LEFT - } else if (start.y > circle.center.y) { - if (start.theta < PI) Direction.RIGHT else Direction.LEFT - } else { - if (start.theta == 0.0) { - if (start.x < circle.center.x) Direction.RIGHT else Direction.LEFT - } else { - if (start.x > circle.center.x) Direction.RIGHT else Direction.LEFT - } - } - -} diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Pose2D.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Pose2D.kt new file mode 100644 index 000000000..3df34c107 --- /dev/null +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Pose2D.kt @@ -0,0 +1,21 @@ +/* + * 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.trajectory.segments + +import space.kscience.kmath.geometry.Vector2D + +/** + * A [Vector2D] with view direction + */ +public data class Pose2D( + override val x: Double, + override val y: Double, + public val theta: Double +) : Vector2D { + public companion object { + public fun of(vector: Vector2D, theta: Double): Pose2D = Pose2D(vector.x, vector.y, theta) + } +} diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Segment.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Segment.kt deleted file mode 100644 index 8a1d086fc..000000000 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Segment.kt +++ /dev/null @@ -1,5 +0,0 @@ -package space.kscience.kmath.trajectory.segments - -public interface Segment { - public val length: Double -} diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Straight.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Straight.kt deleted file mode 100644 index 444025d83..000000000 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Straight.kt +++ /dev/null @@ -1,18 +0,0 @@ -package space.kscience.kmath.trajectory.segments - -import space.kscience.kmath.geometry.Euclidean2DSpace.distanceTo -import space.kscience.kmath.geometry.Vector2D -import space.kscience.kmath.trajectory.dubins.theta -import kotlin.math.PI -import kotlin.math.atan2 - -public data class Straight( - internal val start: Vector2D, - internal val end: Vector2D -) : Segment { - override val length: Double - get() = start.distanceTo(end) - - internal val theta: Double - get() = theta(atan2(end.x - start.x, end.y - start.y)) -} diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Trajectory.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Trajectory.kt new file mode 100644 index 000000000..453eef47f --- /dev/null +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Trajectory.kt @@ -0,0 +1,89 @@ +package space.kscience.kmath.trajectory.segments + +import space.kscience.kmath.geometry.Circle2D +import space.kscience.kmath.geometry.Euclidean2DSpace.distanceTo +import space.kscience.kmath.geometry.Vector2D +import space.kscience.kmath.geometry.circumference +import space.kscience.kmath.trajectory.dubins.theta +import kotlin.math.PI +import kotlin.math.atan2 + +public interface Trajectory { + public val length: Double +} + +/** + * Straight path segment. The order of start and end defines the direction + */ +public data class StraightSegment( + internal val start: Vector2D, + internal val end: Vector2D, +) : Trajectory { + override val length: Double get() = start.distanceTo(end) + + internal val theta: Double get() = theta(atan2(end.x - start.x, end.y - start.y)) +} + +/** + * An arc segment + */ +public data class ArcSegment( + public val circle: Circle2D, + public val start: Pose2D, + public val end: Pose2D, +) : Trajectory { + + public enum class Direction { + LEFT, RIGHT + } + + override val length: Double by lazy { + val angle: Double = theta( + if (direction == Direction.LEFT) { + start.theta - end.theta + } else { + end.theta - start.theta + } + ) + val proportion = angle / (2 * PI) + circle.circumference * proportion + } + + internal val direction: Direction by lazy { + if (start.y < circle.center.y) { + if (start.theta > PI) Direction.RIGHT else Direction.LEFT + } else if (start.y > circle.center.y) { + if (start.theta < PI) Direction.RIGHT else Direction.LEFT + } else { + if (start.theta == 0.0) { + if (start.x < circle.center.x) Direction.RIGHT else Direction.LEFT + } else { + if (start.x > circle.center.x) Direction.RIGHT else Direction.LEFT + } + } + } + + public companion object { + public fun of(center: Vector2D, start: Vector2D, end: Vector2D, direction: Direction): ArcSegment { + fun calculatePose( + vector: Vector2D, + theta: Double, + direction: Direction, + ): Pose2D = Pose2D.of( + vector, + when (direction) { + Direction.LEFT -> theta(theta - PI / 2) + Direction.RIGHT -> theta(theta + PI / 2) + } + ) + + val s1 = StraightSegment(center, start) + val s2 = StraightSegment(center, end) + val pose1 = calculatePose(start, s1.theta, direction) + val pose2 = calculatePose(end, s2.theta, direction) + return ArcSegment(Circle2D(center, s1.length), pose1, pose2) + } + } + +} + diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/components/Circle.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/components/Circle.kt deleted file mode 100644 index 946dd8c6e..000000000 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/components/Circle.kt +++ /dev/null @@ -1,11 +0,0 @@ -package space.kscience.kmath.trajectory.segments.components - -import space.kscience.kmath.geometry.Vector2D -import kotlin.math.PI - -public open class Circle( - internal val center: Vector2D, - internal val radius: Double -) { - internal val circumference = radius * 2 * PI -} diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/components/Pose2D.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/components/Pose2D.kt deleted file mode 100644 index c49da3187..000000000 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/components/Pose2D.kt +++ /dev/null @@ -1,13 +0,0 @@ -package space.kscience.kmath.trajectory.segments.components - -import space.kscience.kmath.geometry.Vector2D - -public data class Pose2D( - override val x: Double, - override val y: Double, - public val theta: Double -) : Vector2D { - internal companion object { - internal fun of(vector: Vector2D, theta: Double) = Pose2D(vector.x, vector.y, theta) - } -} diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/Math.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/Math.kt index 92b2f1df9..4f8fda826 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/Math.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/Math.kt @@ -1,8 +1,8 @@ package space.kscience.kmath.trajectory import space.kscience.kmath.geometry.Vector2D -import space.kscience.kmath.trajectory.segments.Straight -import space.kscience.kmath.trajectory.segments.components.Pose2D +import space.kscience.kmath.trajectory.segments.Pose2D +import space.kscience.kmath.trajectory.segments.StraightSegment import kotlin.math.PI import kotlin.math.abs import kotlin.math.sin @@ -14,12 +14,12 @@ fun Double.radiansToDegrees() = this * 180 / PI fun Double.equalFloat(other: Double) = abs(this - other) < maxFloatDelta fun Pose2D.equalsFloat(other: Pose2D) = x.equalFloat(other.x) && y.equalFloat(other.y) && theta.equalFloat(other.theta) -fun Straight.inverse() = Straight(end, start) -fun Straight.shift(shift: Int, width: Double): Straight { +fun StraightSegment.inverse() = StraightSegment(end, start) +fun StraightSegment.shift(shift: Int, width: Double): StraightSegment { val dX = width * sin(inverse().theta) val dY = width * sin(theta) - return Straight( + return StraightSegment( Vector2D(start.x - dX * shift, start.y - dY * shift), Vector2D(end.x - dX * shift, end.y - dY * shift) ) diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/dubins/DubinsTests.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/dubins/DubinsTests.kt index 47e6ac2ef..9069f6dd2 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/dubins/DubinsTests.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/dubins/DubinsTests.kt @@ -10,9 +10,9 @@ import space.kscience.kmath.geometry.Vector2D import space.kscience.kmath.trajectory.equalFloat import space.kscience.kmath.trajectory.equalsFloat import space.kscience.kmath.trajectory.inverse -import space.kscience.kmath.trajectory.segments.Arc -import space.kscience.kmath.trajectory.segments.Straight -import space.kscience.kmath.trajectory.segments.components.Pose2D +import space.kscience.kmath.trajectory.segments.ArcSegment +import space.kscience.kmath.trajectory.segments.Pose2D +import space.kscience.kmath.trajectory.segments.StraightSegment import space.kscience.kmath.trajectory.shift import kotlin.test.Test import kotlin.test.assertNotNull @@ -23,7 +23,7 @@ class DubinsTests { @Test fun dubinsTest() { - val straight = Straight(Vector2D(0.0, 0.0), Vector2D(100.0, 100.0)) + val straight = StraightSegment(Vector2D(0.0, 0.0), Vector2D(100.0, 100.0)) val lineP1 = straight.shift(1, 10.0).inverse() val start = Pose2D.of(straight.end, straight.theta) @@ -52,12 +52,12 @@ class DubinsTests { assertTrue(end.equalsFloat(path.c.end)) // Not working, theta double precision inaccuracy - if (path.b is Arc) { - val b = path.b as Arc + if (path.b is ArcSegment) { + val b = path.b as ArcSegment assertTrue(path.a.end.equalsFloat(b.start)) assertTrue(path.c.start.equalsFloat(b.end)) - } else if (path.b is Straight) { - val b = path.b as Straight + } else if (path.b is StraightSegment) { + val b = path.b as StraightSegment assertTrue(path.a.end.equalsFloat(Pose2D.of(b.start, b.theta))) assertTrue(path.c.start.equalsFloat(Pose2D.of(b.end, b.theta))) } diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/ArcTests.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/ArcTests.kt index 5b4ae6d7a..aa8778315 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/ArcTests.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/ArcTests.kt @@ -1,8 +1,9 @@ package space.kscience.kmath.trajectory.segments +import space.kscience.kmath.geometry.Circle2D import space.kscience.kmath.geometry.Vector2D +import space.kscience.kmath.geometry.circumference import space.kscience.kmath.trajectory.radiansToDegrees -import space.kscience.kmath.trajectory.segments.components.Circle import kotlin.test.Test import kotlin.test.assertEquals @@ -10,8 +11,8 @@ class ArcTests { @Test fun arcTest() { - val circle = Circle(Vector2D(0.0, 0.0), 2.0) - val arc = Arc.of(circle.center, Vector2D(-2.0, 0.0), Vector2D(0.0, 2.0), Arc.Direction.RIGHT) + val circle = Circle2D(Vector2D(0.0, 0.0), 2.0) + val arc = ArcSegment.of(circle.center, Vector2D(-2.0, 0.0), Vector2D(0.0, 2.0), ArcSegment.Direction.RIGHT) assertEquals(circle.circumference / 4, arc.length, 1.0) assertEquals(0.0, arc.start.theta.radiansToDegrees()) assertEquals(90.0, arc.end.theta.radiansToDegrees()) diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/components/CircleTests.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/CircleTests.kt similarity index 74% rename from kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/components/CircleTests.kt rename to kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/CircleTests.kt index 6f28885e0..5170c1db5 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/components/CircleTests.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/CircleTests.kt @@ -3,9 +3,11 @@ * 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.trajectory.segments.components +package space.kscience.kmath.trajectory.segments +import space.kscience.kmath.geometry.Circle2D import space.kscience.kmath.geometry.Vector2D +import space.kscience.kmath.geometry.circumference import space.kscience.kmath.trajectory.maxFloatDelta import kotlin.test.Test import kotlin.test.assertEquals @@ -17,7 +19,7 @@ class CircleTests { val center = Vector2D(0.0, 0.0) val radius = 2.0 val expectedCircumference = 12.56637 - val circle = Circle(center, radius) + val circle = Circle2D(center, radius) assertEquals(expectedCircumference, circle.circumference, maxFloatDelta) } } diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/LineTests.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/LineTests.kt index e8184e178..afc473d79 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/LineTests.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/LineTests.kt @@ -12,21 +12,21 @@ class LineTests { @Test fun lineTest() { - val straight = Straight(Vector2D(0.0, 0.0), Vector2D(100.0, 100.0)) + val straight = StraightSegment(Vector2D(0.0, 0.0), Vector2D(100.0, 100.0)) assertEquals(sqrt(100.0.pow(2) + 100.0.pow(2)), straight.length) assertEquals(45.0, straight.theta.radiansToDegrees()) } @Test fun lineAngleTest() { - val zero = Vector2D(0.0, 0.0) - val north = Straight(Euclidean2DSpace.zero, Vector2D(0.0, 2.0)) + //val zero = Vector2D(0.0, 0.0) + val north = StraightSegment(Euclidean2DSpace.zero, Vector2D(0.0, 2.0)) assertEquals(0.0, north.theta.radiansToDegrees()) - val east = Straight(Euclidean2DSpace.zero, Vector2D(2.0, 0.0)) + val east = StraightSegment(Euclidean2DSpace.zero, Vector2D(2.0, 0.0)) assertEquals(90.0, east.theta.radiansToDegrees()) - val south = Straight(Euclidean2DSpace.zero, Vector2D(0.0, -2.0)) + val south = StraightSegment(Euclidean2DSpace.zero, Vector2D(0.0, -2.0)) assertEquals(180.0, south.theta.radiansToDegrees()) - val west = Straight(Euclidean2DSpace.zero, Vector2D(-2.0, 0.0)) + val west = StraightSegment(Euclidean2DSpace.zero, Vector2D(-2.0, 0.0)) assertEquals(270.0, west.theta.radiansToDegrees()) } } -- 2.34.1 From c2025ee1c9f1323b446f992a8f80b302bcd46774 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Wed, 27 Jul 2022 14:31:55 +0300 Subject: [PATCH 122/123] Remove Polynomial interface, fix consequent platform clashes. Add invariance. --- .../kmath/functions/LabeledPolynomial.kt | 4 +- .../kmath/functions/ListPolynomial.kt | 4 +- .../kmath/functions/NumberedPolynomial.kt | 4 +- .../kscience/kmath/functions/Polynomial.kt | 41 ++++-- .../kmath/functions/RationalFunction.kt | 130 ++++++++++++++++-- 5 files changed, 160 insertions(+), 23 deletions(-) diff --git a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt index e2320114b..6a4d1409f 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt @@ -19,7 +19,7 @@ import kotlin.math.max * * @param C the type of constants. */ -public data class LabeledPolynomial +public data class LabeledPolynomial @PublishedApi internal constructor( /** @@ -63,7 +63,7 @@ internal constructor( * @usesMathJax */ public val coefficients: Map, C> -) : Polynomial { +) { override fun toString(): String = "LabeledPolynomial$coefficients" } diff --git a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt index d0e58c0d6..6ab660b63 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt @@ -19,7 +19,7 @@ import kotlin.math.min * * @param C the type of constants. */ -public data class ListPolynomial( +public data class ListPolynomial( /** * List that contains coefficients of the polynomial. * @@ -48,7 +48,7 @@ public data class ListPolynomial( * @usesMathJax */ public val coefficients: List -) : Polynomial { +) { override fun toString(): String = "ListPolynomial$coefficients" } diff --git a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt index d2fc5ffa1..267bbd91d 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -18,7 +18,7 @@ import kotlin.math.max * * @param C the type of constants. */ -public data class NumberedPolynomial +public data class NumberedPolynomial @PublishedApi internal constructor( /** @@ -47,7 +47,7 @@ internal constructor( * @usesMathJax */ public val coefficients: Map, C> -) : Polynomial { +) { override fun toString(): String = "NumberedPolynomial$coefficients" } diff --git a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt index 66308a7bc..6a11eb1bd 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt @@ -11,11 +11,6 @@ import kotlin.js.JsName import kotlin.jvm.JvmName -/** - * Abstraction of polynomials. - */ -public interface Polynomial - /** * Abstraction of ring of polynomials of type [P] over ring of constants of type [C]. * @@ -23,24 +18,27 @@ public interface Polynomial * @param P the type of polynomials. */ @Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") // FIXME: Waiting for KT-31420 -public interface PolynomialSpace> : Ring

{ +public interface PolynomialSpace : Ring

{ /** * Returns sum of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. */ + @JvmName("plusConstantInt") public operator fun C.plus(other: Int): C /** * Returns difference between the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. */ + @JvmName("minusConstantInt") public operator fun C.minus(other: Int): C /** * Returns product of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to sum of [other] copies of [this]. */ + @JvmName("timesConstantInt") public operator fun C.times(other: Int): C /** @@ -48,18 +46,21 @@ public interface PolynomialSpace> : Ring

{ * * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. */ + @JvmName("plusIntConstant") public operator fun Int.plus(other: C): C /** * Returns difference between the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. */ + @JvmName("minusIntConstant") public operator fun Int.minus(other: C): C /** * Returns product of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ + @JvmName("timesIntConstant") public operator fun Int.times(other: C): C /** @@ -167,27 +168,33 @@ public interface PolynomialSpace> : Ring

{ /** * Returns sum of the constant represented as a polynomial and the polynomial. */ + @JvmName("plusConstantPolynomial") public operator fun C.plus(other: P): P /** * Returns difference between the constant represented as a polynomial and the polynomial. */ + @JvmName("minusConstantPolynomial") public operator fun C.minus(other: P): P /** * Returns product of the constant represented as a polynomial and the polynomial. */ + @JvmName("timesConstantPolynomial") public operator fun C.times(other: P): P /** * Returns sum of the constant represented as a polynomial and the polynomial. */ + @JvmName("plusPolynomialConstant") public operator fun P.plus(other: C): P /** * Returns difference between the constant represented as a polynomial and the polynomial. */ + @JvmName("minusPolynomialConstant") public operator fun P.minus(other: C): P /** * Returns product of the constant represented as a polynomial and the polynomial. */ + @JvmName("timesPolynomialConstant") public operator fun P.times(other: C): P /** @@ -252,7 +259,7 @@ public interface PolynomialSpace> : Ring

{ * @param A the type of algebraic structure (precisely, of ring) provided for constants. */ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 -public interface PolynomialSpaceOverRing, out A: Ring> : PolynomialSpace { +public interface PolynomialSpaceOverRing> : PolynomialSpace { /** * Underlying ring of constants. Its operations on constants are inherited by local operations on constants. @@ -264,18 +271,21 @@ public interface PolynomialSpaceOverRing, out A: Ring> : * * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. */ + @JvmName("plusConstantInt") public override operator fun C.plus(other: Int): C = ring { addMultipliedByDoubling(this@plus, one, other) } /** * Returns difference between the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. */ + @JvmName("minusConstantInt") public override operator fun C.minus(other: Int): C = ring { addMultipliedByDoubling(this@minus, one, -other) } /** * Returns product of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to sum of [other] copies of [this]. */ + @JvmName("timesConstantInt") public override operator fun C.times(other: Int): C = ring { multiplyByDoubling(this@times, other) } /** @@ -283,18 +293,21 @@ public interface PolynomialSpaceOverRing, out A: Ring> : * * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. */ + @JvmName("plusIntConstant") public override operator fun Int.plus(other: C): C = ring { addMultipliedByDoubling(other, one, this@plus) } /** * Returns difference between the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. */ + @JvmName("minusIntConstant") public override operator fun Int.minus(other: C): C = ring { addMultipliedByDoubling(-other, one, this@minus) } /** * Returns product of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ + @JvmName("timesIntConstant") public override operator fun Int.times(other: C): C = ring { multiplyByDoubling(other, this@times) } /** @@ -341,69 +354,81 @@ public interface PolynomialSpaceOverRing, out A: Ring> : * @param P the type of polynomials. */ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 -public interface MultivariatePolynomialSpace>: PolynomialSpace { +public interface MultivariatePolynomialSpace: PolynomialSpace { /** * Returns sum of the variable represented as a monic monomial and the integer represented as a constant polynomial. */ @JvmName("plusVariableInt") + @JsName("plusVariableInt") public operator fun V.plus(other: Int): P /** * Returns difference between the variable represented as a monic monomial and the integer represented as a constant polynomial. */ @JvmName("minusVariableInt") + @JsName("minusVariableInt") public operator fun V.minus(other: Int): P /** * Returns product of the variable represented as a monic monomial and the integer represented as a constant polynomial. */ @JvmName("timesVariableInt") + @JsName("timesVariableInt") public operator fun V.times(other: Int): P /** * Returns sum of the integer represented as a constant polynomial and the variable represented as a monic monomial. */ @JvmName("plusIntVariable") + @JsName("plusIntVariable") public operator fun Int.plus(other: V): P /** * Returns difference between the integer represented as a constant polynomial and the variable represented as a monic monomial. */ @JvmName("minusIntVariable") + @JsName("minusIntVariable") public operator fun Int.minus(other: V): P /** * Returns product of the integer represented as a constant polynomial and the variable represented as a monic monomial. */ @JvmName("timesIntVariable") + @JsName("timesIntVariable") public operator fun Int.times(other: V): P /** * Returns sum of the variable represented as a monic monomial and the constant represented as a constant polynomial. */ @JvmName("plusVariableConstant") + @JsName("plusVariableConstant") public operator fun V.plus(other: C): P /** * Returns difference between the variable represented as a monic monomial and the constant represented as a constant polynomial. */ @JvmName("minusVariableConstant") + @JsName("minusVariableConstant") public operator fun V.minus(other: C): P /** * Returns product of the variable represented as a monic monomial and the constant represented as a constant polynomial. */ @JvmName("timesVariableConstant") + @JsName("timesVariableConstant") public operator fun V.times(other: C): P /** * Returns sum of the constant represented as a constant polynomial and the variable represented as a monic monomial. */ @JvmName("plusConstantVariable") + @JsName("plusConstantVariable") public operator fun C.plus(other: V): P /** * Returns difference between the constant represented as a constant polynomial and the variable represented as a monic monomial. */ @JvmName("minusConstantVariable") + @JsName("minusConstantVariable") public operator fun C.minus(other: V): P /** * Returns product of the constant represented as a constant polynomial and the variable represented as a monic monomial. */ @JvmName("timesConstantVariable") + @JsName("timesConstantVariable") public operator fun C.times(other: V): P /** diff --git a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt index da91c8d61..3c1548516 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt @@ -14,7 +14,7 @@ import kotlin.jvm.JvmName /** * Abstraction of rational function. */ -public interface RationalFunction> { +public interface RationalFunction { public val numerator: P public val denominator: P public operator fun component1(): P = numerator @@ -30,24 +30,27 @@ public interface RationalFunction> { * @param R the type of rational functions. */ @Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") // FIXME: Waiting for KT-31420 -public interface RationalFunctionSpace, R: RationalFunction> : Ring { +public interface RationalFunctionSpace> : Ring { /** * Returns sum of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. */ + @JvmName("plusConstantInt") public operator fun C.plus(other: Int): C /** * Returns difference between the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. */ + @JvmName("minusConstantInt") public operator fun C.minus(other: Int): C /** * Returns product of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to sum of [other] copies of [this]. */ + @JvmName("timesConstantInt") public operator fun C.times(other: Int): C /** @@ -55,18 +58,21 @@ public interface RationalFunctionSpace, R: RationalFunction< * * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. */ + @JvmName("plusIntConstant") public operator fun Int.plus(other: C): C /** * Returns difference between the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. */ + @JvmName("minusIntConstant") public operator fun Int.minus(other: C): C /** * Returns product of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ + @JvmName("timesIntConstant") public operator fun Int.times(other: C): C /** @@ -83,18 +89,21 @@ public interface RationalFunctionSpace, R: RationalFunction< * * The operation is equivalent to adding [other] copies of unit polynomial to [this]. */ + @JvmName("plusPolynomialInt") public operator fun P.plus(other: Int): P /** * Returns difference between the constant and the integer represented as a polynomial. * * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. */ + @JvmName("minusPolynomialInt") public operator fun P.minus(other: Int): P /** * Returns product of the constant and the integer represented as a polynomial. * * The operation is equivalent to sum of [other] copies of [this]. */ + @JvmName("timesPolynomialInt") public operator fun P.times(other: Int): P /** @@ -102,18 +111,21 @@ public interface RationalFunctionSpace, R: RationalFunction< * * The operation is equivalent to adding [this] copies of unit polynomial to [other]. */ + @JvmName("plusIntPolynomial") public operator fun Int.plus(other: P): P /** * Returns difference between the integer represented as a polynomial and the constant. * * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. */ + @JvmName("minusIntPolynomial") public operator fun Int.minus(other: P): P /** * Returns product of the integer represented as a polynomial and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ + @JvmName("timesIntPolynomial") public operator fun Int.times(other: P): P /** @@ -235,27 +247,33 @@ public interface RationalFunctionSpace, R: RationalFunction< /** * Returns sum of the constant represented as a polynomial and the polynomial. */ + @JvmName("plusConstantPolynomial") public operator fun C.plus(other: P): P /** * Returns difference between the constant represented as a polynomial and the polynomial. */ + @JvmName("minusConstantPolynomial") public operator fun C.minus(other: P): P /** * Returns product of the constant represented as a polynomial and the polynomial. */ + @JvmName("timesConstantPolynomial") public operator fun C.times(other: P): P /** * Returns sum of the constant represented as a polynomial and the polynomial. */ + @JvmName("plusPolynomialConstant") public operator fun P.plus(other: C): P /** * Returns difference between the constant represented as a polynomial and the polynomial. */ + @JvmName("minusPolynomialConstant") public operator fun P.minus(other: C): P /** * Returns product of the constant represented as a polynomial and the polynomial. */ + @JvmName("timesPolynomialConstant") public operator fun P.times(other: C): P /** @@ -270,30 +288,37 @@ public interface RationalFunctionSpace, R: RationalFunction< /** * Returns the same polynomial. */ + @JvmName("unaryPlusPolynomial") public operator fun P.unaryPlus(): P = this /** * Returns negation of the polynomial. */ + @JvmName("unaryMinusPolynomial") public operator fun P.unaryMinus(): P /** * Returns sum of the polynomials. */ + @JvmName("plusPolynomialPolynomial") public operator fun P.plus(other: P): P /** * Returns difference of the polynomials. */ + @JvmName("minusPolynomialPolynomial") public operator fun P.minus(other: P): P /** * Returns product of the polynomials. */ + @JvmName("timesPolynomialPolynomial") public operator fun P.times(other: P): P /** * Returns quotient of the polynomials as rational function. */ + @JvmName("divPolynomialPolynomial") public operator fun P.div(other: P): R /** * Raises [arg] to the integer power [exponent]. */ + @JvmName("powerPolynomial") public fun power(arg: P, exponent: UInt) : P /** @@ -308,87 +333,107 @@ public interface RationalFunctionSpace, R: RationalFunction< /** * Returns sum of the constant represented as a rational function and the rational function. */ + @JvmName("plusConstantRational") public operator fun C.plus(other: R): R /** * Returns difference between the constant represented as a polynomial and the rational function. */ + @JvmName("minusConstantRational") public operator fun C.minus(other: R): R /** * Returns product of the constant represented as a polynomial and the rational function. */ + @JvmName("timesConstantRational") public operator fun C.times(other: R): R /** * Returns quotient of the constant represented as a polynomial and the rational function. */ + @JvmName("divConstantRational") public operator fun C.div(other: R): R /** * Returns sum of the rational function and the constant represented as a rational function. */ + @JvmName("plusRationalConstant") public operator fun R.plus(other: C): R /** * Returns difference between the rational function and the constant represented as a rational function. */ + @JvmName("minusRationalConstant") public operator fun R.minus(other: C): R /** * Returns product of the rational function and the constant represented as a rational function. */ + @JvmName("timesRationalConstant") public operator fun R.times(other: C): R /** * Returns quotient of the rational function and the constant represented as a rational function. */ + @JvmName("divRationalConstant") public operator fun R.div(other: C): R /** * Converts the constant [value] to rational function. */ + @JvmName("numberConstant") public fun number(value: C): R = one * value /** * Converts the constant to rational function. */ + @JvmName("asRationalFunctionConstant") public fun C.asRationalFunction(): R = number(this) /** * Returns sum of the polynomial represented as a rational function and the rational function. */ + @JvmName("plusPolynomialRational") public operator fun P.plus(other: R): R /** * Returns difference between the polynomial represented as a polynomial and the rational function. */ + @JvmName("minusPolynomialRational") public operator fun P.minus(other: R): R /** * Returns product of the polynomial represented as a polynomial and the rational function. */ + @JvmName("timesPolynomialRational") public operator fun P.times(other: R): R /** * Returns quotient of the polynomial represented as a polynomial and the rational function. */ + @JvmName("divPolynomialRational") public operator fun P.div(other: R): R /** * Returns sum of the rational function and the polynomial represented as a rational function. */ + @JvmName("plusRationalPolynomial") public operator fun R.plus(other: P): R /** * Returns difference between the rational function and the polynomial represented as a rational function. */ + @JvmName("minusRationalPolynomial") public operator fun R.minus(other: P): R /** * Returns product of the rational function and the polynomial represented as a rational function. */ + @JvmName("timesRationalPolynomial") public operator fun R.times(other: P): R /** * Returns quotient of the rational function and the polynomial represented as a rational function. */ + @JvmName("divRationalPolynomial") public operator fun R.div(other: P): R /** * Converts the polynomial [value] to rational function. */ + @JvmName("numberPolynomial") public fun number(value: P): R = one * value /** * Converts the polynomial to rational function. */ + @JvmName("asRationalFunctionPolynomial") public fun P.asRationalFunction(): R = number(this) /** @@ -462,7 +507,7 @@ public interface RationalFunctionSpace, R: RationalFunction< @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public interface RationalFunctionSpaceOverRing< C, - P: Polynomial, + P, R: RationalFunction, out A: Ring > : RationalFunctionSpace { @@ -477,18 +522,21 @@ public interface RationalFunctionSpaceOverRing< * * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. */ + @JvmName("plusConstantInt") public override operator fun C.plus(other: Int): C = ring { addMultipliedByDoubling(this@plus, one, other) } /** * Returns difference between the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. */ + @JvmName("minusConstantInt") public override operator fun C.minus(other: Int): C = ring { addMultipliedByDoubling(this@minus, one, -other) } /** * Returns product of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to sum of [other] copies of [this]. */ + @JvmName("timesConstantInt") public override operator fun C.times(other: Int): C = ring { multiplyByDoubling(this@times, other) } /** @@ -496,18 +544,21 @@ public interface RationalFunctionSpaceOverRing< * * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. */ + @JvmName("plusIntConstant") public override operator fun Int.plus(other: C): C = ring { addMultipliedByDoubling(other, one, this@plus) } /** * Returns difference between the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. */ + @JvmName("minusIntConstant") public override operator fun Int.minus(other: C): C = ring { addMultipliedByDoubling(-other, one, this@minus) } /** * Returns product of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ + @JvmName("timesIntConstant") public override operator fun Int.times(other: C): C = ring { multiplyByDoubling(other, this@times) } /** @@ -564,7 +615,7 @@ public interface RationalFunctionSpaceOverRing< @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public interface RationalFunctionSpaceOverPolynomialSpace< C, - P: Polynomial, + P, R: RationalFunction, out AP: PolynomialSpace, > : RationalFunctionSpace { @@ -579,18 +630,21 @@ public interface RationalFunctionSpaceOverPolynomialSpace< * * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. */ + @JvmName("plusConstantInt") public override operator fun C.plus(other: Int): C = polynomialRing { this@plus + other } /** * Returns difference between the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. */ + @JvmName("minusConstantInt") public override operator fun C.minus(other: Int): C = polynomialRing { this@minus - other } /** * Returns product of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to sum of [other] copies of [this]. */ + @JvmName("timesConstantInt") public override operator fun C.times(other: Int): C = polynomialRing { this@times * other } /** @@ -598,18 +652,21 @@ public interface RationalFunctionSpaceOverPolynomialSpace< * * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. */ + @JvmName("plusIntConstant") public override operator fun Int.plus(other: C): C = polynomialRing { this@plus + other } /** * Returns difference between the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. */ + @JvmName("minusIntConstant") public override operator fun Int.minus(other: C): C = polynomialRing { this@minus - other } /** * Returns product of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ + @JvmName("timesIntConstant") public override operator fun Int.times(other: C): C = polynomialRing { this@times * other } /** @@ -626,18 +683,21 @@ public interface RationalFunctionSpaceOverPolynomialSpace< * * The operation is equivalent to adding [other] copies of unit polynomial to [this]. */ + @JvmName("plusPolynomialInt") public override operator fun P.plus(other: Int): P = polynomialRing { this@plus + other } /** * Returns difference between the constant and the integer represented as a polynomial. * * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. */ + @JvmName("minusPolynomialInt") public override operator fun P.minus(other: Int): P = polynomialRing { this@minus - other } /** * Returns product of the constant and the integer represented as a polynomial. * * The operation is equivalent to sum of [other] copies of [this]. */ + @JvmName("timesPolynomialInt") public override operator fun P.times(other: Int): P = polynomialRing { this@times * other } /** @@ -645,18 +705,21 @@ public interface RationalFunctionSpaceOverPolynomialSpace< * * The operation is equivalent to adding [this] copies of unit polynomial to [other]. */ + @JvmName("plusIntPolynomial") public override operator fun Int.plus(other: P): P = polynomialRing { this@plus + other } /** * Returns difference between the integer represented as a polynomial and the constant. * * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. */ + @JvmName("minusIntPolynomial") public override operator fun Int.minus(other: P): P = polynomialRing { this@minus - other } /** * Returns product of the integer represented as a polynomial and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ + @JvmName("timesIntPolynomial") public override operator fun Int.times(other: P): P = polynomialRing { this@times * other } /** @@ -711,27 +774,33 @@ public interface RationalFunctionSpaceOverPolynomialSpace< /** * Returns sum of the constant represented as a polynomial and the polynomial. */ + @JvmName("plusConstantPolynomial") public override operator fun C.plus(other: P): P = polynomialRing { this@plus + other } /** * Returns difference between the constant represented as a polynomial and the polynomial. */ + @JvmName("minusConstantPolynomial") public override operator fun C.minus(other: P): P = polynomialRing { this@minus - other } /** * Returns product of the constant represented as a polynomial and the polynomial. */ + @JvmName("timesConstantPolynomial") public override operator fun C.times(other: P): P = polynomialRing { this@times * other } /** * Returns sum of the constant represented as a polynomial and the polynomial. */ + @JvmName("plusPolynomialConstant") public override operator fun P.plus(other: C): P = polynomialRing { this@plus + other } /** * Returns difference between the constant represented as a polynomial and the polynomial. */ + @JvmName("minusPolynomialConstant") public override operator fun P.minus(other: C): P = polynomialRing { this@minus - other } /** * Returns product of the constant represented as a polynomial and the polynomial. */ + @JvmName("timesPolynomialConstant") public override operator fun P.times(other: C): P = polynomialRing { this@times * other } /** @@ -746,26 +815,32 @@ public interface RationalFunctionSpaceOverPolynomialSpace< /** * Returns the same polynomial. */ + @JvmName("unaryPlusPolynomial") public override operator fun P.unaryPlus(): P = polynomialRing { +this@unaryPlus } /** * Returns negation of the polynomial. */ + @JvmName("unaryMinusPolynomial") public override operator fun P.unaryMinus(): P = polynomialRing { -this@unaryMinus } /** * Returns sum of the polynomials. */ + @JvmName("plusPolynomialPolynomial") public override operator fun P.plus(other: P): P = polynomialRing { this@plus + other } /** * Returns difference of the polynomials. */ + @JvmName("minusPolynomialPolynomial") public override operator fun P.minus(other: P): P = polynomialRing { this@minus - other } /** * Returns product of the polynomials. */ + @JvmName("timesPolynomialPolynomial") public override operator fun P.times(other: P): P = polynomialRing { this@times * other } /** * Raises [arg] to the integer power [exponent]. */ + @JvmName("powerPolynomial") public override fun power(arg: P, exponent: UInt) : P = polynomialRing { power(arg, exponent) } /** @@ -796,7 +871,7 @@ public interface RationalFunctionSpaceOverPolynomialSpace< @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public abstract class PolynomialSpaceOfFractions< C, - P: Polynomial, + P, R: RationalFunction, > : RationalFunctionSpace { @@ -897,11 +972,13 @@ public abstract class PolynomialSpaceOfFractions< /** * Returns quotient of the polynomials as rational function. */ + @JvmName("divPolynomialPolynomial") public override operator fun P.div(other: P): R = constructRationalFunction(this, other) /** * Returns sum of the constant represented as a rational function and the rational function. */ + @JvmName("plusConstantRational") public override operator fun C.plus(other: R): R = constructRationalFunction( other.denominator * this + other.numerator, @@ -910,6 +987,7 @@ public abstract class PolynomialSpaceOfFractions< /** * Returns difference between the constant represented as a polynomial and the rational function. */ + @JvmName("minusConstantRational") public override operator fun C.minus(other: R): R = constructRationalFunction( other.denominator * this - other.numerator, @@ -918,6 +996,7 @@ public abstract class PolynomialSpaceOfFractions< /** * Returns product of the constant represented as a polynomial and the rational function. */ + @JvmName("timesConstantRational") public override operator fun C.times(other: R): R = constructRationalFunction( this * other.numerator, @@ -926,6 +1005,7 @@ public abstract class PolynomialSpaceOfFractions< /** * Returns quotient of the constant represented as a polynomial and the rational function. */ + @JvmName("divConstantRational") public override operator fun C.div(other: R): R = constructRationalFunction( this * other.denominator, @@ -935,6 +1015,7 @@ public abstract class PolynomialSpaceOfFractions< /** * Returns sum of the constant represented as a rational function and the rational function. */ + @JvmName("plusRationalConstant") public override operator fun R.plus(other: C): R = constructRationalFunction( numerator + denominator * other, @@ -943,6 +1024,7 @@ public abstract class PolynomialSpaceOfFractions< /** * Returns difference between the constant represented as a rational function and the rational function. */ + @JvmName("minusRationalConstant") public override operator fun R.minus(other: C): R = constructRationalFunction( numerator - denominator * other, @@ -951,6 +1033,7 @@ public abstract class PolynomialSpaceOfFractions< /** * Returns product of the constant represented as a rational function and the rational function. */ + @JvmName("timesRationalConstant") public override operator fun R.times(other: C): R = constructRationalFunction( numerator * other, @@ -959,6 +1042,7 @@ public abstract class PolynomialSpaceOfFractions< /** * Returns quotient of the rational function and the constant represented as a rational function. */ + @JvmName("divRationalConstant") public override operator fun R.div(other: C): R = constructRationalFunction( numerator, @@ -968,11 +1052,13 @@ public abstract class PolynomialSpaceOfFractions< /** * Converts the constant [value] to rational function. */ + @JvmName("numberConstant") public override fun number(value: C): R = constructRationalFunction(polynomialNumber(value)) /** * Returns sum of the polynomial represented as a rational function and the rational function. */ + @JvmName("plusPolynomialRational") public override operator fun P.plus(other: R): R = constructRationalFunction( other.denominator * this + other.numerator, @@ -981,6 +1067,7 @@ public abstract class PolynomialSpaceOfFractions< /** * Returns difference between the polynomial represented as a polynomial and the rational function. */ + @JvmName("minusPolynomialRational") public override operator fun P.minus(other: R): R = constructRationalFunction( other.denominator * this - other.numerator, @@ -989,6 +1076,7 @@ public abstract class PolynomialSpaceOfFractions< /** * Returns product of the polynomial represented as a polynomial and the rational function. */ + @JvmName("timesPolynomialRational") public override operator fun P.times(other: R): R = constructRationalFunction( this * other.numerator, @@ -997,6 +1085,7 @@ public abstract class PolynomialSpaceOfFractions< /** * Returns quotient of the polynomial represented as a polynomial and the rational function. */ + @JvmName("divPolynomialRational") public override operator fun P.div(other: R): R = constructRationalFunction( this * other.denominator, @@ -1006,6 +1095,7 @@ public abstract class PolynomialSpaceOfFractions< /** * Returns sum of the polynomial represented as a rational function and the rational function. */ + @JvmName("plusRationalPolynomial") public override operator fun R.plus(other: P): R = constructRationalFunction( numerator + denominator * other, @@ -1014,6 +1104,7 @@ public abstract class PolynomialSpaceOfFractions< /** * Returns difference between the polynomial represented as a rational function and the rational function. */ + @JvmName("minusRationalPolynomial") public override operator fun R.minus(other: P): R = constructRationalFunction( numerator - denominator * other, @@ -1022,6 +1113,7 @@ public abstract class PolynomialSpaceOfFractions< /** * Returns product of the polynomial represented as a rational function and the rational function. */ + @JvmName("timesRationalPolynomial") public override operator fun R.times(other: P): R = constructRationalFunction( numerator * other, @@ -1030,6 +1122,7 @@ public abstract class PolynomialSpaceOfFractions< /** * Returns quotient of the rational function and the polynomial represented as a rational function. */ + @JvmName("divRationalPolynomial") public override operator fun R.div(other: P): R = constructRationalFunction( numerator, @@ -1039,6 +1132,7 @@ public abstract class PolynomialSpaceOfFractions< /** * Converts the polynomial [value] to rational function. */ + @JvmName("numberPolynomial") public override fun number(value: P): R = constructRationalFunction(value) /** @@ -1110,97 +1204,114 @@ public abstract class PolynomialSpaceOfFractions< public interface MultivariateRationalFunctionSpace< C, V, - P: Polynomial, + P, R: RationalFunction >: RationalFunctionSpace { /** * Returns sum of the variable represented as a monic monomial and the integer represented as a constant polynomial. */ @JvmName("plusVariableInt") + @JsName("plusVariableInt") public operator fun V.plus(other: Int): P /** * Returns difference between the variable represented as a monic monomial and the integer represented as a constant polynomial. */ @JvmName("minusVariableInt") + @JsName("minusVariableInt") public operator fun V.minus(other: Int): P /** * Returns product of the variable represented as a monic monomial and the integer represented as a constant polynomial. */ @JvmName("timesVariableInt") + @JsName("timesVariableInt") public operator fun V.times(other: Int): P /** * Returns sum of the integer represented as a constant polynomial and the variable represented as a monic monomial. */ @JvmName("plusIntVariable") + @JsName("plusIntVariable") public operator fun Int.plus(other: V): P /** * Returns difference between the integer represented as a constant polynomial and the variable represented as a monic monomial. */ @JvmName("minusIntVariable") + @JsName("minusIntVariable") public operator fun Int.minus(other: V): P /** * Returns product of the integer represented as a constant polynomial and the variable represented as a monic monomial. */ @JvmName("timesIntVariable") + @JsName("timesIntVariable") public operator fun Int.times(other: V): P /** * Returns sum of the variable represented as a monic monomial and the constant represented as a constant polynomial. */ @JvmName("plusVariableConstant") + @JsName("plusVariableConstant") public operator fun V.plus(other: C): P /** * Returns difference between the variable represented as a monic monomial and the constant represented as a constant polynomial. */ @JvmName("minusVariableConstant") + @JsName("minusVariableConstant") public operator fun V.minus(other: C): P /** * Returns product of the variable represented as a monic monomial and the constant represented as a constant polynomial. */ @JvmName("timesVariableConstant") + @JsName("timesVariableConstant") public operator fun V.times(other: C): P /** * Returns sum of the constant represented as a constant polynomial and the variable represented as a monic monomial. */ @JvmName("plusConstantVariable") + @JsName("plusConstantVariable") public operator fun C.plus(other: V): P /** * Returns difference between the constant represented as a constant polynomial and the variable represented as a monic monomial. */ @JvmName("minusConstantVariable") + @JsName("minusConstantVariable") public operator fun C.minus(other: V): P /** * Returns product of the constant represented as a constant polynomial and the variable represented as a monic monomial. */ @JvmName("timesConstantVariable") + @JsName("timesConstantVariable") public operator fun C.times(other: V): P /** * Represents the variable as a monic monomial. */ @JvmName("unaryPlusVariable") + @JsName("unaryPlusVariable") public operator fun V.unaryPlus(): P /** * Returns negation of representation of the variable as a monic monomial. */ @JvmName("unaryMinusVariable") + @JsName("unaryMinusVariable") public operator fun V.unaryMinus(): P /** * Returns sum of the variables represented as monic monomials. */ @JvmName("plusVariableVariable") + @JsName("plusVariableVariable") public operator fun V.plus(other: V): P /** * Returns difference between the variables represented as monic monomials. */ @JvmName("minusVariableVariable") + @JsName("minusVariableVariable") public operator fun V.minus(other: V): P /** * Returns product of the variables represented as monic monomials. */ @JvmName("timesVariableVariable") + @JsName("timesVariableVariable") public operator fun V.times(other: V): P /** @@ -1218,11 +1329,13 @@ public interface MultivariateRationalFunctionSpace< * Represents the [variable] as a rational function. */ @JvmName("numberVariable") + @JsName("numberVariable") public fun number(variable: V): R = number(polynomialNumber(variable)) /** * Represents the variable as a rational function. */ @JvmName("asRationalFunctionVariable") + @JsName("asRationalFunctionVariable") public fun V.asRationalFunction(): R = number(this) /** @@ -1339,7 +1452,7 @@ public interface MultivariateRationalFunctionSpace< public interface MultivariateRationalFunctionSpaceOverMultivariatePolynomialSpace< C, V, - P: Polynomial, + P, R: RationalFunction, out AP: MultivariatePolynomialSpace, > : RationalFunctionSpaceOverPolynomialSpace, MultivariateRationalFunctionSpace { @@ -1516,7 +1629,7 @@ public interface MultivariateRationalFunctionSpaceOverMultivariatePolynomialSpac public abstract class MultivariatePolynomialSpaceOfFractions< C, V, - P: Polynomial, + P, R: RationalFunction, > : MultivariateRationalFunctionSpace, PolynomialSpaceOfFractions() { /** @@ -1568,7 +1681,6 @@ public abstract class MultivariatePolynomialSpaceOfFractions< /** * Returns product of the rational function and the variable represented as a rational function. */ - @JvmName("timesRationalVariable") public override operator fun R.times(other: V): R = constructRationalFunction( numerator * other, -- 2.34.1 From 137ddb3ade4f57ee11d2fb05defaa68829d93925 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Fri, 29 Jul 2022 14:12:44 +0300 Subject: [PATCH 123/123] Code simplification for Dubins path --- .../trajectory/{dubins => }/DubinsPath.kt | 75 ++++++++++++++++--- .../space/kscience/kmath/trajectory/Pose2D.kt | 33 ++++++++ .../trajectory/{segments => }/Trajectory.kt | 17 +++-- .../kmath/trajectory/TrajectoryCost.kt | 14 ++++ .../trajectory/dubins/trajectoryFunctions.kt | 72 ------------------ .../space/kscience/kmath/trajectory/route.kt | 16 ++++ .../kmath/trajectory/segments/Pose2D.kt | 21 ------ .../space/kscience/kmath/trajectory/Math.kt | 2 - .../kmath/trajectory/dubins/DubinsTests.kt | 16 ++-- .../kmath/trajectory/segments/ArcTests.kt | 1 + .../kmath/trajectory/segments/LineTests.kt | 1 + 11 files changed, 146 insertions(+), 122 deletions(-) rename kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/{dubins => }/DubinsPath.kt (67%) create mode 100644 kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Pose2D.kt rename kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/{segments => }/Trajectory.kt (85%) create mode 100644 kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/TrajectoryCost.kt delete mode 100644 kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/trajectoryFunctions.kt create mode 100644 kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/route.kt delete mode 100644 kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Pose2D.kt diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/DubinsPath.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPath.kt similarity index 67% rename from kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/DubinsPath.kt rename to kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPath.kt index f510e3572..134342b33 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/DubinsPath.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPath.kt @@ -3,24 +3,79 @@ * 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.trajectory.dubins +package space.kscience.kmath.trajectory import space.kscience.kmath.geometry.Circle2D import space.kscience.kmath.geometry.Euclidean2DSpace.distanceTo import space.kscience.kmath.geometry.Vector2D -import space.kscience.kmath.trajectory.segments.ArcSegment -import space.kscience.kmath.trajectory.segments.Pose2D -import space.kscience.kmath.trajectory.segments.StraightSegment -import space.kscience.kmath.trajectory.segments.Trajectory +import kotlin.math.PI import kotlin.math.acos import kotlin.math.cos import kotlin.math.sin +internal fun Pose2D.getLeftCircle(radius: Double): Circle2D = getTangentCircles(radius).first + +internal fun Pose2D.getRightCircle(radius: Double): Circle2D = getTangentCircles(radius).second + +internal fun Pose2D.getTangentCircles(radius: Double): Pair { + val dX = radius * cos(theta) + val dY = radius * sin(theta) + return Circle2D(Vector2D(x - dX, y + dY), radius) to Circle2D(Vector2D(x + dX, y - dY), radius) +} + +internal fun leftOuterTangent(a: Circle2D, b: Circle2D): StraightSegment = outerTangent(a, b, ArcSegment.Direction.LEFT) + +internal fun rightOuterTangent(a: Circle2D, b: Circle2D): StraightSegment = outerTangent(a, b, + ArcSegment.Direction.RIGHT +) + +private fun outerTangent(a: Circle2D, b: Circle2D, side: ArcSegment.Direction): StraightSegment { + val centers = StraightSegment(a.center, b.center) + val p1 = when (side) { + ArcSegment.Direction.LEFT -> Vector2D( + a.center.x - a.radius * cos(centers.theta), + a.center.y + a.radius * sin(centers.theta) + ) + ArcSegment.Direction.RIGHT -> Vector2D( + a.center.x + a.radius * cos(centers.theta), + a.center.y - a.radius * sin(centers.theta) + ) + } + return StraightSegment( + p1, + Vector2D(p1.x + (centers.end.x - centers.start.x), p1.y + (centers.end.y - centers.start.y)) + ) +} + +internal fun leftInnerTangent(base: Circle2D, direction: Circle2D): StraightSegment? = + innerTangent(base, direction, ArcSegment.Direction.LEFT) + +internal fun rightInnerTangent(base: Circle2D, direction: Circle2D): StraightSegment? = + innerTangent(base, direction, ArcSegment.Direction.RIGHT) + +private fun innerTangent(base: Circle2D, direction: Circle2D, side: ArcSegment.Direction): StraightSegment? { + val centers = StraightSegment(base.center, direction.center) + if (centers.length < base.radius * 2) return null + val angle = theta( + when (side) { + ArcSegment.Direction.LEFT -> centers.theta + acos(base.radius * 2 / centers.length) + ArcSegment.Direction.RIGHT -> centers.theta - acos(base.radius * 2 / centers.length) + } + ) + val dX = base.radius * sin(angle) + val dY = base.radius * cos(angle) + val p1 = Vector2D(base.center.x + dX, base.center.y + dY) + val p2 = Vector2D(direction.center.x - dX, direction.center.y - dY) + return StraightSegment(p1, p2) +} + +internal fun theta(theta: Double): Double = (theta + (2 * PI)) % (2 * PI) + public class DubinsPath( public val a: ArcSegment, public val b: Trajectory, public val c: ArcSegment, -) : Trajectory { +) : CompositeTrajectory(listOf(a,b,c)) { public val type: TYPE = TYPE.valueOf( arrayOf( @@ -30,8 +85,6 @@ public class DubinsPath( ).toCharArray().concatToString() ) - override val length: Double get() = a.length + b.length + c.length - public enum class TYPE { RLR, LRL, RSR, LSL, RSL, LSR } @@ -119,7 +172,7 @@ public class DubinsPath( val c1 = start.getRightCircle(turningRadius) val c2 = end.getLeftCircle(turningRadius) val s = rightInnerTangent(c1, c2) - if (c1.center.distanceTo(c2.center) < turningRadius * 2 || s == null) return null + if (s == null || c1.center.distanceTo(c2.center) < turningRadius * 2) return null val a1 = ArcSegment.of(c1.center, start, s.start, ArcSegment.Direction.RIGHT) val a3 = ArcSegment.of(c2.center, s.end, end, ArcSegment.Direction.LEFT) @@ -130,11 +183,11 @@ public class DubinsPath( val c1 = start.getLeftCircle(turningRadius) val c2 = end.getRightCircle(turningRadius) val s = leftInnerTangent(c1, c2) - if (c1.center.distanceTo(c2.center) < turningRadius * 2 || s == null) return null + if (s == null || c1.center.distanceTo(c2.center) < turningRadius * 2) return null val a1 = ArcSegment.of(c1.center, start, s.start, ArcSegment.Direction.LEFT) val a3 = ArcSegment.of(c2.center, s.end, end, ArcSegment.Direction.RIGHT) return DubinsPath(a1, s, a3) } } -} +} \ No newline at end of file diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Pose2D.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Pose2D.kt new file mode 100644 index 000000000..1f7c4a52e --- /dev/null +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Pose2D.kt @@ -0,0 +1,33 @@ +/* + * 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.trajectory + +import space.kscience.kmath.geometry.Vector +import space.kscience.kmath.geometry.Vector2D +import kotlin.math.atan2 + +/** + * Combination of [Vector] and its view angle + */ +public interface Pose2D: Vector2D{ + public val coordinate: Vector2D + public val theta: Double +} + +public class PhaseVector2D( + override val coordinate: Vector2D, + public val velocity: Vector2D +): Pose2D, Vector2D by coordinate{ + override val theta: Double get() = atan2(velocity.y, velocity.x) +} + +internal class Pose2DImpl( + override val coordinate: Vector2D, + override val theta: Double +) : Pose2D, Vector2D by coordinate + + +public fun Pose2D(coordinate: Vector2D, theta: Double): Pose2D = Pose2DImpl(coordinate, theta) \ No newline at end of file diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Trajectory.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Trajectory.kt similarity index 85% rename from kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Trajectory.kt rename to kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Trajectory.kt index 453eef47f..2e97d43b0 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Trajectory.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Trajectory.kt @@ -1,14 +1,18 @@ -package space.kscience.kmath.trajectory.segments +/* + * 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.trajectory import space.kscience.kmath.geometry.Circle2D import space.kscience.kmath.geometry.Euclidean2DSpace.distanceTo import space.kscience.kmath.geometry.Vector2D import space.kscience.kmath.geometry.circumference -import space.kscience.kmath.trajectory.dubins.theta import kotlin.math.PI import kotlin.math.atan2 -public interface Trajectory { +public sealed interface Trajectory { public val length: Double } @@ -69,7 +73,7 @@ public data class ArcSegment( vector: Vector2D, theta: Double, direction: Direction, - ): Pose2D = Pose2D.of( + ): Pose2D = Pose2D( vector, when (direction) { Direction.LEFT -> theta(theta - PI / 2) @@ -84,6 +88,9 @@ public data class ArcSegment( return ArcSegment(Circle2D(center, s1.length), pose1, pose2) } } - +} + +public open class CompositeTrajectory(public val segments: Collection) : Trajectory { + override val length: Double get() = segments.sumOf { it.length } } diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/TrajectoryCost.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/TrajectoryCost.kt new file mode 100644 index 000000000..170851c43 --- /dev/null +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/TrajectoryCost.kt @@ -0,0 +1,14 @@ +/* + * 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.trajectory + +public fun interface TrajectoryCost { + public fun estimate(trajectory: Trajectory): Double + + public companion object{ + public val length: TrajectoryCost = TrajectoryCost { it.length } + } +} \ No newline at end of file diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/trajectoryFunctions.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/trajectoryFunctions.kt deleted file mode 100644 index 18384d349..000000000 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/trajectoryFunctions.kt +++ /dev/null @@ -1,72 +0,0 @@ -/* - * 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.trajectory.dubins - -import space.kscience.kmath.geometry.Circle2D -import space.kscience.kmath.geometry.Vector2D -import space.kscience.kmath.trajectory.segments.Pose2D -import space.kscience.kmath.trajectory.segments.StraightSegment -import kotlin.math.PI -import kotlin.math.acos -import kotlin.math.cos -import kotlin.math.sin - -private enum class SIDE { - LEFT, RIGHT -} - -internal fun Pose2D.getLeftCircle(radius: Double): Circle2D = getTangentCircles(radius).first -internal fun Pose2D.getRightCircle(radius: Double): Circle2D = getTangentCircles(radius).second -internal fun Pose2D.getTangentCircles(radius: Double): Pair { - val dX = radius * cos(theta) - val dY = radius * sin(theta) - return Circle2D(Vector2D(x - dX, y + dY), radius) to Circle2D(Vector2D(x + dX, y - dY), radius) -} - -internal fun leftOuterTangent(a: Circle2D, b: Circle2D): StraightSegment = outerTangent(a, b, SIDE.LEFT) -internal fun rightOuterTangent(a: Circle2D, b: Circle2D): StraightSegment = outerTangent(a, b, SIDE.RIGHT) - -private fun outerTangent(a: Circle2D, b: Circle2D, side: SIDE): StraightSegment { - val centers = StraightSegment(a.center, b.center) - val p1 = when (side) { - SIDE.LEFT -> Vector2D( - a.center.x - a.radius * cos(centers.theta), - a.center.y + a.radius * sin(centers.theta) - ) - SIDE.RIGHT -> Vector2D( - a.center.x + a.radius * cos(centers.theta), - a.center.y - a.radius * sin(centers.theta) - ) - } - return StraightSegment( - p1, - Vector2D(p1.x + (centers.end.x - centers.start.x), p1.y + (centers.end.y - centers.start.y)) - ) -} - -internal fun leftInnerTangent(base: Circle2D, direction: Circle2D): StraightSegment? = - innerTangent(base, direction, SIDE.LEFT) - -internal fun rightInnerTangent(base: Circle2D, direction: Circle2D): StraightSegment? = - innerTangent(base, direction, SIDE.RIGHT) - -private fun innerTangent(base: Circle2D, direction: Circle2D, side: SIDE): StraightSegment? { - val centers = StraightSegment(base.center, direction.center) - if (centers.length < base.radius * 2) return null - val angle = theta( - when (side) { - SIDE.LEFT -> centers.theta + acos(base.radius * 2 / centers.length) - SIDE.RIGHT -> centers.theta - acos(base.radius * 2 / centers.length) - } - ) - val dX = base.radius * sin(angle) - val dY = base.radius * cos(angle) - val p1 = Vector2D(base.center.x + dX, base.center.y + dY) - val p2 = Vector2D(direction.center.x - dX, direction.center.y - dY) - return StraightSegment(p1, p2) -} - -internal fun theta(theta: Double): Double = (theta + (2 * PI)) % (2 * PI) diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/route.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/route.kt new file mode 100644 index 000000000..f67ab124d --- /dev/null +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/route.kt @@ -0,0 +1,16 @@ +/* + * 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.trajectory + +public fun interface MaxCurvature { + public fun compute(startPoint: PhaseVector2D): Double +} + +public fun DubinsPath.Companion.shortest( + start: PhaseVector2D, + end: PhaseVector2D, + computer: MaxCurvature, +): DubinsPath = shortest(start, end, computer.compute(start)) diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Pose2D.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Pose2D.kt deleted file mode 100644 index 3df34c107..000000000 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Pose2D.kt +++ /dev/null @@ -1,21 +0,0 @@ -/* - * 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.trajectory.segments - -import space.kscience.kmath.geometry.Vector2D - -/** - * A [Vector2D] with view direction - */ -public data class Pose2D( - override val x: Double, - override val y: Double, - public val theta: Double -) : Vector2D { - public companion object { - public fun of(vector: Vector2D, theta: Double): Pose2D = Pose2D(vector.x, vector.y, theta) - } -} diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/Math.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/Math.kt index 4f8fda826..7ee68bd92 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/Math.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/Math.kt @@ -1,8 +1,6 @@ package space.kscience.kmath.trajectory import space.kscience.kmath.geometry.Vector2D -import space.kscience.kmath.trajectory.segments.Pose2D -import space.kscience.kmath.trajectory.segments.StraightSegment import kotlin.math.PI import kotlin.math.abs import kotlin.math.sin diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/dubins/DubinsTests.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/dubins/DubinsTests.kt index 9069f6dd2..09375a400 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/dubins/DubinsTests.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/dubins/DubinsTests.kt @@ -7,13 +7,7 @@ package space.kscience.kmath.trajectory.dubins import space.kscience.kmath.geometry.Euclidean2DSpace.distanceTo import space.kscience.kmath.geometry.Vector2D -import space.kscience.kmath.trajectory.equalFloat -import space.kscience.kmath.trajectory.equalsFloat -import space.kscience.kmath.trajectory.inverse -import space.kscience.kmath.trajectory.segments.ArcSegment -import space.kscience.kmath.trajectory.segments.Pose2D -import space.kscience.kmath.trajectory.segments.StraightSegment -import space.kscience.kmath.trajectory.shift +import space.kscience.kmath.trajectory.* import kotlin.test.Test import kotlin.test.assertNotNull import kotlin.test.assertTrue @@ -26,8 +20,8 @@ class DubinsTests { val straight = StraightSegment(Vector2D(0.0, 0.0), Vector2D(100.0, 100.0)) val lineP1 = straight.shift(1, 10.0).inverse() - val start = Pose2D.of(straight.end, straight.theta) - val end = Pose2D.of(lineP1.start, lineP1.theta) + val start = Pose2D(straight.end, straight.theta) + val end = Pose2D(lineP1.start, lineP1.theta) val radius = 2.0 val dubins = DubinsPath.all(start, end, radius) @@ -58,8 +52,8 @@ class DubinsTests { assertTrue(path.c.start.equalsFloat(b.end)) } else if (path.b is StraightSegment) { val b = path.b as StraightSegment - assertTrue(path.a.end.equalsFloat(Pose2D.of(b.start, b.theta))) - assertTrue(path.c.start.equalsFloat(Pose2D.of(b.end, b.theta))) + assertTrue(path.a.end.equalsFloat(Pose2D(b.start, b.theta))) + assertTrue(path.c.start.equalsFloat(Pose2D(b.end, b.theta))) } } } diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/ArcTests.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/ArcTests.kt index aa8778315..c66fa201b 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/ArcTests.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/ArcTests.kt @@ -3,6 +3,7 @@ package space.kscience.kmath.trajectory.segments import space.kscience.kmath.geometry.Circle2D import space.kscience.kmath.geometry.Vector2D import space.kscience.kmath.geometry.circumference +import space.kscience.kmath.trajectory.ArcSegment import space.kscience.kmath.trajectory.radiansToDegrees import kotlin.test.Test import kotlin.test.assertEquals diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/LineTests.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/LineTests.kt index afc473d79..11eaa0fb3 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/LineTests.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/LineTests.kt @@ -2,6 +2,7 @@ package space.kscience.kmath.trajectory.segments import space.kscience.kmath.geometry.Euclidean2DSpace import space.kscience.kmath.geometry.Vector2D +import space.kscience.kmath.trajectory.StraightSegment import space.kscience.kmath.trajectory.radiansToDegrees import kotlin.math.pow import kotlin.math.sqrt -- 2.34.1