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] 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