diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt index 69c45798a..0ca2d1409 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt @@ -149,7 +149,7 @@ public interface AbstractPolynomialSpace> : Ring

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

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

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