From de53d032afbe7da603b7bc7cc919718c0c193811 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Mon, 14 Mar 2022 14:14:24 +0300 Subject: [PATCH] 1. Prototyped Rational Functions 2. Added abstract interfaces for removing boilerplates 3. Changed or added default values in interfaces 4. Renamed non-operator `equals` to `equalsTo`, and made it infix --- .../kmath/functions/AbstractPolynomial.kt | 128 ++++- .../functions/AbstractRationalFunction.kt | 500 ++++++++++++++++-- .../kmath/functions/LabeledPolynomial.kt | 24 +- .../kmath/functions/NumberedPolynomial.kt | 74 +-- .../kscience/kmath/functions/Polynomial.kt | 51 +- .../kmath/functions/RationalFunction.kt | 355 +++++++++++++ .../kmath/functions/rationalFunctionUtil.kt | 34 ++ 7 files changed, 998 insertions(+), 168 deletions(-) create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/rationalFunctionUtil.kt diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt index b7b7116f0..69c45798a 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt @@ -154,7 +154,7 @@ public interface AbstractPolynomialSpace> : Ring

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

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

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

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

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

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