From b44c99c265d0d8a43679c694135585047a489813 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Tue, 22 Mar 2022 15:28:34 +0300 Subject: [PATCH] Added multivariate abstractions. --- .../kmath/functions/LabeledPolynomial.kt | 68 +++--- .../functions/LabeledRationalFunction.kt | 33 +-- .../kscience/kmath/functions/Polynomial.kt | 60 +++++- .../kmath/functions/RationalFunction.kt | 197 ++++++++++++++++++ 4 files changed, 303 insertions(+), 55 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt index e0b92a712..29aeb6bb0 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt @@ -117,8 +117,8 @@ public fun C.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomia */ public class LabeledPolynomialSpace>( public override val ring: A, -) : PolynomialSpaceOverRing, A> { - public operator fun Symbol.plus(other: Int): LabeledPolynomial = +) : MultivariatePolynomialSpace>, PolynomialSpaceOverRing, A> { + public override operator fun Symbol.plus(other: Int): LabeledPolynomial = if (other == 0) LabeledPolynomial(mapOf( mapOf(this@plus to 1U) to constantOne, )) @@ -126,7 +126,7 @@ public class LabeledPolynomialSpace>( mapOf(this@plus to 1U) to constantOne, emptyMap() to constantOne * other, )) - public operator fun Symbol.minus(other: Int): LabeledPolynomial = + public override operator fun Symbol.minus(other: Int): LabeledPolynomial = if (other == 0) LabeledPolynomial(mapOf( mapOf(this@minus to 1U) to -constantOne, )) @@ -134,13 +134,13 @@ public class LabeledPolynomialSpace>( mapOf(this@minus to 1U) to -constantOne, emptyMap() to constantOne * other, )) - public operator fun Symbol.times(other: Int): LabeledPolynomial = + public override operator fun Symbol.times(other: Int): LabeledPolynomial = if (other == 0) zero else LabeledPolynomial(mapOf( mapOf(this to 1U) to constantOne * other, )) - public operator fun Int.plus(other: Symbol): LabeledPolynomial = + public override operator fun Int.plus(other: Symbol): LabeledPolynomial = if (this == 0) LabeledPolynomial(mapOf( mapOf(other to 1U) to constantOne, )) @@ -148,7 +148,7 @@ public class LabeledPolynomialSpace>( mapOf(other to 1U) to constantOne, emptyMap() to constantOne * this@plus, )) - public operator fun Int.minus(other: Symbol): LabeledPolynomial = + public override operator fun Int.minus(other: Symbol): LabeledPolynomial = if (this == 0) LabeledPolynomial(mapOf( mapOf(other to 1U) to -constantOne, )) @@ -156,7 +156,7 @@ public class LabeledPolynomialSpace>( mapOf(other to 1U) to -constantOne, emptyMap() to constantOne * this@minus, )) - public operator fun Int.times(other: Symbol): LabeledPolynomial = + public override operator fun Int.times(other: Symbol): LabeledPolynomial = if (this == 0) zero else LabeledPolynomial(mapOf( mapOf(other to 1U) to constantOne * this@times, @@ -275,7 +275,7 @@ public class LabeledPolynomialSpace>( */ public override fun number(value: Int): LabeledPolynomial = number(constantNumber(value)) - public operator fun C.plus(other: Symbol): LabeledPolynomial = + public override operator fun C.plus(other: Symbol): LabeledPolynomial = if (isZero()) LabeledPolynomial(mapOf( mapOf(other to 1U) to constantOne, )) @@ -283,7 +283,7 @@ public class LabeledPolynomialSpace>( mapOf(other to 1U) to constantOne, emptyMap() to this@plus, )) - public operator fun C.minus(other: Symbol): LabeledPolynomial = + public override operator fun C.minus(other: Symbol): LabeledPolynomial = if (isZero()) LabeledPolynomial(mapOf( mapOf(other to 1U) to -constantOne, )) @@ -291,13 +291,13 @@ public class LabeledPolynomialSpace>( mapOf(other to 1U) to -constantOne, emptyMap() to this@minus, )) - public operator fun C.times(other: Symbol): LabeledPolynomial = + public override operator fun C.times(other: Symbol): LabeledPolynomial = if (isZero()) zero else LabeledPolynomial(mapOf( mapOf(other to 1U) to this@times, )) - public operator fun Symbol.plus(other: C): LabeledPolynomial = + public override operator fun Symbol.plus(other: C): LabeledPolynomial = if (other.isZero()) LabeledPolynomial(mapOf( mapOf(this@plus to 1U) to constantOne, )) @@ -305,7 +305,7 @@ public class LabeledPolynomialSpace>( mapOf(this@plus to 1U) to constantOne, emptyMap() to other, )) - public operator fun Symbol.minus(other: C): LabeledPolynomial = + public override operator fun Symbol.minus(other: C): LabeledPolynomial = if (other.isZero()) LabeledPolynomial(mapOf( mapOf(this@minus to 1U) to -constantOne, )) @@ -313,7 +313,7 @@ public class LabeledPolynomialSpace>( mapOf(this@minus to 1U) to -constantOne, emptyMap() to other, )) - public operator fun Symbol.times(other: C): LabeledPolynomial = + public override operator fun Symbol.times(other: C): LabeledPolynomial = if (other.isZero()) zero else LabeledPolynomial(mapOf( mapOf(this@times to 1U) to other, @@ -430,7 +430,15 @@ public class LabeledPolynomialSpace>( if (value == 0) zero else LabeledPolynomial(mapOf(emptyMap() to value)) - public operator fun Symbol.plus(other: Symbol): LabeledPolynomial = + public override operator fun Symbol.unaryPlus(): LabeledPolynomial = + LabeledPolynomial(mapOf( + mapOf(this to 1U) to constantOne, + )) + public override operator fun Symbol.unaryMinus(): LabeledPolynomial = + LabeledPolynomial(mapOf( + mapOf(this to 1U) to -constantOne, + )) + public override operator fun Symbol.plus(other: Symbol): LabeledPolynomial = if (this == other) LabeledPolynomial(mapOf( mapOf(this to 1U) to constantOne * 2 )) @@ -438,13 +446,13 @@ public class LabeledPolynomialSpace>( mapOf(this to 1U) to constantOne, mapOf(other to 1U) to constantOne, )) - public operator fun Symbol.minus(other: Symbol): LabeledPolynomial = + public override operator fun Symbol.minus(other: Symbol): LabeledPolynomial = if (this == other) zero else LabeledPolynomial(mapOf( mapOf(this to 1U) to constantOne, mapOf(other to 1U) to -constantOne, )) - public operator fun Symbol.times(other: Symbol): LabeledPolynomial = + public override operator fun Symbol.times(other: Symbol): LabeledPolynomial = if (this == other) LabeledPolynomial(mapOf( mapOf(this to 2U) to constantOne )) @@ -452,7 +460,7 @@ public class LabeledPolynomialSpace>( mapOf(this to 1U, other to 1U) to constantOne, )) - public operator fun Symbol.plus(other: LabeledPolynomial): LabeledPolynomial = + public override operator fun Symbol.plus(other: LabeledPolynomial): LabeledPolynomial = with(other.coefficients) { if (isEmpty()) LabeledPolynomial(mapOf(mapOf(this@plus to 1u) to constantOne)) else LabeledPolynomial( @@ -467,7 +475,7 @@ public class LabeledPolynomialSpace>( } ) } - public operator fun Symbol.minus(other: LabeledPolynomial): LabeledPolynomial = + public override operator fun Symbol.minus(other: LabeledPolynomial): LabeledPolynomial = with(other.coefficients) { if (isEmpty()) LabeledPolynomial(mapOf(mapOf(this@minus to 1u) to constantOne)) else LabeledPolynomial( @@ -484,13 +492,13 @@ public class LabeledPolynomialSpace>( } ) } - public operator fun Symbol.times(other: LabeledPolynomial): LabeledPolynomial = + public override operator fun Symbol.times(other: LabeledPolynomial): LabeledPolynomial = LabeledPolynomial( other.coefficients .mapKeys { (degs, _) -> degs.toMutableMap().also{ it[this] = if (this in it) it[this]!! + 1U else 1U } } ) - public operator fun LabeledPolynomial.plus(other: Symbol): LabeledPolynomial = + public override operator fun LabeledPolynomial.plus(other: Symbol): LabeledPolynomial = with(coefficients) { if (isEmpty()) LabeledPolynomial(mapOf(mapOf(other to 1u) to constantOne)) else LabeledPolynomial( @@ -505,7 +513,7 @@ public class LabeledPolynomialSpace>( } ) } - public operator fun LabeledPolynomial.minus(other: Symbol): LabeledPolynomial = + public override operator fun LabeledPolynomial.minus(other: Symbol): LabeledPolynomial = with(coefficients) { if (isEmpty()) LabeledPolynomial(mapOf(mapOf(other to 1u) to constantOne)) else LabeledPolynomial( @@ -520,7 +528,7 @@ public class LabeledPolynomialSpace>( } ) } - public operator fun LabeledPolynomial.times(other: Symbol): LabeledPolynomial = + public override operator fun LabeledPolynomial.times(other: Symbol): LabeledPolynomial = LabeledPolynomial( coefficients .mapKeys { (degs, _) -> degs.toMutableMap().also{ it[other] = if (other in it) it[other]!! + 1U else 1U } } @@ -604,7 +612,7 @@ public class LabeledPolynomialSpace>( * As consequence all values in the map are positive integers. Also, if the polynomial is constant, the map is empty. * And keys of the map is the same as in [variables]. */ - public val LabeledPolynomial.degrees: Map + public override val LabeledPolynomial.degrees: Map get() = buildMap { coefficients.entries.forEach { (degs, c) -> @@ -613,10 +621,20 @@ public class LabeledPolynomialSpace>( } } } + /** + * Counts degree of the polynomial by the specified [variable]. + */ + public override fun LabeledPolynomial.degreeBy(variable: Symbol): UInt = + coefficients.entries.maxOfOrNull { (degs, c) -> if (c.isZero()) 0u else degs.getOrElse(variable) { 0u } } ?: 0u + /** + * Counts degree of the polynomial by the specified [variables]. + */ + public override fun LabeledPolynomial.degreeBy(variables: Collection): UInt = + coefficients.entries.maxOfOrNull { (degs, c) -> if (c.isZero()) 0u else degs.filterKeys { it in variables }.values.sum() } ?: 0u /** * Set of all variables that appear in the polynomial in positive exponents. */ - public val LabeledPolynomial.variables: Set + public override val LabeledPolynomial.variables: Set get() = buildSet { coefficients.entries.forEach { (degs, c) -> if (c.isNotZero()) addAll(degs.keys) } @@ -624,7 +642,7 @@ public class LabeledPolynomialSpace>( /** * Count of all variables that appear in the polynomial in positive exponents. */ - public val LabeledPolynomial.countOfVariables: Int get() = variables.size + public override val LabeledPolynomial.countOfVariables: Int get() = variables.size /** * Checks if the instant is constant polynomial (of degree no more than 0) over considered ring. diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt index 599660b52..00dd3bb47 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt @@ -63,14 +63,16 @@ public fun > A.LabeledRationalFunction(numeratorCoefficients: Map< public class LabeledRationalFunctionSpace>( public val ring: A, ) : - RationalFunctionalSpaceOverPolynomialSpace< + MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSpace< C, + Symbol, LabeledPolynomial, LabeledRationalFunction, LabeledPolynomialSpace, >, - PolynomialSpaceOfFractions< + MultivariatePolynomialSpaceOfFractions< C, + Symbol, LabeledPolynomial, LabeledRationalFunction, >() { @@ -113,33 +115,6 @@ public class LabeledRationalFunctionSpace>( return numerator * other.denominator equalsTo other.numerator * denominator } - /** - * Map that associates variables (that appear in the polynomial in positive exponents) with their most exponents - * in which they are appeared in the polynomial. - * - * As consequence all values in the map are positive integers. Also, if the polynomial is constant, the map is empty. - * And keys of the map is the same as in [variables]. - */ - public val LabeledPolynomial.degrees: Map get() = polynomialRing { degrees } - /** - * Set of all variables that appear in the polynomial in positive exponents. - */ - public val LabeledPolynomial.variables: Set get() = polynomialRing { variables } - /** - * Count of all variables that appear in the polynomial in positive exponents. - */ - public val LabeledPolynomial.countOfVariables: Int get() = polynomialRing { countOfVariables } - - /** - * Count of all variables that appear in the polynomial in positive exponents. - */ - public val LabeledRationalFunction.variables: Set - get() = numerator.variables union denominator.variables - /** - * Count of all variables that appear in the polynomial in positive exponents. - */ - public val LabeledRationalFunction.countOfVariables: Int get() = variables.size - // TODO: Разобрать // operator fun invoke(arg: Map): LabeledRationalFunction = diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt index f8d7d5a36..224e18832 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt @@ -5,7 +5,8 @@ package space.kscience.kmath.functions -import space.kscience.kmath.operations.* +import space.kscience.kmath.operations.Ring +import space.kscience.kmath.operations.invoke import kotlin.js.JsName import kotlin.jvm.JvmName @@ -413,4 +414,61 @@ public interface PolynomialSpaceOverRing, A: Ring> : Poly * Instance of unit constant (unit of the underlying ring). */ public override val constantOne: C get() = ring.one +} + +public interface MultivariatePolynomialSpace>: PolynomialSpace { + public operator fun V.plus(other: Int): P + public operator fun V.minus(other: Int): P + public operator fun V.times(other: Int): P + + public operator fun Int.plus(other: V): P + public operator fun Int.minus(other: V): P + public operator fun Int.times(other: V): P + + public operator fun C.plus(other: V): P + public operator fun C.minus(other: V): P + public operator fun C.times(other: V): P + + public operator fun V.plus(other: C): P + public operator fun V.minus(other: C): P + public operator fun V.times(other: C): P + + public operator fun V.unaryPlus(): P + public operator fun V.unaryMinus(): P + public operator fun V.plus(other: V): P + public operator fun V.minus(other: V): P + public operator fun V.times(other: V): P + + public operator fun V.plus(other: P): P + public operator fun V.minus(other: P): P + public operator fun V.times(other: P): P + + public operator fun P.plus(other: V): P + public operator fun P.minus(other: V): P + public operator fun P.times(other: V): P + + /** + * Map that associates variables (that appear in the polynomial in positive exponents) with their most exponents + * in which they are appeared in the polynomial. + * + * As consequence all values in the map are positive integers. Also, if the polynomial is constant, the map is empty. + * And keys of the map is the same as in [variables]. + */ + public val P.degrees: Map + /** + * Counts degree of the polynomial by the specified [variable]. + */ + public fun P.degreeBy(variable: V): UInt = degrees.getOrElse(variable) { 0u } + /** + * Counts degree of the polynomial by the specified [variables]. + */ + public fun P.degreeBy(variables: Collection): UInt + /** + * Set of all variables that appear in the polynomial in positive exponents. + */ + public val P.variables: Set get() = degrees.keys + /** + * Count of all variables that appear in the polynomial in positive exponents. + */ + public val P.countOfVariables: Int get() = variables.size } \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt index 90e3bdbb1..c5fcde8ed 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt @@ -1306,4 +1306,201 @@ public abstract class PolynomialSpaceOfFractions< * Instance of unit polynomial (unit of the rational functions ring). */ public override val one: R get() = constructRationalFunction(polynomialOne) +} + +public interface MultivariateRationalFunctionalSpace< + C, + V, + P: Polynomial, + R: RationalFunction + >: RationalFunctionalSpace { + public operator fun V.plus(other: Int): P + public operator fun V.minus(other: Int): P + public operator fun V.times(other: Int): P + + public operator fun Int.plus(other: V): P + public operator fun Int.minus(other: V): P + public operator fun Int.times(other: V): P + + public operator fun C.plus(other: V): P + public operator fun C.minus(other: V): P + public operator fun C.times(other: V): P + + public operator fun V.plus(other: C): P + public operator fun V.minus(other: C): P + public operator fun V.times(other: C): P + + public operator fun V.unaryPlus(): P + public operator fun V.unaryMinus(): P + public operator fun V.plus(other: V): P + public operator fun V.minus(other: V): P + public operator fun V.times(other: V): P + + public operator fun V.plus(other: P): P + public operator fun V.minus(other: P): P + public operator fun V.times(other: P): P + + public operator fun P.plus(other: V): P + public operator fun P.minus(other: V): P + public operator fun P.times(other: V): P + + public operator fun V.plus(other: R): R + public operator fun V.minus(other: R): R + public operator fun V.times(other: R): R + + public operator fun R.plus(other: V): R + public operator fun R.minus(other: V): R + public operator fun R.times(other: V): R + + /** + * Map that associates variables (that appear in the polynomial in positive exponents) with their most exponents + * in which they are appeared in the polynomial. + * + * As consequence all values in the map are positive integers. Also, if the polynomial is constant, the map is empty. + * And keys of the map is the same as in [variables]. + */ + public val P.degrees: Map + /** + * Counts degree of the polynomial by the specified [variable]. + */ + public fun P.degreeBy(variable: V): UInt = degrees.getOrElse(variable) { 0u } + /** + * Counts degree of the polynomial by the specified [variables]. + */ + public fun P.degreeBy(variables: Collection): UInt + /** + * Set of all variables that appear in the polynomial in positive exponents. + */ + public val P.variables: Set get() = degrees.keys + /** + * Count of all variables that appear in the polynomial in positive exponents. + */ + public val P.countOfVariables: Int get() = variables.size + + /** + * Set of all variables that appear in the polynomial in positive exponents. + */ + public val R.variables: Set get() = numerator.variables union denominator.variables + /** + * Count of all variables that appear in the polynomial in positive exponents. + */ + public val R.countOfVariables: Int get() = variables.size +} + +public interface MultivariateRationalFunctionalSpaceOverRing< + C, + V, + P: Polynomial, + R: RationalFunction, + A: Ring + > : RationalFunctionalSpaceOverRing, MultivariateRationalFunctionalSpace + +public interface MultivariateRationalFunctionalSpaceOverPolynomialSpace< + C, + V, + P: Polynomial, + R: RationalFunction, + AP: PolynomialSpace, + > : RationalFunctionalSpaceOverPolynomialSpace, MultivariateRationalFunctionalSpace + +public interface MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSpace< + C, + V, + P: Polynomial, + R: RationalFunction, + AP: MultivariatePolynomialSpace, + > : MultivariateRationalFunctionalSpaceOverPolynomialSpace { + public override operator fun V.plus(other: Int): P = polynomialRing { this@plus + other } + public override operator fun V.minus(other: Int): P = polynomialRing { this@minus - other } + public override operator fun V.times(other: Int): P = polynomialRing { this@times * other } + + public override operator fun Int.plus(other: V): P = polynomialRing { this@plus + other } + public override operator fun Int.minus(other: V): P = polynomialRing { this@minus - other } + public override operator fun Int.times(other: V): P = polynomialRing { this@times * other } + + public override operator fun C.plus(other: V): P = polynomialRing { this@plus + other } + public override operator fun C.minus(other: V): P = polynomialRing { this@minus - other } + public override operator fun C.times(other: V): P = polynomialRing { this@times * other } + + public override operator fun V.plus(other: C): P = polynomialRing { this@plus + other } + public override operator fun V.minus(other: C): P = polynomialRing { this@minus - other } + public override operator fun V.times(other: C): P = polynomialRing { this@times * other } + + public override operator fun V.unaryPlus(): P = polynomialRing { +this@unaryPlus } + public override operator fun V.unaryMinus(): P = polynomialRing { -this@unaryMinus } + public override operator fun V.plus(other: V): P = polynomialRing { this@plus + other } + public override operator fun V.minus(other: V): P = polynomialRing { this@minus - other } + public override operator fun V.times(other: V): P = polynomialRing { this@times * other } + + public override operator fun V.plus(other: P): P = polynomialRing { this@plus + other } + public override operator fun V.minus(other: P): P = polynomialRing { this@minus - other } + public override operator fun V.times(other: P): P = polynomialRing { this@times * other } + + public override operator fun P.plus(other: V): P = polynomialRing { this@plus + other } + public override operator fun P.minus(other: V): P = polynomialRing { this@minus - other } + public override operator fun P.times(other: V): P = polynomialRing { this@times * other } + + /** + * Map that associates variables (that appear in the polynomial in positive exponents) with their most exponents + * in which they are appeared in the polynomial. + * + * As consequence all values in the map are positive integers. Also, if the polynomial is constant, the map is empty. + * And keys of the map is the same as in [variables]. + */ + public override val P.degrees: Map get() = polynomialRing { degrees } + /** + * Counts degree of the polynomial by the specified [variable]. + */ + public override fun P.degreeBy(variable: V): UInt = polynomialRing { degreeBy(variable) } + /** + * Counts degree of the polynomial by the specified [variables]. + */ + public override fun P.degreeBy(variables: Collection): UInt = polynomialRing { degreeBy(variables) } + /** + * Set of all variables that appear in the polynomial in positive exponents. + */ + public override val P.variables: Set get() = polynomialRing { variables } + /** + * Count of all variables that appear in the polynomial in positive exponents. + */ + public override val P.countOfVariables: Int get() = polynomialRing { countOfVariables } +} + +public abstract class MultivariatePolynomialSpaceOfFractions< + C, + V, + P: Polynomial, + R: RationalFunction, + > : MultivariateRationalFunctionalSpace, PolynomialSpaceOfFractions() { + public override operator fun V.plus(other: R): R = + constructRationalFunction( + this * other.denominator + other.numerator, + other.denominator + ) + public override operator fun V.minus(other: R): R = + constructRationalFunction( + this * other.denominator - other.numerator, + other.denominator + ) + public override operator fun V.times(other: R): R = + constructRationalFunction( + this * other.numerator, + other.denominator + ) + + public override operator fun R.plus(other: V): R = + constructRationalFunction( + numerator + denominator * other, + denominator + ) + public override operator fun R.minus(other: V): R = + constructRationalFunction( + numerator - denominator * other, + denominator + ) + public override operator fun R.times(other: V): R = + constructRationalFunction( + numerator * other, + denominator + ) } \ No newline at end of file