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

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

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

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

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

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

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

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

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

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

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

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

{ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public interface PolynomialSpaceOverRing, A: Ring> : PolynomialSpace { + /** + * Underlying ring of constants. Its operations on constants are inherited by local operations on constants. + */ public val ring: A /** - * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * Returns sum of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. */ public override operator fun C.plus(other: Int): C = ring { addMultipliedByDoubling(this@plus, one, other) } /** - * Returns difference between the constant and the integer represented as constant (member of underlying ring). + * Returns difference between the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. */ public override operator fun C.minus(other: Int): C = ring { addMultipliedByDoubling(this@minus, one, -other) } /** - * Returns product of the constant and the integer represented as constant (member of underlying ring). + * Returns product of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to sum of [other] copies of [this]. */ public override operator fun C.times(other: Int): C = ring { multiplyByDoubling(this@times, other) } /** - * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * Returns sum of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. */ public override operator fun Int.plus(other: C): C = ring { addMultipliedByDoubling(other, one, this@plus) } /** - * Returns difference between the integer represented as constant (member of underlying ring) and the constant. + * Returns difference between the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. */ public override operator fun Int.minus(other: C): C = ring { addMultipliedByDoubling(-other, one, this@minus) } /** - * Returns product of the integer represented as constant (member of underlying ring) and the constant. + * Returns product of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -330,58 +333,145 @@ public interface PolynomialSpaceOverRing, A: Ring> : Poly public override val constantOne: C get() = ring.one } +/** + * Abstraction of ring of polynomials of type [P] of variables of type [V] and over ring of constants of type [C]. + * + * @param C the type of constants. Polynomials have them as coefficients in their terms. + * @param V the type of variables. Polynomials have them in representations of terms. + * @param P the type of polynomials. + */ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public interface MultivariatePolynomialSpace>: PolynomialSpace { + /** + * Returns sum of the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("plusVariableInt") public operator fun V.plus(other: Int): P + /** + * Returns difference between the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("minusVariableInt") public operator fun V.minus(other: Int): P + /** + * Returns product of the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("timesVariableInt") public operator fun V.times(other: Int): P + /** + * Returns sum of the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("plusIntVariable") public operator fun Int.plus(other: V): P + /** + * Returns difference between the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("minusIntVariable") public operator fun Int.minus(other: V): P + /** + * Returns product of the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("timesIntVariable") public operator fun Int.times(other: V): P - @JvmName("plusConstantVariable") - public operator fun C.plus(other: V): P - @JvmName("minusConstantVariable") - public operator fun C.minus(other: V): P - @JvmName("timesConstantVariable") - public operator fun C.times(other: V): P - + /** + * Returns sum of the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("plusVariableConstant") public operator fun V.plus(other: C): P + /** + * Returns difference between the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("minusVariableConstant") public operator fun V.minus(other: C): P + /** + * Returns product of the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("timesVariableConstant") public operator fun V.times(other: C): P + /** + * Returns sum of the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("plusConstantVariable") + public operator fun C.plus(other: V): P + /** + * Returns difference between the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("minusConstantVariable") + public operator fun C.minus(other: V): P + /** + * Returns product of the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("timesConstantVariable") + public operator fun C.times(other: V): P + + /** + * Represents the variable as a monic monomial. + */ @JvmName("unaryPlusVariable") public operator fun V.unaryPlus(): P + /** + * Returns negation of representation of the variable as a monic monomial. + */ @JvmName("unaryMinusVariable") public operator fun V.unaryMinus(): P + /** + * Returns sum of the variables represented as monic monomials. + */ @JvmName("plusVariableVariable") public operator fun V.plus(other: V): P + /** + * Returns difference between the variables represented as monic monomials. + */ @JvmName("minusVariableVariable") public operator fun V.minus(other: V): P + /** + * Returns product of the variables represented as monic monomials. + */ @JvmName("timesVariableVariable") public operator fun V.times(other: V): P + /** + * Represents the [variable] as a monic monomial. + */ + @JvmName("numberVariable") + public fun number(variable: V): P = +variable + /** + * Represents the variable as a monic monomial. + */ + @JvmName("asPolynomialVariable") + public fun V.asPolynomial(): P = number(this) + + /** + * Returns sum of the variable represented as a monic monomial and the polynomial. + */ @JvmName("plusVariablePolynomial") public operator fun V.plus(other: P): P + /** + * Returns difference between the variable represented as a monic monomial and the polynomial. + */ @JvmName("minusVariablePolynomial") public operator fun V.minus(other: P): P + /** + * Returns product of the variable represented as a monic monomial and the polynomial. + */ @JvmName("timesVariablePolynomial") public operator fun V.times(other: P): P + /** + * Returns sum of the polynomial and the variable represented as a monic monomial. + */ @JvmName("plusPolynomialVariable") public operator fun P.plus(other: V): P + /** + * Returns difference between the polynomial and the variable represented as a monic monomial. + */ @JvmName("minusPolynomialVariable") public operator fun P.minus(other: V): P + /** + * Returns product of the polynomial and the variable represented as a monic monomial. + */ @JvmName("timesPolynomialVariable") public operator fun P.times(other: V): P diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt index dfec126f3..01911f980 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt @@ -25,44 +25,44 @@ public interface RationalFunction> { * [C]. * * @param C the type of constants. Polynomials have them as coefficients in their terms. - * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. + * @param P the type of polynomials. Rational functions have them as numerators and denominators. * @param R the type of rational functions. */ @Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") // FIXME: Waiting for KT-31420 public interface RationalFunctionalSpace, R: RationalFunction> : Ring { /** - * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * Returns sum of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. */ public operator fun C.plus(other: Int): C /** - * Returns difference between the constant and the integer represented as constant (member of underlying ring). + * Returns difference between the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. */ public operator fun C.minus(other: Int): C /** - * Returns product of the constant and the integer represented as constant (member of underlying ring). + * Returns product of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to sum of [other] copies of [this]. */ public operator fun C.times(other: Int): C /** - * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * Returns sum of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. */ public operator fun Int.plus(other: C): C /** - * Returns difference between the integer represented as constant (member of underlying ring) and the constant. + * Returns difference between the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. */ public operator fun Int.minus(other: C): C /** - * Returns product of the integer represented as constant (member of underlying ring) and the constant. + * Returns product of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -78,38 +78,38 @@ public interface RationalFunctionalSpace, R: RationalFunctio public fun Int.asConstant(): C = constantNumber(this) /** - * Returns sum of the constant and the integer represented as polynomial. + * Returns sum of the constant and the integer represented as a polynomial. * * The operation is equivalent to adding [other] copies of unit polynomial to [this]. */ public operator fun P.plus(other: Int): P /** - * Returns difference between the constant and the integer represented as polynomial. + * Returns difference between the constant and the integer represented as a polynomial. * * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. */ public operator fun P.minus(other: Int): P /** - * Returns product of the constant and the integer represented as polynomial. + * Returns product of the constant and the integer represented as a polynomial. * * The operation is equivalent to sum of [other] copies of [this]. */ public operator fun P.times(other: Int): P /** - * Returns sum of the integer represented as polynomial and the constant. + * Returns sum of the integer represented as a polynomial and the constant. * * The operation is equivalent to adding [this] copies of unit polynomial to [other]. */ public operator fun Int.plus(other: P): P /** - * Returns difference between the integer represented as polynomial and the constant. + * Returns difference between the integer represented as a polynomial and the constant. * * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. */ public operator fun Int.minus(other: P): P /** - * Returns product of the integer represented as polynomial and the constant. + * Returns product of the integer represented as a polynomial and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -125,25 +125,25 @@ public interface RationalFunctionalSpace, R: RationalFunctio public fun Int.asPolynomial(): P = polynomialNumber(this) /** - * Returns sum of the rational function and the integer represented as rational function. + * Returns sum of the rational function and the integer represented as a rational function. * * The operation is equivalent to adding [other] copies of unit polynomial to [this]. */ public operator fun R.plus(other: Int): R = addMultipliedByDoubling(this, one, other) /** - * Returns difference between the rational function and the integer represented as rational function. + * Returns difference between the rational function and the integer represented as a rational function. * * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. */ public operator fun R.minus(other: Int): R = addMultipliedByDoubling(this, one, -other) /** - * Returns product of the rational function and the integer represented as rational function. + * Returns product of the rational function and the integer represented as a rational function. * * The operation is equivalent to sum of [other] copies of [this]. */ public operator fun R.times(other: Int): R = multiplyByDoubling(this, other) /** - * Returns quotient of the rational function and the integer represented as rational function. + * Returns quotient of the rational function and the integer represented as a rational function. * * The operation is equivalent to creating a new rational function by preserving numerator of [this] and * multiplication denominator of [this] to [other]. @@ -151,25 +151,25 @@ public interface RationalFunctionalSpace, R: RationalFunctio public operator fun R.div(other: Int): R = this / multiplyByDoubling(one, other) /** - * Returns sum of the integer represented as rational function and the rational function. + * Returns sum of the integer represented as a rational function and the rational function. * * The operation is equivalent to adding [this] copies of unit polynomial to [other]. */ public operator fun Int.plus(other: R): R = addMultipliedByDoubling(other, one, this) /** - * Returns difference between the integer represented as rational function and the rational function. + * Returns difference between the integer represented as a rational function and the rational function. * * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. */ public operator fun Int.minus(other: R): R = addMultipliedByDoubling(-other, one, this) /** - * Returns product of the integer represented as rational function and the rational function. + * Returns product of the integer represented as a rational function and the rational function. * * The operation is equivalent to sum of [this] copies of [other]. */ public operator fun Int.times(other: R): R = multiplyByDoubling(other, this) /** - * Returns quotient of the integer represented as rational function and the rational function. + * Returns quotient of the integer represented as a rational function and the rational function. * * The operation is equivalent to creating a new rational function which numerator is [this] times denominator of * [other] and which denominator is [other]'s numerator. @@ -232,28 +232,28 @@ public interface RationalFunctionalSpace, R: RationalFunctio public val constantOne: C /** - * Returns sum of the constant represented as polynomial and the polynomial. + * Returns sum of the constant represented as a polynomial and the polynomial. */ public operator fun C.plus(other: P): P /** - * Returns difference between the constant represented as polynomial and the polynomial. + * Returns difference between the constant represented as a polynomial and the polynomial. */ public operator fun C.minus(other: P): P /** - * Returns product of the constant represented as polynomial and the polynomial. + * Returns product of the constant represented as a polynomial and the polynomial. */ public operator fun C.times(other: P): P /** - * Returns sum of the constant represented as polynomial and the polynomial. + * Returns sum of the constant represented as a polynomial and the polynomial. */ public operator fun P.plus(other: C): P /** - * Returns difference between the constant represented as polynomial and the polynomial. + * Returns difference between the constant represented as a polynomial and the polynomial. */ public operator fun P.minus(other: C): P /** - * Returns product of the constant represented as polynomial and the polynomial. + * Returns product of the constant represented as a polynomial and the polynomial. */ public operator fun P.times(other: C): P @@ -305,36 +305,36 @@ public interface RationalFunctionalSpace, R: RationalFunctio public val polynomialOne: P /** - * Returns sum of the constant represented as rational function and the rational function. + * Returns sum of the constant represented as a rational function and the rational function. */ public operator fun C.plus(other: R): R /** - * Returns difference between the constant represented as polynomial and the rational function. + * Returns difference between the constant represented as a polynomial and the rational function. */ public operator fun C.minus(other: R): R /** - * Returns product of the constant represented as polynomial and the rational function. + * Returns product of the constant represented as a polynomial and the rational function. */ public operator fun C.times(other: R): R /** - * Returns quotient of the constant represented as polynomial and the rational function. + * Returns quotient of the constant represented as a polynomial and the rational function. */ public operator fun C.div(other: R): R /** - * Returns sum of the rational function and the constant represented as rational function. + * Returns sum of the rational function and the constant represented as a rational function. */ public operator fun R.plus(other: C): R /** - * Returns difference between the rational function and the constant represented as rational function. + * Returns difference between the rational function and the constant represented as a rational function. */ public operator fun R.minus(other: C): R /** - * Returns product of the rational function and the constant represented as rational function. + * Returns product of the rational function and the constant represented as a rational function. */ public operator fun R.times(other: C): R /** - * Returns quotient of the rational function and the constant represented as rational function. + * Returns quotient of the rational function and the constant represented as a rational function. */ public operator fun R.div(other: C): R @@ -348,36 +348,36 @@ public interface RationalFunctionalSpace, R: RationalFunctio public fun C.asRationalFunction(): R = number(this) /** - * Returns sum of the polynomial represented as rational function and the rational function. + * Returns sum of the polynomial represented as a rational function and the rational function. */ public operator fun P.plus(other: R): R /** - * Returns difference between the polynomial represented as polynomial and the rational function. + * Returns difference between the polynomial represented as a polynomial and the rational function. */ public operator fun P.minus(other: R): R /** - * Returns product of the polynomial represented as polynomial and the rational function. + * Returns product of the polynomial represented as a polynomial and the rational function. */ public operator fun P.times(other: R): R /** - * Returns quotient of the polynomial represented as polynomial and the rational function. + * Returns quotient of the polynomial represented as a polynomial and the rational function. */ public operator fun P.div(other: R): R /** - * Returns sum of the rational function and the polynomial represented as rational function. + * Returns sum of the rational function and the polynomial represented as a rational function. */ public operator fun R.plus(other: P): R /** - * Returns difference between the rational function and the polynomial represented as rational function. + * Returns difference between the rational function and the polynomial represented as a rational function. */ public operator fun R.minus(other: P): R /** - * Returns product of the rational function and the polynomial represented as rational function. + * Returns product of the rational function and the polynomial represented as a rational function. */ public operator fun R.times(other: P): R /** - * Returns quotient of the rational function and the polynomial represented as rational function. + * Returns quotient of the rational function and the polynomial represented as a rational function. */ public operator fun R.div(other: P): R @@ -459,43 +459,51 @@ public interface RationalFunctionalSpace, R: RationalFunctio * @param A the type of algebraic structure (precisely, of ring) provided for constants. */ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 -public interface RationalFunctionalSpaceOverRing, R: RationalFunction, A: Ring> : RationalFunctionalSpace { +public interface RationalFunctionalSpaceOverRing< + C, + P: Polynomial, + R: RationalFunction, + A: Ring + > : RationalFunctionalSpace { + /** + * Underlying ring of constants. Its operations on constants are inherited by local operations on constants. + */ public val ring: A /** - * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * Returns sum of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. */ public override operator fun C.plus(other: Int): C = ring { addMultipliedByDoubling(this@plus, one, other) } /** - * Returns difference between the constant and the integer represented as constant (member of underlying ring). + * Returns difference between the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. */ public override operator fun C.minus(other: Int): C = ring { addMultipliedByDoubling(this@minus, one, -other) } /** - * Returns product of the constant and the integer represented as constant (member of underlying ring). + * Returns product of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to sum of [other] copies of [this]. */ public override operator fun C.times(other: Int): C = ring { multiplyByDoubling(this@times, other) } /** - * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * Returns sum of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. */ public override operator fun Int.plus(other: C): C = ring { addMultipliedByDoubling(other, one, this@plus) } /** - * Returns difference between the integer represented as constant (member of underlying ring) and the constant. + * Returns difference between the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. */ public override operator fun Int.minus(other: C): C = ring { addMultipliedByDoubling(-other, one, this@minus) } /** - * Returns product of the integer represented as constant (member of underlying ring) and the constant. + * Returns product of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -560,41 +568,44 @@ public interface RationalFunctionalSpaceOverPolynomialSpace< AP: PolynomialSpace, > : RationalFunctionalSpace { + /** + * Underlying polynomial ring. Its polynomial operations are inherited by local polynomial operations. + */ public val polynomialRing: AP /** - * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * Returns sum of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. */ public override operator fun C.plus(other: Int): C = polynomialRing { this@plus + other } /** - * Returns difference between the constant and the integer represented as constant (member of underlying ring). + * Returns difference between the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. */ public override operator fun C.minus(other: Int): C = polynomialRing { this@minus - other } /** - * Returns product of the constant and the integer represented as constant (member of underlying ring). + * Returns product of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to sum of [other] copies of [this]. */ public override operator fun C.times(other: Int): C = polynomialRing { this@times * other } /** - * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * Returns sum of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. */ public override operator fun Int.plus(other: C): C = polynomialRing { this@plus + other } /** - * Returns difference between the integer represented as constant (member of underlying ring) and the constant. + * Returns difference between the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. */ public override operator fun Int.minus(other: C): C = polynomialRing { this@minus - other } /** - * Returns product of the integer represented as constant (member of underlying ring) and the constant. + * Returns product of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -610,38 +621,38 @@ public interface RationalFunctionalSpaceOverPolynomialSpace< override fun Int.asConstant(): C = polynomialRing { asConstant() } /** - * Returns sum of the constant and the integer represented as polynomial. + * Returns sum of the constant and the integer represented as a polynomial. * * The operation is equivalent to adding [other] copies of unit polynomial to [this]. */ public override operator fun P.plus(other: Int): P = polynomialRing { this@plus + other } /** - * Returns difference between the constant and the integer represented as polynomial. + * Returns difference between the constant and the integer represented as a polynomial. * * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. */ public override operator fun P.minus(other: Int): P = polynomialRing { this@minus - other } /** - * Returns product of the constant and the integer represented as polynomial. + * Returns product of the constant and the integer represented as a polynomial. * * The operation is equivalent to sum of [other] copies of [this]. */ public override operator fun P.times(other: Int): P = polynomialRing { this@times * other } /** - * Returns sum of the integer represented as polynomial and the constant. + * Returns sum of the integer represented as a polynomial and the constant. * * The operation is equivalent to adding [this] copies of unit polynomial to [other]. */ public override operator fun Int.plus(other: P): P = polynomialRing { this@plus + other } /** - * Returns difference between the integer represented as polynomial and the constant. + * Returns difference between the integer represented as a polynomial and the constant. * * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. */ public override operator fun Int.minus(other: P): P = polynomialRing { this@minus - other } /** - * Returns product of the integer represented as polynomial and the constant. + * Returns product of the integer represented as a polynomial and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -697,28 +708,28 @@ public interface RationalFunctionalSpaceOverPolynomialSpace< public override val constantOne: C get() = polynomialRing.constantOne /** - * Returns sum of the constant represented as polynomial and the polynomial. + * Returns sum of the constant represented as a polynomial and the polynomial. */ public override operator fun C.plus(other: P): P = polynomialRing { this@plus + other } /** - * Returns difference between the constant represented as polynomial and the polynomial. + * Returns difference between the constant represented as a polynomial and the polynomial. */ public override operator fun C.minus(other: P): P = polynomialRing { this@minus - other } /** - * Returns product of the constant represented as polynomial and the polynomial. + * Returns product of the constant represented as a polynomial and the polynomial. */ public override operator fun C.times(other: P): P = polynomialRing { this@times * other } /** - * Returns sum of the constant represented as polynomial and the polynomial. + * Returns sum of the constant represented as a polynomial and the polynomial. */ public override operator fun P.plus(other: C): P = polynomialRing { this@plus + other } /** - * Returns difference between the constant represented as polynomial and the polynomial. + * Returns difference between the constant represented as a polynomial and the polynomial. */ public override operator fun P.minus(other: C): P = polynomialRing { this@minus - other } /** - * Returns product of the constant represented as polynomial and the polynomial. + * Returns product of the constant represented as a polynomial and the polynomial. */ public override operator fun P.times(other: C): P = polynomialRing { this@times * other } @@ -774,7 +785,8 @@ public interface RationalFunctionalSpaceOverPolynomialSpace< /** * Abstraction of field of rational functions of type [R] with respect to polynomials of type [P] and constants of type - * [C]. It also assumes that there is provided constructor + * [C]. It also assumes that there is provided constructor [constructRationalFunction] of rational functions from + * polynomial numerator and denominator. * * @param C the type of constants. Polynomials have them as coefficients in their terms. * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. @@ -786,10 +798,14 @@ public abstract class PolynomialSpaceOfFractions< P: Polynomial, R: RationalFunction, > : RationalFunctionalSpace { + + /** + * Constructor of rational functions (of type [R]) from numerator and denominator (of type [P]). + */ protected abstract fun constructRationalFunction(numerator: P, denominator: P = polynomialOne) : R /** - * Returns sum of the rational function and the integer represented as rational function. + * Returns sum of the rational function and the integer represented as a rational function. * * The operation is equivalent to adding [other] copies of unit polynomial to [this]. */ @@ -799,7 +815,7 @@ public abstract class PolynomialSpaceOfFractions< denominator ) /** - * Returns difference between the rational function and the integer represented as rational function. + * Returns difference between the rational function and the integer represented as a rational function. * * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. */ @@ -809,7 +825,7 @@ public abstract class PolynomialSpaceOfFractions< denominator ) /** - * Returns product of the rational function and the integer represented as rational function. + * Returns product of the rational function and the integer represented as a rational function. * * The operation is equivalent to sum of [other] copies of [this]. */ @@ -818,7 +834,12 @@ public abstract class PolynomialSpaceOfFractions< numerator * other, denominator ) - + /** + * Returns quotient of the rational function and the integer represented as a rational function. + * + * The operation is equivalent to creating a new rational function by preserving numerator of [this] and + * multiplication denominator of [this] to [other]. + */ public override operator fun R.div(other: Int): R = constructRationalFunction( numerator, @@ -826,7 +847,7 @@ public abstract class PolynomialSpaceOfFractions< ) /** - * Returns sum of the integer represented as rational function and the rational function. + * Returns sum of the integer represented as a rational function and the rational function. * * The operation is equivalent to adding [this] copies of unit polynomial to [other]. */ @@ -836,7 +857,7 @@ public abstract class PolynomialSpaceOfFractions< other.denominator ) /** - * Returns difference between the integer represented as rational function and the rational function. + * Returns difference between the integer represented as a rational function and the rational function. * * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. */ @@ -846,7 +867,7 @@ public abstract class PolynomialSpaceOfFractions< other.denominator ) /** - * Returns product of the integer represented as rational function and the rational function. + * Returns product of the integer represented as a rational function and the rational function. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -855,7 +876,12 @@ public abstract class PolynomialSpaceOfFractions< this * other.numerator, other.denominator ) - + /** + * Returns quotient of the integer represented as a rational function and the rational function. + * + * The operation is equivalent to creating a new rational function which numerator is [this] times denominator of + * [other] and which denominator is [other]'s numerator. + */ public override operator fun Int.div(other: R): R = constructRationalFunction( this * other.denominator, @@ -873,7 +899,7 @@ public abstract class PolynomialSpaceOfFractions< public override operator fun P.div(other: P): R = constructRationalFunction(this, other) /** - * Returns sum of the constant represented as rational function and the rational function. + * Returns sum of the constant represented as a rational function and the rational function. */ public override operator fun C.plus(other: R): R = constructRationalFunction( @@ -881,7 +907,7 @@ public abstract class PolynomialSpaceOfFractions< other.denominator ) /** - * Returns difference between the constant represented as polynomial and the rational function. + * Returns difference between the constant represented as a polynomial and the rational function. */ public override operator fun C.minus(other: R): R = constructRationalFunction( @@ -889,14 +915,16 @@ public abstract class PolynomialSpaceOfFractions< other.denominator ) /** - * Returns product of the constant represented as polynomial and the rational function. + * Returns product of the constant represented as a polynomial and the rational function. */ public override operator fun C.times(other: R): R = constructRationalFunction( this * other.numerator, other.denominator ) - + /** + * Returns quotient of the constant represented as a polynomial and the rational function. + */ public override operator fun C.div(other: R): R = constructRationalFunction( this * other.denominator, @@ -904,7 +932,7 @@ public abstract class PolynomialSpaceOfFractions< ) /** - * Returns sum of the constant represented as rational function and the rational function. + * Returns sum of the constant represented as a rational function and the rational function. */ public override operator fun R.plus(other: C): R = constructRationalFunction( @@ -912,7 +940,7 @@ public abstract class PolynomialSpaceOfFractions< denominator ) /** - * Returns difference between the constant represented as rational function and the rational function. + * Returns difference between the constant represented as a rational function and the rational function. */ public override operator fun R.minus(other: C): R = constructRationalFunction( @@ -920,14 +948,16 @@ public abstract class PolynomialSpaceOfFractions< denominator ) /** - * Returns product of the constant represented as rational function and the rational function. + * Returns product of the constant represented as a rational function and the rational function. */ public override operator fun R.times(other: C): R = constructRationalFunction( numerator * other, denominator ) - + /** + * Returns quotient of the rational function and the constant represented as a rational function. + */ public override operator fun R.div(other: C): R = constructRationalFunction( numerator, @@ -940,7 +970,7 @@ public abstract class PolynomialSpaceOfFractions< public override fun number(value: C): R = constructRationalFunction(polynomialNumber(value)) /** - * Returns sum of the polynomial represented as rational function and the rational function. + * Returns sum of the polynomial represented as a rational function and the rational function. */ public override operator fun P.plus(other: R): R = constructRationalFunction( @@ -948,7 +978,7 @@ public abstract class PolynomialSpaceOfFractions< other.denominator ) /** - * Returns difference between the polynomial represented as polynomial and the rational function. + * Returns difference between the polynomial represented as a polynomial and the rational function. */ public override operator fun P.minus(other: R): R = constructRationalFunction( @@ -956,14 +986,16 @@ public abstract class PolynomialSpaceOfFractions< other.denominator ) /** - * Returns product of the polynomial represented as polynomial and the rational function. + * Returns product of the polynomial represented as a polynomial and the rational function. */ public override operator fun P.times(other: R): R = constructRationalFunction( this * other.numerator, other.denominator ) - + /** + * Returns quotient of the polynomial represented as a polynomial and the rational function. + */ public override operator fun P.div(other: R): R = constructRationalFunction( this * other.denominator, @@ -971,7 +1003,7 @@ public abstract class PolynomialSpaceOfFractions< ) /** - * Returns sum of the polynomial represented as rational function and the rational function. + * Returns sum of the polynomial represented as a rational function and the rational function. */ public override operator fun R.plus(other: P): R = constructRationalFunction( @@ -979,7 +1011,7 @@ public abstract class PolynomialSpaceOfFractions< denominator ) /** - * Returns difference between the polynomial represented as rational function and the rational function. + * Returns difference between the polynomial represented as a rational function and the rational function. */ public override operator fun R.minus(other: P): R = constructRationalFunction( @@ -987,14 +1019,16 @@ public abstract class PolynomialSpaceOfFractions< denominator ) /** - * Returns product of the polynomial represented as rational function and the rational function. + * Returns product of the polynomial represented as a rational function and the rational function. */ public override operator fun R.times(other: P): R = constructRationalFunction( numerator * other, denominator ) - + /** + * Returns quotient of the rational function and the polynomial represented as a rational function. + */ public override operator fun R.div(other: P): R = constructRationalFunction( numerator, @@ -1034,7 +1068,9 @@ public abstract class PolynomialSpaceOfFractions< numerator * other.numerator, denominator * other.denominator ) - + /** + * Returns quotient of the rational functions. + */ public override operator fun R.div(other: R): R = constructRationalFunction( numerator * other.denominator, @@ -1044,14 +1080,23 @@ public abstract class PolynomialSpaceOfFractions< /** * Instance of zero rational function (zero of the rational functions ring). */ - public override val zero: R get() = constructRationalFunction(polynomialZero) + public override val zero: R by lazy { constructRationalFunction(polynomialZero) } /** * Instance of unit polynomial (unit of the rational functions ring). */ - public override val one: R get() = constructRationalFunction(polynomialOne) + public override val one: R by lazy { constructRationalFunction(polynomialOne) } } +/** + * Abstraction of field of rational functions of type [R] with respect to polynomials of type [P] of variables of type + * [V] and over ring of constants of type [C]. + * + * @param C the type of constants. Polynomials have them as coefficients in their terms. + * @param V the type of variables. Polynomials have them in representations of terms. + * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. + * @param R the type of rational functions. + */ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public interface MultivariateRationalFunctionalSpace< C, @@ -1059,70 +1104,179 @@ public interface MultivariateRationalFunctionalSpace< P: Polynomial, R: RationalFunction >: RationalFunctionalSpace { + /** + * Returns sum of the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("plusVariableInt") public operator fun V.plus(other: Int): P + /** + * Returns difference between the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("minusVariableInt") public operator fun V.minus(other: Int): P + /** + * Returns product of the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("timesVariableInt") public operator fun V.times(other: Int): P + /** + * Returns sum of the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("plusIntVariable") public operator fun Int.plus(other: V): P + /** + * Returns difference between the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("minusIntVariable") public operator fun Int.minus(other: V): P + /** + * Returns product of the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("timesIntVariable") public operator fun Int.times(other: V): P - @JvmName("plusConstantVariable") - public operator fun C.plus(other: V): P - @JvmName("minusConstantVariable") - public operator fun C.minus(other: V): P - @JvmName("timesConstantVariable") - public operator fun C.times(other: V): P - + /** + * Returns sum of the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("plusVariableConstant") public operator fun V.plus(other: C): P + /** + * Returns difference between the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("minusVariableConstant") public operator fun V.minus(other: C): P + /** + * Returns product of the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("timesVariableConstant") public operator fun V.times(other: C): P + /** + * Returns sum of the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("plusConstantVariable") + public operator fun C.plus(other: V): P + /** + * Returns difference between the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("minusConstantVariable") + public operator fun C.minus(other: V): P + /** + * Returns product of the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("timesConstantVariable") + public operator fun C.times(other: V): P + + /** + * Represents the variable as a monic monomial. + */ @JvmName("unaryPlusVariable") public operator fun V.unaryPlus(): P + /** + * Returns negation of representation of the variable as a monic monomial. + */ @JvmName("unaryMinusVariable") public operator fun V.unaryMinus(): P + /** + * Returns sum of the variables represented as monic monomials. + */ @JvmName("plusVariableVariable") public operator fun V.plus(other: V): P + /** + * Returns difference between the variables represented as monic monomials. + */ @JvmName("minusVariableVariable") public operator fun V.minus(other: V): P + /** + * Returns product of the variables represented as monic monomials. + */ @JvmName("timesVariableVariable") public operator fun V.times(other: V): P + /** + * Represents the [variable] as a monic monomial. + */ + @JvmName("polynomialNumberVariable") + public fun polynomialNumber(variable: V): P = +variable + /** + * Represents the variable as a monic monomial. + */ + @JvmName("asPolynomialVariable") + public fun V.asPolynomial(): P = polynomialNumber(this) + + /** + * Represents the [variable] as a rational function. + */ + @JvmName("numberVariable") + public fun number(variable: V): R = number(polynomialNumber(variable)) + /** + * Represents the variable as a rational function. + */ + @JvmName("asRationalFunctionVariable") + public fun V.asRationalFunction(): R = number(this) + + /** + * Returns sum of the variable represented as a monic monomial and the polynomial. + */ @JvmName("plusVariablePolynomial") public operator fun V.plus(other: P): P + /** + * Returns difference between the variable represented as a monic monomial and the polynomial. + */ @JvmName("minusVariablePolynomial") public operator fun V.minus(other: P): P + /** + * Returns product of the variable represented as a monic monomial and the polynomial. + */ @JvmName("timesVariablePolynomial") public operator fun V.times(other: P): P + /** + * Returns sum of the polynomial and the variable represented as a monic monomial. + */ @JvmName("plusPolynomialVariable") public operator fun P.plus(other: V): P + /** + * Returns difference between the polynomial and the variable represented as a monic monomial. + */ @JvmName("minusPolynomialVariable") public operator fun P.minus(other: V): P + /** + * Returns product of the polynomial and the variable represented as a monic monomial. + */ @JvmName("timesPolynomialVariable") public operator fun P.times(other: V): P + /** + * Returns sum of the variable represented as a rational function and the rational function. + */ @JvmName("plusVariableRational") public operator fun V.plus(other: R): R + /** + * Returns difference between the variable represented as a rational function and the rational function. + */ @JvmName("minusVariableRational") public operator fun V.minus(other: R): R + /** + * Returns product of the variable represented as a rational function and the rational function. + */ @JvmName("timesVariableRational") public operator fun V.times(other: R): R + /** + * Returns sum of the rational function and the variable represented as a rational function. + */ @JvmName("plusRationalVariable") public operator fun R.plus(other: V): R + /** + * Returns difference between the rational function and the variable represented as a rational function. + */ @JvmName("minusRationalVariable") public operator fun R.minus(other: V): R + /** + * Returns product of the rational function and the variable represented as a rational function. + */ @JvmName("timesRationalVariable") public operator fun R.times(other: V): R @@ -1161,22 +1315,17 @@ public interface MultivariateRationalFunctionalSpace< public val R.countOfVariables: Int get() = variables.size } -public interface MultivariateRationalFunctionalSpaceOverRing< - C, - V, - P: Polynomial, - R: RationalFunction, - A: Ring - > : RationalFunctionalSpaceOverRing, MultivariateRationalFunctionalSpace - -public interface MultivariateRationalFunctionalSpaceOverPolynomialSpace< - C, - V, - P: Polynomial, - R: RationalFunction, - AP: PolynomialSpace, - > : RationalFunctionalSpaceOverPolynomialSpace, MultivariateRationalFunctionalSpace - +/** + * Abstraction of field of rational functions of type [R] with respect to polynomials of type [P] of variables of type + * [V] and over ring of constants of type [C]. It also assumes that there is provided [polynomialRing] (of type [AP]), + * that provides constant-, variable- and polynomial-wise operations. + * + * @param C the type of constants. Polynomials have them as coefficients in their terms. + * @param V the type of variables. Polynomials have them in representations of terms. + * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. + * @param R the type of rational functions. + * @param AP the type of algebraic structure (precisely, of ring) provided for polynomials. + */ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public interface MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSpace< C, @@ -1184,57 +1333,137 @@ public interface MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSp P: Polynomial, R: RationalFunction, AP: MultivariatePolynomialSpace, - > : MultivariateRationalFunctionalSpaceOverPolynomialSpace { + > : RationalFunctionalSpaceOverPolynomialSpace, MultivariateRationalFunctionalSpace { + /** + * Returns sum of the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("plusVariableInt") public override operator fun V.plus(other: Int): P = polynomialRing { this@plus + other } + /** + * Returns difference between the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("minusVariableInt") public override operator fun V.minus(other: Int): P = polynomialRing { this@minus - other } + /** + * Returns product of the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("timesVariableInt") public override operator fun V.times(other: Int): P = polynomialRing { this@times * other } + /** + * Returns sum of the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("plusIntVariable") public override operator fun Int.plus(other: V): P = polynomialRing { this@plus + other } + /** + * Returns difference between the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("minusIntVariable") public override operator fun Int.minus(other: V): P = polynomialRing { this@minus - other } + /** + * Returns product of the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("timesIntVariable") public override operator fun Int.times(other: V): P = polynomialRing { this@times * other } - @JvmName("plusConstantVariable") - public override operator fun C.plus(other: V): P = polynomialRing { this@plus + other } - @JvmName("minusConstantVariable") - public override operator fun C.minus(other: V): P = polynomialRing { this@minus - other } - @JvmName("timesConstantVariable") - public override operator fun C.times(other: V): P = polynomialRing { this@times * other } - + /** + * Returns sum of the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("plusVariableConstant") public override operator fun V.plus(other: C): P = polynomialRing { this@plus + other } + /** + * Returns difference between the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("minusVariableConstant") public override operator fun V.minus(other: C): P = polynomialRing { this@minus - other } + /** + * Returns product of the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("timesVariableConstant") public override operator fun V.times(other: C): P = polynomialRing { this@times * other } + /** + * Returns sum of the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("plusConstantVariable") + public override operator fun C.plus(other: V): P = polynomialRing { this@plus + other } + /** + * Returns difference between the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("minusConstantVariable") + public override operator fun C.minus(other: V): P = polynomialRing { this@minus - other } + /** + * Returns product of the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("timesConstantVariable") + public override operator fun C.times(other: V): P = polynomialRing { this@times * other } + + /** + * Represents the variable as a monic monomial. + */ @JvmName("unaryPlusVariable") public override operator fun V.unaryPlus(): P = polynomialRing { +this@unaryPlus } + /** + * Returns negation of representation of the variable as a monic monomial. + */ @JvmName("unaryMinusVariable") public override operator fun V.unaryMinus(): P = polynomialRing { -this@unaryMinus } + /** + * Returns sum of the variables represented as monic monomials. + */ @JvmName("plusVariableVariable") public override operator fun V.plus(other: V): P = polynomialRing { this@plus + other } + /** + * Returns difference between the variables represented as monic monomials. + */ @JvmName("minusVariableVariable") public override operator fun V.minus(other: V): P = polynomialRing { this@minus - other } + /** + * Returns product of the variables represented as monic monomials. + */ @JvmName("timesVariableVariable") public override operator fun V.times(other: V): P = polynomialRing { this@times * other } + /** + * Represents the [variable] as a monic monomial. + */ + @JvmName("polynomialNumberVariable") + public override fun polynomialNumber(variable: V): P = polynomialRing { number(variable) } + /** + * Represents the variable as a monic monomial. + */ + @JvmName("asPolynomialVariable") + public override fun V.asPolynomial(): P = polynomialRing { this@asPolynomial.asPolynomial() } + + /** + * Returns sum of the variable represented as a monic monomial and the polynomial. + */ @JvmName("plusVariablePolynomial") public override operator fun V.plus(other: P): P = polynomialRing { this@plus + other } + /** + * Returns difference between the variable represented as a monic monomial and the polynomial. + */ @JvmName("minusVariablePolynomial") public override operator fun V.minus(other: P): P = polynomialRing { this@minus - other } + /** + * Returns product of the variable represented as a monic monomial and the polynomial. + */ @JvmName("timesVariablePolynomial") public override operator fun V.times(other: P): P = polynomialRing { this@times * other } + /** + * Returns sum of the polynomial and the variable represented as a monic monomial. + */ @JvmName("plusPolynomialVariable") public override operator fun P.plus(other: V): P = polynomialRing { this@plus + other } + /** + * Returns difference between the polynomial and the variable represented as a monic monomial. + */ @JvmName("minusPolynomialVariable") public override operator fun P.minus(other: V): P = polynomialRing { this@minus - other } + /** + * Returns product of the polynomial and the variable represented as a monic monomial. + */ @JvmName("timesPolynomialVariable") public override operator fun P.times(other: V): P = polynomialRing { this@times * other } @@ -1264,6 +1493,16 @@ public interface MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSp public override val P.countOfVariables: Int get() = polynomialRing { countOfVariables } } +/** + * Abstraction of field of rational functions of type [R] with respect to polynomials of type [P] of variables of type + * [V] and over ring of constants of type [C]. It also assumes that there is provided constructor + * [constructRationalFunction] of rational functions from polynomial numerator and denominator. + * + * @param C the type of constants. Polynomials have them as coefficients in their terms. + * @param V the type of variables. Polynomials have them in representations of terms. + * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. + * @param R the type of rational functions. + */ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public abstract class MultivariatePolynomialSpaceOfFractions< C, @@ -1271,18 +1510,27 @@ public abstract class MultivariatePolynomialSpaceOfFractions< P: Polynomial, R: RationalFunction, > : MultivariateRationalFunctionalSpace, PolynomialSpaceOfFractions() { + /** + * Returns sum of the variable represented as a rational function and the rational function. + */ @JvmName("plusVariableRational") public override operator fun V.plus(other: R): R = constructRationalFunction( this * other.denominator + other.numerator, other.denominator ) + /** + * Returns difference between the variable represented as a rational function and the rational function. + */ @JvmName("minusVariableRational") public override operator fun V.minus(other: R): R = constructRationalFunction( this * other.denominator - other.numerator, other.denominator ) + /** + * Returns product of the variable represented as a rational function and the rational function. + */ @JvmName("timesVariableRational") public override operator fun V.times(other: R): R = constructRationalFunction( @@ -1290,18 +1538,27 @@ public abstract class MultivariatePolynomialSpaceOfFractions< other.denominator ) + /** + * Returns sum of the rational function and the variable represented as a rational function. + */ @JvmName("plusRationalVariable") public override operator fun R.plus(other: V): R = constructRationalFunction( numerator + denominator * other, denominator ) + /** + * Returns difference between the rational function and the variable represented as a rational function. + */ @JvmName("minusRationalVariable") public override operator fun R.minus(other: V): R = constructRationalFunction( numerator - denominator * other, denominator ) + /** + * Returns product of the rational function and the variable represented as a rational function. + */ @JvmName("timesRationalVariable") public override operator fun R.times(other: V): R = constructRationalFunction( diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt deleted file mode 100644 index e81a9388e..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.functions - -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.Ring - - -/** - * Returns the same degrees' description of the monomial, but without zero degrees. - */ -internal fun Map.cleanUp() = filterValues { it > 0U } - -// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available - -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > LabeledPolynomialSpace.LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(coefs, toCheckInput) -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(coefs, toCheckInput) -@Suppress("FunctionName") -internal fun > A.LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : LabeledPolynomial { - if (!toCheckInput) return LabeledPolynomial(coefs) - - val fixedCoefs = LinkedHashMap, C>(coefs.size) - - for (entry in coefs) { - val key = entry.key.cleanUp() - val value = entry.value - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return LabeledPolynomial(fixedCoefs) -} - -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > LabeledPolynomialSpace.LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(pairs, toCheckInput) -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(pairs, toCheckInput) -@Suppress("FunctionName") -internal fun > A.LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : LabeledPolynomial { - if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) - - val fixedCoefs = LinkedHashMap, C>(pairs.size) - - for (entry in pairs) { - val key = entry.first.cleanUp() - val value = entry.second - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return LabeledPolynomial(fixedCoefs) -} - -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > LabeledPolynomialSpace.LabeledPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(pairs = pairs, toCheckInput = toCheckInput) -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(pairs = pairs, toCheckInput = toCheckInput) -@Suppress("FunctionName") -internal fun > A.LabeledPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : LabeledPolynomial { - if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) - - val fixedCoefs = LinkedHashMap, C>(pairs.size) - - for (entry in pairs) { - val key = entry.first.cleanUp() - val value = entry.second - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return LabeledPolynomial(fixedCoefs) -} - -@Suppress("FunctionName") -public fun > A.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) -@Suppress("FunctionName") -public fun > LabeledPolynomialSpace.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) -@Suppress("FunctionName") -public fun > LabeledRationalFunctionSpace.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) - -@Suppress("FunctionName") -public fun > A.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > LabeledPolynomialSpace.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > LabeledRationalFunctionSpace.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) - -@Suppress("FunctionName") -public fun > A.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > LabeledPolynomialSpace.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > LabeledRationalFunctionSpace.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs, toCheckInput = true) - -//context(A) -//public fun > Symbol.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1u) to one)) -//context(LabeledPolynomialSpace) -//public fun > Symbol.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1u) to constantOne)) -//context(LabeledRationalFunctionSpace) -//public fun > Symbol.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1u) to constantOne)) - -public fun C.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to this)) - -@DslMarker -@UnstableKMathAPI -internal annotation class LabeledPolynomialConstructorDSL - -@UnstableKMathAPI -@LabeledPolynomialConstructorDSL -public class LabeledPolynomialTermSignatureBuilder { - private val signature: MutableMap = LinkedHashMap() - public fun build(): Map = signature - public infix fun Symbol.inPowerOf(deg: UInt) { - signature[this] = deg - } - @Suppress("NOTHING_TO_INLINE") - public inline infix fun Symbol.pow(deg: UInt): Unit = this inPowerOf deg - @Suppress("NOTHING_TO_INLINE") - public inline infix fun Symbol.`in`(deg: UInt): Unit = this inPowerOf deg - @Suppress("NOTHING_TO_INLINE") - public inline infix fun Symbol.of(deg: UInt): Unit = this inPowerOf deg -} - -@UnstableKMathAPI -public class LabeledPolynomialBuilder(private val zero: C, private val add: (C, C) -> C, capacity: Int = 0) { - private val coefficients: MutableMap, C> = LinkedHashMap(capacity) - public fun build(): LabeledPolynomial = LabeledPolynomial(coefficients) - public operator fun C.invoke(block: LabeledPolynomialTermSignatureBuilder.() -> Unit) { - val signature = LabeledPolynomialTermSignatureBuilder().apply(block).build() - coefficients[signature] = add(coefficients.getOrElse(signature) { zero }, this@invoke) - } - @Suppress("NOTHING_TO_INLINE") - public inline infix fun C.with(noinline block: LabeledPolynomialTermSignatureBuilder.() -> Unit): Unit = this.invoke(block) - @Suppress("NOTHING_TO_INLINE") - public inline infix fun (LabeledPolynomialTermSignatureBuilder.() -> Unit).with(coef: C): Unit = coef.invoke(this) - @Suppress("NOTHING_TO_INLINE") - public infix fun sig(block: LabeledPolynomialTermSignatureBuilder.() -> Unit): LabeledPolynomialTermSignatureBuilder.() -> Unit = block -} - -// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available - -@UnstableKMathAPI -@LabeledPolynomialConstructorDSL -@Suppress("FunctionName") -public inline fun > A.LabeledPolynomial(block: LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = LabeledPolynomialBuilder(zero, ::add).apply(block).build() -@UnstableKMathAPI -@LabeledPolynomialConstructorDSL -@Suppress("FunctionName") -public inline fun > A.LabeledPolynomial(capacity: Int, block: LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = LabeledPolynomialBuilder(zero, ::add, capacity).apply(block).build() -@UnstableKMathAPI -@LabeledPolynomialConstructorDSL -@Suppress("FunctionName") -public inline fun > LabeledPolynomialSpace.LabeledPolynomial(block: LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = LabeledPolynomialBuilder(constantZero, { left: C, right: C -> left + right}).apply(block).build() -@UnstableKMathAPI -@LabeledPolynomialConstructorDSL -@Suppress("FunctionName") -public inline fun > LabeledPolynomialSpace.LabeledPolynomial(capacity: Int, block: LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = LabeledPolynomialBuilder(constantZero, { left: C, right: C -> left + right}, capacity).apply(block).build() - -// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available - -@Suppress("FunctionName") -public fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): LabeledRationalFunction = - LabeledRationalFunction( - LabeledPolynomial(numeratorCoefficients, toCheckInput = true), - LabeledPolynomial(denominatorCoefficients, toCheckInput = true) - ) -@Suppress("FunctionName") -public fun > A.LabeledRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): LabeledRationalFunction = - LabeledRationalFunction( - LabeledPolynomial(numeratorCoefficients, toCheckInput = true), - LabeledPolynomial(denominatorCoefficients, toCheckInput = true) - ) -@Suppress("FunctionName") -public fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numerator: LabeledPolynomial): LabeledRationalFunction = - LabeledRationalFunction(numerator, polynomialOne) -@Suppress("FunctionName") -public fun > A.LabeledRationalFunction(numerator: LabeledPolynomial): LabeledRationalFunction = - LabeledRationalFunction(numerator, LabeledPolynomial(mapOf(emptyMap() to one), toCheckInput = false)) -@Suppress("FunctionName") -public fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numeratorCoefficients: Map, C>): LabeledRationalFunction = - LabeledRationalFunction( - LabeledPolynomial(numeratorCoefficients, toCheckInput = true), - polynomialOne - ) -@Suppress("FunctionName") -public fun > A.LabeledRationalFunction(numeratorCoefficients: Map, C>): LabeledRationalFunction = - LabeledRationalFunction( - LabeledPolynomial(numeratorCoefficients, toCheckInput = true), - LabeledPolynomial(mapOf(emptyMap() to one), toCheckInput = false) - ) - -//context(A) -//public fun > Symbol.asLabeledRationalFunction() : LabeledRationalFunction = LabeledRationalFunction(asLabeledPolynomial()) -//context(LabeledRationalFunctionSpace) -//public fun > Symbol.asLabeledRationalFunction() : LabeledRationalFunction = LabeledRationalFunction(asLabeledPolynomial()) - -//context(A) -//public fun > C.asLabeledRationalFunction() : LabeledRationalFunction = LabeledRationalFunction(asLabeledPolynomial()) -//context(LabeledRationalFunctionSpace) -//public fun > C.asLabeledRationalFunction() : LabeledRationalFunction = LabeledRationalFunction(asLabeledPolynomial()) \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt deleted file mode 100644 index af918b9ae..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt +++ /dev/null @@ -1,495 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.functions - -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.Field -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.invoke -import kotlin.contracts.ExperimentalContracts -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract - - -// TODO: Docs - -/** - * Creates a [LabeledPolynomialSpace] over a received ring. - */ -public fun > A.labeledPolynomial(): LabeledPolynomialSpace = - LabeledPolynomialSpace(this) - -/** - * Creates a [LabeledPolynomialSpace]'s scope over a received ring. - */ -@OptIn(ExperimentalContracts::class) -public inline fun , R> A.labeledPolynomial(block: LabeledPolynomialSpace.() -> R): R { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return LabeledPolynomialSpace(this).block() -} - -///** -// * Represents the polynomial as a [String] with names of variables substituted with names from [names]. -// * Consider that monomials are sorted in lexicographic order. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.represent(names: Map = emptyMap()): String = -// coefficients.entries -// .sortedWith { o1, o2 -> LabeledPolynomial.monomialComparator.compare(o1.key, o2.key) } -// .asSequence() -// .map { (degs, t) -> -// if (degs.isEmpty()) "$t" -// else { -// when { -// t.isOne() -> "" -// t.isMinusOne() -> "-" -// else -> "$t " -// } + -// degs -// .toSortedMap() -// .filter { it.value > 0U } -// .map { (variable, deg) -> -// val variableName = names.getOrDefault(variable, variable.toString()) -// when (deg) { -// 1U -> variableName -// else -> "$variableName^$deg" -// } -// } -// .joinToString(separator = " ") { it } -// } -// } -// .joinToString(separator = " + ") { it } -// .ifEmpty { "0" } -// -///** -// * Represents the polynomial as a [String] naming variables by [namer]. -// * Consider that monomials are sorted in lexicographic order. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.represent(namer: (Symbol) -> String): String = -// coefficients.entries -// .sortedWith { o1, o2 -> LabeledPolynomial.monomialComparator.compare(o1.key, o2.key) } -// .asSequence() -// .map { (degs, t) -> -// if (degs.isEmpty()) "$t" -// else { -// when { -// t.isOne() -> "" -// t.isMinusOne() -> "-" -// else -> "$t " -// } + -// degs -// .toSortedMap() -// .filter { it.value > 0U } -// .map { (variable, deg) -> -// when (deg) { -// 1U -> namer(variable) -// else -> "${namer(variable)}^$deg" -// } -// } -// .joinToString(separator = " ") { it } -// } -// } -// .joinToString(separator = " + ") { it } -// .ifEmpty { "0" } -// -///** -// * Represents the polynomial as a [String] with names of variables substituted with names from [names] and with -// * brackets around the string if needed (i.e. when there are at least two addends in the representation). -// * Consider that monomials are sorted in lexicographic order. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.representWithBrackets(names: Map = emptyMap()): String = -// with(represent(names)) { if (coefficients.count() == 1) this else "($this)" } -// -///** -// * Represents the polynomial as a [String] naming variables by [namer] and with brackets around the string if needed -// * (i.e. when there are at least two addends in the representation). -// * Consider that monomials are sorted in lexicographic order. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.representWithBrackets(namer: (Symbol) -> String): String = -// with(represent(namer)) { if (coefficients.count() == 1) this else "($this)" } -// -///** -// * Represents the polynomial as a [String] with names of variables substituted with names from [names]. -// * Consider that monomials are sorted in **reversed** lexicographic order. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.representReversed(names: Map = emptyMap()): String = -// coefficients.entries -// .sortedWith { o1, o2 -> -LabeledPolynomial.monomialComparator.compare(o1.key, o2.key) } -// .asSequence() -// .map { (degs, t) -> -// if (degs.isEmpty()) "$t" -// else { -// when { -// t.isOne() -> "" -// t.isMinusOne() -> "-" -// else -> "$t " -// } + -// degs -// .toSortedMap() -// .filter { it.value > 0U } -// .map { (variable, deg) -> -// val variableName = names.getOrDefault(variable, variable.toString()) -// when (deg) { -// 1U -> variableName -// else -> "$variableName^$deg" -// } -// } -// .joinToString(separator = " ") { it } -// } -// } -// .joinToString(separator = " + ") { it } -// .ifEmpty { "0" } -// -///** -// * Represents the polynomial as a [String] naming variables by [namer]. -// * Consider that monomials are sorted in **reversed** lexicographic order. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.representReversed(namer: (Symbol) -> String): String = -// coefficients.entries -// .sortedWith { o1, o2 -> -LabeledPolynomial.monomialComparator.compare(o1.key, o2.key) } -// .asSequence() -// .map { (degs, t) -> -// if (degs.isEmpty()) "$t" -// else { -// when { -// t.isOne() -> "" -// t.isMinusOne() -> "-" -// else -> "$t " -// } + -// degs -// .toSortedMap() -// .filter { it.value > 0U } -// .map { (variable, deg) -> -// when (deg) { -// 1U -> namer(variable) -// else -> "${namer(variable)}^$deg" -// } -// } -// .joinToString(separator = " ") { it } -// } -// } -// .joinToString(separator = " + ") { it } -// .ifEmpty { "0" } -// -///** -// * Represents the polynomial as a [String] with names of variables substituted with names from [names] and with -// * brackets around the string if needed (i.e. when there are at least two addends in the representation). -// * Consider that monomials are sorted in **reversed** lexicographic order. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.representReversedWithBrackets(names: Map = emptyMap()): String = -// with(representReversed(names)) { if (coefficients.count() == 1) this else "($this)" } -// -///** -// * Represents the polynomial as a [String] naming variables by [namer] and with brackets around the string if needed -// * (i.e. when there are at least two addends in the representation). -// * Consider that monomials are sorted in **reversed** lexicographic order. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.representReversedWithBrackets(namer: (Symbol) -> String): String = -// with(representReversed(namer)) { if (coefficients.count() == 1) this else "($this)" } - -//operator fun > Polynomial.div(other: T): Polynomial = -// if (other.isZero()) throw ArithmeticException("/ by zero") -// else -// Polynomial( -// coefficients -// .mapValues { it.value / other }, -// toCheckInput = false -// ) - -//public fun LabeledPolynomial.substitute(ring: Ring, args: Map): LabeledPolynomial = ring { -// if (coefficients.isEmpty()) return this@substitute -// LabeledPolynomial( -// buildMap { -// coefficients.forEach { (degs, c) -> -// val newDegs = degs.filterKeys { it !in args } -// val newC = degs.entries.asSequence().filter { it.key in args }.fold(c) { acc, (variable, deg) -> -// multiplyWithPower(acc, args[variable]!!, deg) -// } -// this[newDegs] = if (newDegs in this) this[newDegs]!! + newC else newC -// } -// } -// ) -//} -// -//// TODO: Replace with optimisation: the [result] may be unboxed, and all operations may be performed as soon as -//// possible on it -//@JvmName("substitutePolynomial") -//fun LabeledPolynomial.substitute(ring: Ring, arg: Map>) : LabeledPolynomial = -// ring.labeledPolynomial { -// if (coefficients.isEmpty()) return zero -// coefficients -// .asSequence() -// .map { (degs, c) -> -// degs.entries -// .asSequence() -// .filter { it.key in arg } -// .fold(LabeledPolynomial(mapOf(degs.filterKeys { it !in arg } to c))) { acc, (index, deg) -> -// multiplyWithPower(acc, arg[index]!!, deg) -// } -// } -// .reduce { acc, polynomial -> acc + polynomial } // TODO: Rewrite. Might be slow. -// } -// -//// TODO: Substitute rational function -// -//fun > LabeledPolynomial.asFunctionOver(ring: A): (Map) -> LabeledPolynomial = -// { substitute(ring, it) } -// -//fun > LabeledPolynomial.asPolynomialFunctionOver(ring: A): (Map>) -> LabeledPolynomial = -// { substitute(ring, it) } - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > LabeledPolynomial.derivativeWithRespectTo( - algebra: A, - variable: Symbol, -): LabeledPolynomial = algebra { - LabeledPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - if (variable !in degs) return@forEach - put( - buildMap { - degs.forEach { (vari, deg) -> - when { - vari != variable -> put(vari, deg) - deg > 1u -> put(vari, deg - 1u) - } - } - }, - multiplyByDoubling(c, degs[variable]!!) - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > LabeledPolynomial.derivativeWithRespectTo( - algebra: A, - variables: Collection, -): LabeledPolynomial = algebra { - val cleanedVariables = variables.toSet() - if (cleanedVariables.isEmpty()) return this@derivativeWithRespectTo - LabeledPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - if (!degs.keys.containsAll(cleanedVariables)) return@forEach - put( - buildMap { - degs.forEach { (vari, deg) -> - when { - vari !in cleanedVariables -> put(vari, deg) - deg > 1u -> put(vari, deg - 1u) - } - } - }, - cleanedVariables.fold(c) { acc, variable -> multiplyByDoubling(acc, degs[variable]!!) } - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > LabeledPolynomial.nthDerivativeWithRespectTo( - algebra: A, - variable: Symbol, - order: UInt -): LabeledPolynomial = algebra { - if (order == 0u) return this@nthDerivativeWithRespectTo - LabeledPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - if (degs.getOrElse(variable) { 0u } < order) return@forEach - put( - buildMap { - degs.forEach { (vari, deg) -> - when { - vari != variable -> put(vari, deg) - deg > order -> put(vari, deg - order) - } - } - }, - degs[variable]!!.let { deg -> - (deg downTo deg - order + 1u) - .fold(c) { acc, ord -> multiplyByDoubling(acc, ord) } - } - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > LabeledPolynomial.nthDerivativeWithRespectTo( - algebra: A, - variablesAndOrders: Map, -): LabeledPolynomial = algebra { - val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u } - if (filteredVariablesAndOrders.isEmpty()) return this@nthDerivativeWithRespectTo - LabeledPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - if (filteredVariablesAndOrders.any { (variable, order) -> degs.getOrElse(variable) { 0u } < order }) return@forEach - put( - buildMap { - degs.forEach { (vari, deg) -> - if (vari !in filteredVariablesAndOrders) put(vari, deg) - else { - val order = filteredVariablesAndOrders[vari]!! - if (deg > order) put(vari, deg - order) - } - } - }, - filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> - degs[index]!!.let { deg -> - (deg downTo deg - order + 1u) - .fold(acc1) { acc2, ord -> multiplyByDoubling(acc2, ord) } - } - } - ) - } - } - ) -} - -/** - * Returns algebraic antiderivative of received polynomial. - */ -@UnstableKMathAPI -public fun > LabeledPolynomial.antiderivativeWithRespectTo( - algebra: A, - variable: Symbol, -): LabeledPolynomial = algebra { - LabeledPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - val newDegs = buildMap(degs.size + 1) { - put(variable, 1u) - for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) - } - put( - newDegs, - c / multiplyByDoubling(one, newDegs[variable]!!) - ) - } - } - ) -} - -/** - * Returns algebraic antiderivative of received polynomial. - */ -@UnstableKMathAPI -public fun > LabeledPolynomial.antiderivativeWithRespectTo( - algebra: A, - variables: Collection, -): LabeledPolynomial = algebra { - val cleanedVariables = variables.toSet() - if (cleanedVariables.isEmpty()) return this@antiderivativeWithRespectTo - LabeledPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - val newDegs = buildMap(degs.size + 1) { - for (variable in cleanedVariables) put(variable, 1u) - for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) - } - put( - newDegs, - cleanedVariables.fold(c) { acc, variable -> acc / multiplyByDoubling(one, newDegs[variable]!!) } - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > LabeledPolynomial.nthAntiderivativeWithRespectTo( - algebra: A, - variable: Symbol, - order: UInt -): LabeledPolynomial = algebra { - if (order == 0u) return this@nthAntiderivativeWithRespectTo - LabeledPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - val newDegs = buildMap(degs.size + 1) { - put(variable, order) - for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) - } - put( - newDegs, - newDegs[variable]!!.let { deg -> - (deg downTo deg - order + 1u) - .fold(c) { acc, ord -> acc / multiplyByDoubling(one, ord) } - } - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > LabeledPolynomial.nthAntiderivativeWithRespectTo( - algebra: A, - variablesAndOrders: Map, -): LabeledPolynomial = algebra { - val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u } - if (filteredVariablesAndOrders.isEmpty()) return this@nthAntiderivativeWithRespectTo - LabeledPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - val newDegs = buildMap(degs.size + 1) { - for ((variable, order) in filteredVariablesAndOrders) put(variable, order) - for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) - } - put( - newDegs, - filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> - newDegs[index]!!.let { deg -> - (deg downTo deg - order + 1u) - .fold(acc1) { acc2, ord -> acc2 / multiplyByDoubling(one, ord) } - } - } - ) - } - } - ) -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt deleted file mode 100644 index 583160cf4..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.functions - -import space.kscience.kmath.operations.Ring -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract - - -/** - * Creates a [LabeledRationalFunctionSpace] over a received ring. - */ -public fun > A.labeledRationalFunction(): LabeledRationalFunctionSpace = - LabeledRationalFunctionSpace(this) - -/** - * Creates a [LabeledRationalFunctionSpace]'s scope over a received ring. - */ -public inline fun , R> A.labeledRationalFunction(block: LabeledRationalFunctionSpace.() -> R): R { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return LabeledRationalFunctionSpace(this).block() -} - -//fun > LabeledRationalFunction.reduced(): LabeledRationalFunction { -// val greatestCommonDivider = polynomialGCD(numerator, denominator) -// return LabeledRationalFunction( -// numerator / greatestCommonDivider, -// denominator / greatestCommonDivider -// ) -//} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt index 9498c77ca..35c736914 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt @@ -3,58 +3,95 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + package space.kscience.kmath.functions import space.kscience.kmath.operations.Ring /** - * Returns a [ListPolynomial] instance with given [coefficients]. The collection of coefficients will be reversed if - * [reverse] parameter is true. + * Constructs a [ListPolynomial] instance with provided [coefficients]. The collection of coefficients will be reversed + * if [reverse] parameter is true. */ @Suppress("FunctionName") public fun ListPolynomial(coefficients: List, reverse: Boolean = false): ListPolynomial = ListPolynomial(with(coefficients) { if (reverse) reversed() else this }) /** - * Returns a [ListPolynomial] instance with given [coefficients]. The collection of coefficients will be reversed if - * [reverse] parameter is true. + * Constructs a [ListPolynomial] instance with provided [coefficients]. The collection of coefficients will be reversed + * if [reverse] parameter is true. */ @Suppress("FunctionName") public fun ListPolynomial(vararg coefficients: C, reverse: Boolean = false): ListPolynomial = ListPolynomial(with(coefficients) { if (reverse) reversed() else toList() }) +/** + * Represents [this] constant as a [ListPolynomial]. + */ public fun C.asListPolynomial() : ListPolynomial = ListPolynomial(listOf(this)) // Waiting for context receivers :( FIXME: Replace with context receivers when they will be available +/** + * Constructs [ListRationalFunction] instance with numerator and denominator constructed with provided + * [numeratorCoefficients] and [denominatorCoefficients]. The both collections of coefficients will be reversed if + * [reverse] parameter is true. + */ @Suppress("FunctionName") public fun ListRationalFunction(numeratorCoefficients: List, denominatorCoefficients: List, reverse: Boolean = false): ListRationalFunction = ListRationalFunction( ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), ListPolynomial( with(denominatorCoefficients) { if (reverse) reversed() else this } ) ) -@Suppress("FunctionName") -public fun > ListRationalFunctionSpace.ListRationalFunction(numerator: ListPolynomial): ListRationalFunction = - ListRationalFunction(numerator, polynomialOne) +/** + * Constructs [ListRationalFunction] instance with provided [numerator] and unit denominator. + */ @Suppress("FunctionName") public fun > A.ListRationalFunction(numerator: ListPolynomial): ListRationalFunction = ListRationalFunction(numerator, ListPolynomial(listOf(one))) +/** + * Constructs [ListRationalFunction] instance with provided [numerator] and unit denominator. + */ @Suppress("FunctionName") -public fun > ListRationalFunctionSpace.ListRationalFunction(numeratorCoefficients: List, reverse: Boolean = false): ListRationalFunction = - ListRationalFunction( - ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), - polynomialOne - ) +public fun > ListRationalFunctionSpace.ListRationalFunction(numerator: ListPolynomial): ListRationalFunction = + ListRationalFunction(numerator, polynomialOne) +/** + * Constructs [ListRationalFunction] instance with numerator constructed with provided [numeratorCoefficients] and unit + * denominator. The collection of numerator coefficients will be reversed if [reverse] parameter is true. + */ @Suppress("FunctionName") public fun > A.ListRationalFunction(numeratorCoefficients: List, reverse: Boolean = false): ListRationalFunction = ListRationalFunction( ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), ListPolynomial(listOf(one)) ) +/** + * Constructs [ListRationalFunction] instance with numerator constructed with provided [numeratorCoefficients] and unit + * denominator. The collection of numerator coefficients will be reversed if [reverse] parameter is true. + */ +@Suppress("FunctionName") +public fun > ListRationalFunctionSpace.ListRationalFunction(numeratorCoefficients: List, reverse: Boolean = false): ListRationalFunction = + ListRationalFunction( + ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), + polynomialOne + ) +/** + * Represents [this] constant as a rational function. + */ // FIXME: When context receivers will be ready, delete this function and uncomment the following two +public fun > C.asListRationalFunction(ring: A) : ListRationalFunction = ring.ListRationalFunction(asListPolynomial()) +///** +// * Represents [this] constant as a rational function. +// */ //context(A) //public fun > C.asListRationalFunction() : ListRationalFunction = ListRationalFunction(asListPolynomial()) +///** +// * Represents [this] constant as a rational function. +// */ //context(ListRationalFunctionSpace) //public fun > C.asListRationalFunction() : ListRationalFunction = ListRationalFunction(asListPolynomial()) \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listPolynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listPolynomialUtil.kt deleted file mode 100644 index 50313cab9..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listPolynomialUtil.kt +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.functions - -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.* -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract -import kotlin.math.max -import kotlin.math.min -import kotlin.math.pow - - -/** - * Removes zeros on the end of the coefficient list of polynomial. - */ -//context(PolynomialSpace) -//fun > Polynomial.removeZeros() : Polynomial = -// if (degree > -1) Polynomial(coefficients.subList(0, degree + 1)) else zero - -/** - * Creates a [ListPolynomialSpace] over a received ring. - */ -public fun > A.listPolynomial(): ListPolynomialSpace = - ListPolynomialSpace(this) - -/** - * Creates a [ListPolynomialSpace]'s scope over a received ring. - */ -public inline fun , R> A.listPolynomial(block: ListPolynomialSpace.() -> R): R { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return ListPolynomialSpace(this).block() -} - -/** - * Creates a [ScalableListPolynomialSpace] over a received scalable ring. - */ -public fun A.scalableListPolynomial(): ScalableListPolynomialSpace where A : Ring, A : ScaleOperations = - ScalableListPolynomialSpace(this) - -/** - * Creates a [ScalableListPolynomialSpace]'s scope over a received scalable ring. - */ -public inline fun A.scalableListPolynomial(block: ScalableListPolynomialSpace.() -> R): R where A : Ring, A : ScaleOperations { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return ScalableListPolynomialSpace(this).block() -} - -@Suppress("NOTHING_TO_INLINE") -internal inline fun copyTo( - origin: List, - originDegree: Int, - target: MutableList, -) { - for (deg in 0 .. originDegree) target[deg] = origin[deg] -} - -@Suppress("NOTHING_TO_INLINE") -internal inline fun multiplyAddingToUpdater( - ring: Ring, - multiplicand: MutableList, - multiplicandDegree: Int, - multiplier: List, - multiplierDegree: Int, - updater: MutableList, - zero: C, -) { - multiplyAddingTo( - ring = ring, - multiplicand = multiplicand, - multiplicandDegree = multiplicandDegree, - multiplier = multiplier, - multiplierDegree = multiplierDegree, - target = updater - ) - for (updateDeg in 0 .. multiplicandDegree + multiplierDegree) { - multiplicand[updateDeg] = updater[updateDeg] - updater[updateDeg] = zero - } -} - -@Suppress("NOTHING_TO_INLINE") -internal inline fun multiplyAddingTo( - ring: Ring, - multiplicand: List, - multiplicandDegree: Int, - multiplier: List, - multiplierDegree: Int, - target: MutableList -) = ring { - for (d in 0 .. multiplicandDegree + multiplierDegree) - for (k in max(0, d - multiplierDegree)..min(multiplicandDegree, d)) - target[d] += multiplicand[k] * multiplier[d - k] -} - -/** - * Evaluates the value of the given double polynomial for given double argument. - */ -public fun ListPolynomial.substitute(arg: Double): Double = - coefficients.reduceIndexedOrNull { index, acc, c -> - acc + c * arg.pow(index) - } ?: .0 - -/** - * Evaluates the value of the given polynomial for given argument. - * - * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). - */ -public fun ListPolynomial.substitute(ring: Ring, arg: C): C = ring { - if (coefficients.isEmpty()) return@ring zero - var result: C = coefficients.last() - for (j in coefficients.size - 2 downTo 0) { - result = (arg * result) + coefficients[j] - } - return result -} - -public fun ListPolynomial.substitute(ring: Ring, arg: ListPolynomial) : ListPolynomial = ring { - if (coefficients.isEmpty()) return ListPolynomial(emptyList()) - - val thisDegree = coefficients.lastIndex - if (thisDegree == -1) return ListPolynomial(emptyList()) - val argDegree = arg.coefficients.lastIndex - if (argDegree == -1) return coefficients[0].asListPolynomial() - val constantZero = zero - val resultCoefs: MutableList = MutableList(thisDegree * argDegree + 1) { constantZero } - resultCoefs[0] = coefficients[thisDegree] - val resultCoefsUpdate: MutableList = MutableList(thisDegree * argDegree + 1) { constantZero } - var resultDegree = 0 - for (deg in thisDegree - 1 downTo 0) { - resultCoefsUpdate[0] = coefficients[deg] - multiplyAddingToUpdater( - ring = ring, - multiplicand = resultCoefs, - multiplicandDegree = resultDegree, - multiplier = arg.coefficients, - multiplierDegree = argDegree, - updater = resultCoefsUpdate, - zero = constantZero - ) - resultDegree += argDegree - } - - return ListPolynomial(resultCoefs) -} - -/** - * Represent the polynomial as a regular context-less function. - */ -public fun > ListPolynomial.asFunction(ring: A): (C) -> C = { substitute(ring, it) } - -/** - * Represent the polynomial as a regular context-less function. - */ -public fun > ListPolynomial.asPolynomialFunctionOver(ring: A): (ListPolynomial) -> ListPolynomial = { substitute(ring, it) } - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun ListPolynomial.derivative( - algebra: A, -): ListPolynomial where A : Ring, A : NumericAlgebra = algebra { - ListPolynomial( - buildList(max(0, coefficients.size - 1)) { - for (deg in 1 .. coefficients.lastIndex) add(number(deg) * coefficients[deg]) - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun ListPolynomial.nthDerivative( - algebra: A, - order: Int, -): ListPolynomial where A : Ring, A : NumericAlgebra = algebra { - require(order >= 0) { "Order of derivative must be non-negative" } - ListPolynomial( - buildList(max(0, coefficients.size - order)) { - for (deg in order.. coefficients.lastIndex) - add((deg - order + 1 .. deg).fold(coefficients[deg]) { acc, d -> acc * number(d) }) - } - ) -} - -/** - * Returns algebraic antiderivative of received polynomial. - */ -@UnstableKMathAPI -public fun ListPolynomial.antiderivative( - algebra: A, -): ListPolynomial where A : Field, A : NumericAlgebra = algebra { - ListPolynomial( - buildList(coefficients.size + 1) { - add(zero) - coefficients.mapIndexedTo(this) { index, t -> t / number(index + 1) } - } - ) -} - -/** - * Returns algebraic antiderivative of received polynomial. - */ -@UnstableKMathAPI -public fun ListPolynomial.nthAntiderivative( - algebra: A, - order: Int, -): ListPolynomial where A : Field, A : NumericAlgebra = algebra { - require(order >= 0) { "Order of antiderivative must be non-negative" } - ListPolynomial( - buildList(coefficients.size + order) { - repeat(order) { add(zero) } - coefficients.mapIndexedTo(this) { index, c -> (1..order).fold(c) { acc, i -> acc / number(index + i) } } - } - ) -} - -/** - * Compute a definite integral of a given polynomial in a [range] - */ -@UnstableKMathAPI -public fun > ListPolynomial.integrate( - algebra: Field, - range: ClosedRange, -): C = algebra { - val integral = antiderivative(algebra) - integral.substitute(algebra, range.endInclusive) - integral.substitute(algebra, range.start) -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt new file mode 100644 index 000000000..127dd8c7a --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt @@ -0,0 +1,268 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.functions + +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.* +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract +import kotlin.math.max +import kotlin.math.pow + + +/** + * Creates a [ListPolynomialSpace] over a received ring. + */ +public fun > A.listPolynomialSpace(): ListPolynomialSpace = + ListPolynomialSpace(this) + +/** + * Creates a [ListPolynomialSpace]'s scope over a received ring. + */ // TODO: When context will be ready move [ListPolynomialSpace] and add [A] to context receivers of [block] +public inline fun , R> A.listPolynomialSpace(block: ListPolynomialSpace.() -> R): R { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return ListPolynomialSpace(this).block() +} + +/** + * Creates a [ScalableListPolynomialSpace] over a received scalable ring. + */ +public fun A.scalableListPolynomialSpace(): ScalableListPolynomialSpace where A : Ring, A : ScaleOperations = + ScalableListPolynomialSpace(this) + +/** + * Creates a [ScalableListPolynomialSpace]'s scope over a received scalable ring. + */ // TODO: When context will be ready move [ListPolynomialSpace] and add [A] to context receivers of [block] +public inline fun A.scalableListPolynomialSpace(block: ScalableListPolynomialSpace.() -> R): R where A : Ring, A : ScaleOperations { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return ScalableListPolynomialSpace(this).block() +} + +/** + * Creates a [ListRationalFunctionSpace] over a received ring. + */ +public fun > A.listRationalFunctionSpace(): ListRationalFunctionSpace = + ListRationalFunctionSpace(this) + +/** + * Creates a [ListRationalFunctionSpace]'s scope over a received ring. + */ // TODO: When context will be ready move [ListRationalFunctionSpace] and add [A] to context receivers of [block] +public inline fun , R> A.listRationalFunctionSpace(block: ListRationalFunctionSpace.() -> R): R { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return ListRationalFunctionSpace(this).block() +} + + +/** + * Evaluates value of [this] Double polynomial on provided Double argument. + */ +public fun ListPolynomial.substitute(arg: Double): Double = + coefficients.reduceIndexedOrNull { index, acc, c -> + acc + c * arg.pow(index) + } ?: .0 + +/** + * Evaluates value of [this] polynomial on provided argument. + * + * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). + */ +public fun ListPolynomial.substitute(ring: Ring, arg: C): C = ring { + if (coefficients.isEmpty()) return zero + var result: C = coefficients.last() + for (j in coefficients.size - 2 downTo 0) { + result = (arg * result) + coefficients[j] + } + return result +} + +/** + * Substitutes provided polynomial [arg] into [this] polynomial. + * + * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). + */ // TODO: To optimize boxing +public fun ListPolynomial.substitute(ring: Ring, arg: ListPolynomial) : ListPolynomial = + ring.listPolynomialSpace { + if (coefficients.isEmpty()) return zero + var result: ListPolynomial = coefficients.last().asPolynomial() + for (j in coefficients.size - 2 downTo 0) { + result = (arg * result) + coefficients[j] + } + return result + } + +/** + * Substitutes provided rational function [arg] into [this] polynomial. + * + * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). + */ // TODO: To optimize boxing +public fun ListPolynomial.substitute(ring: Ring, arg: ListRationalFunction) : ListRationalFunction = + ring.listRationalFunctionSpace { + if (coefficients.isEmpty()) return zero + var result: ListRationalFunction = coefficients.last().asRationalFunction() + for (j in coefficients.size - 2 downTo 0) { + result = (arg * result) + coefficients[j] + } + return result + } + +/** + * Evaluates value of [this] Double rational function in provided Double argument. + */ +public fun ListRationalFunction.substitute(arg: Double): Double = + numerator.substitute(arg) / denominator.substitute(arg) + +/** + * Evaluates value of [this] polynomial for provided argument. + * + * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). + */ +public fun ListRationalFunction.substitute(ring: Field, arg: C): C = ring { + numerator.substitute(ring, arg) / denominator.substitute(ring, arg) +} + +/** + * Substitutes provided polynomial [arg] into [this] rational function. + */ // TODO: To optimize boxing +public fun ListRationalFunction.substitute(ring: Ring, arg: ListPolynomial) : ListRationalFunction = + ring.listRationalFunctionSpace { + numerator.substitute(ring, arg) / denominator.substitute(ring, arg) + } + +/** + * Substitutes provided rational function [arg] into [this] rational function. + */ // TODO: To optimize boxing +public fun ListRationalFunction.substitute(ring: Ring, arg: ListRationalFunction) : ListRationalFunction = + ring.listRationalFunctionSpace { + numerator.substitute(ring, arg) / denominator.substitute(ring, arg) + } + +/** + * Represent [this] polynomial as a regular context-less function. + */ +public fun > ListPolynomial.asFunctionOver(ring: A): (C) -> C = { substitute(ring, it) } + +/** + * Represent [this] polynomial as a regular context-less function. + */ +public fun > ListPolynomial.asPolynomialFunctionOver(ring: A): (ListPolynomial) -> ListPolynomial = { substitute(ring, it) } + +/** + * Represent [this] polynomial as a regular context-less function. + */ +public fun > ListPolynomial.asFunctionOfRationalFunctionOver(ring: A): (ListPolynomial) -> ListPolynomial = { substitute(ring, it) } + +/** + * Represent [this] rational function as a regular context-less function. + */ +public fun > ListRationalFunction.asFunctionOver(ring: A): (C) -> C = { substitute(ring, it) } + +/** + * Represent [this] rational function as a regular context-less function. + */ +public fun > ListRationalFunction.asPolynomialFunctionOver(ring: A): (ListPolynomial) -> ListRationalFunction = { substitute(ring, it) } + +/** + * Represent [this] rational function as a regular context-less function. + */ +public fun > ListRationalFunction.asFunctionOfRationalFunctionOver(ring: A): (ListPolynomial) -> ListRationalFunction = { substitute(ring, it) } + +/** + * Returns algebraic derivative of received polynomial. + */ +@UnstableKMathAPI +public fun ListPolynomial.derivative( + ring: A, +): ListPolynomial where A : Ring, A : NumericAlgebra = ring { + ListPolynomial( + buildList(max(0, coefficients.size - 1)) { + for (deg in 1 .. coefficients.lastIndex) add(number(deg) * coefficients[deg]) + } + ) +} + +/** + * Returns algebraic derivative of received polynomial of specified [order]. The [order] should be non-negative integer. + */ +@UnstableKMathAPI +public fun ListPolynomial.nthDerivative( + ring: A, + order: Int, +): ListPolynomial where A : Ring, A : NumericAlgebra = ring { + require(order >= 0) { "Order of derivative must be non-negative" } + ListPolynomial( + buildList(max(0, coefficients.size - order)) { + for (deg in order.. coefficients.lastIndex) + add((deg - order + 1 .. deg).fold(coefficients[deg]) { acc, d -> acc * number(d) }) + } + ) +} + +/** + * Returns algebraic antiderivative of received polynomial. + */ +@UnstableKMathAPI +public fun ListPolynomial.antiderivative( + ring: A, +): ListPolynomial where A : Field, A : NumericAlgebra = ring { + ListPolynomial( + buildList(coefficients.size + 1) { + add(zero) + coefficients.mapIndexedTo(this) { index, t -> t / number(index + 1) } + } + ) +} + +/** + * Returns algebraic antiderivative of received polynomial of specified [order]. The [order] should be non-negative integer. + */ +@UnstableKMathAPI +public fun ListPolynomial.nthAntiderivative( + ring: A, + order: Int, +): ListPolynomial where A : Field, A : NumericAlgebra = ring { + require(order >= 0) { "Order of antiderivative must be non-negative" } + ListPolynomial( + buildList(coefficients.size + order) { + repeat(order) { add(zero) } + coefficients.mapIndexedTo(this) { index, c -> (1..order).fold(c) { acc, i -> acc / number(index + i) } } + } + ) +} + +/** + * Computes a definite integral of [this] polynomial in the specified [range]. + */ +@UnstableKMathAPI +public fun > ListPolynomial.integrate( + ring: Field, + range: ClosedRange, +): C = ring { + val antiderivative = antiderivative(ring) + antiderivative.substitute(ring, range.endInclusive) - antiderivative.substitute(ring, range.start) +} + +/** + * Returns algebraic derivative of received rational function. + */ +@UnstableKMathAPI +public fun ListRationalFunction.derivative( + ring: A, +): ListRationalFunction where A : Ring, A : NumericAlgebra = ring.listRationalFunctionSpace { + ListRationalFunction( + numerator.derivative(ring) * denominator - numerator * denominator.derivative(ring), + denominator * denominator + ) +} + +/** + * Returns algebraic derivative of received rational function of specified [order]. The [order] should be non-negative integer. + */ +@UnstableKMathAPI +public tailrec fun ListRationalFunction.nthDerivative( + ring: A, + order: Int, +): ListRationalFunction where A : Ring, A : NumericAlgebra = + if (order == 0) this else derivative(ring).nthDerivative(ring, order - 1) \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listRationalFunctionUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtilOptimized.kt similarity index 72% rename from kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listRationalFunctionUtil.kt rename to kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtilOptimized.kt index 367212588..6eb3a1dc7 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listRationalFunctionUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtilOptimized.kt @@ -5,41 +5,91 @@ package space.kscience.kmath.functions -import space.kscience.kmath.operations.Field import space.kscience.kmath.operations.Ring import space.kscience.kmath.operations.invoke -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract import kotlin.math.max +import kotlin.math.min -/** - * Creates a [ListRationalFunctionSpace] over a received ring. - */ -public fun > A.listRationalFunction(): ListRationalFunctionSpace = - ListRationalFunctionSpace(this) - -/** - * Creates a [ListRationalFunctionSpace]'s scope over a received ring. - */ -public inline fun , R> A.listRationalFunction(block: ListRationalFunctionSpace.() -> R): R { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return ListRationalFunctionSpace(this).block() +// TODO: Optimized copies of substitution and invocation +@UnstablePolynomialBoxingOptimization +@Suppress("NOTHING_TO_INLINE") +internal inline fun copyTo( + origin: List, + originDegree: Int, + target: MutableList, +) { + for (deg in 0 .. originDegree) target[deg] = origin[deg] } -/** - * Evaluates the value of the given double polynomial for given double argument. - */ -public fun ListRationalFunction.substitute(arg: Double): Double = - numerator.substitute(arg) / denominator.substitute(arg) +@UnstablePolynomialBoxingOptimization +@Suppress("NOTHING_TO_INLINE") +internal inline fun multiplyAddingToUpdater( + ring: Ring, + multiplicand: MutableList, + multiplicandDegree: Int, + multiplier: List, + multiplierDegree: Int, + updater: MutableList, + zero: C, +) { + multiplyAddingTo( + ring = ring, + multiplicand = multiplicand, + multiplicandDegree = multiplicandDegree, + multiplier = multiplier, + multiplierDegree = multiplierDegree, + target = updater + ) + for (updateDeg in 0 .. multiplicandDegree + multiplierDegree) { + multiplicand[updateDeg] = updater[updateDeg] + updater[updateDeg] = zero + } +} -/** - * Evaluates the value of the given polynomial for given argument. - * - * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). - */ -public fun ListRationalFunction.substitute(ring: Field, arg: C): C = ring { - numerator.substitute(ring, arg) / denominator.substitute(ring, arg) +@UnstablePolynomialBoxingOptimization +@Suppress("NOTHING_TO_INLINE") +internal inline fun multiplyAddingTo( + ring: Ring, + multiplicand: List, + multiplicandDegree: Int, + multiplier: List, + multiplierDegree: Int, + target: MutableList +) = ring { + for (d in 0 .. multiplicandDegree + multiplierDegree) + for (k in max(0, d - multiplierDegree)..min(multiplicandDegree, d)) + target[d] += multiplicand[k] * multiplier[d - k] +} + +@UnstablePolynomialBoxingOptimization +public fun ListPolynomial.substitute2(ring: Ring, arg: ListPolynomial) : ListPolynomial = ring { + if (coefficients.isEmpty()) return ListPolynomial(emptyList()) + + val thisDegree = coefficients.lastIndex + if (thisDegree == -1) return ListPolynomial(emptyList()) + val argDegree = arg.coefficients.lastIndex + if (argDegree == -1) return coefficients[0].asListPolynomial() + val constantZero = zero + val resultCoefs: MutableList = MutableList(thisDegree * argDegree + 1) { constantZero } + resultCoefs[0] = coefficients[thisDegree] + val resultCoefsUpdate: MutableList = MutableList(thisDegree * argDegree + 1) { constantZero } + var resultDegree = 0 + for (deg in thisDegree - 1 downTo 0) { + resultCoefsUpdate[0] = coefficients[deg] + multiplyAddingToUpdater( + ring = ring, + multiplicand = resultCoefs, + multiplicandDegree = resultDegree, + multiplier = arg.coefficients, + multiplierDegree = argDegree, + updater = resultCoefsUpdate, + zero = constantZero + ) + resultDegree += argDegree + } + + return ListPolynomial(resultCoefs) } /** @@ -52,6 +102,7 @@ public fun ListRationalFunction.substitute(ring: Field, arg: C): C = r * * Used in [ListPolynomial.substitute] and [ListRationalFunction.substitute] for performance optimisation. */ // TODO: Дописать +@UnstablePolynomialBoxingOptimization internal fun ListPolynomial.substituteRationalFunctionTakeNumerator(ring: Ring, arg: ListRationalFunction): ListPolynomial = ring { if (coefficients.isEmpty()) return ListPolynomial(emptyList()) @@ -196,26 +247,4 @@ internal fun ListPolynomial.substituteRationalFunctionTakeNumerator(ring: end = thisDegree + 1 ) ) -} - -//operator fun > RationalFunction.invoke(arg: T): T = numerator(arg) / denominator(arg) -// -//fun > RationalFunction.reduced(): RationalFunction = -// polynomialGCD(numerator, denominator).let { -// RationalFunction( -// numerator / it, -// denominator / it -// ) -// } - -///** -// * Returns result of applying formal derivative to the polynomial. -// * -// * @param T Field where we are working now. -// * @return Result of the operator. -// */ -//fun > RationalFunction.derivative() = -// RationalFunction( -// numerator.derivative() * denominator - denominator.derivative() * numerator, -// denominator * denominator -// ) \ No newline at end of file +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt new file mode 100644 index 000000000..8b6fac39e --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt @@ -0,0 +1,13 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.functions + + +@RequiresOptIn( + message = "It's copy of operation with optimized boxing. It's currently unstable.", + level = RequiresOptIn.Level.ERROR +) +internal annotation class UnstablePolynomialBoxingOptimization \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt deleted file mode 100644 index dca8a0cff..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.functions - -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.Ring - - -/** - * Returns the same degrees' description of the monomial, but without extra zero degrees on the end. - */ -internal fun List.cleanUp() = subList(0, indexOfLast { it != 0U } + 1) - -// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available - -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > NumberedPolynomialSpace.NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(coefs, toCheckInput) -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(coefs, toCheckInput) -@Suppress("FunctionName") -internal fun > A.NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : NumberedPolynomial { - if (!toCheckInput) return NumberedPolynomial(coefs) - - val fixedCoefs = mutableMapOf, C>() - - for (entry in coefs) { - val key = entry.key.cleanUp() - val value = entry.value - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return NumberedPolynomial(fixedCoefs) -} - -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > NumberedPolynomialSpace.NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(pairs, toCheckInput) -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(pairs, toCheckInput) -@Suppress("FunctionName") -internal fun > A.NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : NumberedPolynomial { - if (!toCheckInput) return NumberedPolynomial(pairs.toMap()) - - val fixedCoefs = mutableMapOf, C>() - - for (entry in pairs) { - val key = entry.first.cleanUp() - val value = entry.second - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return NumberedPolynomial(fixedCoefs) -} - -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > NumberedPolynomialSpace.NumberedPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(pairs = pairs, toCheckInput = toCheckInput) -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(pairs = pairs, toCheckInput = toCheckInput) -@Suppress("FunctionName") -internal fun > A.NumberedPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : NumberedPolynomial { - if (!toCheckInput) return NumberedPolynomial(pairs.toMap()) - - val fixedCoefs = mutableMapOf, C>() - - for (entry in pairs) { - val key = entry.first.cleanUp() - val value = entry.second - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return NumberedPolynomial(fixedCoefs) -} - -@Suppress("FunctionName") -public fun > A.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, toCheckInput = true) -@Suppress("FunctionName") -public fun > NumberedPolynomialSpace.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, toCheckInput = true) -@Suppress("FunctionName") -public fun > NumberedRationalFunctionSpace.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, toCheckInput = true) - -@Suppress("FunctionName") -public fun > A.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > NumberedPolynomialSpace.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > NumberedRationalFunctionSpace.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, toCheckInput = true) - -@Suppress("FunctionName") -public fun > A.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > NumberedPolynomialSpace.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > NumberedRationalFunctionSpace.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs, toCheckInput = true) - -public fun C.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomial(mapOf(emptyList() to this)) - -@DslMarker -@UnstableKMathAPI -internal annotation class NumberedPolynomialConstructorDSL - -@UnstableKMathAPI -@NumberedPolynomialConstructorDSL -public class NumberedPolynomialTermSignatureBuilder { - private val signature: MutableList = ArrayList() - public fun build(): List = signature - public infix fun Int.inPowerOf(deg: UInt) { - if (this > signature.lastIndex) { - signature.addAll(List(this - signature.lastIndex - 1) { 0u }) - signature.add(deg) - } else { - signature[this] = deg - } - } - @Suppress("NOTHING_TO_INLINE") - public inline infix fun Int.pow(deg: UInt): Unit = this inPowerOf deg - @Suppress("NOTHING_TO_INLINE") - public inline infix fun Int.`in`(deg: UInt): Unit = this inPowerOf deg - @Suppress("NOTHING_TO_INLINE") - public inline infix fun Int.of(deg: UInt): Unit = this inPowerOf deg -} - -@UnstableKMathAPI -public class NumberedPolynomialBuilder(private val zero: C, private val add: (C, C) -> C, capacity: Int = 0) { - private val coefficients: MutableMap, C> = LinkedHashMap(capacity) - public fun build(): NumberedPolynomial = NumberedPolynomial(coefficients) - public operator fun C.invoke(block: NumberedPolynomialTermSignatureBuilder.() -> Unit) { - val signature = NumberedPolynomialTermSignatureBuilder().apply(block).build() - coefficients[signature] = add(coefficients.getOrElse(signature) { zero }, this@invoke) - } - @Suppress("NOTHING_TO_INLINE") - public inline infix fun C.with(noinline block: NumberedPolynomialTermSignatureBuilder.() -> Unit): Unit = this.invoke(block) - @Suppress("NOTHING_TO_INLINE") - public inline infix fun (NumberedPolynomialTermSignatureBuilder.() -> Unit).with(coef: C): Unit = coef.invoke(this) - @Suppress("NOTHING_TO_INLINE") - public infix fun sig(block: NumberedPolynomialTermSignatureBuilder.() -> Unit): NumberedPolynomialTermSignatureBuilder.() -> Unit = block -} - -// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available - -@UnstableKMathAPI -@NumberedPolynomialConstructorDSL -@Suppress("FunctionName") -public inline fun > A.NumberedPolynomial(block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder(zero, ::add).apply(block).build() -@UnstableKMathAPI -@NumberedPolynomialConstructorDSL -@Suppress("FunctionName") -public inline fun > A.NumberedPolynomial(capacity: Int, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder(zero, ::add, capacity).apply(block).build() -@UnstableKMathAPI -@NumberedPolynomialConstructorDSL -@Suppress("FunctionName") -public inline fun > NumberedPolynomialSpace.NumberedPolynomial(block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder(constantZero, { left: C, right: C -> left + right}).apply(block).build() -@UnstableKMathAPI -@NumberedPolynomialConstructorDSL -@Suppress("FunctionName") -public inline fun > NumberedPolynomialSpace.NumberedPolynomial(capacity: Int, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder(constantZero, { left: C, right: C -> left + right}, capacity).apply(block).build() - -// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available - -@Suppress("FunctionName") -public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): NumberedRationalFunction = - NumberedRationalFunction( - NumberedPolynomial(numeratorCoefficients, toCheckInput = true), - NumberedPolynomial(denominatorCoefficients, toCheckInput = true) - ) -@Suppress("FunctionName") -public fun > A.NumberedRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): NumberedRationalFunction = - NumberedRationalFunction( - NumberedPolynomial(numeratorCoefficients, toCheckInput = true), - NumberedPolynomial(denominatorCoefficients, toCheckInput = true) - ) -@Suppress("FunctionName") -public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numerator: NumberedPolynomial): NumberedRationalFunction = - NumberedRationalFunction(numerator, polynomialOne) -@Suppress("FunctionName") -public fun > A.NumberedRationalFunction(numerator: NumberedPolynomial): NumberedRationalFunction = - NumberedRationalFunction(numerator, NumberedPolynomial(mapOf(emptyList() to one), toCheckInput = false)) -@Suppress("FunctionName") -public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numeratorCoefficients: Map, C>): NumberedRationalFunction = - NumberedRationalFunction( - NumberedPolynomial(numeratorCoefficients, toCheckInput = true), - polynomialOne - ) -@Suppress("FunctionName") -public fun > A.NumberedRationalFunction(numeratorCoefficients: Map, C>): NumberedRationalFunction = - NumberedRationalFunction( - NumberedPolynomial(numeratorCoefficients, toCheckInput = true), - NumberedPolynomial(mapOf(emptyList() to one), toCheckInput = false) - ) - -//context(A) -//public fun > C.asNumberedRationalFunction() : NumberedRationalFunction = NumberedRationalFunction(asLabeledPolynomial()) -//context(NumberedRationalFunctionSpace) -//public fun > C.asNumberedRationalFunction() : NumberedRationalFunction = NumberedRationalFunction(asLabeledPolynomial()) \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt deleted file mode 100644 index ad817c7ba..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt +++ /dev/null @@ -1,528 +0,0 @@ -package space.kscience.kmath.functions - -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.* -import kotlin.contracts.* -import kotlin.jvm.JvmName -import kotlin.math.max - - -// TODO: Docs - -/** - * Creates a [NumberedPolynomialSpace] over a received ring. - */ -public fun > A.numberedPolynomial(): NumberedPolynomialSpace = - NumberedPolynomialSpace(this) - -/** - * Creates a [NumberedPolynomialSpace]'s scope over a received ring. - */ -@OptIn(ExperimentalContracts::class) -public inline fun , R> A.numberedPolynomial(block: NumberedPolynomialSpace.() -> R): R { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return NumberedPolynomialSpace(this).block() -} - -///** -// * Represents the polynomial as a [String] where name of variable with index `i` is [withVariableName] + `"_${i+1}"`. -// * Consider that monomials are sorted in lexicographic order. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial.represent(withVariableName: String = NumberedPolynomial.defaultVariableName): String = -// coefficients.entries -// .sortedWith { o1, o2 -> NumberedPolynomial.monomialComparator.compare(o1.key, o2.key) } -// .asSequence() -// .map { (degs, t) -> -// if (degs.isEmpty()) "$t" -// else { -// when { -// t.isOne() -> "" -// t.isMinusOne() -> "-" -// else -> "$t " -// } + -// degs -// .mapIndexed { index, deg -> -// when (deg) { -// 0U -> "" -// 1U -> "${withVariableName}_${index+1}" -// else -> "${withVariableName}_${index+1}^$deg" -// } -// } -// .filter { it.isNotEmpty() } -// .joinToString(separator = " ") { it } -// } -// } -// .joinToString(separator = " + ") { it } -// .ifEmpty { "0" } -// -///** -// * Represents the polynomial as a [String] naming variables by [namer]. -// * Consider that monomials are sorted in lexicographic order. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial.represent(namer: (Int) -> String): String = -// coefficients.entries -// .sortedWith { o1, o2 -> NumberedPolynomial.monomialComparator.compare(o1.key, o2.key) } -// .asSequence() -// .map { (degs, t) -> -// if (degs.isEmpty()) "$t" -// else { -// when { -// t.isOne() -> "" -// t.isMinusOne() -> "-" -// else -> "$t " -// } + -// degs -// .mapIndexed { index, deg -> -// when (deg) { -// 0U -> "" -// 1U -> namer(index) -// else -> "${namer(index)}^$deg" -// } -// } -// .filter { it.isNotEmpty() } -// .joinToString(separator = " ") { it } -// } -// } -// .joinToString(separator = " + ") { it } -// .ifEmpty { "0" } -// -///** -// * Represents the polynomial as a [String] where name of variable with index `i` is [withVariableName] + `"_${i+1}"` -// * and with brackets around the string if needed (i.e. when there are at least two addends in the representation). -// * Consider that monomials are sorted in lexicographic order. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial.representWithBrackets(withVariableName: String = NumberedPolynomial.defaultVariableName): String = -// with(represent(withVariableName)) { if (coefficients.count() == 1) this else "($this)" } -// -///** -// * Represents the polynomial as a [String] naming variables by [namer] and with brackets around the string if needed -// * (i.e. when there are at least two addends in the representation). -// * Consider that monomials are sorted in lexicographic order. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial.representWithBrackets(namer: (Int) -> String): String = -// with(represent(namer)) { if (coefficients.count() == 1) this else "($this)" } -// -///** -// * Represents the polynomial as a [String] where name of variable with index `i` is [withVariableName] + `"_${i+1}"`. -// * Consider that monomials are sorted in **reversed** lexicographic order. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial.representReversed(withVariableName: String = NumberedPolynomial.defaultVariableName): String = -// coefficients.entries -// .sortedWith { o1, o2 -> -NumberedPolynomial.monomialComparator.compare(o1.key, o2.key) } -// .asSequence() -// .map { (degs, t) -> -// if (degs.isEmpty()) "$t" -// else { -// when { -// t.isOne() -> "" -// t.isMinusOne() -> "-" -// else -> "$t " -// } + -// degs -// .mapIndexed { index, deg -> -// when (deg) { -// 0U -> "" -// 1U -> "${withVariableName}_${index+1}" -// else -> "${withVariableName}_${index+1}^$deg" -// } -// } -// .filter { it.isNotEmpty() } -// .joinToString(separator = " ") { it } -// } -// } -// .joinToString(separator = " + ") { it } -// .ifEmpty { "0" } -// -///** -// * Represents the polynomial as a [String] naming variables by [namer]. -// * Consider that monomials are sorted in **reversed** lexicographic order. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial.representReversed(namer: (Int) -> String): String = -// coefficients.entries -// .sortedWith { o1, o2 -> -NumberedPolynomial.monomialComparator.compare(o1.key, o2.key) } -// .asSequence() -// .map { (degs, t) -> -// if (degs.isEmpty()) "$t" -// else { -// when { -// t.isOne() -> "" -// t.isMinusOne() -> "-" -// else -> "$t " -// } + -// degs -// .mapIndexed { index, deg -> -// when (deg) { -// 0U -> "" -// 1U -> namer(index) -// else -> "${namer(index)}^$deg" -// } -// } -// .filter { it.isNotEmpty() } -// .joinToString(separator = " ") { it } -// } -// } -// .joinToString(separator = " + ") { it } -// .ifEmpty { "0" } -// -///** -// * Represents the polynomial as a [String] where name of variable with index `i` is [withVariableName] + `"_${i+1}"` -// * and with brackets around the string if needed (i.e. when there are at least two addends in the representation). -// * Consider that monomials are sorted in **reversed** lexicographic order. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial.representReversedWithBrackets(withVariableName: String = NumberedPolynomial.defaultVariableName): String = -// with(representReversed(withVariableName)) { if (coefficients.count() == 1) this else "($this)" } -// -///** -// * Represents the polynomial as a [String] naming variables by [namer] and with brackets around the string if needed -// * (i.e. when there are at least two addends in the representation). -// * Consider that monomials are sorted in **reversed** lexicographic order. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial.representReversedWithBrackets(namer: (Int) -> String): String = -// with(representReversed(namer)) { if (coefficients.count() == 1) this else "($this)" } - -//public fun NumberedPolynomial.substitute(ring: Ring, args: Map): NumberedPolynomial = ring { -// if (coefficients.isEmpty()) return this@substitute -// NumberedPolynomial( -// buildMap { -// coefficients.forEach { (degs, c) -> -// val newDegs = degs.mapIndexed { index, deg -> if (index in args) 0U else deg }.cleanUp() -// val newC = degs.foldIndexed(c) { index, acc, deg -> -// if (index in args) multiplyWithPower(acc, args[index]!!, deg) -// else acc -// } -// this[newDegs] = if (newDegs in this) this[newDegs]!! + newC else newC -// } -// } -// ) -//} -// -//// TODO: Replace with optimisation: the [result] may be unboxed, and all operations may be performed as soon as -//// possible on it -//@JvmName("substitutePolynomial") -//public fun NumberedPolynomial.substitute(ring: Ring, arg: Map>) : NumberedPolynomial = -// ring.numberedPolynomialSpace { -// if (coefficients.isEmpty()) return zero -// coefficients -// .asSequence() -// .map { (degs, c) -> -// degs.foldIndexed( -// NumberedPolynomial( -// degs.mapIndexed { index, deg -> if (index in arg) 0U else deg } to c -// ) -// ) { index, acc, deg -> if (index in arg) multiplyWithPower(acc, arg[index]!!, deg) else acc } -// } -// .reduce { acc, polynomial -> acc + polynomial } // TODO: Rewrite. Might be slow. -// } -// -//// TODO: Substitute rational function -// -//public fun > NumberedPolynomial.asFunctionOver(ring: A): (Map) -> NumberedPolynomial = -// { substitute(ring, it) } -// -//public fun > NumberedPolynomial.asPolynomialFunctionOver(ring: A): (Map>) -> NumberedPolynomial = -// { substitute(ring, it) } - -//operator fun > Polynomial.div(other: T): Polynomial = -// if (other.isZero()) throw ArithmeticException("/ by zero") -// else -// Polynomial( -// coefficients -// .mapValues { it.value / other }, -// toCheckInput = false -// ) - -/** - * Evaluates the value of the given double polynomial for given double argument. - */ -public fun NumberedPolynomial.substitute(args: Map): NumberedPolynomial = Double.algebra { - val acc = LinkedHashMap, Double>(coefficients.size) - for ((degs, c) in coefficients) { - val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp() - val newC = args.entries.fold(c) { product, (variable, substitution) -> - val deg = degs.getOrElse(variable) { 0u } - if (deg == 0u) product else product * substitution.pow(deg.toInt()) - } - if (newDegs !in acc) acc[newDegs] = newC - else acc[newDegs] = acc[newDegs]!! + newC - } - return NumberedPolynomial(acc) -} - -/** - * Evaluates the value of the given polynomial for given argument. - * - * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). - */ -public fun NumberedPolynomial.substitute(ring: Ring, args: Map): NumberedPolynomial = ring { - val acc = LinkedHashMap, C>(coefficients.size) - for ((degs, c) in coefficients) { - val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp() - val newC = args.entries.fold(c) { product, (variable, substitution) -> - val deg = degs.getOrElse(variable) { 0u } - if (deg == 0u) product else product * power(substitution, deg) - } - if (newDegs !in acc) acc[newDegs] = newC - else acc[newDegs] = acc[newDegs]!! + newC - } - return NumberedPolynomial(acc) -} - -// TODO: (Waiting for hero) Replace with optimisation: the [result] may be unboxed, and all operations may be performed -// as soon as possible on it -@JvmName("substitutePolynomial") -public fun NumberedPolynomial.substitute(ring: Ring, args: Map>) : NumberedPolynomial = TODO() /*ring.numberedPolynomial { - val acc = LinkedHashMap, NumberedPolynomial>(coefficients.size) - for ((degs, c) in coefficients) { - val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp() - val newC = args.entries.fold(c.asNumberedPolynomial()) { product, (variable, substitution) -> - val deg = degs.getOrElse(variable) { 0u } - if (deg == 0u) product else product * power(substitution, deg) - } - if (newDegs !in acc) acc[newDegs] = c.asNumberedPolynomial() - else acc[newDegs] = acc[newDegs]!! + c - } -}*/ - -/** - * Represent the polynomial as a regular context-less function. - */ -public fun > NumberedPolynomial.asFunction(ring: A): (Map) -> NumberedPolynomial = { substitute(ring, it) } - -/** - * Represent the polynomial as a regular context-less function. - */ -public fun > NumberedPolynomial.asPolynomialFunctionOver(ring: A): (Map>) -> NumberedPolynomial = { substitute(ring, it) } - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > NumberedPolynomial.derivativeWithRespectTo( - algebra: A, - variable: Int, -): NumberedPolynomial = algebra { - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - if (degs.size > variable) return@forEach - put( - degs.mapIndexed { index, deg -> - when { - index != variable -> deg - deg > 0u -> deg - 1u - else -> return@forEach - } - }.cleanUp(), - multiplyByDoubling(c, degs[variable]) - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > NumberedPolynomial.derivativeWithRespectTo( - algebra: A, - variables: Collection, -): NumberedPolynomial = algebra { - val cleanedVariables = variables.toSet() - if (cleanedVariables.isEmpty()) return this@derivativeWithRespectTo - val maxRespectedVariable = cleanedVariables.maxOrNull()!! - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - if (degs.size > maxRespectedVariable) return@forEach - put( - degs.mapIndexed { index, deg -> - when { - index !in cleanedVariables -> deg - deg > 0u -> deg - 1u - else -> return@forEach - } - }.cleanUp(), - cleanedVariables.fold(c) { acc, variable -> multiplyByDoubling(acc, degs[variable]) } - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > NumberedPolynomial.nthDerivativeWithRespectTo( - algebra: A, - variable: Int, - order: UInt -): NumberedPolynomial = algebra { - if (order == 0u) return this@nthDerivativeWithRespectTo - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - if (degs.size > variable) return@forEach - put( - degs.mapIndexed { index, deg -> - when { - index != variable -> deg - deg >= order -> deg - order - else -> return@forEach - } - }.cleanUp(), - degs[variable].let { deg -> - (deg downTo deg - order + 1u) - .fold(c) { acc, ord -> multiplyByDoubling(acc, ord) } - } - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > NumberedPolynomial.nthDerivativeWithRespectTo( - algebra: A, - variablesAndOrders: Map, -): NumberedPolynomial = algebra { - val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u } - if (filteredVariablesAndOrders.isEmpty()) return this@nthDerivativeWithRespectTo - val maxRespectedVariable = filteredVariablesAndOrders.keys.maxOrNull()!! - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - if (degs.size > maxRespectedVariable) return@forEach - put( - degs.mapIndexed { index, deg -> - if (index !in filteredVariablesAndOrders) return@mapIndexed deg - val order = filteredVariablesAndOrders[index]!! - if (deg >= order) deg - order else return@forEach - }.cleanUp(), - filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> - degs[index].let { deg -> - (deg downTo deg - order + 1u) - .fold(acc1) { acc2, ord -> multiplyByDoubling(acc2, ord) } - } - } - ) - } - } - ) -} - -/** - * Returns algebraic antiderivative of received polynomial. - */ -@UnstableKMathAPI -public fun > NumberedPolynomial.antiderivativeWithRespectTo( - algebra: A, - variable: Int, -): NumberedPolynomial = algebra { - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - put( - List(max(variable + 1, degs.size)) { if (it != variable) degs[it] else degs[it] + 1u }, - c / multiplyByDoubling(one, degs[variable]) - ) - } - } - ) -} - -/** - * Returns algebraic antiderivative of received polynomial. - */ -@UnstableKMathAPI -public fun > NumberedPolynomial.antiderivativeWithRespectTo( - algebra: A, - variables: Collection, -): NumberedPolynomial = algebra { - val cleanedVariables = variables.toSet() - if (cleanedVariables.isEmpty()) return this@antiderivativeWithRespectTo - val maxRespectedVariable = cleanedVariables.maxOrNull()!! - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - put( - List(max(maxRespectedVariable + 1, degs.size)) { if (it !in variables) degs[it] else degs[it] + 1u }, - cleanedVariables.fold(c) { acc, variable -> acc / multiplyByDoubling(one, degs[variable]) } - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > NumberedPolynomial.nthAntiderivativeWithRespectTo( - algebra: A, - variable: Int, - order: UInt -): NumberedPolynomial = algebra { - if (order == 0u) return this@nthAntiderivativeWithRespectTo - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - put( - List(max(variable + 1, degs.size)) { if (it != variable) degs[it] else degs[it] + order }, - degs[variable].let { deg -> - (deg downTo deg - order + 1u) - .fold(c) { acc, ord -> acc / multiplyByDoubling(one, ord) } - } - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > NumberedPolynomial.nthAntiderivativeWithRespectTo( - algebra: A, - variablesAndOrders: Map, -): NumberedPolynomial = algebra { - val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u } - if (filteredVariablesAndOrders.isEmpty()) return this@nthAntiderivativeWithRespectTo - val maxRespectedVariable = filteredVariablesAndOrders.keys.maxOrNull()!! - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - put( - List(max(maxRespectedVariable + 1, degs.size)) { degs[it] + filteredVariablesAndOrders.getOrElse(it) { 0u } }, - filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> - degs[index].let { deg -> - (deg downTo deg - order + 1u) - .fold(acc1) { acc2, ord -> acc2 / multiplyByDoubling(one, ord) } - } - } - ) - } - } - ) -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt deleted file mode 100644 index 5cd0679ab..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.functions - -import space.kscience.kmath.operations.Ring -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract - - -/** - * Creates a [NumberedRationalFunctionSpace] over a received ring. - */ -public fun > A.numberedRationalFunction(): NumberedRationalFunctionSpace = - NumberedRationalFunctionSpace(this) - -/** - * Creates a [NumberedRationalFunctionSpace]'s scope over a received ring. - */ -public inline fun , R> A.numberedRationalFunction(block: NumberedRationalFunctionSpace.() -> R): R { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return NumberedRationalFunctionSpace(this).block() -} - -//fun > NumberedRationalFunction.reduced(): NumberedRationalFunction { -// val greatestCommonDivider = polynomialGCD(numerator, denominator) -// return NumberedRationalFunction( -// numerator / greatestCommonDivider, -// denominator / greatestCommonDivider -// ) -//} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt index 5401be707..c9950fac5 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt @@ -12,7 +12,7 @@ import kotlin.test.* class ListPolynomialTest { @Test fun test_Polynomial_Int_plus() { - RationalField.listPolynomial { + RationalField.listPolynomialSpace { assertEquals( ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + -3, @@ -52,7 +52,7 @@ class ListPolynomialTest { } @Test fun test_Polynomial_Int_minus() { - RationalField.listPolynomial { + RationalField.listPolynomialSpace { assertEquals( ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - -3, @@ -92,7 +92,7 @@ class ListPolynomialTest { } @Test fun test_Polynomial_Int_times() { - IntModuloRing(35).listPolynomial { + IntModuloRing(35).listPolynomialSpace { assertEquals( ListPolynomial(34, 2, 1, 20, 2), ListPolynomial(22, 26, 13, 15, 26) * 27, @@ -107,7 +107,7 @@ class ListPolynomialTest { } @Test fun test_Int_Polynomial_plus() { - RationalField.listPolynomial { + RationalField.listPolynomialSpace { assertEquals( ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), -3 + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)), @@ -147,7 +147,7 @@ class ListPolynomialTest { } @Test fun test_Int_Polynomial_minus() { - RationalField.listPolynomial { + RationalField.listPolynomialSpace { assertEquals( ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), 3 - ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), @@ -187,7 +187,7 @@ class ListPolynomialTest { } @Test fun test_Int_Polynomial_times() { - IntModuloRing(35).listPolynomial { + IntModuloRing(35).listPolynomialSpace { assertEquals( ListPolynomial(34, 2, 1, 20, 2), 27 * ListPolynomial(22, 26, 13, 15, 26), @@ -202,7 +202,7 @@ class ListPolynomialTest { } @Test fun test_Polynomial_Constant_plus() { - RationalField.listPolynomial { + RationalField.listPolynomialSpace { assertEquals( ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + Rational(-3), @@ -242,7 +242,7 @@ class ListPolynomialTest { } @Test fun test_Polynomial_Constant_minus() { - RationalField.listPolynomial { + RationalField.listPolynomialSpace { assertEquals( ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - Rational(-3), @@ -282,7 +282,7 @@ class ListPolynomialTest { } @Test fun test_Polynomial_Constant_times() { - IntModuloRing(35).listPolynomial { + IntModuloRing(35).listPolynomialSpace { assertEquals( ListPolynomial(34, 2, 1, 20, 2), ListPolynomial(22, 26, 13, 15, 26) * 27.asConstant(), @@ -297,7 +297,7 @@ class ListPolynomialTest { } @Test fun test_Constant_Polynomial_plus() { - RationalField.listPolynomial { + RationalField.listPolynomialSpace { assertEquals( ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), Rational(-3) + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)), @@ -337,7 +337,7 @@ class ListPolynomialTest { } @Test fun test_Constant_Polynomial_minus() { - RationalField.listPolynomial { + RationalField.listPolynomialSpace { assertEquals( ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), Rational(3) - ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), @@ -377,7 +377,7 @@ class ListPolynomialTest { } @Test fun test_Constant_Polynomial_times() { - IntModuloRing(35).listPolynomial { + IntModuloRing(35).listPolynomialSpace { assertEquals( ListPolynomial(34, 2, 1, 20, 2), 27 * ListPolynomial(22, 26, 13, 15, 26), @@ -392,7 +392,7 @@ class ListPolynomialTest { } @Test fun test_Polynomial_unaryMinus() { - RationalField.listPolynomial { + RationalField.listPolynomialSpace { assertEquals( ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), -ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)), @@ -407,7 +407,7 @@ class ListPolynomialTest { } @Test fun test_Polynomial_Polynomial_plus() { - RationalField.listPolynomial { + RationalField.listPolynomialSpace { // (5/9 - 8/9 x - 8/7 x^2) + (-5/7 + 5/1 x + 5/8 x^2) ?= -10/63 + 37/9 x - 29/56 x^2 assertEquals( ListPolynomial(Rational(-10, 63), Rational(37, 9), Rational(-29, 56)), @@ -440,7 +440,7 @@ class ListPolynomialTest { } @Test fun test_Polynomial_Polynomial_minus() { - RationalField.listPolynomial { + RationalField.listPolynomialSpace { // (5/9 - 8/9 x - 8/7 x^2) - (-5/7 + 5/1 x + 5/8 x^2) ?= 80/63 - 53/9 x - 99/56 x^2 assertEquals( ListPolynomial(Rational(80, 63), Rational(-53, 9), Rational(-99, 56)), @@ -473,7 +473,7 @@ class ListPolynomialTest { } @Test fun test_Polynomial_Polynomial_times() { - IntModuloRing(35).listPolynomial { + IntModuloRing(35).listPolynomialSpace { // (1 + x + x^2) * (1 - x + x^2) ?= 1 + x^2 + x^4 assertEquals( ListPolynomial(1, 0, 1, 0, 1), diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt index c5eb8fb81..69c1611f3 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt @@ -5,6 +5,7 @@ package space.kscience.kmath.functions +import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.test.misc.Rational import space.kscience.kmath.test.misc.RationalField import kotlin.test.Test @@ -12,6 +13,7 @@ import kotlin.test.assertEquals import kotlin.test.assertFailsWith +@OptIn(UnstableKMathAPI::class) class ListPolynomialUtilTest { @Test fun test_substitute_Double() { diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt new file mode 100644 index 000000000..89764db46 --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt @@ -0,0 +1,138 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.test.misc + +import space.kscience.kmath.functions.ListPolynomial +import space.kscience.kmath.functions.ListPolynomialSpace +import space.kscience.kmath.operations.Ring + + +class IntModulo { + val residue: Int + val modulus: Int + + @PublishedApi + internal constructor(residue: Int, modulus: Int, toCheckInput: Boolean = true) { + if (toCheckInput) { + require(modulus != 0) { "modulus can not be zero" } + this.modulus = if (modulus < 0) -modulus else modulus + this.residue = residue.mod(modulus) + } else { + this.residue = residue + this.modulus = modulus + } + } + + constructor(residue: Int, modulus: Int) : this(residue, modulus, true) + + operator fun unaryPlus(): IntModulo = this + operator fun unaryMinus(): IntModulo = + IntModulo( + if (residue == 0) 0 else modulus - residue, + modulus, + toCheckInput = false + ) + operator fun plus(other: IntModulo): IntModulo { + require(modulus == other.modulus) { "can not add two residue different modulo" } + return IntModulo( + (residue + other.residue) % modulus, + modulus, + toCheckInput = false + ) + } + operator fun plus(other: Int): IntModulo = + IntModulo( + (residue + other) % modulus, + modulus, + toCheckInput = false + ) + operator fun minus(other: IntModulo): IntModulo { + require(modulus == other.modulus) { "can not subtract two residue different modulo" } + return IntModulo( + (residue - other.residue) % modulus, + modulus, + toCheckInput = false + ) + } + operator fun minus(other: Int): IntModulo = + IntModulo( + (residue - other) % modulus, + modulus, + toCheckInput = false + ) + operator fun times(other: IntModulo): IntModulo { + require(modulus == other.modulus) { "can not multiply two residue different modulo" } + return IntModulo( + (residue * other.residue) % modulus, + modulus, + toCheckInput = false + ) + } + operator fun times(other: Int): IntModulo = + IntModulo( + (residue * other) % modulus, + modulus, + toCheckInput = false + ) + operator fun div(other: IntModulo): IntModulo { + require(modulus == other.modulus) { "can not divide two residue different modulo" } + val (reciprocalCandidate, gcdOfOtherResidueAndModulus) = bezoutIdentityWithGCD(other.residue, modulus) + require(gcdOfOtherResidueAndModulus == 1) { "can not divide to residue that has non-trivial GCD with modulo" } + return IntModulo( + (residue * reciprocalCandidate) % modulus, + modulus, + toCheckInput = false + ) + } + operator fun div(other: Int): IntModulo { + val (reciprocalCandidate, gcdOfOtherResidueAndModulus) = bezoutIdentityWithGCD(other, modulus) + require(gcdOfOtherResidueAndModulus == 1) { "can not divide to residue that has non-trivial GCD with modulo" } + return IntModulo( + (residue * reciprocalCandidate) % modulus, + modulus, + toCheckInput = false + ) + } + override fun equals(other: Any?): Boolean = + when (other) { + is IntModulo -> residue == other.residue && modulus == other.modulus + else -> false + } + + override fun hashCode(): Int = residue.hashCode() + + override fun toString(): String = "$residue mod $modulus" +} + +@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") +class IntModuloRing : Ring { + + val modulus: Int + + constructor(modulus: Int) { + require(modulus != 0) { "modulus can not be zero" } + this.modulus = if (modulus < 0) -modulus else modulus + } + + override inline val zero: IntModulo get() = IntModulo(0, modulus, toCheckInput = false) + override inline val one: IntModulo get() = IntModulo(1, modulus, toCheckInput = false) + + fun number(arg: Int) = IntModulo(arg, modulus, toCheckInput = false) + + override inline fun add(left: IntModulo, right: IntModulo): IntModulo = left + right + override inline fun multiply(left: IntModulo, right: IntModulo): IntModulo = left * right + + override inline fun IntModulo.unaryMinus(): IntModulo = -this + override inline fun IntModulo.plus(arg: IntModulo): IntModulo = this + arg + override inline fun IntModulo.minus(arg: IntModulo): IntModulo = this - arg + override inline fun IntModulo.times(arg: IntModulo): IntModulo = this * arg + inline fun IntModulo.div(arg: IntModulo): IntModulo = this / arg +} + +fun ListPolynomialSpace.ListPolynomial(vararg coefs: Int): ListPolynomial = + ListPolynomial(coefs.map { IntModulo(it, ring.modulus) }) +fun IntModuloRing.ListPolynomial(vararg coefs: Int): ListPolynomial = + ListPolynomial(coefs.map { IntModulo(it, modulus) }) \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt new file mode 100644 index 000000000..72bb5942c --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt @@ -0,0 +1,135 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.test.misc + +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.Field +import space.kscience.kmath.operations.NumbersAddOps + +class Rational { + companion object { + val ZERO: Rational = Rational(0L) + val ONE: Rational = Rational(1L) + } + + val numerator: Long + val denominator: Long + + internal constructor(numerator: Long, denominator: Long, toCheckInput: Boolean = true) { + if (toCheckInput) { + if (denominator == 0L) throw ArithmeticException("/ by zero") + + val greatestCommonDivider = gcd(numerator, denominator).let { if (denominator < 0L) -it else it } + + this.numerator = numerator / greatestCommonDivider + this.denominator = denominator / greatestCommonDivider + } else { + this.numerator = numerator + this.denominator = denominator + } + } + + constructor(numerator: Int, denominator: Int) : this(numerator.toLong(), denominator.toLong(), true) + constructor(numerator: Int, denominator: Long) : this(numerator.toLong(), denominator, true) + constructor(numerator: Long, denominator: Int) : this(numerator, denominator.toLong(), true) + constructor(numerator: Long, denominator: Long) : this(numerator, denominator, true) + constructor(numerator: Int) : this(numerator.toLong(), 1L, false) + constructor(numerator: Long) : this(numerator, 1L, false) + + operator fun unaryPlus(): Rational = this + operator fun unaryMinus(): Rational = Rational(-this.numerator, this.denominator) + operator fun plus(other: Rational): Rational = + Rational( + numerator * other.denominator + denominator * other.numerator, + denominator * other.denominator + ) + operator fun plus(other: Int): Rational = + Rational( + numerator + denominator * other.toLong(), + denominator + ) + operator fun plus(other: Long): Rational = + Rational( + numerator + denominator * other, + denominator + ) + operator fun minus(other: Rational): Rational = + Rational( + numerator * other.denominator - denominator * other.numerator, + denominator * other.denominator + ) + operator fun minus(other: Int): Rational = + Rational( + numerator - denominator * other.toLong(), + denominator + ) + operator fun minus(other: Long): Rational = + Rational( + numerator - denominator * other, + denominator + ) + operator fun times(other: Rational): Rational = + Rational( + numerator * other.numerator, + denominator * other.denominator + ) + operator fun times(other: Int): Rational = + Rational( + numerator * other.toLong(), + denominator + ) + operator fun times(other: Long): Rational = + Rational( + numerator * other, + denominator + ) + operator fun div(other: Rational): Rational = + Rational( + numerator * other.denominator, + denominator * other.numerator + ) + operator fun div(other: Int): Rational = + Rational( + numerator, + denominator * other.toLong() + ) + operator fun div(other: Long): Rational = + Rational( + numerator, + denominator * other + ) + override fun equals(other: Any?): Boolean = + when (other) { + is Rational -> numerator == other.numerator && denominator == other.denominator + is Int -> numerator == other && denominator == 1L + is Long -> numerator == other && denominator == 1L + else -> false + } + + override fun hashCode(): Int = 31 * numerator.hashCode() + denominator.hashCode() + + override fun toString(): String = if (denominator == 1L) "$numerator" else "$numerator/$denominator" +} + +@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") +@OptIn(UnstableKMathAPI::class) +object RationalField : Field, NumbersAddOps { + override inline val zero: Rational get() = Rational.ZERO + override inline val one: Rational get() = Rational.ONE + + override inline fun number(value: Number): Rational = Rational(value.toLong()) + + override inline fun add(left: Rational, right: Rational): Rational = left + right + override inline fun multiply(left: Rational, right: Rational): Rational = left * right + override inline fun divide(left: Rational, right: Rational): Rational = left / right + override inline fun scale(a: Rational, value: Double): Rational = a * number(value) + + override inline fun Rational.unaryMinus(): Rational = -this + override inline fun Rational.plus(arg: Rational): Rational = this + arg + override inline fun Rational.minus(arg: Rational): Rational = this - arg + override inline fun Rational.times(arg: Rational): Rational = this * arg + override inline fun Rational.div(arg: Rational): Rational = this / arg +} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt new file mode 100644 index 000000000..ed41b9245 --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt @@ -0,0 +1,29 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.test.misc + +import kotlin.math.abs + + +data class BezoutIdentityWithGCD(val first: T, val second: T, val gcd: T) + +tailrec fun gcd(a: Long, b: Long): Long = if (a == 0L) abs(b) else gcd(b % a, a) + +fun bezoutIdentityWithGCD(a: Int, b: Int): BezoutIdentityWithGCD = + when { + a < 0 && b < 0 -> with(bezoutIdentityWithGCDInternalLogic(-a, -b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(-first, -second, gcd) } + a < 0 -> with(bezoutIdentityWithGCDInternalLogic(-a, b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(-first, second, gcd) } + b < 0 -> with(bezoutIdentityWithGCDInternalLogic(a, -b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(first, -second, gcd) } + else -> bezoutIdentityWithGCDInternalLogic(a, b, 1, 0, 0, 1) + } + +internal tailrec fun bezoutIdentityWithGCDInternalLogic(a: Int, b: Int, m1: Int, m2: Int, m3: Int, m4: Int): BezoutIdentityWithGCD = + if (b == 0) BezoutIdentityWithGCD(m1, m3, a) + else { + val quotient = a / b + val reminder = a % b + bezoutIdentityWithGCDInternalLogic(b, reminder, m2, m1 - quotient * m2, m4, m3 - quotient * m4) + } \ No newline at end of file From 5928adfe45fc4b1d608e94fb5b2c12c447377c24 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Mon, 13 Jun 2022 12:08:58 +0300 Subject: [PATCH 12/17] Fixed merging accidents. --- .../kscience/kmath/functions/Piecewise.kt | 132 ++++++++++++++++++ .../kmath/integration/SplineIntegrator.kt | 112 +++++++++++++++ .../kmath/interpolation/Interpolator.kt | 92 ++++++++++++ .../kmath/interpolation/LinearInterpolator.kt | 43 ++++++ .../kmath/interpolation/SplineInterpolator.kt | 88 ++++++++++++ .../kmath/integration/SplineIntegralTest.kt | 48 +++++++ .../interpolation/LinearInterpolatorTest.kt | 29 ++++ .../interpolation/SplineInterpolatorTest.kt | 36 +++++ 8 files changed, 580 insertions(+) create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt new file mode 100644 index 000000000..612b00535 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt @@ -0,0 +1,132 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.functions + +import space.kscience.kmath.misc.PerformancePitfall +import space.kscience.kmath.operations.Ring + +/** + * Represents piecewise-defined function. + * + * @param T the piece key type. + * @param R the sub-function type. + */ +public fun interface Piecewise { + /** + * Returns the appropriate sub-function for given piece key. + */ + public fun findPiece(arg: T): R? +} + +/** + * Represents piecewise-defined function where all the sub-functions are polynomials. + * + * @property pieces An ordered list of range-polynomial pairs. The list does not in general guarantee that there are no + * "holes" in it. + */ +public interface PiecewisePolynomial> : Piecewise> { + public val pieces: Collection, ListPolynomial>> + + override fun findPiece(arg: T): ListPolynomial? +} + +/** + * A generic piecewise without constraints on how pieces are placed + */ +@PerformancePitfall("findPiece method of resulting piecewise is slow") +public fun > PiecewisePolynomial( + pieces: Collection, ListPolynomial>>, +): PiecewisePolynomial = object : PiecewisePolynomial { + override val pieces: Collection, ListPolynomial>> = pieces + + override fun findPiece(arg: T): ListPolynomial? = pieces.firstOrNull { arg in it.first }?.second +} + +/** + * An optimized piecewise that uses not separate pieces, but a range separated by delimiters. + * The pieces search is logarithmic. + */ +private class OrderedPiecewisePolynomial>( + override val pieces: List, ListPolynomial>>, +) : PiecewisePolynomial { + + override fun findPiece(arg: T): ListPolynomial? { + val index = pieces.binarySearch { (range, _) -> + when { + arg >= range.endInclusive -> -1 + arg < range.start -> +1 + else -> 0 + } + } + return if (index < 0) null else pieces[index].second + } + +} + +/** + * A [Piecewise] builder where all the pieces are ordered by the [Comparable] type instances. + * + * @param T the comparable piece key type. + * @param delimiter the initial piecewise separator + */ +public class PiecewiseBuilder>(delimiter: T) { + private val delimiters: MutableList = arrayListOf(delimiter) + private val pieces: MutableList> = arrayListOf() + + /** + * Dynamically adds a piece to the right side (beyond maximum argument value of previous piece) + * + * @param right new rightmost position. If is less than current rightmost position, an error is thrown. + * @param piece the sub-function. + */ + public fun putRight(right: T, piece: ListPolynomial) { + require(right > delimiters.last()) { "New delimiter should be to the right of old one" } + delimiters += right + pieces += piece + } + + /** + * Dynamically adds a piece to the left side (beyond maximum argument value of previous piece) + * + * @param left the new leftmost position. If is less than current rightmost position, an error is thrown. + * @param piece the sub-function. + */ + public fun putLeft(left: T, piece: ListPolynomial) { + require(left < delimiters.first()) { "New delimiter should be to the left of old one" } + delimiters.add(0, left) + pieces.add(0, piece) + } + + public fun build(): PiecewisePolynomial = OrderedPiecewisePolynomial(delimiters.zipWithNext { l, r -> + l..r + }.zip(pieces)) +} + +/** + * A builder for [PiecewisePolynomial] + */ +public fun > PiecewisePolynomial( + startingPoint: T, + builder: PiecewiseBuilder.() -> Unit, +): PiecewisePolynomial = PiecewiseBuilder(startingPoint).apply(builder).build() + +/** + * Return a value of polynomial function with given [ring] a given [arg] or null if argument is outside piecewise + * definition. + */ +public fun , C : Ring> PiecewisePolynomial.substitute(ring: C, arg: T): T? = + findPiece(arg)?.substitute(ring, arg) + +/** + * Convert this polynomial to a function returning nullable value (null if argument is outside piecewise range). + */ +public fun , C : Ring> PiecewisePolynomial.asFunction(ring: C): (T) -> T? = { substitute(ring, it) } + +/** + * Convert this polynomial to a function using [defaultValue] for arguments outside the piecewise range. + */ +public fun , C : Ring> PiecewisePolynomial.asFunction(ring: C, defaultValue: T): (T) -> T = + { substitute(ring, it) ?: defaultValue } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt new file mode 100644 index 000000000..80006c2de --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt @@ -0,0 +1,112 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.integration + +import space.kscience.kmath.functions.PiecewisePolynomial +import space.kscience.kmath.functions.integrate +import space.kscience.kmath.functions.antiderivative +import space.kscience.kmath.interpolation.PolynomialInterpolator +import space.kscience.kmath.interpolation.SplineInterpolator +import space.kscience.kmath.interpolation.interpolatePolynomials +import space.kscience.kmath.misc.PerformancePitfall +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.* +import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.DoubleBuffer +import space.kscience.kmath.structures.MutableBufferFactory + +/** + * Compute analytical indefinite integral of this [PiecewisePolynomial], keeping all intervals intact + */ +@OptIn(PerformancePitfall::class) +@UnstableKMathAPI +public fun > PiecewisePolynomial.integrate(algebra: Field): PiecewisePolynomial = + PiecewisePolynomial(pieces.map { it.first to it.second.antiderivative(algebra) }) + +/** + * Compute definite integral of given [PiecewisePolynomial] piece by piece in a given [range] + * Requires [UnivariateIntegrationNodes] or [IntegrationRange] and [IntegrandMaxCalls] + * + * TODO use context receiver for algebra + */ +@UnstableKMathAPI +public fun > PiecewisePolynomial.integrate( + algebra: Field, range: ClosedRange, +): T = algebra.sum( + pieces.map { (region, poly) -> + val intersectedRange = maxOf(range.start, region.start)..minOf(range.endInclusive, region.endInclusive) + //Check if polynomial range is not used + if (intersectedRange.start == intersectedRange.endInclusive) algebra.zero + else poly.integrate(algebra, intersectedRange) + } +) + +/** + * A generic spline-interpolation-based analytic integration + * * [IntegrationRange]—the univariate range of integration. By default, uses `0..1` interval. + * * [IntegrandMaxCalls]—the maximum number of function calls during integration. For non-iterative rules, always uses + * the maximum number of points. By default, uses 10 points. + */ +@UnstableKMathAPI +public class SplineIntegrator>( + public val algebra: Field, + public val bufferFactory: MutableBufferFactory, +) : UnivariateIntegrator { + override fun process(integrand: UnivariateIntegrand): UnivariateIntegrand = algebra { + val range = integrand.getFeature()?.range ?: 0.0..1.0 + + val interpolator: PolynomialInterpolator = SplineInterpolator(algebra, bufferFactory) + + val nodes: Buffer = integrand.getFeature()?.nodes ?: run { + val numPoints = integrand.getFeature()?.maxCalls ?: 100 + val step = (range.endInclusive - range.start) / (numPoints - 1) + DoubleBuffer(numPoints) { i -> range.start + i * step } + } + + val values = nodes.map(bufferFactory) { integrand.function(it) } + val polynomials = interpolator.interpolatePolynomials( + nodes.map(bufferFactory) { number(it) }, + values + ) + val res = polynomials.integrate(algebra, number(range.start)..number(range.endInclusive)) + integrand + IntegrandValue(res) + IntegrandCallsPerformed(integrand.calls + nodes.size) + } +} + +/** + * A simplified double-based spline-interpolation-based analytic integration + * * [IntegrationRange]—the univariate range of integration. By default, uses `0.0..1.0` interval. + * * [IntegrandMaxCalls]—the maximum number of function calls during integration. For non-iterative rules, always + * uses the maximum number of points. By default, uses 10 points. + */ +@UnstableKMathAPI +public object DoubleSplineIntegrator : UnivariateIntegrator { + override fun process(integrand: UnivariateIntegrand): UnivariateIntegrand { + val range = integrand.getFeature()?.range ?: 0.0..1.0 + val interpolator: PolynomialInterpolator = SplineInterpolator(DoubleField, ::DoubleBuffer) + + val nodes: Buffer = integrand.getFeature()?.nodes ?: run { + val numPoints = integrand.getFeature()?.maxCalls ?: 100 + val step = (range.endInclusive - range.start) / (numPoints - 1) + DoubleBuffer(numPoints) { i -> range.start + i * step } + } + + val values = nodes.map { integrand.function(it) } + val polynomials = interpolator.interpolatePolynomials(nodes, values) + val res = polynomials.integrate(DoubleField, range) + return integrand + IntegrandValue(res) + IntegrandCallsPerformed(integrand.calls + nodes.size) + } +} + +@Suppress("unused") +@UnstableKMathAPI +public inline val DoubleField.splineIntegrator: UnivariateIntegrator + get() = DoubleSplineIntegrator \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt new file mode 100644 index 000000000..62819be0c --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt @@ -0,0 +1,92 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +@file:OptIn(UnstableKMathAPI::class) + +package space.kscience.kmath.interpolation + +import space.kscience.kmath.data.XYColumnarData +import space.kscience.kmath.functions.PiecewisePolynomial +import space.kscience.kmath.functions.asFunction +import space.kscience.kmath.functions.substitute +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.Ring +import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.asBuffer + +/** + * And interpolator for data with x column type [X], y column type [Y]. + */ +public fun interface Interpolator { + public fun interpolate(points: XYColumnarData): (X) -> Y +} + +/** + * And interpolator returning [PiecewisePolynomial] function + */ +public interface PolynomialInterpolator> : Interpolator { + public val algebra: Ring + + public fun getDefaultValue(): T = error("Out of bounds") + + public fun interpolatePolynomials(points: XYColumnarData): PiecewisePolynomial + + override fun interpolate(points: XYColumnarData): (T) -> T = { x -> + interpolatePolynomials(points).substitute(algebra, x) ?: getDefaultValue() + } +} + + +public fun > PolynomialInterpolator.interpolatePolynomials( + x: Buffer, + y: Buffer, +): PiecewisePolynomial { + val pointSet = XYColumnarData.of(x, y) + return interpolatePolynomials(pointSet) +} + +public fun > PolynomialInterpolator.interpolatePolynomials( + data: Map, +): PiecewisePolynomial { + val pointSet = XYColumnarData.of(data.keys.toList().asBuffer(), data.values.toList().asBuffer()) + return interpolatePolynomials(pointSet) +} + +public fun > PolynomialInterpolator.interpolatePolynomials( + data: List>, +): PiecewisePolynomial { + val pointSet = XYColumnarData.of(data.map { it.first }.asBuffer(), data.map { it.second }.asBuffer()) + return interpolatePolynomials(pointSet) +} + +public fun > PolynomialInterpolator.interpolate( + x: Buffer, + y: Buffer, +): (T) -> T? = interpolatePolynomials(x, y).asFunction(algebra) + +public fun > PolynomialInterpolator.interpolate( + data: Map, +): (T) -> T? = interpolatePolynomials(data).asFunction(algebra) + +public fun > PolynomialInterpolator.interpolate( + data: List>, +): (T) -> T? = interpolatePolynomials(data).asFunction(algebra) + + +public fun > PolynomialInterpolator.interpolate( + x: Buffer, + y: Buffer, + defaultValue: T, +): (T) -> T = interpolatePolynomials(x, y).asFunction(algebra, defaultValue) + +public fun > PolynomialInterpolator.interpolate( + data: Map, + defaultValue: T, +): (T) -> T = interpolatePolynomials(data).asFunction(algebra, defaultValue) + +public fun > PolynomialInterpolator.interpolate( + data: List>, + defaultValue: T, +): (T) -> T = interpolatePolynomials(data).asFunction(algebra, defaultValue) \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt new file mode 100644 index 000000000..b55f16cf2 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt @@ -0,0 +1,43 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.interpolation + +import space.kscience.kmath.data.XYColumnarData +import space.kscience.kmath.functions.PiecewisePolynomial +import space.kscience.kmath.functions.ListPolynomial +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.Field +import space.kscience.kmath.operations.invoke + +@OptIn(UnstableKMathAPI::class) +internal fun > insureSorted(points: XYColumnarData<*, T, *>) { + for (i in 0 until points.size - 1) + require(points.x[i + 1] > points.x[i]) { "Input data is not sorted at index $i" } +} + +/** + * Reference JVM implementation: https://github.com/apache/commons-math/blob/master/src/main/java/org/apache/commons/math4/analysis/interpolation/LinearInterpolator.java + */ +public class LinearInterpolator>(override val algebra: Field) : PolynomialInterpolator { + + @OptIn(UnstableKMathAPI::class) + override fun interpolatePolynomials(points: XYColumnarData): PiecewisePolynomial = algebra { + require(points.size > 0) { "Point array should not be empty" } + insureSorted(points) + + PiecewisePolynomial(points.x[0]) { + for (i in 0 until points.size - 1) { + val slope = (points.y[i + 1] - points.y[i]) / (points.x[i + 1] - points.x[i]) + val const = points.y[i] - slope * points.x[i] + val polynomial = ListPolynomial(const, slope) + putRight(points.x[i + 1], polynomial) + } + } + } +} + +public val > Field.linearInterpolator: LinearInterpolator + get() = LinearInterpolator(this) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt new file mode 100644 index 000000000..0bcbfd0c6 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt @@ -0,0 +1,88 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.interpolation + +import space.kscience.kmath.data.XYColumnarData +import space.kscience.kmath.functions.PiecewisePolynomial +import space.kscience.kmath.functions.ListPolynomial +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.operations.Field +import space.kscience.kmath.operations.invoke +import space.kscience.kmath.structures.DoubleBuffer +import space.kscience.kmath.structures.MutableBufferFactory + +/** + * Generic spline interpolator. Not recommended for performance critical places, use platform-specific and type + * specific ones. + * + * Based on + * https://github.com/apache/commons-math/blob/eb57d6d457002a0bb5336d789a3381a24599affe/src/main/java/org/apache/commons/math4/analysis/interpolation/SplineInterpolator.java + */ +public class SplineInterpolator>( + override val algebra: Field, + public val bufferFactory: MutableBufferFactory, +) : PolynomialInterpolator { + //TODO possibly optimize zeroed buffers + + @OptIn(UnstableKMathAPI::class) + override fun interpolatePolynomials(points: XYColumnarData): PiecewisePolynomial = algebra { + require(points.size >= 3) { "Can't use spline interpolator with less than 3 points" } + insureSorted(points) + // Number of intervals. The number of data points is n + 1. + val n = points.size - 1 + // Differences between knot points + val h = bufferFactory(n) { i -> points.x[i + 1] - points.x[i] } + val mu = bufferFactory(n) { zero } + val z = bufferFactory(n + 1) { zero } + + for (i in 1 until n) { + val g = 2.0 * (points.x[i + 1] - points.x[i - 1]) - h[i - 1] * mu[i - 1] + mu[i] = h[i] / g + z[i] = + ((points.y[i + 1] * h[i - 1] - points.y[i] * (points.x[i + 1] - points.x[i - 1]) + points.y[i - 1] * h[i]) * 3.0 / + (h[i - 1] * h[i]) - h[i - 1] * z[i - 1]) / g + } + + // cubic spline coefficients -- b is linear, c quadratic, d is cubic (original y's are constants) + + PiecewisePolynomial(points.x[points.size - 1]) { + var cOld = zero + + for (j in n - 1 downTo 0) { + val c = z[j] - mu[j] * cOld + val a = points.y[j] + val b = (points.y[j + 1] - points.y[j]) / h[j] - h[j] * (cOld + 2.0 * c) / 3.0 + val d = (cOld - c) / (3.0 * h[j]) + val x0 = points.x[j] + val x02 = x0 * x0 + val x03 = x02 * x0 + //Shift coefficients to represent absolute polynomial instead of one with an offset + val polynomial = ListPolynomial( + a - b * x0 + c * x02 - d * x03, + b - 2 * c * x0 + 3 * d * x02, + c - 3 * d * x0, + d + ) + cOld = c + putLeft(x0, polynomial) + } + } + } +} + + +public fun > Field.splineInterpolator( + bufferFactory: MutableBufferFactory, +): SplineInterpolator = SplineInterpolator(this, bufferFactory) + +public val DoubleField.splineInterpolator: SplineInterpolator + get() = SplineInterpolator(this, ::DoubleBuffer) \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt new file mode 100644 index 000000000..aae0ad017 --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt @@ -0,0 +1,48 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.integration + +import space.kscience.kmath.functions.ListPolynomial +import space.kscience.kmath.functions.integrate +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.DoubleField +import kotlin.math.PI +import kotlin.math.sin +import kotlin.test.Test +import kotlin.test.assertEquals + +@OptIn(UnstableKMathAPI::class) +class SplineIntegralTest { + + @Test + fun integratePolynomial(){ + val polynomial = ListPolynomial(1.0, 2.0, 3.0) + val integral = polynomial.integrate(DoubleField,1.0..2.0) + assertEquals(11.0, integral, 0.001) + } + + @Test + fun gaussSin() { + val res = DoubleField.splineIntegrator.integrate(0.0..2 * PI, IntegrandMaxCalls(5)) { x -> + sin(x) + } + assertEquals(0.0, res.value, 1e-2) + } + + @Test + fun gaussUniform() { + val res = DoubleField.splineIntegrator.integrate(35.0..100.0, IntegrandMaxCalls(20)) { x -> + if(x in 30.0..50.0){ + 1.0 + } else { + 0.0 + } + } + assertEquals(15.0, res.value, 0.5) + } + + +} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt new file mode 100644 index 000000000..1143036d4 --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt @@ -0,0 +1,29 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.interpolation + +import space.kscience.kmath.operations.DoubleField +import kotlin.test.Test +import kotlin.test.assertEquals + +internal class LinearInterpolatorTest { + @Test + fun testInterpolation() { + val data = listOf( + 0.0 to 0.0, + 1.0 to 1.0, + 2.0 to 3.0, + 3.0 to 4.0 + ) + + //val polynomial: PiecewisePolynomial = DoubleField.linearInterpolator.interpolatePolynomials(data) + val function = DoubleField.linearInterpolator.interpolate(data) + assertEquals(null, function(-1.0)) + assertEquals(0.5, function(0.5)) + assertEquals(2.0, function(1.5)) + assertEquals(3.0, function(2.0)) + } +} diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt new file mode 100644 index 000000000..f748535e2 --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt @@ -0,0 +1,36 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.interpolation + +import space.kscience.kmath.operations.DoubleField +import kotlin.math.PI +import kotlin.math.sin +import kotlin.test.Test +import kotlin.test.assertEquals + +internal class SplineInterpolatorTest { + @Test + fun testInterpolation() { + val data = (0..10).map { + val x = it.toDouble() / 5 * PI + x to sin(x) + } + + //val polynomial: PiecewisePolynomial = DoubleField.splineInterpolator.interpolatePolynomials(data) + + val function = DoubleField.splineInterpolator.interpolate(data, Double.NaN) + + assertEquals(Double.NaN, function(-1.0)) + assertEquals(sin(0.5), function(0.5), 0.1) + assertEquals(sin(1.5), function(1.5), 0.1) + assertEquals(sin(2.0), function(2.0), 0.1) + } +} From 58e0715714487323a46f5b86e121a46782d356c5 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Mon, 13 Jun 2022 12:15:14 +0300 Subject: [PATCH 13/17] Removed duplicates of copyright comments. --- .../space/kscience/kmath/integration/SplineIntegrator.kt | 5 ----- .../space/kscience/kmath/interpolation/SplineInterpolator.kt | 5 ----- .../kscience/kmath/interpolation/SplineInterpolatorTest.kt | 5 ----- 3 files changed, 15 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt index 80006c2de..0fcd4c6e5 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt @@ -3,11 +3,6 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - package space.kscience.kmath.integration import space.kscience.kmath.functions.PiecewisePolynomial diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt index 0bcbfd0c6..48c90ff23 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt @@ -3,11 +3,6 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - package space.kscience.kmath.interpolation import space.kscience.kmath.data.XYColumnarData diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt index f748535e2..4c7d816d4 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt @@ -3,11 +3,6 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - package space.kscience.kmath.interpolation import space.kscience.kmath.operations.DoubleField From d0134bdbe9eb65b45f3764c775e657ee0186d163 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Tue, 14 Jun 2022 19:15:36 +0300 Subject: [PATCH 14/17] Sift 4. Cleaned up "numbered" case. Tests are in progress. --- .../kmath/operations/bufferOperation.kt | 9 + .../kmath/functions/ListPolynomial.kt | 24 +- .../kmath/functions/ListRationalFunction.kt | 34 +- .../kmath/functions/NumberedPolynomial.kt | 429 +++++++++++++++ .../functions/NumberedRationalFunction.kt | 239 ++++++++ .../kmath/functions/RationalFunction.kt | 8 + .../kscience/kmath/functions/listUtil.kt | 43 +- .../kmath/functions/numberedConstructors.kt | 478 ++++++++++++++++ .../kscience/kmath/functions/numberedUtil.kt | 515 ++++++++++++++++++ 9 files changed, 1724 insertions(+), 55 deletions(-) create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/bufferOperation.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/bufferOperation.kt index 31b0c2841..762f08be1 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/bufferOperation.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/bufferOperation.kt @@ -91,6 +91,15 @@ public inline fun Buffer.fold(initial: R, operation: (acc: R, T) return accumulator } +/** + * Fold given buffer according to indexed [operation] + */ +public inline fun Buffer.foldIndexed(initial: R, operation: (index: Int, acc: R, T) -> R): R { + var accumulator = initial + for (index in this.indices) accumulator = operation(index, accumulator, get(index)) + return accumulator +} + /** * Zip two buffers using given [transform]. */ diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt index fce179fc8..42e3f7301 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt @@ -48,8 +48,8 @@ public data class ListPolynomial( } /** - * Arithmetic context for univariate polynomials with coefficients stored as a [List] constructed with the given [ring] - * of constants. + * Arithmetic context for univariate polynomials with coefficients stored as a [List] constructed with the provided + * [ring] of constants. * * @param C the type of constants. Polynomials have them a coefficients in their terms. * @param A type of provided underlying ring of constants. It's [Ring] of [C]. @@ -313,6 +313,10 @@ public open class ListPolynomialSpace>( } ) } + /** + * Raises [arg] to the integer power [exponent]. + */ // TODO: To optimize boxing + override fun power(arg: ListPolynomial, exponent: UInt): ListPolynomial = super.power(arg, exponent) /** * Instance of zero polynomial (zero of the polynomial ring). @@ -332,42 +336,42 @@ public open class ListPolynomialSpace>( // TODO: When context receivers will be ready move all of this substitutions and invocations to utilities with // [ListPolynomialSpace] as a context receiver /** - * Evaluates value of [this] polynomial on provided argument. + * Evaluates value of [this] polynomial on provided [argument]. */ @Suppress("NOTHING_TO_INLINE") - public inline fun ListPolynomial.substitute(argument: C): C = this.substitute(ring, argument) + public inline fun ListPolynomial.substitute(argument: C): C = substitute(ring, argument) /** * Substitutes provided polynomial [argument] into [this] polynomial. */ @Suppress("NOTHING_TO_INLINE") - public inline fun ListPolynomial.substitute(argument: ListPolynomial): ListPolynomial = this.substitute(ring, argument) + public inline fun ListPolynomial.substitute(argument: ListPolynomial): ListPolynomial = substitute(ring, argument) /** * Represent [this] polynomial as a regular context-less function. */ @Suppress("NOTHING_TO_INLINE") - public inline fun ListPolynomial.asFunction(): (C) -> C = { this.substitute(ring, it) } + public inline fun ListPolynomial.asFunction(): (C) -> C = asFunctionOver(ring) /** * Represent [this] polynomial as a regular context-less function. */ @Suppress("NOTHING_TO_INLINE") - public inline fun ListPolynomial.asFunctionOfConstant(): (C) -> C = { this.substitute(ring, it) } + public inline fun ListPolynomial.asFunctionOfConstant(): (C) -> C = asFunctionOfConstantOver(ring) /** * Represent [this] polynomial as a regular context-less function. */ @Suppress("NOTHING_TO_INLINE") - public inline fun ListPolynomial.asFunctionOfPolynomial(): (ListPolynomial) -> ListPolynomial = { this.substitute(ring, it) } + public inline fun ListPolynomial.asFunctionOfPolynomial(): (ListPolynomial) -> ListPolynomial = asFunctionOfPolynomialOver(ring) /** * Evaluates value of [this] polynomial on provided [argument]. */ @Suppress("NOTHING_TO_INLINE") - public inline operator fun ListPolynomial.invoke(argument: C): C = this.substitute(ring, argument) + public inline operator fun ListPolynomial.invoke(argument: C): C = substitute(ring, argument) /** * Evaluates value of [this] polynomial on provided [argument]. */ @Suppress("NOTHING_TO_INLINE") - public inline operator fun ListPolynomial.invoke(argument: ListPolynomial): ListPolynomial = this.substitute(ring, argument) + public inline operator fun ListPolynomial.invoke(argument: ListPolynomial): ListPolynomial = substitute(ring, argument) } /** diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt index f3e352bcd..e23baa548 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt @@ -9,7 +9,7 @@ import space.kscience.kmath.operations.Ring /** - * Represents rational function that stores its numerator and denominator as [ListPolynomial]s. + * Represents univariate rational function that stores its numerator and denominator as [ListPolynomial]s. */ public data class ListRationalFunction( public override val numerator: ListPolynomial, @@ -56,82 +56,82 @@ public class ListRationalFunctionSpace> ( * Evaluates value of [this] polynomial on provided argument. */ @Suppress("NOTHING_TO_INLINE") - public inline fun ListPolynomial.substitute(argument: C): C = this.substitute(ring, argument) + public inline fun ListPolynomial.substitute(argument: C): C = substitute(ring, argument) /** * Substitutes provided polynomial [argument] into [this] polynomial. */ @Suppress("NOTHING_TO_INLINE") - public inline fun ListPolynomial.substitute(argument: ListPolynomial): ListPolynomial = this.substitute(ring, argument) + public inline fun ListPolynomial.substitute(argument: ListPolynomial): ListPolynomial = substitute(ring, argument) /** * Substitutes provided rational function [argument] into [this] polynomial. */ @Suppress("NOTHING_TO_INLINE") - public inline fun ListPolynomial.substitute(argument: ListRationalFunction): ListRationalFunction = this.substitute(ring, argument) + public inline fun ListPolynomial.substitute(argument: ListRationalFunction): ListRationalFunction = substitute(ring, argument) /** * Substitutes provided polynomial [argument] into [this] rational function. */ @Suppress("NOTHING_TO_INLINE") - public inline fun ListRationalFunction.substitute(argument: ListPolynomial): ListRationalFunction = this.substitute(ring, argument) + public inline fun ListRationalFunction.substitute(argument: ListPolynomial): ListRationalFunction = substitute(ring, argument) /** * Substitutes provided rational function [argument] into [this] rational function. */ @Suppress("NOTHING_TO_INLINE") - public inline fun ListRationalFunction.substitute(argument: ListRationalFunction): ListRationalFunction = this.substitute(ring, argument) + public inline fun ListRationalFunction.substitute(argument: ListRationalFunction): ListRationalFunction = substitute(ring, argument) /** * Represent [this] polynomial as a regular context-less function. */ @Suppress("NOTHING_TO_INLINE") - public inline fun ListPolynomial.asFunction(): (C) -> C = { this.substitute(ring, it) } + public inline fun ListPolynomial.asFunction(): (C) -> C = { substitute(ring, it) } /** * Represent [this] polynomial as a regular context-less function. */ @Suppress("NOTHING_TO_INLINE") - public inline fun ListPolynomial.asFunctionOfConstant(): (C) -> C = { this.substitute(ring, it) } + public inline fun ListPolynomial.asFunctionOfConstant(): (C) -> C = { substitute(ring, it) } /** * Represent [this] polynomial as a regular context-less function. */ @Suppress("NOTHING_TO_INLINE") - public inline fun ListPolynomial.asFunctionOfPolynomial(): (ListPolynomial) -> ListPolynomial = { this.substitute(ring, it) } + public inline fun ListPolynomial.asFunctionOfPolynomial(): (ListPolynomial) -> ListPolynomial = { substitute(ring, it) } /** * Represent [this] polynomial as a regular context-less function. */ @Suppress("NOTHING_TO_INLINE") - public inline fun ListPolynomial.asFunctionOfRationalFunction(): (ListRationalFunction) -> ListRationalFunction = { this.substitute(ring, it) } + public inline fun ListPolynomial.asFunctionOfRationalFunction(): (ListRationalFunction) -> ListRationalFunction = { substitute(ring, it) } /** * Represent [this] rational function as a regular context-less function. */ @Suppress("NOTHING_TO_INLINE") - public inline fun ListRationalFunction.asFunctionOfPolynomial(): (ListPolynomial) -> ListRationalFunction = { this.substitute(ring, it) } + public inline fun ListRationalFunction.asFunctionOfPolynomial(): (ListPolynomial) -> ListRationalFunction = { substitute(ring, it) } /** * Represent [this] rational function as a regular context-less function. */ @Suppress("NOTHING_TO_INLINE") - public inline fun ListRationalFunction.asFunctionOfRationalFunction(): (ListRationalFunction) -> ListRationalFunction = { this.substitute(ring, it) } + public inline fun ListRationalFunction.asFunctionOfRationalFunction(): (ListRationalFunction) -> ListRationalFunction = { substitute(ring, it) } /** * Evaluates value of [this] polynomial on provided argument. */ @Suppress("NOTHING_TO_INLINE") - public inline operator fun ListPolynomial.invoke(argument: C): C = this.substitute(ring, argument) + public inline operator fun ListPolynomial.invoke(argument: C): C = substitute(ring, argument) /** * Evaluates value of [this] polynomial on provided argument. */ @Suppress("NOTHING_TO_INLINE") - public inline operator fun ListPolynomial.invoke(argument: ListPolynomial): ListPolynomial = this.substitute(ring, argument) + public inline operator fun ListPolynomial.invoke(argument: ListPolynomial): ListPolynomial = substitute(ring, argument) /** * Evaluates value of [this] polynomial on provided argument. */ @Suppress("NOTHING_TO_INLINE") - public inline operator fun ListPolynomial.invoke(argument: ListRationalFunction): ListRationalFunction = this.substitute(ring, argument) + public inline operator fun ListPolynomial.invoke(argument: ListRationalFunction): ListRationalFunction = substitute(ring, argument) /** * Evaluates value of [this] rational function on provided argument. */ @Suppress("NOTHING_TO_INLINE") - public inline operator fun ListRationalFunction.invoke(argument: ListPolynomial): ListRationalFunction = this.substitute(ring, argument) + public inline operator fun ListRationalFunction.invoke(argument: ListPolynomial): ListRationalFunction = substitute(ring, argument) /** * Evaluates value of [this] rational function on provided argument. */ @Suppress("NOTHING_TO_INLINE") - public inline operator fun ListRationalFunction.invoke(argument: ListRationalFunction): ListRationalFunction = this.substitute(ring, argument) + public inline operator fun ListRationalFunction.invoke(argument: ListRationalFunction): ListRationalFunction = substitute(ring, argument) } \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt new file mode 100644 index 000000000..9304e66da --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -0,0 +1,429 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.functions + +import space.kscience.kmath.operations.Ring +import space.kscience.kmath.structures.Buffer +import kotlin.jvm.JvmName +import kotlin.math.max + + +/** + * Represents univariate polynomial that stores its coefficients in a [Map] and terms' signatures in a [List]. + * + * @param C the type of constants. + */ +public data class NumberedPolynomial +@PublishedApi +internal constructor( + /** + * Map that contains coefficients of the polynomial. Every monomial `a x_1^{d_1} ... x_n^{d_n}` is stored as pair + * "key-value" in the map, where the value is the coefficients `a` and the key is a list that associates index of + * every variable in the monomial with multiplicity of the variable occurring in the monomial. For example + * coefficients of a polynomial `5 x_1^2 x_3^3 - 6 x_2` can be represented as + * ``` + * mapOf( + * listOf(2, 0, 3) to 5, // 5 x_1^2 x_3^3 + + * listOf(0, 1) to (-6), // (-6) x_2^1 + * ) + * ``` + * and also as + * ``` + * mapOf( + * listOf(2, 0, 3) to 5, // 5 x_1^2 x_3^3 + + * listOf(0, 1) to (-6), // (-6) x_2^1 + * listOf(0, 1, 1) to 0, // 0 x_2^1 x_3^1 + * ) + * ``` + * It is not prohibited to put extra zero monomials into the map (as for `0 x_2 x_3` in the example). But the + * bigger the coefficients map the worse performance of arithmetical operations performed on it. Thus, it is + * recommended not to put (or even to remove) extra (or useless) monomials in the coefficients map. + */ + public val coefficients: Map, C> +) : Polynomial { + override fun toString(): String = "NumberedPolynomial$coefficients" +} + +/** + * Arithmetic context for multivariate polynomials with coefficients stored as a [Map] and terms' signatures stored as a + * [List] constructed with the provided [ring] of constants. + * + * @param C the type of constants. Polynomials have them a coefficients in their terms. + * @param A type of provided underlying ring of constants. It's [Ring] of [C]. + * @param ring underlying ring of constants of type [A]. + */ +public class NumberedPolynomialSpace>( + public override val ring: A, +) : PolynomialSpaceOverRing, A> { + /** + * Returns sum of the polynomial and the integer represented as a polynomial. + * + * The operation is equivalent to adding [other] copies of unit polynomial to [this]. + */ + public override operator fun NumberedPolynomial.plus(other: Int): NumberedPolynomial = + if (other == 0) this + else + NumberedPolynomialAsIs( + coefficients + .toMutableMap() + .apply { + val degs = emptyList() + + this[degs] = getOrElse(degs) { constantZero } + other + } + ) + /** + * Returns difference between the polynomial and the integer represented as a polynomial. + * + * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. + */ + public override operator fun NumberedPolynomial.minus(other: Int): NumberedPolynomial = + if (other == 0) this + else + NumberedPolynomialAsIs( + coefficients + .toMutableMap() + .apply { + val degs = emptyList() + + this[degs] = getOrElse(degs) { constantZero } - other + } + ) + /** + * Returns product of the polynomial and the integer represented as a polynomial. + * + * The operation is equivalent to sum of [other] copies of [this]. + */ + public override operator fun NumberedPolynomial.times(other: Int): NumberedPolynomial = + if (other == 0) zero + else NumberedPolynomialAsIs( + coefficients + .toMutableMap() + .apply { + for (degs in keys) this[degs] = this[degs]!! * other + } + ) + + /** + * Returns sum of the integer represented as a polynomial and the polynomial. + * + * The operation is equivalent to adding [this] copies of unit polynomial to [other]. + */ + public override operator fun Int.plus(other: NumberedPolynomial): NumberedPolynomial = + if (this == 0) other + else + NumberedPolynomialAsIs( + other.coefficients + .toMutableMap() + .apply { + val degs = emptyList() + + this[degs] = this@plus + getOrElse(degs) { constantZero } + } + ) + /** + * Returns difference between the integer represented as a polynomial and the polynomial. + * + * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. + */ + public override operator fun Int.minus(other: NumberedPolynomial): NumberedPolynomial = + if (this == 0) other + else + NumberedPolynomialAsIs( + other.coefficients + .toMutableMap() + .apply { + val degs = emptyList() + + this[degs] = this@minus - getOrElse(degs) { constantZero } + } + ) + /** + * Returns product of the integer represented as a polynomial and the polynomial. + * + * The operation is equivalent to sum of [this] copies of [other]. + */ + public override operator fun Int.times(other: NumberedPolynomial): NumberedPolynomial = + if (this == 0) zero + else NumberedPolynomialAsIs( + other.coefficients + .toMutableMap() + .apply { + for (degs in keys) this[degs] = this@times * this[degs]!! + } + ) + + /** + * Converts the integer [value] to polynomial. + */ + public override fun number(value: Int): NumberedPolynomial = number(constantNumber(value)) + + /** + * Returns sum of the constant represented as a polynomial and the polynomial. + */ + override operator fun C.plus(other: NumberedPolynomial): NumberedPolynomial = + with(other.coefficients) { + if (isEmpty()) NumberedPolynomialAsIs(mapOf(emptyList() to this@plus)) + else NumberedPolynomialAsIs( + toMutableMap() + .apply { + val degs = emptyList() + + this[degs] = this@plus + getOrElse(degs) { constantZero } + } + ) + } + /** + * Returns difference between the constant represented as a polynomial and the polynomial. + */ + override operator fun C.minus(other: NumberedPolynomial): NumberedPolynomial = + with(other.coefficients) { + if (isEmpty()) NumberedPolynomialAsIs(mapOf(emptyList() to this@minus)) + else NumberedPolynomialAsIs( + toMutableMap() + .apply { + forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } + + val degs = emptyList() + + this[degs] = this@minus - getOrElse(degs) { constantZero } + } + ) + } + /** + * Returns product of the constant represented as a polynomial and the polynomial. + */ + override operator fun C.times(other: NumberedPolynomial): NumberedPolynomial = + NumberedPolynomialAsIs( + other.coefficients + .toMutableMap() + .apply { + for (degs in keys) this[degs] = this@times * this[degs]!! + } + ) + + /** + * Returns sum of the constant represented as a polynomial and the polynomial. + */ + override operator fun NumberedPolynomial.plus(other: C): NumberedPolynomial = + with(coefficients) { + if (isEmpty()) NumberedPolynomialAsIs(mapOf(emptyList() to other)) + else NumberedPolynomialAsIs( + toMutableMap() + .apply { + val degs = emptyList() + + this[degs] = getOrElse(degs) { constantZero } + other + } + ) + } + /** + * Returns difference between the constant represented as a polynomial and the polynomial. + */ + override operator fun NumberedPolynomial.minus(other: C): NumberedPolynomial = + with(coefficients) { + if (isEmpty()) NumberedPolynomialAsIs(mapOf(emptyList() to other)) + else NumberedPolynomialAsIs( + toMutableMap() + .apply { + val degs = emptyList() + + this[degs] = getOrElse(degs) { constantZero } - other + } + ) + } + /** + * Returns product of the constant represented as a polynomial and the polynomial. + */ + override operator fun NumberedPolynomial.times(other: C): NumberedPolynomial = + NumberedPolynomialAsIs( + coefficients + .toMutableMap() + .apply { + for (degs in keys) this[degs] = this[degs]!! * other + } + ) + + /** + * Converts the constant [value] to polynomial. + */ + public override fun number(value: C): NumberedPolynomial = + NumberedPolynomialAsIs(mapOf(emptyList() to value)) + + /** + * Returns negation of the polynomial. + */ + override fun NumberedPolynomial.unaryMinus(): NumberedPolynomial = + NumberedPolynomialAsIs( + coefficients.mapValues { -it.value } + ) + /** + * Returns sum of the polynomials. + */ + override operator fun NumberedPolynomial.plus(other: NumberedPolynomial): NumberedPolynomial = + NumberedPolynomialAsIs( + buildMap(coefficients.size + other.coefficients.size) { + other.coefficients.mapValuesTo(this) { it.value } + other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! + value else value } + } + ) + /** + * Returns difference of the polynomials. + */ + override operator fun NumberedPolynomial.minus(other: NumberedPolynomial): NumberedPolynomial = + NumberedPolynomialAsIs( + buildMap(coefficients.size + other.coefficients.size) { + other.coefficients.mapValuesTo(this) { it.value } + other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! - value else -value } + } + ) + /** + * Returns product of the polynomials. + */ + override operator fun NumberedPolynomial.times(other: NumberedPolynomial): NumberedPolynomial = + NumberedPolynomialAsIs( + buildMap(coefficients.size * other.coefficients.size) { + for ((degs1, c1) in coefficients) for ((degs2, c2) in other.coefficients) { + val degs = + (0..max(degs1.lastIndex, degs2.lastIndex)) + .map { degs1.getOrElse(it) { 0U } + degs2.getOrElse(it) { 0U } } + val c = c1 * c2 + this[degs] = if (degs in this) this[degs]!! + c else c + } + } + ) + /** + * Raises [arg] to the integer power [exponent]. + */ // TODO: To optimize boxing + override fun power(arg: NumberedPolynomial, exponent: UInt): NumberedPolynomial = super.power(arg, exponent) + + /** + * Instance of zero polynomial (zero of the polynomial ring). + */ + override val zero: NumberedPolynomial = NumberedPolynomialAsIs(emptyMap()) + /** + * Instance of unit polynomial (unit of the polynomial ring). + */ + override val one: NumberedPolynomial by lazy { + NumberedPolynomialAsIs( + mapOf( + emptyList() to constantOne // 1 * x_1^0 * x_2^0 * ... + ) + ) + } + + /** + * Maximal index (ID) of variable occurring in the polynomial with positive power. If there is no such variable, + * the result is `-1`. + */ + public val NumberedPolynomial.lastVariable: Int + get() = coefficients.entries.maxOfOrNull { (degs, _) -> degs.lastIndex } ?: -1 + /** + * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is + * zero, degree is -1. + */ + override val NumberedPolynomial.degree: Int + get() = coefficients.entries.maxOfOrNull { (degs, _) -> degs.sum().toInt() } ?: -1 + /** + * List that associates indices of variables (that appear in the polynomial in positive exponents) with their most + * exponents in which the variables are appeared in the polynomial. + * + * As consequence all values in the list are non-negative integers. Also, if the polynomial is constant, the list is empty. + * And last index of the list is [lastVariable]. + */ + public val NumberedPolynomial.degrees: List + get() = + MutableList(lastVariable + 1) { 0u }.apply { + coefficients.entries.forEach { (degs, _) -> + degs.forEachIndexed { index, deg -> + this[index] = max(this[index], deg) + } + } + } + /** + * Counts degree of the polynomial by the specified [variable]. + */ + public fun NumberedPolynomial.degreeBy(variable: Int): UInt = + coefficients.entries.maxOfOrNull { (degs, _) -> degs.getOrElse(variable) { 0u } } ?: 0u + /** + * Counts degree of the polynomial by the specified [variables]. + */ + public fun NumberedPolynomial.degreeBy(variables: Collection): UInt = + coefficients.entries.maxOfOrNull { (degs, _) -> + degs.withIndex().filter { (index, _) -> index in variables }.sumOf { it.value } + } ?: 0u + /** + * Count of variables occurring in the polynomial with positive power. If there is no such variable, + * the result is `0`. + */ + public val NumberedPolynomial.countOfVariables: Int + get() = + MutableList(lastVariable + 1) { false }.apply { + coefficients.entries.forEach { (degs, _) -> + degs.forEachIndexed { index, deg -> + if (deg != 0u) this[index] = true + } + } + }.count { it } + + // TODO: When context receivers will be ready move all of this substitutions and invocations to utilities with + // [ListPolynomialSpace] as a context receiver + /** + * Substitutes provided arguments [arguments] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.substitute(arguments: Map): NumberedPolynomial = substitute(ring, arguments) + /** + * Substitutes provided arguments [arguments] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + @JvmName("substitutePolynomial") + public inline fun NumberedPolynomial.substitute(arguments: Map>) : NumberedPolynomial = substitute(ring, arguments) + /** + * Substitutes provided arguments [arguments] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.substitute(arguments: Buffer): NumberedPolynomial = substitute(ring, arguments) + /** + * Substitutes provided arguments [arguments] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + @JvmName("substitutePolynomial") + public inline fun NumberedPolynomial.substitute(arguments: Buffer>) : NumberedPolynomial = substitute(ring, arguments) + /** + * Substitutes provided arguments [arguments] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.substituteFully(arguments: Buffer): C = this.substituteFully(ring, arguments) + + /** + * Represent [this] polynomial as a regular context-less function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.asFunction(): (Buffer) -> C = asFunctionOver(ring) + /** + * Represent [this] polynomial as a regular context-less function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.asFunctionOfConstant(): (Buffer) -> C = asFunctionOfConstantOver(ring) + /** + * Represent [this] polynomial as a regular context-less function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.asFunctionOfPolynomial(): (Buffer>) -> NumberedPolynomial = asFunctionOfPolynomialOver(ring) + + /** + * Evaluates value of [this] polynomial on provided [arguments]. + */ + @Suppress("NOTHING_TO_INLINE") + public inline operator fun NumberedPolynomial.invoke(arguments: Buffer): C = substituteFully(ring, arguments) + /** + * Substitutes provided [arguments] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + @JvmName("invokePolynomial") + public inline operator fun NumberedPolynomial.invoke(arguments: Buffer>): NumberedPolynomial = substitute(ring, arguments) +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt new file mode 100644 index 000000000..a2986879d --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt @@ -0,0 +1,239 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.functions + +import space.kscience.kmath.operations.Ring +import space.kscience.kmath.operations.invoke +import space.kscience.kmath.structures.Buffer +import kotlin.jvm.JvmName +import kotlin.math.max + + +/** + * Represents multivariate rational function that stores its numerator and denominator as [NumberedPolynomial]s. + */ +public class NumberedRationalFunction internal constructor( + public override val numerator: NumberedPolynomial, + public override val denominator: NumberedPolynomial +) : RationalFunction> { + override fun toString(): String = "NumberedRationalFunction${numerator.coefficients}/${denominator.coefficients}" +} + +/** + * Arithmetic context for univariate rational functions with numerator and denominator represented as [NumberedPolynomial]s. + * + * @param C the type of constants. Polynomials have them a coefficients in their terms. + * @param A type of provided underlying ring of constants. It's [Ring] of [C]. + * @param ring underlying ring of constants of type [A]. + */ +public class NumberedRationalFunctionSpace> ( + public val ring: A, +) : + RationalFunctionalSpaceOverPolynomialSpace< + C, + NumberedPolynomial, + NumberedRationalFunction, + NumberedPolynomialSpace, + >, + PolynomialSpaceOfFractions< + C, + NumberedPolynomial, + NumberedRationalFunction, + >() { + + /** + * Underlying polynomial ring. Its polynomial operations are inherited by local polynomial operations. + */ + public override val polynomialRing : NumberedPolynomialSpace = NumberedPolynomialSpace(ring) + /** + * Constructor of rational functions (of type [NumberedRationalFunction]) from numerator and denominator (of type [NumberedPolynomial]). + */ + protected override fun constructRationalFunction( + numerator: NumberedPolynomial, + denominator: NumberedPolynomial + ): NumberedRationalFunction = + NumberedRationalFunction(numerator, denominator) + + /** + * Maximal index (ID) of variable occurring in the polynomial with positive power. If there is no such variable, + * the result is `-1`. + */ + public val NumberedPolynomial.lastVariable: Int get() = polynomialRing { lastVariable } + /** + * List that associates indices of variables (that appear in the polynomial in positive exponents) with their most + * exponents in which the variables are appeared in the polynomial. + * + * As consequence all values in the list are non-negative integers. Also, if the polynomial is constant, the list is empty. + * And last index of the list is [lastVariable]. + */ + public val NumberedPolynomial.degrees: List get() = polynomialRing { degrees } + /** + * Counts degree of the polynomial by the specified [variable]. + */ + public fun NumberedPolynomial.degreeBy(variable: Int): UInt = polynomialRing { degreeBy(variable) } + /** + * Counts degree of the polynomial by the specified [variables]. + */ + public fun NumberedPolynomial.degreeBy(variables: Collection): UInt = polynomialRing { degreeBy(variables) } + /** + * Count of variables occurring in the polynomial with positive power. If there is no such variable, + * the result is `0`. + */ + public val NumberedPolynomial.countOfVariables: Int get() = polynomialRing { countOfVariables } + + /** + * Count of all variables that appear in the polynomial in positive exponents. + */ + public val NumberedRationalFunction.lastVariable: Int + get() = polynomialRing { max(numerator.lastVariable, denominator.lastVariable) } + /** + * Count of variables occurring in the rational function with positive power. If there is no such variable, + * the result is `0`. + */ + public val NumberedRationalFunction.countOfVariables: Int + get() = + MutableList(lastVariable + 1) { false }.apply { + numerator.coefficients.entries.forEach { (degs, _) -> + degs.forEachIndexed { index, deg -> + if (deg != 0u) this[index] = true + } + } + denominator.coefficients.entries.forEach { (degs, _) -> + degs.forEachIndexed { index, deg -> + if (deg != 0u) this[index] = true + } + } + }.count { it } + + // TODO: When context receivers will be ready move all of this substitutions and invocations to utilities with + // [ListPolynomialSpace] as a context receiver + /** + * Substitutes provided constant [argument] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.substitute(argument: Map): NumberedPolynomial = substitute(ring, argument) + /** + * Substitutes provided polynomial [argument] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.substitute(argument: Map>): NumberedPolynomial = substitute(ring, argument) + /** + * Substitutes provided rational function [argument] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.substitute(argument: Map>): NumberedRationalFunction = substitute(ring, argument) + /** + * Substitutes provided constant [argument] into [this] rational function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedRationalFunction.substitute(argument: Map): NumberedRationalFunction = substitute(ring, argument) + /** + * Substitutes provided polynomial [argument] into [this] rational function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedRationalFunction.substitute(argument: Map>): NumberedRationalFunction = substitute(ring, argument) + /** + * Substitutes provided rational function [argument] into [this] rational function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedRationalFunction.substitute(argument: Map>): NumberedRationalFunction = substitute(ring, argument) + /** + * Substitutes provided constant [argument] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.substitute(argument: Buffer): NumberedPolynomial = substitute(ring, argument) + /** + * Substitutes provided polynomial [argument] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.substitute(argument: Buffer>): NumberedPolynomial = substitute(ring, argument) + /** + * Substitutes provided rational function [argument] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.substitute(argument: Buffer>): NumberedRationalFunction = substitute(ring, argument) + /** + * Substitutes provided constant [argument] into [this] rational function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedRationalFunction.substitute(argument: Buffer): NumberedRationalFunction = substitute(ring, argument) + /** + * Substitutes provided polynomial [arguments] into [this] rational function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedRationalFunction.substitute(arguments: Buffer>): NumberedRationalFunction = substitute(ring, arguments) + /** + * Substitutes provided rational function [arguments] into [this] rational function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedRationalFunction.substitute(arguments: Buffer>): NumberedRationalFunction = substitute(ring, arguments) + /** + * Substitutes provided constant [arguments] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.substituteFully(arguments: Buffer): C = substituteFully(ring, arguments) + + /** + * Represent [this] polynomial as a regular context-less function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.asFunction(): (Buffer) -> C = asFunctionOver(ring) + /** + * Represent [this] polynomial as a regular context-less function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.asFunctionOfConstant(): (Buffer) -> C = asFunctionOfConstantOver(ring) + /** + * Represent [this] polynomial as a regular context-less function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.asFunctionOfPolynomial(): (Buffer>) -> NumberedPolynomial = asFunctionOfPolynomialOver(ring) + /** + * Represent [this] polynomial as a regular context-less function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.asFunctionOfRationalFunction(): (Buffer>) -> NumberedRationalFunction = asFunctionOfRationalFunctionOver(ring) + /** + * Represent [this] polynomial as a regular context-less function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedRationalFunction.asFunctionOfPolynomial(): (Buffer>) -> NumberedRationalFunction = asFunctionOfPolynomialOver(ring) + /** + * Represent [this] polynomial as a regular context-less function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedRationalFunction.asFunctionOfRationalFunction(): (Buffer>) -> NumberedRationalFunction = asFunctionOfRationalFunctionOver(ring) + + /** + * Evaluates value of [this] polynomial on provided [arguments]. + */ + @Suppress("NOTHING_TO_INLINE") + public inline operator fun NumberedPolynomial.invoke(arguments: Buffer): C = substituteFully(ring, arguments) + /** + * Substitutes provided [arguments] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + @JvmName("invokePolynomial") + public inline operator fun NumberedPolynomial.invoke(arguments: Buffer>): NumberedPolynomial = substitute(ring, arguments) + /** + * Substitutes provided [arguments] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + @JvmName("invokePolynomial") + public inline operator fun NumberedPolynomial.invoke(arguments: Buffer>): NumberedRationalFunction = substitute(ring, arguments) + /** + * Substitutes provided [arguments] into [this] rational function. + */ + @Suppress("NOTHING_TO_INLINE") + @JvmName("invokePolynomial") + public inline operator fun NumberedRationalFunction.invoke(arguments: Buffer>): NumberedRationalFunction = substitute(ring, arguments) + /** + * Substitutes provided [arguments] into [this] rational function. + */ + @Suppress("NOTHING_TO_INLINE") + @JvmName("invokePolynomial") + public inline operator fun NumberedRationalFunction.invoke(arguments: Buffer>): NumberedRationalFunction = substitute(ring, arguments) +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt index 01911f980..338ae9935 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt @@ -1076,6 +1076,14 @@ public abstract class PolynomialSpaceOfFractions< numerator * other.denominator, denominator * other.numerator ) + /** + * Raises [arg] to the integer power [exponent]. + */ + public override fun power(arg: R, exponent: UInt): R = + constructRationalFunction( + power(arg.numerator, exponent), + power(arg.denominator, exponent), + ) /** * Instance of zero rational function (zero of the rational functions ring). diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt index 127dd8c7a..649fc48bd 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt @@ -147,12 +147,17 @@ public fun > ListPolynomial.asFunctionOver(ring: A): (C) -> C /** * Represent [this] polynomial as a regular context-less function. */ -public fun > ListPolynomial.asPolynomialFunctionOver(ring: A): (ListPolynomial) -> ListPolynomial = { substitute(ring, it) } +public fun > ListPolynomial.asFunctionOfConstantOver(ring: A): (C) -> C = { substitute(ring, it) } /** * Represent [this] polynomial as a regular context-less function. */ -public fun > ListPolynomial.asFunctionOfRationalFunctionOver(ring: A): (ListPolynomial) -> ListPolynomial = { substitute(ring, it) } +public fun > ListPolynomial.asFunctionOfPolynomialOver(ring: A): (ListPolynomial) -> ListPolynomial = { substitute(ring, it) } + +/** + * Represent [this] polynomial as a regular context-less function. + */ +public fun > ListPolynomial.asFunctionOfRationalFunctionOver(ring: A): (ListRationalFunction) -> ListRationalFunction = { substitute(ring, it) } /** * Represent [this] rational function as a regular context-less function. @@ -162,12 +167,17 @@ public fun > ListRationalFunction.asFunctionOver(ring: A): (C /** * Represent [this] rational function as a regular context-less function. */ -public fun > ListRationalFunction.asPolynomialFunctionOver(ring: A): (ListPolynomial) -> ListRationalFunction = { substitute(ring, it) } +public fun > ListRationalFunction.asFunctionOfConstantOver(ring: A): (C) -> C = { substitute(ring, it) } /** * Represent [this] rational function as a regular context-less function. */ -public fun > ListRationalFunction.asFunctionOfRationalFunctionOver(ring: A): (ListPolynomial) -> ListRationalFunction = { substitute(ring, it) } +public fun > ListRationalFunction.asFunctionOfPolynomialOver(ring: A): (ListPolynomial) -> ListRationalFunction = { substitute(ring, it) } + +/** + * Represent [this] rational function as a regular context-less function. + */ +public fun > ListRationalFunction.asFunctionOfRationalFunctionOver(ring: A): (ListRationalFunction) -> ListRationalFunction = { substitute(ring, it) } /** * Returns algebraic derivative of received polynomial. @@ -242,27 +252,4 @@ public fun > ListPolynomial.integrate( ): C = ring { val antiderivative = antiderivative(ring) antiderivative.substitute(ring, range.endInclusive) - antiderivative.substitute(ring, range.start) -} - -/** - * Returns algebraic derivative of received rational function. - */ -@UnstableKMathAPI -public fun ListRationalFunction.derivative( - ring: A, -): ListRationalFunction where A : Ring, A : NumericAlgebra = ring.listRationalFunctionSpace { - ListRationalFunction( - numerator.derivative(ring) * denominator - numerator * denominator.derivative(ring), - denominator * denominator - ) -} - -/** - * Returns algebraic derivative of received rational function of specified [order]. The [order] should be non-negative integer. - */ -@UnstableKMathAPI -public tailrec fun ListRationalFunction.nthDerivative( - ring: A, - order: Int, -): ListRationalFunction where A : Ring, A : NumericAlgebra = - if (order == 0) this else derivative(ring).nthDerivative(ring, order - 1) \ No newline at end of file +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt new file mode 100644 index 000000000..05fff3472 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt @@ -0,0 +1,478 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.functions + +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.Ring + + +/** + * Returns the same degrees' description of the monomial, but without extra zero degrees on the end. + */ +internal fun List.cleanUp() = subList(0, indexOfLast { it != 0U } + 1) + +/** + * Constructs [NumberedPolynomial] with provided coefficients map [coefs]. The map is used as is. + */ +@Suppress("FunctionName", "NOTHING_TO_INLINE") +@PublishedApi +internal inline fun NumberedPolynomialAsIs(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs) + +/** + * Constructs [NumberedPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient". + * The collections will be transformed to map with [toMap] and then will be used as is. + */ +@Suppress("FunctionName", "NOTHING_TO_INLINE") +@PublishedApi +internal inline fun NumberedPolynomialAsIs(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs.toMap()) + +/** + * Constructs [NumberedPolynomial] with provided array of [pairs] of pairs "term's signature — term's coefficient". + * The array will be transformed to map with [toMap] and then will be used as is. + */ +@Suppress("FunctionName", "NOTHING_TO_INLINE") +@PublishedApi +internal inline fun NumberedPolynomialAsIs(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(pairs.toMap()) + +/** + * Constructs [NumberedPolynomial] with provided coefficients map [coefs]. + * + * [coefs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [coefs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +@Suppress("FunctionName") +public fun NumberedPolynomial(coefs: Map, C>, add: (C, C) -> C) : NumberedPolynomial { + val fixedCoefs = mutableMapOf, C>() + + for (entry in coefs) { + val key = entry.key.cleanUp() + val value = entry.value + fixedCoefs[key] = if (key in fixedCoefs) add(fixedCoefs[key]!!, value) else value + } + + return NumberedPolynomial(fixedCoefs) +} + +/** + * Constructs [NumberedPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient". + * + * [pairs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +@Suppress("FunctionName") +public fun NumberedPolynomial(pairs: Collection, C>>, add: (C, C) -> C) : NumberedPolynomial { + val fixedCoefs = mutableMapOf, C>() + + for (entry in pairs) { + val key = entry.first.cleanUp() + val value = entry.second + fixedCoefs[key] = if (key in fixedCoefs) add(fixedCoefs[key]!!, value) else value + } + + return NumberedPolynomial(fixedCoefs) +} + +/** + * Constructs [NumberedPolynomial] with provided array [pairs] of pairs "term's signature — term's coefficient". + * + * [pairs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +@Suppress("FunctionName") +public fun NumberedPolynomial(vararg pairs: Pair, C>, add: (C, C) -> C) : NumberedPolynomial { + val fixedCoefs = mutableMapOf, C>() + + for (entry in pairs) { + val key = entry.first.cleanUp() + val value = entry.second + fixedCoefs[key] = if (key in fixedCoefs) add(fixedCoefs[key]!!, value) else value + } + + return NumberedPolynomial(fixedCoefs) +} + +// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available + +/** + * Constructs [NumberedPolynomial] with provided coefficients map [coefs]. + * + * [coefs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [coefs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +@Suppress("FunctionName", "NOTHING_TO_INLINE") +public inline fun > A.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, ::add) +/** + * Constructs [NumberedPolynomial] with provided coefficients map [coefs]. + * + * [coefs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [coefs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +@Suppress("FunctionName", "NOTHING_TO_INLINE") +public inline fun > NumberedPolynomialSpace.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs) { left: C, right: C -> left + right } + +/** + * Constructs [NumberedPolynomial] with provided coefficients map [coefs]. + * + * [coefs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [coefs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +@Suppress("FunctionName", "NOTHING_TO_INLINE") +public inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs) { left: C, right: C -> left + right } + +/** + * Constructs [NumberedPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient". + * + * [pairs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +@Suppress("FunctionName", "NOTHING_TO_INLINE") +public inline fun > A.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, ::add) + +/** + * Constructs [NumberedPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient". + * + * [pairs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +@Suppress("FunctionName", "NOTHING_TO_INLINE") +public inline fun > NumberedPolynomialSpace.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs) { left: C, right: C -> left + right } +/** + * Constructs [NumberedPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient". + * + * [pairs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +@Suppress("FunctionName", "NOTHING_TO_INLINE") +public inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs) { left: C, right: C -> left + right } + +/** + * Constructs [NumberedPolynomial] with provided array [pairs] of pairs "term's signature — term's coefficient". + * + * [pairs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +@Suppress("FunctionName", "NOTHING_TO_INLINE") +public inline fun > A.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs) { left: C, right: C -> left + right } +/** + * Constructs [NumberedPolynomial] with provided array [pairs] of pairs "term's signature — term's coefficient". + * + * [pairs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +@Suppress("FunctionName", "NOTHING_TO_INLINE") +public inline fun > NumberedPolynomialSpace.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs) { left: C, right: C -> left + right } +/** + * Constructs [NumberedPolynomial] with provided array [pairs] of pairs "term's signature — term's coefficient". + * + * [pairs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +@Suppress("FunctionName", "NOTHING_TO_INLINE") +public inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs) { left: C, right: C -> left + right } + +/** + * Converts [this] constant to [NumberedPolynomial]. + */ +@Suppress("NOTHING_TO_INLINE") +public inline fun C.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomialAsIs(mapOf(emptyList() to this)) + +/** + * Marks DSL that allows to more simply create [NumberedPolynomial]s with good performance. + * + * For example, polynomial `5 x_1^2 x_3^3 - 6 x_2` can be described as + * ``` + * Int.algebra { + * val numberedPolynomial : NumberedPolynomial = NumberedPolynomial { + * 5 { 1 inPowerOf 2u; 3 inPowerOf 3u } // 5 x_1^2 x_3^3 + + * (-6) { 2 inPowerOf 1u } // (-6) x_2^1 + * } + * } + * ``` + */ +@DslMarker +@UnstableKMathAPI +internal annotation class NumberedPolynomialConstructorDSL + +/** + * Builder of [NumberedPolynomial] signature. It should be used as an implicit context for lambdas that describe term signature. + */ +@UnstableKMathAPI +@NumberedPolynomialConstructorDSL +public class NumberedPolynomialTermSignatureBuilder { + /** + * Signature storage. Any declaration of any variable's power updates the storage by increasing corresponding value. + * Afterward the storage will be used as a resulting signature. + */ + private val signature: MutableList = ArrayList() + + /** + * Builds the resulting signature. + * + * In fact, it just returns [signature] as regular signature of type `List`. + */ + internal fun build(): List = signature + + /** + * Declares power of variable #[this] of degree [deg]. + * + * Declaring another power of the same variable will increase its degree by received degree. + */ + public infix fun Int.inPowerOf(deg: UInt) { + if (this > signature.lastIndex) { + signature.addAll(List(this - signature.lastIndex - 1) { 0u }) + signature.add(deg) + } else { + signature[this] += deg + } + } + /** + * Declares power of variable #[this] of degree [deg]. + * + * Declaring another power of the same variable will increase its degree by received degree. + */ + @Suppress("NOTHING_TO_INLINE") + public inline infix fun Int.pow(deg: UInt): Unit = this inPowerOf deg + /** + * Declares power of variable #[this] of degree [deg]. + * + * Declaring another power of the same variable will increase its degree by received degree. + */ + @Suppress("NOTHING_TO_INLINE") + public inline infix fun Int.`in`(deg: UInt): Unit = this inPowerOf deg + /** + * Declares power of variable #[this] of degree [deg]. + * + * Declaring another power of the same variable will increase its degree by received degree. + */ + @Suppress("NOTHING_TO_INLINE") + public inline infix fun Int.of(deg: UInt): Unit = this inPowerOf deg +} + +/** + * Builder of [NumberedPolynomial]. It should be used as an implicit context for lambdas that describe [NumberedPolynomial]. + */ +@UnstableKMathAPI +@NumberedPolynomialConstructorDSL +public class NumberedPolynomialBuilder( + /** + * Summation operation that will be used to sum coefficients of monomials of same signatures. + */ + private val add: (C, C) -> C, + /** + * Initial capacity of coefficients map. + */ + initialCapacity: Int = 0 +) { + /** + * Coefficients storage. Any declaration of any monomial updates the storage. + * Afterward the storage will be used as a resulting coefficients map. + */ + private val coefficients: MutableMap, C> = LinkedHashMap(initialCapacity) + + /** + * Builds the resulting coefficients map. + * + * In fact, it just returns [coefficients] as regular coefficients map of type `Map, C>`. + */ + @PublishedApi + internal fun build(): NumberedPolynomial = NumberedPolynomial(coefficients) + + /** + * Declares monomial with [this] coefficient and provided [signature]. + * + * Declaring another monomial with the same signature will add [this] coefficient to existing one. If the sum of such + * coefficients is zero at any moment the monomial won't be removed but will be left as it is. + */ + public infix fun C.with(signature: List) { + if (signature in coefficients) coefficients[signature] = add(coefficients[signature]!!, this@with) + else coefficients[signature] = this@with + } + /** + * Declares monomial with [this] coefficient and signature constructed by [block]. + * + * Declaring another monomial with the same signature will add [this] coefficient to existing one. If the sum of such + * coefficients is zero at any moment the monomial won't be removed but will be left as it is. + */ + @Suppress("NOTHING_TO_INLINE") + public inline infix fun C.with(noinline block: NumberedPolynomialTermSignatureBuilder.() -> Unit): Unit = this.invoke(block) + /** + * Declares monomial with [this] coefficient and signature constructed by [block]. + * + * Declaring another monomial with the same signature will add [this] coefficient to existing one. If the sum of such + * coefficients is zero at any moment the monomial won't be removed but will be left as it is. + */ + public operator fun C.invoke(block: NumberedPolynomialTermSignatureBuilder.() -> Unit): Unit = + this with NumberedPolynomialTermSignatureBuilder().apply(block).build() +} + +// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available + +/** + * Creates [NumberedPolynomial] with lambda [block] in context of [this] ring of constants. + * + * For example, polynomial `5 x_1^2 x_3^3 - 6 x_2` can be described as + * ``` + * Int.algebra { + * val numberedPolynomial : NumberedPolynomial = NumberedPolynomial { + * 5 { 1 inPowerOf 2u; 3 inPowerOf 3u } // 5 x_1^2 x_3^3 + + * (-6) { 2 inPowerOf 1u } // (-6) x_2^1 + * } + * } + * ``` + */ +@UnstableKMathAPI +@Suppress("FunctionName") +public inline fun > A.NumberedPolynomial(initialCapacity: Int = 0, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder(::add, initialCapacity).apply(block).build() +/** + * Creates [NumberedPolynomial] with lambda [block] in context of [this] ring of [NumberedPolynomial]s. + * + * For example, polynomial `5 x_1^2 x_3^3 - 6 x_2` can be described as + * ``` + * Int.algebra { + * val numberedPolynomial : NumberedPolynomial = NumberedPolynomial { + * 5 { 1 inPowerOf 2u; 3 inPowerOf 3u } // 5 x_1^2 x_3^3 + + * (-6) { 2 inPowerOf 1u } // (-6) x_2^1 + * } + * } + * ``` + */ +@UnstableKMathAPI +@Suppress("FunctionName") +public inline fun > NumberedPolynomialSpace.NumberedPolynomial(initialCapacity: Int, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() +/** + * Creates [NumberedPolynomial] with lambda [block] in context of [this] field of [NumberedRationalFunction]s. + * + * For example, polynomial `5 x_1^2 x_3^3 - 6 x_2` can be described as + * ``` + * Int.algebra { + * val numberedPolynomial : NumberedPolynomial = NumberedPolynomial { + * 5 { 1 inPowerOf 2u; 3 inPowerOf 3u } // 5 x_1^2 x_3^3 + + * (-6) { 2 inPowerOf 1u } // (-6) x_2^1 + * } + * } + * ``` + */ +@UnstableKMathAPI +@Suppress("FunctionName") +public inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(initialCapacity: Int, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() + +// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available + +/** + * Constructs [NumberedRationalFunction] with provided coefficients maps [numeratorCoefficients] and [denominatorCoefficients]. + * + * The maps will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. the maps' keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +@Suppress("FunctionName") +public fun > A.NumberedRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): NumberedRationalFunction = + NumberedRationalFunction( + NumberedPolynomial(numeratorCoefficients), + NumberedPolynomial(denominatorCoefficients) + ) +/** + * Constructs [NumberedRationalFunction] with provided coefficients maps [numeratorCoefficients] and [denominatorCoefficients]. + * + * The maps will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. the maps' keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +@Suppress("FunctionName") +public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): NumberedRationalFunction = + NumberedRationalFunction( + NumberedPolynomial(numeratorCoefficients), + NumberedPolynomial(denominatorCoefficients) + ) + +/** + * Constructs [NumberedRationalFunction] with provided [numerator] and unit denominator. + */ +@Suppress("FunctionName") +public fun > A.NumberedRationalFunction(numerator: NumberedPolynomial): NumberedRationalFunction = + NumberedRationalFunction(numerator, NumberedPolynomial(mapOf(emptyList() to one))) +/** + * Constructs [NumberedRationalFunction] with provided [numerator] and unit denominator. + */ +@Suppress("FunctionName") +public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numerator: NumberedPolynomial): NumberedRationalFunction = + NumberedRationalFunction(numerator, polynomialOne) + +/** + * Constructs [NumberedRationalFunction] with provided coefficients map [numeratorCoefficients] for numerator and unit + * denominator. + * + * [numeratorCoefficients] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [numeratorCoefficients]'s keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +@Suppress("FunctionName") +public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numeratorCoefficients: Map, C>): NumberedRationalFunction = + NumberedRationalFunction( + NumberedPolynomial(numeratorCoefficients), + polynomialOne + ) +/** + * Constructs [NumberedRationalFunction] with provided coefficients map [numeratorCoefficients] for numerator and unit + * denominator. + * + * [numeratorCoefficients] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [numeratorCoefficients]'s keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +@Suppress("FunctionName") +public fun > A.NumberedRationalFunction(numeratorCoefficients: Map, C>): NumberedRationalFunction = + NumberedRationalFunction( + NumberedPolynomial(numeratorCoefficients), + NumberedPolynomialAsIs(mapOf(emptyList() to one)) + ) + +///** +// * Converts [this] coefficient to [NumberedRationalFunction]. +// */ +//context(A) +//public fun > C.asNumberedRationalFunction() : NumberedRationalFunction = +// NumberedRationalFunction( +// NumberedPolynomialAsIs(mapOf(emptyList() to this)), +// NumberedPolynomialAsIs(mapOf(emptyList() to one)) +// ) +///** +// * Converts [this] coefficient to [NumberedRationalFunction]. +// */ +//context(NumberedRationalFunctionSpace) +//public fun > C.asNumberedRationalFunction() : NumberedRationalFunction = +// NumberedRationalFunction( +// NumberedPolynomialAsIs(mapOf(emptyList() to this)), +// NumberedPolynomialAsIs(mapOf(emptyList() to constantOne)) +// ) \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt new file mode 100644 index 000000000..484cd11e3 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt @@ -0,0 +1,515 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.functions + +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.Field +import space.kscience.kmath.operations.Ring +import space.kscience.kmath.operations.algebra +import space.kscience.kmath.operations.invoke +import space.kscience.kmath.structures.Buffer +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract +import kotlin.jvm.JvmName +import kotlin.math.max +import kotlin.math.min + + +/** + * Creates a [NumberedPolynomialSpace] over a received ring. + */ +public fun > A.numberedPolynomialSpace(): NumberedPolynomialSpace = + NumberedPolynomialSpace(this) + +/** + * Creates a [NumberedPolynomialSpace]'s scope over a received ring. + */ +public inline fun , R> A.numberedPolynomialSpace(block: NumberedPolynomialSpace.() -> R): R { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return NumberedPolynomialSpace(this).block() +} + +/** + * Creates a [NumberedRationalFunctionSpace] over a received ring. + */ +public fun > A.numberedRationalFunctionSpace(): NumberedRationalFunctionSpace = + NumberedRationalFunctionSpace(this) + +/** + * Creates a [NumberedRationalFunctionSpace]'s scope over a received ring. + */ +public inline fun , R> A.numberedRationalFunctionSpace(block: NumberedRationalFunctionSpace.() -> R): R { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return NumberedRationalFunctionSpace(this).block() +} + +/** + * Substitutes provided Double arguments [args] into [this] Double polynomial. + */ +public fun NumberedPolynomial.substitute(args: Map): NumberedPolynomial = Double.algebra { + NumberedPolynomial( + buildMap, Double>(coefficients.size) { + for ((degs, c) in coefficients) { + val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp() + val newC = args.entries.fold(c) { product, (variable, substitution) -> + val deg = degs.getOrElse(variable) { 0u } + if (deg == 0u) product else product * substitution.pow(deg.toInt()) + } + if (newDegs !in this) this[newDegs] = newC + else this[newDegs] = this[newDegs]!! + newC + } + } + ) +} + +/** + * Substitutes provided arguments [args] into [this] polynomial. + */ +public fun NumberedPolynomial.substitute(ring: Ring, args: Map): NumberedPolynomial = ring { + NumberedPolynomial( + buildMap, C>(coefficients.size) { + for ((degs, c) in coefficients) { + val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp() + val newC = args.entries.fold(c) { product, (variable, substitution) -> + val deg = degs.getOrElse(variable) { 0u } + if (deg == 0u) product else product * power(substitution, deg) + } + if (newDegs !in this) this[newDegs] = newC + else this[newDegs] = this[newDegs]!! + newC + } + } + ) +} + +/** + * Substitutes provided arguments [args] into [this] polynomial. + */ // TODO: To optimize boxing +@JvmName("substitutePolynomial") +public fun NumberedPolynomial.substitute(ring: Ring, args: Map>) : NumberedPolynomial = + ring.numberedPolynomialSpace { + coefficients.entries.fold(zero) { acc, (degs, c) -> + val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp() + acc + args.entries.fold(NumberedPolynomial(mapOf(newDegs to c))) { product, (variable, substitution) -> + val deg = degs.getOrElse(variable) { 0u } + if (deg == 0u) product else product * power(substitution, deg) + } + } + } + +/** + * Substitutes provided arguments [args] into [this] polynomial. + */ // TODO: To optimize boxing +@JvmName("substituteRationalFunction") +public fun NumberedPolynomial.substitute(ring: Ring, args: Map>) : NumberedRationalFunction = + ring.numberedRationalFunctionSpace { + coefficients.entries.fold(zero) { acc, (degs, c) -> + val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp() + acc + args.entries.fold(NumberedRationalFunction(NumberedPolynomial(mapOf(newDegs to c)))) { product, (variable, substitution) -> + val deg = degs.getOrElse(variable) { 0u } + if (deg == 0u) product else product * power(substitution, deg) + } + } + } + +/** + * Substitutes provided Double arguments [args] into [this] Double rational function. + */ +public fun NumberedRationalFunction.substitute(args: Map): NumberedRationalFunction = + NumberedRationalFunction(numerator.substitute(args), denominator.substitute(args)) + +/** + * Substitutes provided arguments [args] into [this] rational function. + */ +public fun NumberedRationalFunction.substitute(ring: Ring, args: Map): NumberedRationalFunction = + NumberedRationalFunction(numerator.substitute(ring, args), denominator.substitute(ring, args)) + +/** + * Substitutes provided arguments [args] into [this] rational function. + */ // TODO: To optimize boxing +@JvmName("substitutePolynomial") +public fun NumberedRationalFunction.substitute(ring: Ring, args: Map>) : NumberedRationalFunction = + NumberedRationalFunction(numerator.substitute(ring, args), denominator.substitute(ring, args)) + +/** + * Substitutes provided arguments [args] into [this] rational function. + */ // TODO: To optimize boxing +@JvmName("substituteRationalFunction") +public fun NumberedRationalFunction.substitute(ring: Ring, args: Map>) : NumberedRationalFunction = + ring.numberedRationalFunctionSpace { + numerator.substitute(ring, args) / denominator.substitute(ring, args) + } + +/** + * Substitutes provided Double arguments [args] into [this] Double polynomial. + */ +public fun NumberedPolynomial.substitute(args: Buffer): NumberedPolynomial = Double.algebra { + val lastSubstitutionVariable = args.size - 1 + NumberedPolynomial( + buildMap(coefficients.size) { + for ((degs, c) in coefficients) { + val lastDegsIndex = degs.lastIndex + val newDegs = + if (lastDegsIndex <= lastSubstitutionVariable) emptyList() + else degs.toMutableList().apply { + for (i in 0..lastSubstitutionVariable) this[i] = 0u + } + val newC = (0..min(lastDegsIndex, lastSubstitutionVariable)).fold(c) { product, variable -> + val deg = degs[variable] + if (deg == 0u) product else product * args[variable].pow(deg.toInt()) + } + if (newDegs !in this) this[newDegs] = newC + else this[newDegs] = this[newDegs]!! + newC + } + } + ) +} + +/** + * Substitutes provided arguments [args] into [this] polynomial. + */ +public fun NumberedPolynomial.substitute(ring: Ring, args: Buffer): NumberedPolynomial = ring { + val lastSubstitutionVariable = args.size - 1 + NumberedPolynomial( + buildMap, C>(coefficients.size) { + for ((degs, c) in coefficients) { + val lastDegsIndex = degs.lastIndex + val newDegs = + if (lastDegsIndex <= lastSubstitutionVariable) emptyList() + else degs.toMutableList().apply { + for (i in 0..lastSubstitutionVariable) this[i] = 0u + } + val newC = (0..min(lastDegsIndex, lastSubstitutionVariable)).fold(c) { product, variable -> + val deg = degs[variable] + if (deg == 0u) product else product * power(args[variable], deg) + } + if (newDegs !in this) this[newDegs] = newC + else this[newDegs] = this[newDegs]!! + newC + } + } + ) +} + +/** + * Substitutes provided arguments [args] into [this] polynomial. + */ // TODO: To optimize boxing +@JvmName("substitutePolynomial") +public fun NumberedPolynomial.substitute(ring: Ring, args: Buffer>) : NumberedPolynomial = + ring.numberedPolynomialSpace { + val lastSubstitutionVariable = args.size - 1 + coefficients.entries.fold(zero) { acc, (degs, c) -> + val lastDegsIndex = degs.lastIndex + val newDegs = + if (lastDegsIndex <= lastSubstitutionVariable) emptyList() + else degs.toMutableList().apply { + for (i in 0..lastSubstitutionVariable) this[i] = 0u + } + acc + (0..min(lastDegsIndex, lastSubstitutionVariable)) + .fold(NumberedPolynomial(mapOf(newDegs to c))) { product, variable -> + val deg = degs[variable] + if (deg == 0u) product else product * power(args[variable], deg) + } + } + } + +/** + * Substitutes provided arguments [args] into [this] polynomial. + */ // TODO: To optimize boxing +@JvmName("substituteRationalFunction") +public fun NumberedPolynomial.substitute(ring: Ring, args: Buffer>) : NumberedRationalFunction = + ring.numberedRationalFunctionSpace { + val lastSubstitutionVariable = args.size - 1 + coefficients.entries.fold(zero) { acc, (degs, c) -> + val lastDegsIndex = degs.lastIndex + val newDegs = + if (lastDegsIndex <= lastSubstitutionVariable) emptyList() + else degs.toMutableList().apply { + for (i in 0..lastSubstitutionVariable) this[i] = 0u + } + acc + (0..min(lastDegsIndex, lastSubstitutionVariable)) + .fold(NumberedRationalFunction(NumberedPolynomial(mapOf(newDegs to c)))) { product, variable -> + val deg = degs[variable] + if (deg == 0u) product else product * power(args[variable], deg) + } + } + } + +/** + * Substitutes provided Double arguments [args] into [this] Double rational function. + */ +public fun NumberedRationalFunction.substitute(args: Buffer): NumberedRationalFunction = + NumberedRationalFunction(numerator.substitute(args), denominator.substitute(args)) + +/** + * Substitutes provided arguments [args] into [this] rational function. + */ +public fun NumberedRationalFunction.substitute(ring: Ring, args: Buffer): NumberedRationalFunction = + NumberedRationalFunction(numerator.substitute(ring, args), denominator.substitute(ring, args)) + +/** + * Substitutes provided arguments [args] into [this] rational function. + */ // TODO: To optimize boxing +@JvmName("substitutePolynomial") +public fun NumberedRationalFunction.substitute(ring: Ring, args: Buffer>) : NumberedRationalFunction = + NumberedRationalFunction(numerator.substitute(ring, args), denominator.substitute(ring, args)) + +/** + * Substitutes provided arguments [args] into [this] rational function. + */ // TODO: To optimize boxing +@JvmName("substituteRationalFunction") +public fun NumberedRationalFunction.substitute(ring: Ring, args: Buffer>) : NumberedRationalFunction = + ring.numberedRationalFunctionSpace { + numerator.substitute(ring, args) / denominator.substitute(ring, args) + } + +/** + * Substitutes provided Double arguments [args] into [this] Double polynomial. + */ +public fun NumberedPolynomial.substituteFully(args: Buffer): Double = Double.algebra { + val lastSubstitutionVariable = args.size - 1 + require(coefficients.keys.all { it.lastIndex <= lastSubstitutionVariable }) { "Fully substituting buffer should cover all variables of the polynomial." } + coefficients.entries.fold(.0) { acc, (degs, c) -> + acc + degs.foldIndexed(c) { variable, product, deg -> + if (deg == 0u) product else product * args[variable].pow(deg.toInt()) + } + } +} + +/** + * Substitutes provided arguments [args] into [this] polynomial. + */ +public fun NumberedPolynomial.substituteFully(ring: Ring, args: Buffer): C = ring { + val lastSubstitutionVariable = args.size - 1 + require(coefficients.keys.all { it.lastIndex <= lastSubstitutionVariable }) { "Fully substituting buffer should cover all variables of the polynomial." } + coefficients.entries.fold(zero) { acc, (degs, c) -> + acc + degs.foldIndexed(c) { variable, product, deg -> + if (deg == 0u) product else product * power(args[variable], deg) + } + } +} + +/** + * Substitutes provided Double arguments [args] into [this] Double rational function. + */ +public fun NumberedRationalFunction.substituteFully(args: Buffer): Double = + numerator.substituteFully(args) / denominator.substituteFully(args) + +/** + * Substitutes provided arguments [args] into [this] rational function. + */ +public fun NumberedRationalFunction.substituteFully(ring: Field, args: Buffer): C = ring { + numerator.substituteFully(ring, args) / denominator.substituteFully(ring, args) +} + +/** + * Represent [this] polynomial as a regular context-less function. + */ +public fun > NumberedPolynomial.asFunctionOver(ring: A): (Buffer) -> C = { substituteFully(ring, it) } + +/** + * Represent [this] polynomial as a regular context-less function. + */ +public fun > NumberedPolynomial.asFunctionOfConstantOver(ring: A): (Buffer) -> C = { substituteFully(ring, it) } + +/** + * Represent [this] polynomial as a regular context-less function. + */ +public fun > NumberedPolynomial.asFunctionOfPolynomialOver(ring: A): (Buffer>) -> NumberedPolynomial = { substitute(ring, it) } + +/** + * Represent [this] polynomial as a regular context-less function. + */ +public fun > NumberedPolynomial.asFunctionOfRationalFunctionOver(ring: A): (Buffer>) -> NumberedRationalFunction = { substitute(ring, it) } + +/** + * Represent [this] rational function as a regular context-less function. + */ +public fun > NumberedRationalFunction.asFunctionOver(ring: A): (Buffer) -> C = { substituteFully(ring, it) } + +/** + * Represent [this] rational function as a regular context-less function. + */ +public fun > NumberedRationalFunction.asFunctionOfConstantOver(ring: A): (Buffer) -> C = { substituteFully(ring, it) } + +/** + * Represent [this] rational function as a regular context-less function. + */ +public fun > NumberedRationalFunction.asFunctionOfPolynomialOver(ring: A): (Buffer>) -> NumberedRationalFunction = { substitute(ring, it) } + +/** + * Represent [this] rational function as a regular context-less function. + */ +public fun > NumberedRationalFunction.asFunctionOfRationalFunctionOver(ring: A): (Buffer>) -> NumberedRationalFunction = { substitute(ring, it) } + +/** + * Returns algebraic derivative of received polynomial with respect to provided variable. + */ +@UnstableKMathAPI +public fun > NumberedPolynomial.derivativeWithRespectTo( + ring: A, + variable: Int, +): NumberedPolynomial = ring { + NumberedPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + if (degs.size > variable) return@forEach + put( + degs.mapIndexed { index, deg -> + when { + index != variable -> deg + deg > 0u -> deg - 1u + else -> return@forEach + } + }.cleanUp(), + multiplyByDoubling(c, degs[variable]) + ) + } + } + ) +} + +/** + * Returns algebraic derivative of received polynomial with respect to provided variable of specified order. + */ +@UnstableKMathAPI +public fun > NumberedPolynomial.nthDerivativeWithRespectTo( + ring: A, + variable: Int, + order: UInt +): NumberedPolynomial = ring { + if (order == 0u) return this@nthDerivativeWithRespectTo + NumberedPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + if (degs.size > variable) return@forEach + put( + degs.mapIndexed { index, deg -> + when { + index != variable -> deg + deg >= order -> deg - order + else -> return@forEach + } + }.cleanUp(), + degs[variable].let { deg -> + (deg downTo deg - order + 1u) + .fold(c) { acc, ord -> multiplyByDoubling(acc, ord) } + } + ) + } + } + ) +} + +/** + * Returns algebraic derivative of received polynomial with respect to provided variables of specified orders. + */ +@UnstableKMathAPI +public fun > NumberedPolynomial.nthDerivativeWithRespectTo( + ring: A, + variablesAndOrders: Map, +): NumberedPolynomial = ring { + val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u } + if (filteredVariablesAndOrders.isEmpty()) return this@nthDerivativeWithRespectTo + val maxRespectedVariable = filteredVariablesAndOrders.keys.maxOrNull()!! + NumberedPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + if (degs.size > maxRespectedVariable) return@forEach + put( + degs.mapIndexed { index, deg -> + if (index !in filteredVariablesAndOrders) return@mapIndexed deg + val order = filteredVariablesAndOrders[index]!! + if (deg >= order) deg - order else return@forEach + }.cleanUp(), + filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> + degs[index].let { deg -> + (deg downTo deg - order + 1u) + .fold(acc1) { acc2, ord -> multiplyByDoubling(acc2, ord) } + } + } + ) + } + } + ) +} + +/** + * Returns algebraic antiderivative of received polynomial with respect to provided variable. + */ +@UnstableKMathAPI +public fun > NumberedPolynomial.antiderivativeWithRespectTo( + ring: A, + variable: Int, +): NumberedPolynomial = ring { + NumberedPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + put( + List(max(variable + 1, degs.size)) { if (it != variable) degs[it] else degs[it] + 1u }, + c / multiplyByDoubling(one, degs[variable]) + ) + } + } + ) +} + +/** + * Returns algebraic antiderivative of received polynomial with respect to provided variable of specified order. + */ +@UnstableKMathAPI +public fun > NumberedPolynomial.nthAntiderivativeWithRespectTo( + ring: A, + variable: Int, + order: UInt +): NumberedPolynomial = ring { + if (order == 0u) return this@nthAntiderivativeWithRespectTo + NumberedPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + put( + List(max(variable + 1, degs.size)) { if (it != variable) degs[it] else degs[it] + order }, + degs[variable].let { deg -> + (deg downTo deg - order + 1u) + .fold(c) { acc, ord -> acc / multiplyByDoubling(one, ord) } + } + ) + } + } + ) +} + +/** + * Returns algebraic derivative of received polynomial with respect to provided variables of specified orders. + */ +@UnstableKMathAPI +public fun > NumberedPolynomial.nthAntiderivativeWithRespectTo( + ring: A, + variablesAndOrders: Map, +): NumberedPolynomial = ring { + val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u } + if (filteredVariablesAndOrders.isEmpty()) return this@nthAntiderivativeWithRespectTo + val maxRespectedVariable = filteredVariablesAndOrders.keys.maxOrNull()!! + NumberedPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + put( + List(max(maxRespectedVariable + 1, degs.size)) { degs[it] + filteredVariablesAndOrders.getOrElse(it) { 0u } }, + filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> + degs[index].let { deg -> + (deg downTo deg - order + 1u) + .fold(acc1) { acc2, ord -> acc2 / multiplyByDoubling(one, ord) } + } + } + ) + } + } + ) +} \ No newline at end of file From b5a94923b574bb840214fde3e1af1875c64777ef Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Fri, 17 Jun 2022 01:53:40 +0300 Subject: [PATCH 15/17] Fixed problems with JVM names. Exposed internal NumberedPolynomial constructor with opt-in condition. Added and upgraded tests. Fixed small bugs (mistakes). Upgraded arithmetic operations a bit. --- .../kmath/functions/ListPolynomial.kt | 60 +- .../kmath/functions/NumberedPolynomial.kt | 60 +- .../functions/NumberedRationalFunction.kt | 12 +- .../space/kscience/kmath/functions/misc.kt | 21 +- .../kmath/functions/numberedConstructors.kt | 79 +- .../kscience/kmath/functions/numberedUtil.kt | 2 +- .../kmath/functions/ListPolynomialTest.kt | 94 +- .../functions/NumberedConstructorsTest.kt | 111 ++ .../kmath/functions/NumberedPolynomialTest.kt | 1368 +++++++++++++++++ .../kscience/kmath/test/misc/IntModulo.kt | 6 +- 10 files changed, 1714 insertions(+), 99 deletions(-) create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt index 42e3f7301..b3f1eb8f7 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt @@ -100,14 +100,17 @@ public open class ListPolynomialSpace>( * The operation is equivalent to sum of [other] copies of [this]. */ public override operator fun ListPolynomial.times(other: Int): ListPolynomial = - if (other == 0) zero - else ListPolynomial( - coefficients - .toMutableList() - .apply { - for (deg in indices) this[deg] = this[deg] * other - } - ) + when (other) { + 0 -> zero + 1 -> this + else -> ListPolynomial( + coefficients + .toMutableList() + .apply { + for (deg in indices) this[deg] = this[deg] * other + } + ) + } /** * Returns sum of the integer represented as a polynomial and the polynomial. @@ -133,34 +136,39 @@ public open class ListPolynomialSpace>( * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. */ public override operator fun Int.minus(other: ListPolynomial): ListPolynomial = - if (this == 0) other - else - ListPolynomial( - other.coefficients - .toMutableList() - .apply { - forEachIndexed { index, c -> if (index != 0) this[index] = -c } + ListPolynomial( + other.coefficients + .toMutableList() + .apply { + if (this@minus == 0) { + indices.forEach { this[it] = -this[it] } + } else { + (1..lastIndex).forEach { this[it] = -this[it] } val result = this@minus - getOrElse(0) { constantZero } - if(size == 0) add(result) + if (size == 0) add(result) else this[0] = result } - ) + } + ) /** * Returns product of the integer represented as a polynomial and the polynomial. * * The operation is equivalent to sum of [this] copies of [other]. */ public override operator fun Int.times(other: ListPolynomial): ListPolynomial = - if (this == 0) zero - else ListPolynomial( - other.coefficients - .toMutableList() - .apply { - for (deg in indices) this[deg] = this@times * this[deg] - } - ) + when (this) { + 0 -> zero + 1 -> other + else -> ListPolynomial( + other.coefficients + .toMutableList() + .apply { + for (deg in indices) this[deg] = this@times * this[deg] + } + ) + } /** * Converts the integer [value] to polynomial. @@ -192,7 +200,7 @@ public open class ListPolynomialSpace>( else ListPolynomial( toMutableList() .apply { - forEachIndexed { index, c -> if (index != 0) this[index] = -c } + (1 .. lastIndex).forEach { this[it] = -this[it] } val result = if (size == 0) this@minus else this@minus - get(0) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt index 9304e66da..02a3af683 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -98,14 +98,17 @@ public class NumberedPolynomialSpace>( * The operation is equivalent to sum of [other] copies of [this]. */ public override operator fun NumberedPolynomial.times(other: Int): NumberedPolynomial = - if (other == 0) zero - else NumberedPolynomialAsIs( - coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this[degs]!! * other - } - ) + when (other) { + 0 -> zero + 1 -> this + else -> NumberedPolynomialAsIs( + coefficients + .toMutableMap() + .apply { + for (degs in keys) this[degs] = this[degs]!! * other + } + ) + } /** * Returns sum of the integer represented as a polynomial and the polynomial. @@ -130,16 +133,20 @@ public class NumberedPolynomialSpace>( * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. */ public override operator fun Int.minus(other: NumberedPolynomial): NumberedPolynomial = - if (this == 0) other - else - NumberedPolynomialAsIs( - other.coefficients - .toMutableMap() - .apply { + NumberedPolynomialAsIs( + other.coefficients + .toMutableMap() + .apply { + if (this@minus == 0) { + forEach { (key, value) -> this[key] = -value } + } else { + forEach { (key, value) -> if (key.isNotEmpty()) this[key] = -value } + val degs = emptyList() this[degs] = this@minus - getOrElse(degs) { constantZero } } + } ) /** * Returns product of the integer represented as a polynomial and the polynomial. @@ -147,14 +154,17 @@ public class NumberedPolynomialSpace>( * The operation is equivalent to sum of [this] copies of [other]. */ public override operator fun Int.times(other: NumberedPolynomial): NumberedPolynomial = - if (this == 0) zero - else NumberedPolynomialAsIs( - other.coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this@times * this[degs]!! - } - ) + when (this) { + 0 -> zero + 1 -> other + else -> NumberedPolynomialAsIs( + other.coefficients + .toMutableMap() + .apply { + for (degs in keys) this[degs] = this@times * this[degs]!! + } + ) + } /** * Converts the integer [value] to polynomial. @@ -185,7 +195,7 @@ public class NumberedPolynomialSpace>( else NumberedPolynomialAsIs( toMutableMap() .apply { - forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } + forEach { (degs, c) -> if (degs.isNotEmpty()) this[degs] = -c } val degs = emptyList() @@ -266,7 +276,7 @@ public class NumberedPolynomialSpace>( override operator fun NumberedPolynomial.plus(other: NumberedPolynomial): NumberedPolynomial = NumberedPolynomialAsIs( buildMap(coefficients.size + other.coefficients.size) { - other.coefficients.mapValuesTo(this) { it.value } + coefficients.mapValuesTo(this) { it.value } other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! + value else value } } ) @@ -276,7 +286,7 @@ public class NumberedPolynomialSpace>( override operator fun NumberedPolynomial.minus(other: NumberedPolynomial): NumberedPolynomial = NumberedPolynomialAsIs( buildMap(coefficients.size + other.coefficients.size) { - other.coefficients.mapValuesTo(this) { it.value } + coefficients.mapValuesTo(this) { it.value } other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! - value else -value } } ) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt index a2986879d..92f507735 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt @@ -119,11 +119,13 @@ public class NumberedRationalFunctionSpace> ( * Substitutes provided polynomial [argument] into [this] polynomial. */ @Suppress("NOTHING_TO_INLINE") + @JvmName("substitutePolynomial") public inline fun NumberedPolynomial.substitute(argument: Map>): NumberedPolynomial = substitute(ring, argument) /** * Substitutes provided rational function [argument] into [this] polynomial. */ @Suppress("NOTHING_TO_INLINE") + @JvmName("substituteRationalFunction") public inline fun NumberedPolynomial.substitute(argument: Map>): NumberedRationalFunction = substitute(ring, argument) /** * Substitutes provided constant [argument] into [this] rational function. @@ -134,11 +136,13 @@ public class NumberedRationalFunctionSpace> ( * Substitutes provided polynomial [argument] into [this] rational function. */ @Suppress("NOTHING_TO_INLINE") + @JvmName("substitutePolynomial") public inline fun NumberedRationalFunction.substitute(argument: Map>): NumberedRationalFunction = substitute(ring, argument) /** * Substitutes provided rational function [argument] into [this] rational function. */ @Suppress("NOTHING_TO_INLINE") + @JvmName("substituteRationalFunction") public inline fun NumberedRationalFunction.substitute(argument: Map>): NumberedRationalFunction = substitute(ring, argument) /** * Substitutes provided constant [argument] into [this] polynomial. @@ -149,11 +153,13 @@ public class NumberedRationalFunctionSpace> ( * Substitutes provided polynomial [argument] into [this] polynomial. */ @Suppress("NOTHING_TO_INLINE") + @JvmName("substitutePolynomial") public inline fun NumberedPolynomial.substitute(argument: Buffer>): NumberedPolynomial = substitute(ring, argument) /** * Substitutes provided rational function [argument] into [this] polynomial. */ @Suppress("NOTHING_TO_INLINE") + @JvmName("substituteRationalFunction") public inline fun NumberedPolynomial.substitute(argument: Buffer>): NumberedRationalFunction = substitute(ring, argument) /** * Substitutes provided constant [argument] into [this] rational function. @@ -164,11 +170,13 @@ public class NumberedRationalFunctionSpace> ( * Substitutes provided polynomial [arguments] into [this] rational function. */ @Suppress("NOTHING_TO_INLINE") + @JvmName("substitutePolynomial") public inline fun NumberedRationalFunction.substitute(arguments: Buffer>): NumberedRationalFunction = substitute(ring, arguments) /** * Substitutes provided rational function [arguments] into [this] rational function. */ @Suppress("NOTHING_TO_INLINE") + @JvmName("substituteRationalFunction") public inline fun NumberedRationalFunction.substitute(arguments: Buffer>): NumberedRationalFunction = substitute(ring, arguments) /** * Substitutes provided constant [arguments] into [this] polynomial. @@ -222,7 +230,7 @@ public class NumberedRationalFunctionSpace> ( * Substitutes provided [arguments] into [this] polynomial. */ @Suppress("NOTHING_TO_INLINE") - @JvmName("invokePolynomial") + @JvmName("invokeRationalFunction") public inline operator fun NumberedPolynomial.invoke(arguments: Buffer>): NumberedRationalFunction = substitute(ring, arguments) /** * Substitutes provided [arguments] into [this] rational function. @@ -234,6 +242,6 @@ public class NumberedRationalFunctionSpace> ( * Substitutes provided [arguments] into [this] rational function. */ @Suppress("NOTHING_TO_INLINE") - @JvmName("invokePolynomial") + @JvmName("invokeRationalFunction") public inline operator fun NumberedRationalFunction.invoke(arguments: Buffer>): NumberedRationalFunction = substitute(ring, arguments) } \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt index 8b6fac39e..7d6fc84fa 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt @@ -6,8 +6,27 @@ package space.kscience.kmath.functions +/** + * Marks operations that are going to be optimized reimplementations by reducing number of boxings but currently is + * under development and is not stable (or even ready to use). + */ @RequiresOptIn( message = "It's copy of operation with optimized boxing. It's currently unstable.", level = RequiresOptIn.Level.ERROR ) -internal annotation class UnstablePolynomialBoxingOptimization \ No newline at end of file +internal annotation class UnstablePolynomialBoxingOptimization + +/** + * Marks declarations that give access to internal entities of polynomials delicate structure. Thus, it allows to + * optimize performance a bit by skipping standard steps, but such skips may cause critical errors if something is + * implemented badly. Make sure you fully read and understand documentation and don't break internal contracts. + */ +@RequiresOptIn( + message = "This declaration gives access to delicate internal structure of polynomials. " + + "It allows to optimize performance by skipping unnecessary arguments check. " + + "But at the same time makes it easy to make a mistake " + + "that will cause wrong computation result or even runtime error. " + + "Make sure you fully read and understand documentation.", + level = RequiresOptIn.Level.WARNING +) +internal annotation class DelicatePolynomialAPI \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt index 05fff3472..37d5d7fb6 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt @@ -37,6 +37,38 @@ internal inline fun NumberedPolynomialAsIs(pairs: Collection @PublishedApi internal inline fun NumberedPolynomialAsIs(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(pairs.toMap()) +/** + * Constructs [NumberedPolynomial] with provided coefficients map [coefs]. The map is used as is. + * + * **Be sure you read description of [NumberedPolynomial.coefficients]. Otherwise, you may make a mistake that will + * cause wrong computation result or even runtime error.** + */ +@Suppress("FunctionName", "NOTHING_TO_INLINE") +@DelicatePolynomialAPI +public inline fun NumberedPolynomialWithoutCheck(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs) + +/** + * Constructs [NumberedPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient". + * The collections will be transformed to map with [toMap] and then will be used as is. + * + * **Be sure you read description of [NumberedPolynomial.coefficients]. Otherwise, you may make a mistake that will + * cause wrong computation result or even runtime error.** + */ +@Suppress("FunctionName", "NOTHING_TO_INLINE") +@DelicatePolynomialAPI +public inline fun NumberedPolynomialWithoutCheck(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs.toMap()) + +/** + * Constructs [NumberedPolynomial] with provided array of [pairs] of pairs "term's signature — term's coefficient". + * The array will be transformed to map with [toMap] and then will be used as is. + * + * **Be sure you read description of [NumberedPolynomial.coefficients]. Otherwise, you may make a mistake that will + * cause wrong computation result or even runtime error.** + */ +@Suppress("FunctionName", "NOTHING_TO_INLINE") +@DelicatePolynomialAPI +public inline fun NumberedPolynomialWithoutCheck(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(pairs.toMap()) + /** * Constructs [NumberedPolynomial] with provided coefficients map [coefs]. * @@ -245,11 +277,12 @@ public class NumberedPolynomialTermSignatureBuilder { * Declaring another power of the same variable will increase its degree by received degree. */ public infix fun Int.inPowerOf(deg: UInt) { - if (this > signature.lastIndex) { - signature.addAll(List(this - signature.lastIndex - 1) { 0u }) + val index = this - 1 + if (index > signature.lastIndex) { + signature.addAll(List(index - signature.lastIndex - 1) { 0u }) signature.add(deg) } else { - signature[this] += deg + signature[index] += deg } } /** @@ -334,22 +367,26 @@ public class NumberedPolynomialBuilder( // Waiting for context receivers :( FIXME: Replace with context receivers when they will be available -/** - * Creates [NumberedPolynomial] with lambda [block] in context of [this] ring of constants. - * - * For example, polynomial `5 x_1^2 x_3^3 - 6 x_2` can be described as - * ``` - * Int.algebra { - * val numberedPolynomial : NumberedPolynomial = NumberedPolynomial { - * 5 { 1 inPowerOf 2u; 3 inPowerOf 3u } // 5 x_1^2 x_3^3 + - * (-6) { 2 inPowerOf 1u } // (-6) x_2^1 - * } - * } - * ``` - */ -@UnstableKMathAPI -@Suppress("FunctionName") -public inline fun > A.NumberedPolynomial(initialCapacity: Int = 0, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder(::add, initialCapacity).apply(block).build() +///** +// * Creates [NumberedPolynomial] with lambda [block] in context of [this] ring of constants. +// * +// * For example, polynomial `5 x_1^2 x_3^3 - 6 x_2` can be described as +// * ``` +// * Int.algebra { +// * val numberedPolynomial : NumberedPolynomial = NumberedPolynomial { +// * 5 { 1 inPowerOf 2u; 3 inPowerOf 3u } // 5 x_1^2 x_3^3 + +// * (-6) { 2 inPowerOf 1u } // (-6) x_2^1 +// * } +// * } +// * ``` +// */ +// FIXME: For now this fabric does not let next two fabrics work. (See KT-52803.) Possible feature solutions: +// 1. `LowPriorityInOverloadResolution` becomes public. Then it should be applied to this function. +// 2. Union types are implemented. Then all three functions should be rewritten +// as one with single union type as a (context) receiver. +//@UnstableKMathAPI +//@Suppress("FunctionName") +//public inline fun > A.NumberedPolynomial(initialCapacity: Int = 0, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder(::add, initialCapacity).apply(block).build() /** * Creates [NumberedPolynomial] with lambda [block] in context of [this] ring of [NumberedPolynomial]s. * @@ -365,7 +402,7 @@ public inline fun > A.NumberedPolynomial(initialCapacity: Int = 0, */ @UnstableKMathAPI @Suppress("FunctionName") -public inline fun > NumberedPolynomialSpace.NumberedPolynomial(initialCapacity: Int, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() +public inline fun > NumberedPolynomialSpace.NumberedPolynomial(initialCapacity: Int = 0, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() /** * Creates [NumberedPolynomial] with lambda [block] in context of [this] field of [NumberedRationalFunction]s. * @@ -381,7 +418,7 @@ public inline fun > NumberedPolynomialSpace.NumberedPolynomi */ @UnstableKMathAPI @Suppress("FunctionName") -public inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(initialCapacity: Int, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() +public inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(initialCapacity: Int = 0, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() // Waiting for context receivers :( FIXME: Replace with context receivers when they will be available diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt index 484cd11e3..fca9a8ab8 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt @@ -86,7 +86,7 @@ public fun NumberedPolynomial.substitute(ring: Ring, args: Map /** * Substitutes provided arguments [args] into [this] polynomial. - */ // TODO: To optimize boxing + */ // TODO: To optimize boxing @JvmName("substitutePolynomial") public fun NumberedPolynomial.substitute(ring: Ring, args: Map>) : NumberedPolynomial = ring.numberedPolynomialSpace { diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt index c9950fac5..c4a7cc564 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt @@ -3,6 +3,8 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ +@file:Suppress("LocalVariableName") + package space.kscience.kmath.functions import space.kscience.kmath.test.misc.* @@ -28,25 +30,32 @@ class ListPolynomialTest { ListPolynomial(Rational(-2)) + 2, "test 3" ) - assertEquals( - ListPolynomial(), - ListPolynomial() + 0, + val polynomial_4 = ListPolynomial() + assertSame( + polynomial_4, + polynomial_4 + 0, "test 4" ) + val polynomial_5 = ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)) + assertSame( + polynomial_5, + polynomial_5 + 0, + "test 5" + ) assertEquals( ListPolynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + 1, - "test 5" + "test 6" ) assertEquals( ListPolynomial(Rational(-1)), ListPolynomial(Rational(-2)) + 1, - "test 6" + "test 7" ) assertEquals( ListPolynomial(Rational(2)), ListPolynomial() + 2, - "test 7" + "test 8" ) } } @@ -68,25 +77,32 @@ class ListPolynomialTest { ListPolynomial(Rational(2)) - 2, "test 3" ) - assertEquals( - ListPolynomial(), - ListPolynomial() - 0, + val polynomial_4 = ListPolynomial() + assertSame( + polynomial_4, + polynomial_4 - 0, "test 4" ) + val polynomial_5 = ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)) + assertEquals( + polynomial_5, + polynomial_5 - 0, + "test 5" + ) assertEquals( ListPolynomial(Rational(1), Rational(0), Rational(0), Rational(0)), ListPolynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - 1, - "test 5" + "test 6" ) assertEquals( ListPolynomial(Rational(1)), ListPolynomial(Rational(2)) - 1, - "test 6" + "test 7" ) assertEquals( ListPolynomial(Rational(-2)), ListPolynomial() - 2, - "test 7" + "test 8" ) } } @@ -103,6 +119,17 @@ class ListPolynomialTest { ListPolynomial(7, 0, 49, 21, 14) * 15, "test 2" ) + val polynomial = ListPolynomial(22, 26, 13, 15, 26) + assertSame( + zero, + polynomial * 0, + "test 3" + ) + assertSame( + polynomial, + polynomial * 1, + "test 4" + ) } } @Test @@ -123,25 +150,32 @@ class ListPolynomialTest { 2 + ListPolynomial(Rational(-2)), "test 3" ) - assertEquals( - ListPolynomial(), - 0 + ListPolynomial(), + val polynomial_4 = ListPolynomial() + assertSame( + polynomial_4, + 0 + polynomial_4, "test 4" ) + val polynomial_5 = ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)) + assertSame( + polynomial_5, + 0 + polynomial_5, + "test 5" + ) assertEquals( ListPolynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), 1 + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 5" + "test 6" ) assertEquals( ListPolynomial(Rational(-1)), 1 + ListPolynomial(Rational(-2)), - "test 6" + "test 7" ) assertEquals( ListPolynomial(Rational(2)), 2 + ListPolynomial(), - "test 7" + "test 8" ) } } @@ -163,25 +197,30 @@ class ListPolynomialTest { -2 - ListPolynomial(Rational(-2)), "test 3" ) + assertEquals( + ListPolynomial(Rational(-32, 9), Rational(-8, -9), Rational(8, 7)), + 0 - ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), + "test 4" + ) assertEquals( ListPolynomial(), 0 - ListPolynomial(), - "test 4" + "test 5" ) assertEquals( ListPolynomial(Rational(1), Rational(0), Rational(0), Rational(0)), -1 - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 5" + "test 6" ) assertEquals( ListPolynomial(Rational(1)), -1 - ListPolynomial(Rational(-2)), - "test 6" + "test 7" ) assertEquals( ListPolynomial(Rational(-2)), -2 - ListPolynomial(), - "test 7" + "test 8" ) } } @@ -198,6 +237,17 @@ class ListPolynomialTest { 15 * ListPolynomial(7, 0, 49, 21, 14), "test 2" ) + val polynomial = ListPolynomial(22, 26, 13, 15, 26) + assertSame( + zero, + 0 * polynomial, + "test 3" + ) + assertSame( + polynomial, + 1 * polynomial, + "test 4" + ) } } @Test diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt new file mode 100644 index 000000000..14493aaae --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt @@ -0,0 +1,111 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.functions + +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.algebra +import space.kscience.kmath.operations.invoke +import kotlin.test.Test +import kotlin.test.assertEquals + + +class NumberedConstructorsTest { + @Test + @UnstableKMathAPI + fun testBuilder() { + assertEquals( + NumberedPolynomialAsIs( + listOf(2u, 0u, 3u) to 5, + listOf(0u, 1u) to -6, + ), + Int.algebra.numberedPolynomialSpace { + NumberedPolynomial { + 5 { 1 inPowerOf 2u; 3 inPowerOf 3u } + (-6) { 2 inPowerOf 1u } + } + }, + "test 1" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to -1, + ), + Int.algebra.numberedPolynomialSpace { + NumberedPolynomial { + 5 { } + (-6) { } + } + }, + "test 2" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(2u) to -1, + ), + Int.algebra.numberedPolynomialSpace { + NumberedPolynomial { + 5 { 1 inPowerOf 1u; 1 inPowerOf 1u } + (-6) { 1 inPowerOf 2u } + } + }, + "test 3" + ) + } + @Test + @UnstableKMathAPI + fun testFabric() { + assertEquals( + NumberedPolynomialAsIs( + listOf(2u, 0u, 3u) to 5, + listOf(0u, 1u) to -6, + ), + Int.algebra { + NumberedPolynomial( + listOf(2u, 0u, 3u) to 5, + listOf(0u, 1u) to -6, + ) + }, + "test 1" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(2u, 0u, 3u) to 5, + listOf(0u, 1u) to -6, + ), + Int.algebra { + NumberedPolynomial( + listOf(2u, 0u, 3u, 0u) to 5, + listOf(0u, 1u, 0u, 0u) to -6, + ) + }, + "test 2" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to -1, + ), + Int.algebra { + NumberedPolynomial( + listOf(0u) to 5, + listOf(0u, 0u) to -6, + ) + }, + "test 3" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to 0, + ), + Int.algebra { + NumberedPolynomial( + listOf(0u) to 5, + listOf(0u, 0u) to -5, + ) + }, + "test 4" + ) + } +} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt new file mode 100644 index 000000000..537e3b85d --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt @@ -0,0 +1,1368 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +@file:Suppress("LocalVariableName") + +package space.kscience.kmath.functions + +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.test.misc.* +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertSame + + +@UnstableKMathAPI +class NumberedPolynomialTest { + @Test + fun test_Polynomial_Int_plus() { + RationalField.numberedPolynomialSpace { + assertEquals( + NumberedPolynomial { + Rational(-22, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(5, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + -3, + "test 1" + ) + assertEquals( + NumberedPolynomial { + Rational(-3, 1) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + -3, + "test 2" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 1) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(27, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + -3, + "test 3" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 1) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(27, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + -3, + "test 4" + ) + val polynomial_5 = NumberedPolynomial { + Rational(-22, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + assertSame( + polynomial_5, + polynomial_5 + 0, + "test 5" + ) + val polynomial_6 = NumberedPolynomial { + Rational(0, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + assertSame( + polynomial_6, + polynomial_6 + 0, + "test 6" + ) + val polynomial_7 = NumberedPolynomial { + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + assertSame( + polynomial_7, + polynomial_7 + 0, + "test 7" + ) + } + } + @Test + fun test_Polynomial_Int_minus() { + RationalField.numberedPolynomialSpace { + assertEquals( + NumberedPolynomial { + Rational(-22, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(5, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } - 3, + "test 1" + ) + assertEquals( + NumberedPolynomial { + Rational(-3, 1) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } - 3, + "test 2" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 1) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(27, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } - 3, + "test 3" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 1) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(27, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } - 3, + "test 4" + ) + val polynomial_5 = NumberedPolynomial { + Rational(-22, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + assertSame( + polynomial_5, + polynomial_5 - 0, + "test 5" + ) + val polynomial_6 = NumberedPolynomial { + Rational(0, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + assertSame( + polynomial_6, + polynomial_6 - 0, + "test 6" + ) + val polynomial_7 = NumberedPolynomial { + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + assertSame( + polynomial_7, + polynomial_7 - 0, + "test 7" + ) + } + } + @Test + fun test_Polynomial_Int_times() { + IntModuloRing(35).numberedPolynomialSpace { + assertEquals( + NumberedPolynomial { + m(34) with {} + m(2) with { 1 pow 3u } + m(1) with { 2 pow 1u } + m(20) with { 1 pow 1u } + m(2) with { 3 pow 2u } + }, + NumberedPolynomial { + m(22) with {} + m(26) with { 1 pow 3u } + m(13) with { 2 pow 1u } + m(15) with { 1 pow 1u } + m(26) with { 3 pow 2u } + } * 27, + "test 1" + ) + assertEquals( + NumberedPolynomial { + m(0) with {} + m(0) with { 1 pow 3u } + m(0) with { 2 pow 1u } + m(0) with { 1 pow 1u } + m(0) with { 3 pow 2u } + }, + NumberedPolynomial { + m(7) with {} + m(0) with { 1 pow 3u } + m(49) with { 2 pow 1u } + m(21) with { 1 pow 1u } + m(14) with { 3 pow 2u } + } * 15, + "test 2" + ) + val polynomial = NumberedPolynomial { + m(22) with {} + m(26) with { 1 pow 3u } + m(13) with { 2 pow 1u } + m(15) with { 1 pow 1u } + m(26) with { 3 pow 2u } + } + assertSame( + zero, + polynomial * 0, + "test 3" + ) + assertSame( + polynomial, + polynomial * 1, + "test 4" + ) + } + } + @Test + fun test_Int_Polynomial_plus() { + RationalField.numberedPolynomialSpace { + assertEquals( + NumberedPolynomial { + Rational(-22, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + -3 + NumberedPolynomial { + Rational(5, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 1" + ) + assertEquals( + NumberedPolynomial { + Rational(-3, 1) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + -3 + NumberedPolynomial { + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 2" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 1) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + -3 + NumberedPolynomial { + Rational(27, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 3" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 1) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + -3 + NumberedPolynomial { + Rational(27, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 4" + ) + val polynomial_5 = NumberedPolynomial { + Rational(-22, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + assertSame( + polynomial_5, + 0 + polynomial_5, + "test 5" + ) + val polynomial_6 = NumberedPolynomial { + Rational(0, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + assertSame( + polynomial_6, + 0 + polynomial_6, + "test 6" + ) + val polynomial_7 = NumberedPolynomial { + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + assertSame( + polynomial_7, + 0 + polynomial_7, + "test 7" + ) + } + } + @Test + fun test_Int_Polynomial_minus() { + RationalField.numberedPolynomialSpace { + assertEquals( + NumberedPolynomial { + Rational(22, 9) with {} + Rational(8, 9) with { 1 pow 3u } + Rational(8, 7) with { 2 pow 4u } + }, + 3 - NumberedPolynomial { + Rational(5, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 1" + ) + assertEquals( + NumberedPolynomial { + Rational(3, 1) with {} + Rational(8, 9) with { 1 pow 3u } + Rational(8, 7) with { 2 pow 4u } + }, + 3 - NumberedPolynomial { + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 2" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 1) with {} + Rational(8, 9) with { 1 pow 3u } + Rational(8, 7) with { 2 pow 4u } + }, + 3 - NumberedPolynomial { + Rational(27, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 3" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 1) with {} + Rational(8, 9) with { 1 pow 3u } + Rational(8, 7) with { 2 pow 4u } + }, + 3 - NumberedPolynomial { + Rational(27, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 4" + ) + assertEquals( + NumberedPolynomial { + Rational(22, 9) with {} + Rational(8, 9) with { 1 pow 3u } + Rational(8, 7) with { 2 pow 4u } + }, + 0 - NumberedPolynomial { + Rational(-22, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 5" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 9) with {} + Rational(8, 9) with { 1 pow 3u } + Rational(8, 7) with { 2 pow 4u } + }, + 0 - NumberedPolynomial { + Rational(0, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 6" + ) + assertEquals( + NumberedPolynomial { + Rational(8, 9) with { 1 pow 3u } + Rational(8, 7) with { 2 pow 4u } + }, + 0 - NumberedPolynomial { + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 7" + ) + } + } + @Test + fun test_Int_Polynomial_times() { + IntModuloRing(35).numberedPolynomialSpace { + assertEquals( + NumberedPolynomial { + m(34) with {} + m(2) with { 1 pow 3u } + m(1) with { 2 pow 1u } + m(20) with { 1 pow 1u } + m(2) with { 3 pow 2u } + }, + 27 * NumberedPolynomial { + m(22) with {} + m(26) with { 1 pow 3u } + m(13) with { 2 pow 1u } + m(15) with { 1 pow 1u } + m(26) with { 3 pow 2u } + }, + "test 1" + ) + assertEquals( + NumberedPolynomial { + m(0) with {} + m(0) with { 1 pow 3u } + m(0) with { 2 pow 1u } + m(0) with { 1 pow 1u } + m(0) with { 3 pow 2u } + }, + 15 * NumberedPolynomial { + m(7) with {} + m(0) with { 1 pow 3u } + m(49) with { 2 pow 1u } + m(21) with { 1 pow 1u } + m(14) with { 3 pow 2u } + }, + "test 2" + ) + val polynomial = NumberedPolynomial { + m(22) with {} + m(26) with { 1 pow 3u } + m(13) with { 2 pow 1u } + m(15) with { 1 pow 1u } + m(26) with { 3 pow 2u } + } + assertSame( + zero, + 0 * polynomial, + "test 3" + ) + assertSame( + polynomial, + 1 * polynomial, + "test 4" + ) + } + } + @Test + fun test_Polynomial_Constant_plus() { + RationalField.numberedPolynomialSpace { + assertEquals( + NumberedPolynomial { + Rational(-22, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(5, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + Rational(-3), + "test 1" + ) + assertEquals( + NumberedPolynomial { + Rational(-3, 1) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + Rational(-3), + "test 2" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 1) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(27, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + Rational(-3), + "test 3" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 1) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(27, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + Rational(-3), + "test 4" + ) + assertEquals( + NumberedPolynomial { + Rational(-22, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(-22, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + Rational(0), + "test 5" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(0, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + Rational(0), + "test 6" + ) + assertEquals( + NumberedPolynomial { + Rational(0) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + Rational(0), + "test 7" + ) + } + } + @Test + fun test_Polynomial_Constant_minus() { + RationalField.numberedPolynomialSpace { + assertEquals( + NumberedPolynomial { + Rational(-22, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(5, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } - Rational(3), + "test 1" + ) + assertEquals( + NumberedPolynomial { + Rational(-3, 1) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } - Rational(3), + "test 2" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 1) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(27, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } - Rational(3), + "test 3" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 1) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(27, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } - Rational(3), + "test 4" + ) + assertEquals( + NumberedPolynomial { + Rational(-22, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(-22, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } - Rational(0), + "test 5" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(0, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } - Rational(0), + "test 6" + ) + assertEquals( + NumberedPolynomial { + Rational(0) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } - Rational(0), + "test 7" + ) + } + } + @Test + fun test_Polynomial_Constant_times() { + IntModuloRing(35).numberedPolynomialSpace { + assertEquals( + NumberedPolynomial { + m(34) with {} + m(2) with { 1 pow 3u } + m(1) with { 2 pow 1u } + m(20) with { 1 pow 1u } + m(2) with { 3 pow 2u } + }, + NumberedPolynomial { + m(22) with {} + m(26) with { 1 pow 3u } + m(13) with { 2 pow 1u } + m(15) with { 1 pow 1u } + m(26) with { 3 pow 2u } + } * m(27), + "test 1" + ) + assertEquals( + NumberedPolynomial { + m(0) with {} + m(0) with { 1 pow 3u } + m(0) with { 2 pow 1u } + m(0) with { 1 pow 1u } + m(0) with { 3 pow 2u } + }, + NumberedPolynomial { + m(7) with {} + m(0) with { 1 pow 3u } + m(49) with { 2 pow 1u } + m(21) with { 1 pow 1u } + m(14) with { 3 pow 2u } + } * m(15), + "test 2" + ) + assertEquals( + NumberedPolynomial { + m(0) with {} + m(0) with { 1 pow 3u } + m(0) with { 2 pow 1u } + m(0) with { 1 pow 1u } + m(0) with { 3 pow 2u } + }, + NumberedPolynomial { + m(22) with {} + m(26) with { 1 pow 3u } + m(13) with { 2 pow 1u } + m(15) with { 1 pow 1u } + m(26) with { 3 pow 2u } + } * m(0), + "test 3" + ) + assertEquals( + NumberedPolynomial { + m(22) with {} + m(26) with { 1 pow 3u } + m(13) with { 2 pow 1u } + m(15) with { 1 pow 1u } + m(26) with { 3 pow 2u } + }, + NumberedPolynomial { + m(22) with {} + m(26) with { 1 pow 3u } + m(13) with { 2 pow 1u } + m(15) with { 1 pow 1u } + m(26) with { 3 pow 2u } + } * m(1), + "test 4" + ) + } + } + @Test + fun test_Constant_Polynomial_plus() { + RationalField.numberedPolynomialSpace { + assertEquals( + NumberedPolynomial { + Rational(-22, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + Rational(-3) + NumberedPolynomial { + Rational(5, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 1" + ) + assertEquals( + NumberedPolynomial { + Rational(-3, 1) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + Rational(-3) + NumberedPolynomial { + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 2" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 1) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + Rational(-3) + NumberedPolynomial { + Rational(27, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 3" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 1) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + Rational(-3) + NumberedPolynomial { + Rational(27, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 4" + ) + assertEquals( + NumberedPolynomial { + Rational(-22, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + Rational(0) + NumberedPolynomial { + Rational(-22, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 5" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + Rational(0) + NumberedPolynomial { + Rational(0, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 6" + ) + assertEquals( + NumberedPolynomial { + Rational(0) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + Rational(0) + NumberedPolynomial { + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 7" + ) + } + } + @Test + fun test_Constant_Polynomial_minus() { + RationalField.numberedPolynomialSpace { + assertEquals( + NumberedPolynomial { + Rational(22, 9) with {} + Rational(8, 9) with { 1 pow 3u } + Rational(8, 7) with { 2 pow 4u } + }, + Rational(3) - NumberedPolynomial { + Rational(5, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 1" + ) + assertEquals( + NumberedPolynomial { + Rational(3, 1) with {} + Rational(8, 9) with { 1 pow 3u } + Rational(8, 7) with { 2 pow 4u } + }, + Rational(3) - NumberedPolynomial { + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 2" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 1) with {} + Rational(8, 9) with { 1 pow 3u } + Rational(8, 7) with { 2 pow 4u } + }, + Rational(3) - NumberedPolynomial { + Rational(27, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 3" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 1) with {} + Rational(8, 9) with { 1 pow 3u } + Rational(8, 7) with { 2 pow 4u } + }, + Rational(3) - NumberedPolynomial { + Rational(27, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 4" + ) + assertEquals( + NumberedPolynomial { + Rational(22, 9) with {} + Rational(8, 9) with { 1 pow 3u } + Rational(8, 7) with { 2 pow 4u } + }, + Rational(0) - NumberedPolynomial { + Rational(-22, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 5" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 9) with {} + Rational(8, 9) with { 1 pow 3u } + Rational(8, 7) with { 2 pow 4u } + }, + Rational(0) - NumberedPolynomial { + Rational(0, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 6" + ) + assertEquals( + NumberedPolynomial { + Rational(0) with {} + Rational(8, 9) with { 1 pow 3u } + Rational(8, 7) with { 2 pow 4u } + }, + Rational(0) - NumberedPolynomial { + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 7" + ) + } + } + @Test + fun test_Constant_Polynomial_times() { + IntModuloRing(35).numberedPolynomialSpace { + assertEquals( + NumberedPolynomial { + m(34) with {} + m(2) with { 1 pow 3u } + m(1) with { 2 pow 1u } + m(20) with { 1 pow 1u } + m(2) with { 3 pow 2u } + }, + m(27) * NumberedPolynomial { + m(22) with {} + m(26) with { 1 pow 3u } + m(13) with { 2 pow 1u } + m(15) with { 1 pow 1u } + m(26) with { 3 pow 2u } + }, + "test 1" + ) + assertEquals( + NumberedPolynomial { + m(0) with {} + m(0) with { 1 pow 3u } + m(0) with { 2 pow 1u } + m(0) with { 1 pow 1u } + m(0) with { 3 pow 2u } + }, + m(15) * NumberedPolynomial { + m(7) with {} + m(0) with { 1 pow 3u } + m(49) with { 2 pow 1u } + m(21) with { 1 pow 1u } + m(14) with { 3 pow 2u } + }, + "test 2" + ) + assertEquals( + NumberedPolynomial { + m(0) with {} + m(0) with { 1 pow 3u } + m(0) with { 2 pow 1u } + m(0) with { 1 pow 1u } + m(0) with { 3 pow 2u } + }, + m(0) * NumberedPolynomial { + m(22) with {} + m(26) with { 1 pow 3u } + m(13) with { 2 pow 1u } + m(15) with { 1 pow 1u } + m(26) with { 3 pow 2u } + }, + "test 3" + ) + assertEquals( + NumberedPolynomial { + m(22) with {} + m(26) with { 1 pow 3u } + m(13) with { 2 pow 1u } + m(15) with { 1 pow 1u } + m(26) with { 3 pow 2u } + }, + m(1) * NumberedPolynomial { + m(22) with {} + m(26) with { 1 pow 3u } + m(13) with { 2 pow 1u } + m(15) with { 1 pow 1u } + m(26) with { 3 pow 2u } + }, + "test 4" + ) + } + } + @Test + fun test_Polynomial_unaryMinus() { + RationalField.numberedPolynomialSpace { + assertEquals( + NumberedPolynomial { + Rational(-5, 9) with { 1 pow 5u } + Rational(8, 9) with {} + Rational(8, 7) with { 7 pow 13u } + }, + -NumberedPolynomial { + Rational(5, 9) with { 1 pow 5u } + Rational(-8, 9) with {} + Rational(-8, 7) with { 7 pow 13u } + }, + "test 1" + ) + assertEquals( + NumberedPolynomial { + Rational(-5, 9) with { 3 pow 7u } + Rational(8, 9) with {} + Rational(8, 7) with { 1 pow 3u } + Rational(0) with { 2 pow 4u } + Rational(0) with { 1 pow 5u } + }, + -NumberedPolynomial { + Rational(5, 9) with { 3 pow 7u } + Rational(-8, 9) with {} + Rational(-8, 7) with { 1 pow 3u } + Rational(0) with { 2 pow 4u } + Rational(0) with { 1 pow 5u } + }, + "test 2" + ) + } + } + @Test + fun test_Polynomial_Polynomial_plus() { + RationalField.numberedPolynomialSpace { + assertEquals( + NumberedPolynomial { + Rational(-17, 2) with {} + Rational(-1, 3) with { 1 pow 1u } + Rational(-25, 21) with { 1 pow 2u } + Rational(146, 63) with { 2 pow 1u } + Rational(-3, 5) with { 1 pow 1u; 2 pow 1u } + Rational(61, 15) with { 1 pow 2u; 2 pow 1u } + Rational(157, 63) with { 2 pow 2u } + Rational(-55, 21) with { 1 pow 1u; 2 pow 2u } + Rational(11, 24) with { 1 pow 2u; 2 pow 2u } + }, + NumberedPolynomial { + Rational(6, 4) with {} + Rational(-2, 6) with { 1 pow 1u } + Rational(10, 6) with { 1 pow 2u } + Rational(17, 7) with { 2 pow 1u } + Rational(-7, 7) with { 1 pow 1u; 2 pow 1u } + Rational(12, 5) with { 1 pow 2u; 2 pow 1u } + Rational(12, 7) with { 2 pow 2u } + Rational(-10, 3) with { 1 pow 1u; 2 pow 2u } + Rational(9, 8) with { 1 pow 2u; 2 pow 2u } + } + NumberedPolynomial { + Rational(-20, 2) with {} + Rational(0, 9) with { 1 pow 1u } + Rational(-20, 7) with { 1 pow 2u } + Rational(-1, 9) with { 2 pow 1u } + Rational(2, 5) with { 1 pow 1u; 2 pow 1u } + Rational(10, 6) with { 1 pow 2u; 2 pow 1u } + Rational(7, 9) with { 2 pow 2u } + Rational(5, 7) with { 1 pow 1u; 2 pow 2u } + Rational(-2, 3) with { 1 pow 2u; 2 pow 2u } + }, + "test 1" + ) + assertEquals( + NumberedPolynomial { + Rational(-17, 2) with {} + Rational(-1, 3) with { 1 pow 1u } + Rational(-25, 21) with { 1 pow 2u } + Rational(-1, 9) with { 2 pow 1u } + Rational(2, 5) with { 1 pow 1u; 2 pow 1u } + Rational(10, 6) with { 1 pow 2u; 2 pow 1u } + Rational(157, 63) with { 2 pow 2u } + Rational(-55, 21) with { 1 pow 1u; 2 pow 2u } + Rational(11, 24) with { 1 pow 2u; 2 pow 2u } + }, + NumberedPolynomial { + Rational(6, 4) with {} + Rational(-2, 6) with { 1 pow 1u } + Rational(10, 6) with { 1 pow 2u } + Rational(12, 7) with { 2 pow 2u } + Rational(-10, 3) with { 1 pow 1u; 2 pow 2u } + Rational(9, 8) with { 1 pow 2u; 2 pow 2u } + } + NumberedPolynomial { + Rational(-20, 2) with {} + Rational(0, 9) with { 1 pow 1u } + Rational(-20, 7) with { 1 pow 2u } + Rational(-1, 9) with { 2 pow 1u } + Rational(2, 5) with { 1 pow 1u; 2 pow 1u } + Rational(10, 6) with { 1 pow 2u; 2 pow 1u } + Rational(7, 9) with { 2 pow 2u } + Rational(5, 7) with { 1 pow 1u; 2 pow 2u } + Rational(-2, 3) with { 1 pow 2u; 2 pow 2u } + }, + "test 2" + ) + assertEquals( + NumberedPolynomial { + Rational(-17, 2) with {} + Rational(-1, 3) with { 1 pow 1u } + Rational(-25, 21) with { 1 pow 2u } + Rational(-1, 9) with { 2 pow 1u } + Rational(2, 5) with { 1 pow 1u; 2 pow 1u } + Rational(10, 6) with { 1 pow 2u; 2 pow 1u } + Rational(12, 7) with { 2 pow 2u } + Rational(-10, 3) with { 1 pow 1u; 2 pow 2u } + Rational(9, 8) with { 1 pow 2u; 2 pow 2u } + }, + NumberedPolynomial { + Rational(6, 4) with {} + Rational(-2, 6) with { 1 pow 1u } + Rational(10, 6) with { 1 pow 2u } + Rational(12, 7) with { 2 pow 2u } + Rational(-10, 3) with { 1 pow 1u; 2 pow 2u } + Rational(9, 8) with { 1 pow 2u; 2 pow 2u } + } + NumberedPolynomial { + Rational(-20, 2) with {} + Rational(0, 9) with { 1 pow 1u } + Rational(-20, 7) with { 1 pow 2u } + Rational(-1, 9) with { 2 pow 1u } + Rational(2, 5) with { 1 pow 1u; 2 pow 1u } + Rational(10, 6) with { 1 pow 2u; 2 pow 1u } + Rational(0) with { 2 pow 2u } + Rational(0) with { 1 pow 1u; 2 pow 2u } + Rational(0) with { 1 pow 2u; 2 pow 2u } + }, + "test 3" + ) + assertEquals( + NumberedPolynomial { + Rational(0) with {} + Rational(0) with { 1 pow 1u } + Rational(0) with { 1 pow 2u } + Rational(0) with { 2 pow 1u } + Rational(0) with { 1 pow 1u; 2 pow 1u } + Rational(0) with { 1 pow 2u; 2 pow 1u } + Rational(0) with { 2 pow 2u } + Rational(0) with { 1 pow 1u; 2 pow 2u } + Rational(0) with { 1 pow 2u; 2 pow 2u } + }, + NumberedPolynomial { + Rational(6, 4) with {} + Rational(-2, 6) with { 1 pow 1u } + Rational(10, 6) with { 1 pow 2u } + Rational(17, 7) with { 2 pow 1u } + Rational(-7, 7) with { 1 pow 1u; 2 pow 1u } + Rational(12, 5) with { 1 pow 2u; 2 pow 1u } + Rational(12, 7) with { 2 pow 2u } + Rational(-10, 3) with { 1 pow 1u; 2 pow 2u } + Rational(9, 8) with { 1 pow 2u; 2 pow 2u } + } + NumberedPolynomial { + Rational(-6, 4) with {} + Rational(2, 6) with { 1 pow 1u } + Rational(-10, 6) with { 1 pow 2u } + Rational(-17, 7) with { 2 pow 1u } + Rational(7, 7) with { 1 pow 1u; 2 pow 1u } + Rational(-12, 5) with { 1 pow 2u; 2 pow 1u } + Rational(-12, 7) with { 2 pow 2u } + Rational(10, 3) with { 1 pow 1u; 2 pow 2u } + Rational(-9, 8) with { 1 pow 2u; 2 pow 2u } + }, + "test 4" + ) + } + } + @Test + fun test_Polynomial_Polynomial_minus() { + RationalField.numberedPolynomialSpace { + assertEquals( + NumberedPolynomial { + Rational(-17, 2) with {} + Rational(-1, 3) with { 1 pow 1u } + Rational(-25, 21) with { 1 pow 2u } + Rational(146, 63) with { 2 pow 1u } + Rational(-3, 5) with { 1 pow 1u; 2 pow 1u } + Rational(61, 15) with { 1 pow 2u; 2 pow 1u } + Rational(157, 63) with { 2 pow 2u } + Rational(-55, 21) with { 1 pow 1u; 2 pow 2u } + Rational(11, 24) with { 1 pow 2u; 2 pow 2u } + }, + NumberedPolynomial { + Rational(6, 4) with {} + Rational(-2, 6) with { 1 pow 1u } + Rational(10, 6) with { 1 pow 2u } + Rational(17, 7) with { 2 pow 1u } + Rational(-7, 7) with { 1 pow 1u; 2 pow 1u } + Rational(12, 5) with { 1 pow 2u; 2 pow 1u } + Rational(12, 7) with { 2 pow 2u } + Rational(-10, 3) with { 1 pow 1u; 2 pow 2u } + Rational(9, 8) with { 1 pow 2u; 2 pow 2u } + } - NumberedPolynomial { + Rational(20, 2) with {} + Rational(0, 9) with { 1 pow 1u } + Rational(20, 7) with { 1 pow 2u } + Rational(1, 9) with { 2 pow 1u } + Rational(-2, 5) with { 1 pow 1u; 2 pow 1u } + Rational(-10, 6) with { 1 pow 2u; 2 pow 1u } + Rational(-7, 9) with { 2 pow 2u } + Rational(-5, 7) with { 1 pow 1u; 2 pow 2u } + Rational(2, 3) with { 1 pow 2u; 2 pow 2u } + }, + "test 1" + ) + assertEquals( + NumberedPolynomial { + Rational(-17, 2) with {} + Rational(-1, 3) with { 1 pow 1u } + Rational(-25, 21) with { 1 pow 2u } + Rational(-1, 9) with { 2 pow 1u } + Rational(2, 5) with { 1 pow 1u; 2 pow 1u } + Rational(10, 6) with { 1 pow 2u; 2 pow 1u } + Rational(157, 63) with { 2 pow 2u } + Rational(-55, 21) with { 1 pow 1u; 2 pow 2u } + Rational(11, 24) with { 1 pow 2u; 2 pow 2u } + }, + NumberedPolynomial { + Rational(6, 4) with {} + Rational(-2, 6) with { 1 pow 1u } + Rational(10, 6) with { 1 pow 2u } + Rational(12, 7) with { 2 pow 2u } + Rational(-10, 3) with { 1 pow 1u; 2 pow 2u } + Rational(9, 8) with { 1 pow 2u; 2 pow 2u } + } - NumberedPolynomial { + Rational(20, 2) with {} + Rational(0, 9) with { 1 pow 1u } + Rational(20, 7) with { 1 pow 2u } + Rational(1, 9) with { 2 pow 1u } + Rational(-2, 5) with { 1 pow 1u; 2 pow 1u } + Rational(-10, 6) with { 1 pow 2u; 2 pow 1u } + Rational(-7, 9) with { 2 pow 2u } + Rational(-5, 7) with { 1 pow 1u; 2 pow 2u } + Rational(2, 3) with { 1 pow 2u; 2 pow 2u } + }, + "test 2" + ) + assertEquals( + NumberedPolynomial { + Rational(-17, 2) with {} + Rational(-1, 3) with { 1 pow 1u } + Rational(-25, 21) with { 1 pow 2u } + Rational(-1, 9) with { 2 pow 1u } + Rational(2, 5) with { 1 pow 1u; 2 pow 1u } + Rational(10, 6) with { 1 pow 2u; 2 pow 1u } + Rational(12, 7) with { 2 pow 2u } + Rational(-10, 3) with { 1 pow 1u; 2 pow 2u } + Rational(9, 8) with { 1 pow 2u; 2 pow 2u } + }, + NumberedPolynomial { + Rational(6, 4) with {} + Rational(-2, 6) with { 1 pow 1u } + Rational(10, 6) with { 1 pow 2u } + Rational(12, 7) with { 2 pow 2u } + Rational(-10, 3) with { 1 pow 1u; 2 pow 2u } + Rational(9, 8) with { 1 pow 2u; 2 pow 2u } + } - NumberedPolynomial { + Rational(20, 2) with {} + Rational(0, 9) with { 1 pow 1u } + Rational(20, 7) with { 1 pow 2u } + Rational(1, 9) with { 2 pow 1u } + Rational(-2, 5) with { 1 pow 1u; 2 pow 1u } + Rational(-10, 6) with { 1 pow 2u; 2 pow 1u } + Rational(0) with { 2 pow 2u } + Rational(0) with { 1 pow 1u; 2 pow 2u } + Rational(0) with { 1 pow 2u; 2 pow 2u } + }, + "test 3" + ) + assertEquals( + NumberedPolynomial { + Rational(0) with {} + Rational(0) with { 1 pow 1u } + Rational(0) with { 1 pow 2u } + Rational(0) with { 2 pow 1u } + Rational(0) with { 1 pow 1u; 2 pow 1u } + Rational(0) with { 1 pow 2u; 2 pow 1u } + Rational(0) with { 2 pow 2u } + Rational(0) with { 1 pow 1u; 2 pow 2u } + Rational(0) with { 1 pow 2u; 2 pow 2u } + }, + NumberedPolynomial { + Rational(6, 4) with {} + Rational(-2, 6) with { 1 pow 1u } + Rational(10, 6) with { 1 pow 2u } + Rational(17, 7) with { 2 pow 1u } + Rational(-7, 7) with { 1 pow 1u; 2 pow 1u } + Rational(12, 5) with { 1 pow 2u; 2 pow 1u } + Rational(12, 7) with { 2 pow 2u } + Rational(-10, 3) with { 1 pow 1u; 2 pow 2u } + Rational(9, 8) with { 1 pow 2u; 2 pow 2u } + } - NumberedPolynomial { + Rational(6, 4) with {} + Rational(-2, 6) with { 1 pow 1u } + Rational(10, 6) with { 1 pow 2u } + Rational(17, 7) with { 2 pow 1u } + Rational(-7, 7) with { 1 pow 1u; 2 pow 1u } + Rational(12, 5) with { 1 pow 2u; 2 pow 1u } + Rational(12, 7) with { 2 pow 2u } + Rational(-10, 3) with { 1 pow 1u; 2 pow 2u } + Rational(9, 8) with { 1 pow 2u; 2 pow 2u } + }, + "test 4" + ) + } + } + @Test + fun test_Polynomial_Polynomial_times() { + IntModuloRing(35).numberedPolynomialSpace { + // (p + q + r) * (p^2 + q^2 + r^2 - pq - pr - qr) = p^3 + q^3 + r^3 - 3pqr + assertEquals( + NumberedPolynomial { + m(1) with { 1 pow 3u } + m(1) with { 2 pow 3u } + m(1) with { 3 pow 3u } + m(0) with { 1 pow 1u; 2 pow 2u } + m(0) with { 2 pow 1u; 3 pow 2u } + m(0) with { 3 pow 1u; 1 pow 2u } + m(0) with { 1 pow 1u; 3 pow 2u } + m(0) with { 2 pow 1u; 1 pow 2u } + m(0) with { 3 pow 1u; 2 pow 2u } + m(-3) with { 1 pow 1u; 2 pow 1u; 3 pow 1u } + }, + NumberedPolynomial { + m(1) with { 1 pow 1u } + m(1) with { 2 pow 1u } + m(1) with { 3 pow 1u } + } * NumberedPolynomial { + m(1) with { 1 pow 2u } + m(1) with { 2 pow 2u } + m(1) with { 3 pow 2u } + m(-1) with { 1 pow 1u; 2 pow 1u } + m(-1) with { 2 pow 1u; 3 pow 1u } + m(-1) with { 3 pow 1u; 1 pow 1u } + }, + "test 1" + ) + // Spoiler: 5 * 7 = 0 + assertEquals( + NumberedPolynomial { + m(0) with { 1 pow 2u } + m(0) with { 2 pow 2u } + m(0) with { 3 pow 2u } + m(0) with { 1 pow 1u; 2 pow 1u } + m(0) with { 2 pow 1u; 3 pow 1u } + m(0) with { 3 pow 1u; 1 pow 1u } + }, + NumberedPolynomial { + m(5) with { 1 pow 1u } + m(-25) with { 2 pow 1u } + m(10) with { 3 pow 1u } + } * NumberedPolynomial { + m(21) with { 1 pow 1u } + m(14) with { 2 pow 1u } + m(-7) with { 3 pow 1u } + }, + "test 2" + ) + } + } +} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt index 89764db46..afd2b5add 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt @@ -7,6 +7,7 @@ package space.kscience.kmath.test.misc import space.kscience.kmath.functions.ListPolynomial import space.kscience.kmath.functions.ListPolynomialSpace +import space.kscience.kmath.functions.PolynomialSpaceOverRing import space.kscience.kmath.operations.Ring @@ -135,4 +136,7 @@ class IntModuloRing : Ring { fun ListPolynomialSpace.ListPolynomial(vararg coefs: Int): ListPolynomial = ListPolynomial(coefs.map { IntModulo(it, ring.modulus) }) fun IntModuloRing.ListPolynomial(vararg coefs: Int): ListPolynomial = - ListPolynomial(coefs.map { IntModulo(it, modulus) }) \ No newline at end of file + ListPolynomial(coefs.map { IntModulo(it, modulus) }) + +fun IntModuloRing.m(arg: Int) = IntModulo(arg, modulus) +fun PolynomialSpaceOverRing.m(arg: Int) = IntModulo(arg, ring.modulus) \ No newline at end of file From 1ea336b70ea5a0f44722071b29193215c1460b14 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Fri, 17 Jun 2022 22:07:54 +0300 Subject: [PATCH 16/17] Added some test of NumberedPolynomial utilities. --- .../functions/NumberedPolynomialUtilTest.kt | 293 ++++++++++++++++++ .../kscience/kmath/test/misc/assertion.kt | 14 + 2 files changed, 307 insertions(+) create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/assertion.kt diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt new file mode 100644 index 000000000..ecad6198e --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt @@ -0,0 +1,293 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.functions + +import space.kscience.kmath.test.misc.Rational +import space.kscience.kmath.test.misc.RationalField +import space.kscience.kmath.test.misc.assertContentEquals +import kotlin.test.Test +import kotlin.test.assertEquals + + +class NumberedPolynomialUtilTest { + @Test + fun test_substitute_Double_Map() { + assertContentEquals( + mapOf(emptyList() to 0.0), + NumberedPolynomialAsIs( + listOf() to 1.0, + listOf(1u) to -2.0, + listOf(2u) to 1.0, + ).substitute(mapOf( + 0 to 1.0 + )).coefficients, + 0.001, + "test 1" + ) + assertContentEquals( + mapOf( + listOf() to 0.8597048543814783, + listOf(1u) to 0.22997637465889875, + listOf(2u) to 0.32675302591924016, + listOf(0u, 1u) to 0.4561746111587508, + listOf(1u, 1u) to 0.5304946210170756, + listOf(2u, 1u) to 0.6244313712888998, + listOf(0u, 2u) to 0.2700930201481795, + listOf(1u, 2u) to -0.06962351375204712, + listOf(2u, 2u) to -0.015206988092131501, + ), + NumberedPolynomialAsIs( + listOf() to 0.8597048543814783, + listOf(1u) to 0.22997637465889875, + listOf(2u) to 0.32675302591924016, + listOf(0u, 1u) to 0.4561746111587508, + listOf(1u, 1u) to 0.5304946210170756, + listOf(2u, 1u) to 0.6244313712888998, + listOf(0u, 2u) to 0.2700930201481795, + listOf(1u, 2u) to -0.06962351375204712, + listOf(2u, 2u) to -0.015206988092131501, + ).substitute(mapOf()).coefficients, + 0.001, + "test 2" + ) + assertContentEquals( + mapOf( + listOf() to 0.8597048543814783, + listOf(0u, 1u) to 0.4561746111587508, + listOf(0u, 2u) to 0.2700930201481795, + ), + NumberedPolynomialAsIs( + listOf() to 0.8597048543814783, + listOf(1u) to 0.22997637465889875, + listOf(2u) to 0.32675302591924016, + listOf(0u, 1u) to 0.4561746111587508, + listOf(1u, 1u) to 0.5304946210170756, + listOf(2u, 1u) to 0.6244313712888998, + listOf(0u, 2u) to 0.2700930201481795, + listOf(1u, 2u) to -0.06962351375204712, + listOf(2u, 2u) to -0.015206988092131501, + ).substitute(mapOf( + 0 to 0.0 + )).coefficients, + 0.001, + "test 3" + ) + assertContentEquals( + mapOf( + listOf() to 1.433510890645169, + listOf(1u) to 0.6264844682514724, + listOf(2u) to 0.8405727903771333, + ), + NumberedPolynomialAsIs( + listOf() to 0.8597048543814783, + listOf(1u) to 0.22997637465889875, + listOf(2u) to 0.32675302591924016, + listOf(0u, 1u) to 0.4561746111587508, + listOf(1u, 1u) to 0.5304946210170756, + listOf(2u, 1u) to 0.6244313712888998, + listOf(0u, 2u) to 0.2700930201481795, + listOf(1u, 2u) to -0.06962351375204712, + listOf(2u, 2u) to -0.015206988092131501, + ).substitute(mapOf( + 1 to 0.8400458576651112 + )).coefficients, + 0.001, + "test 4" + ) + assertContentEquals( + mapOf( + listOf() to 1.934530767358133, + ), + NumberedPolynomialAsIs( + listOf() to 0.8597048543814783, + listOf(1u) to 0.22997637465889875, + listOf(2u) to 0.32675302591924016, + listOf(0u, 1u) to 0.4561746111587508, + listOf(1u, 1u) to 0.5304946210170756, + listOf(2u, 1u) to 0.6244313712888998, + listOf(0u, 2u) to 0.2700930201481795, + listOf(1u, 2u) to -0.06962351375204712, + listOf(2u, 2u) to -0.015206988092131501, + ).substitute(mapOf( + 0 to 0.4846192734143442, + 1 to 0.8400458576651112, + )).coefficients, + 0.001, + "test 5" + ) + assertContentEquals( + mapOf( + listOf() to 0.8597048543814783, + listOf(1u) to 0.22997637465889875, + listOf(2u) to 0.32675302591924016, + listOf(0u, 1u) to 0.4561746111587508, + listOf(1u, 1u) to 0.5304946210170756, + listOf(2u, 1u) to 0.6244313712888998, + listOf(0u, 2u) to 0.2700930201481795, + listOf(1u, 2u) to -0.06962351375204712, + listOf(2u, 2u) to -0.015206988092131501, + ), + NumberedPolynomialAsIs( + listOf() to 0.8597048543814783, + listOf(1u) to 0.22997637465889875, + listOf(2u) to 0.32675302591924016, + listOf(0u, 1u) to 0.4561746111587508, + listOf(1u, 1u) to 0.5304946210170756, + listOf(2u, 1u) to 0.6244313712888998, + listOf(0u, 2u) to 0.2700930201481795, + listOf(1u, 2u) to -0.06962351375204712, + listOf(2u, 2u) to -0.015206988092131501, + ).substitute(mapOf( + 5 to 0.9211194782050933 + )).coefficients, + 0.001, + "test 6" + ) + } + @Test + fun test_substitute_Constant() { + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(0) + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1) + ).substitute(RationalField, mapOf( + 0 to Rational(1) + )), + "test 1" + ) + // https://www.wolframalpha.com/input?i=%28-3%2F2+%2B+8%2F6+x+%2B+14%2F6+x%5E2%29+%2B+%28-3%2F1+%2B+-19%2F2+x+%2B+9%2F4+x%5E2%29+y+%2B+%285%2F5+%2B+18%2F9+x+%2B+5%2F2+x%5E2%29+y%5E2+where+x+%3D+-2%2F5%2C+y+%3D+12%2F9 + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(143, 150) + ), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + 0 to Rational(-2, 5), + 1 to Rational(12, 9), + )), + "test 2" + ) + // https://www.wolframalpha.com/input?i=%28%28-3%2F2+%2B+8%2F6+x+%2B+14%2F6+x%5E2%29+%2B+%28-3%2F1+%2B+-19%2F2+x+%2B+9%2F4+x%5E2%29+y+%2B+%285%2F5+%2B+18%2F9+x+%2B+5%2F2+x%5E2%29+y%5E2%29+p%5E8+where+x+%3D+q%2Fp%2C+y+%3D+x%5E3%2C+p+%3D+-2%2F5%2C+q+%3D+12%2F9 + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(47639065216, 2562890625) + ), + NumberedPolynomialAsIs( + listOf(8u) to Rational(-3, 2), + listOf(7u, 1u) to Rational(8, 6), + listOf(6u, 2u) to Rational(14, 6), + listOf(5u, 3u) to Rational(-3, 1), + listOf(4u, 4u) to Rational(-19, 2), + listOf(3u, 5u) to Rational(9, 4), + listOf(2u, 6u) to Rational(5, 5), + listOf(1u, 7u) to Rational(18, 9), + listOf(0u, 8u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + 0 to Rational(-2, 5), + 1 to Rational(12, 9), + )), + "test 3" + ) + // https://www.wolframalpha.com/input?i=%28%28-3%2F2+%2B+8%2F6+x+%2B+14%2F6+x%5E2%29+%2B+%28-3%2F1+%2B+-19%2F2+x+%2B+9%2F4+x%5E2%29+y+%2B+%285%2F5+%2B+18%2F9+x+%2B+5%2F2+x%5E2%29+y%5E2%29+p%5E8+where+x+%3D+q%2Fp%2C+y+%3D+x%5E3%2C+p+%3D+-2%2F5%2C+q+%3D+12%2F9 + assertEquals( + NumberedPolynomialAsIs( + listOf(8u) to Rational(-3, 2), + listOf(7u, 1u) to Rational(8, 6), + listOf(6u, 2u) to Rational(14, 6), + listOf(5u, 3u) to Rational(-3, 1), + listOf(4u, 4u) to Rational(-19, 2), + listOf(3u, 5u) to Rational(9, 4), + listOf(2u, 6u) to Rational(5, 5), + listOf(1u, 7u) to Rational(18, 9), + listOf(0u, 8u) to Rational(5, 2), + ), + NumberedPolynomialAsIs( + listOf(8u) to Rational(-3, 2), + listOf(7u, 1u) to Rational(8, 6), + listOf(6u, 2u) to Rational(14, 6), + listOf(5u, 3u) to Rational(-3, 1), + listOf(4u, 4u) to Rational(-19, 2), + listOf(3u, 5u) to Rational(9, 4), + listOf(2u, 6u) to Rational(5, 5), + listOf(1u, 7u) to Rational(18, 9), + listOf(0u, 8u) to Rational(5, 2), + ).substitute(RationalField, mapOf()), + "test 4" + ) + } + @Test + fun test_substitute_Polynomial() { + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(0) + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1) + ).substitute(RationalField, mapOf( + 0 to NumberedPolynomialAsIs( + listOf() to Rational(1) + ) + )), + "test 1" + ) + // https://www.wolframalpha.com/input?i=%28-3%2F2+%2B+8%2F6+x+%2B+14%2F6+x%5E2%29+%2B+%28-3%2F1+%2B+-19%2F2+x+%2B+9%2F4+x%5E2%29+y+%2B+%285%2F5+%2B+18%2F9+x+%2B+5%2F2+x%5E2%29+y%5E2+where+x+%3D+-2%2F5%2C+y+%3D+12%2F9 + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(0u, 1u) to Rational(-92, 21), + listOf(0u, 2u) to Rational(-2627, 2352), + listOf(0u, 3u) to Rational(4565, 3136), + listOf(0u, 4u) to Rational(605, 1568), + listOf(1u) to Rational(-20, 3), + listOf(1u, 1u) to Rational(1445, 21), + listOf(1u, 2u) to Rational(-13145, 392), + listOf(1u, 3u) to Rational(-3025, 196), + listOf(2u) to Rational(175, 3), + listOf(2u, 1u) to Rational(2475, 28), + listOf(2u, 2u) to Rational(15125, 98), + listOf(3u) to Rational(0), + listOf(3u, 1u) to Rational(0), + listOf(4u) to Rational(0), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + 0 to NumberedPolynomialAsIs( + listOf(1u) to Rational(-5, 1), + listOf(0u, 1u) to Rational(2, 8), + ), + 1 to NumberedPolynomialAsIs( + listOf(1u) to Rational(0, 5), + listOf(0u, 1u) to Rational(11, 7), + ), + )), + "test 2" + ) + } +} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/assertion.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/assertion.kt new file mode 100644 index 000000000..52ecf416a --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/assertion.kt @@ -0,0 +1,14 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.test.misc + +import kotlin.test.assertEquals + + +fun assertContentEquals(expected: Map, actual: Map, absoluteTolerance: Double, message: String? = null) { + assertEquals(expected.keys, actual.keys, message) + for ((key, expectedValue) in expected) assertEquals(expectedValue, actual[key]!!, absoluteTolerance, message) +} \ No newline at end of file From 680d23ddcb0c3e11ea779146f3d2ced2d8c741be Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sat, 18 Jun 2022 01:25:14 +0300 Subject: [PATCH 17/17] Last sift. Cleaned up labeled structures. --- .../kmath/functions/LabeledPolynomial.kt | 621 ++++++++++++++++++ .../functions/LabeledRationalFunction.kt | 96 +++ .../kmath/functions/ListPolynomial.kt | 2 +- .../kmath/functions/NumberedPolynomial.kt | 11 +- .../kmath/functions/labeledConstructors.kt | 518 +++++++++++++++ .../kscience/kmath/functions/labeledUtil.kt | 327 +++++++++ .../kmath/functions/numberedConstructors.kt | 40 +- .../kscience/kmath/functions/numberedUtil.kt | 18 +- 8 files changed, 1584 insertions(+), 49 deletions(-) create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledUtil.kt diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt new file mode 100644 index 000000000..b0c54502d --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt @@ -0,0 +1,621 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.functions + +import space.kscience.kmath.expressions.Symbol +import space.kscience.kmath.operations.Ring +import kotlin.jvm.JvmName +import kotlin.math.max + + +/** + * Represents multivariate polynomial that stores its coefficients in a [Map] and terms' signatures in a [Map] that + * associates variables (of type [Symbol]) with their degree. + * + * @param C the type of constants. + */ +public data class LabeledPolynomial +@PublishedApi +internal constructor( + /** + * Map that contains coefficients of the polynomial. + * + * Every monomial `a x_1^{d_1} ... x_n^{d_n}` is stored as a pair "key-value" in the map, where the value is the + * coefficient `a` and the key is a map that associates variables in the monomial with their degree in the monomial. + * For example, coefficients of a polynomial `5 a^2 c^3 - 6 b` can be represented as + * ``` + * mapOf( + * mapOf( + * a to 2, + * c to 3 + * ) to 5, + * mapOf( + * b to 1 + * ) to (-6) + * ) + * ``` + * and also as + * ``` + * mapOf( + * mapOf( + * a to 2, + * c to 3 + * ) to 5, + * mapOf( + * b to 1 + * ) to (-6), + * mapOf( + * b to 1, + * c to 1 + * ) to 0 + * ) + * ``` + * where `a`, `b` and `c` are corresponding [Symbol] objects. + */ + public val coefficients: Map, C> +) : Polynomial { + override fun toString(): String = "LabeledPolynomial$coefficients" +} + +/** + * Arithmetic context for multivariate polynomials with coefficients stored as a [Map] and terms' signatures stored as a + * [Map] constructed with the provided [ring] of constants. + * + * @param C the type of constants. Polynomials have them a coefficients in their terms. + * @param A type of provided underlying ring of constants. It's [Ring] of [C]. + * @param ring underlying ring of constants of type [A]. + */ +public class LabeledPolynomialSpace>( + public override val ring: A, +) : MultivariatePolynomialSpace>, PolynomialSpaceOverRing, A> { + /** + * Returns sum of the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ + public override operator fun Symbol.plus(other: Int): LabeledPolynomial = + if (other == 0) LabeledPolynomialAsIs(mapOf( + mapOf(this@plus to 1U) to constantOne, + )) + else LabeledPolynomialAsIs(mapOf( + mapOf(this@plus to 1U) to constantOne, + emptyMap() to constantOne * other, + )) + /** + * Returns difference between the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ + public override operator fun Symbol.minus(other: Int): LabeledPolynomial = + if (other == 0) LabeledPolynomialAsIs(mapOf( + mapOf(this@minus to 1U) to -constantOne, + )) + else LabeledPolynomialAsIs(mapOf( + mapOf(this@minus to 1U) to -constantOne, + emptyMap() to constantOne * other, + )) + /** + * Returns product of the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ + public override operator fun Symbol.times(other: Int): LabeledPolynomial = + if (other == 0) zero + else LabeledPolynomialAsIs(mapOf( + mapOf(this to 1U) to constantOne * other, + )) + + /** + * Returns sum of the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ + public override operator fun Int.plus(other: Symbol): LabeledPolynomial = + if (this == 0) LabeledPolynomialAsIs(mapOf( + mapOf(other to 1U) to constantOne, + )) + else LabeledPolynomialAsIs(mapOf( + mapOf(other to 1U) to constantOne, + emptyMap() to constantOne * this@plus, + )) + /** + * Returns difference between the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ + public override operator fun Int.minus(other: Symbol): LabeledPolynomial = + if (this == 0) LabeledPolynomialAsIs(mapOf( + mapOf(other to 1U) to -constantOne, + )) + else LabeledPolynomialAsIs(mapOf( + mapOf(other to 1U) to -constantOne, + emptyMap() to constantOne * this@minus, + )) + /** + * Returns product of the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ + public override operator fun Int.times(other: Symbol): LabeledPolynomial = + if (this == 0) zero + else LabeledPolynomialAsIs(mapOf( + mapOf(other to 1U) to constantOne * this@times, + )) + + /** + * Returns sum of the polynomial and the integer represented as a polynomial. + * + * The operation is equivalent to adding [other] copies of unit polynomial to [this]. + */ + public override operator fun LabeledPolynomial.plus(other: Int): LabeledPolynomial = + if (other == 0) this + else with(coefficients) { + if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap() to other.asConstant())) + else LabeledPolynomialAsIs( + toMutableMap() + .apply { + val degs = emptyMap() + + this[degs] = getOrElse(degs) { constantZero } + other + } + ) + } + /** + * Returns difference between the polynomial and the integer represented as a polynomial. + * + * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. + */ + public override operator fun LabeledPolynomial.minus(other: Int): LabeledPolynomial = + if (other == 0) this + else with(coefficients) { + if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap() to (-other).asConstant())) + else LabeledPolynomialAsIs( + toMutableMap() + .apply { + val degs = emptyMap() + + this[degs] = getOrElse(degs) { constantZero } - other + } + ) + } + /** + * Returns product of the polynomial and the integer represented as a polynomial. + * + * The operation is equivalent to sum of [other] copies of [this]. + */ + public override operator fun LabeledPolynomial.times(other: Int): LabeledPolynomial = + if (other == 0) zero + else LabeledPolynomial( + coefficients + .toMutableMap() + .apply { + for (degs in keys) this[degs] = this[degs]!! * other + } + ) + + /** + * Returns sum of the integer represented as a polynomial and the polynomial. + * + * The operation is equivalent to adding [this] copies of unit polynomial to [other]. + */ + public override operator fun Int.plus(other: LabeledPolynomial): LabeledPolynomial = + if (this == 0) other + else with(other.coefficients) { + if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap() to this@plus.asConstant())) + else LabeledPolynomialAsIs( + toMutableMap() + .apply { + val degs = emptyMap() + + this[degs] = this@plus + getOrElse(degs) { constantZero } + } + ) + } + /** + * Returns difference between the integer represented as a polynomial and the polynomial. + * + * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. + */ + public override operator fun Int.minus(other: LabeledPolynomial): LabeledPolynomial = + if (this == 0) other + else with(other.coefficients) { + if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap() to this@minus.asConstant())) + else LabeledPolynomialAsIs( + toMutableMap() + .apply { + forEach { (key, value) -> if (key.isNotEmpty()) this[key] = -value } + + val degs = emptyMap() + + this[degs] = this@minus - getOrElse(degs) { constantZero } + } + ) + } + /** + * Returns product of the integer represented as a polynomial and the polynomial. + * + * The operation is equivalent to sum of [this] copies of [other]. + */ + public override operator fun Int.times(other: LabeledPolynomial): LabeledPolynomial = + if (this == 0) zero + else LabeledPolynomial( + other.coefficients + .toMutableMap() + .apply { + for (degs in keys) this[degs] = this@times * this[degs]!! + } + ) + + /** + * Converts the integer [value] to polynomial. + */ + public override fun number(value: Int): LabeledPolynomial = number(constantNumber(value)) + + /** + * Returns sum of the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ + public override operator fun Symbol.plus(other: C): LabeledPolynomial = + LabeledPolynomialAsIs(mapOf( + mapOf(this@plus to 1U) to constantOne, + emptyMap() to other, + )) + /** + * Returns difference between the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ + public override operator fun Symbol.minus(other: C): LabeledPolynomial = + LabeledPolynomialAsIs(mapOf( + mapOf(this@minus to 1U) to -constantOne, + emptyMap() to other, + )) + /** + * Returns product of the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ + public override operator fun Symbol.times(other: C): LabeledPolynomial = + LabeledPolynomialAsIs(mapOf( + mapOf(this@times to 1U) to other, + )) + + /** + * Returns sum of the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + public override operator fun C.plus(other: Symbol): LabeledPolynomial = + LabeledPolynomialAsIs(mapOf( + mapOf(other to 1U) to constantOne, + emptyMap() to this@plus, + )) + /** + * Returns difference between the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + public override operator fun C.minus(other: Symbol): LabeledPolynomial = + LabeledPolynomialAsIs(mapOf( + mapOf(other to 1U) to -constantOne, + emptyMap() to this@minus, + )) + /** + * Returns product of the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + public override operator fun C.times(other: Symbol): LabeledPolynomial = + LabeledPolynomialAsIs(mapOf( + mapOf(other to 1U) to this@times, + )) + + /** + * Returns sum of the constant represented as a polynomial and the polynomial. + */ + override operator fun C.plus(other: LabeledPolynomial): LabeledPolynomial = + with(other.coefficients) { + if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap() to this@plus)) + else LabeledPolynomialAsIs( + toMutableMap() + .apply { + val degs = emptyMap() + + this[degs] = this@plus + getOrElse(degs) { constantZero } + } + ) + } + /** + * Returns difference between the constant represented as a polynomial and the polynomial. + */ + override operator fun C.minus(other: LabeledPolynomial): LabeledPolynomial = + with(other.coefficients) { + if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap() to this@minus)) + else LabeledPolynomialAsIs( + toMutableMap() + .apply { + forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } + + val degs = emptyMap() + + this[degs] = this@minus - getOrElse(degs) { constantZero } + } + ) + } + /** + * Returns product of the constant represented as a polynomial and the polynomial. + */ + override operator fun C.times(other: LabeledPolynomial): LabeledPolynomial = + LabeledPolynomialAsIs( + other.coefficients + .toMutableMap() + .apply { + for (degs in keys) this[degs] = this@times * this[degs]!! + } + ) + + /** + * Returns sum of the constant represented as a polynomial and the polynomial. + */ + override operator fun LabeledPolynomial.plus(other: C): LabeledPolynomial = + with(coefficients) { + if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap() to other)) + else LabeledPolynomialAsIs( + toMutableMap() + .apply { + val degs = emptyMap() + + this[degs] = getOrElse(degs) { constantZero } + other + } + ) + } + /** + * Returns difference between the constant represented as a polynomial and the polynomial. + */ + override operator fun LabeledPolynomial.minus(other: C): LabeledPolynomial = + with(coefficients) { + if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap() to other)) + else LabeledPolynomialAsIs( + toMutableMap() + .apply { + forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } + + val degs = emptyMap() + + this[degs] = getOrElse(degs) { constantZero } - other + } + ) + } + /** + * Returns product of the constant represented as a polynomial and the polynomial. + */ + override operator fun LabeledPolynomial.times(other: C): LabeledPolynomial = + LabeledPolynomialAsIs( + coefficients + .toMutableMap() + .apply { + for (degs in keys) this[degs] = this[degs]!! * other + } + ) + + /** + * Converts the constant [value] to polynomial. + */ + public override fun number(value: C): LabeledPolynomial = + LabeledPolynomial(mapOf(emptyMap() to value)) + + /** + * Represents the variable as a monic monomial. + */ + public override operator fun Symbol.unaryPlus(): LabeledPolynomial = + LabeledPolynomialAsIs(mapOf( + mapOf(this to 1U) to constantOne, + )) + /** + * Returns negation of representation of the variable as a monic monomial. + */ + public override operator fun Symbol.unaryMinus(): LabeledPolynomial = + LabeledPolynomialAsIs(mapOf( + mapOf(this to 1U) to -constantOne, + )) + /** + * Returns sum of the variables represented as monic monomials. + */ + public override operator fun Symbol.plus(other: Symbol): LabeledPolynomial = + if (this == other) LabeledPolynomialAsIs(mapOf( + mapOf(this to 1U) to constantOne * 2 + )) + else LabeledPolynomialAsIs(mapOf( + mapOf(this to 1U) to constantOne, + mapOf(other to 1U) to constantOne, + )) + /** + * Returns difference between the variables represented as monic monomials. + */ + public override operator fun Symbol.minus(other: Symbol): LabeledPolynomial = + if (this == other) zero + else LabeledPolynomialAsIs(mapOf( + mapOf(this to 1U) to constantOne, + mapOf(other to 1U) to -constantOne, + )) + /** + * Returns product of the variables represented as monic monomials. + */ + public override operator fun Symbol.times(other: Symbol): LabeledPolynomial = + if (this == other) LabeledPolynomialAsIs(mapOf( + mapOf(this to 2U) to constantOne + )) + else LabeledPolynomialAsIs(mapOf( + mapOf(this to 1U, other to 1U) to constantOne, + )) + + /** + * Returns sum of the variable represented as a monic monomial and the polynomial. + */ + public override operator fun Symbol.plus(other: LabeledPolynomial): LabeledPolynomial = + with(other.coefficients) { + if (isEmpty()) LabeledPolynomialAsIs(mapOf(mapOf(this@plus to 1u) to constantOne)) + else LabeledPolynomialAsIs( + toMutableMap() + .apply { + val degs = mapOf(this@plus to 1U) + + this[degs] = constantOne + getOrElse(degs) { constantZero } + } + ) + } + /** + * Returns difference between the variable represented as a monic monomial and the polynomial. + */ + public override operator fun Symbol.minus(other: LabeledPolynomial): LabeledPolynomial = + with(other.coefficients) { + if (isEmpty()) LabeledPolynomialAsIs(mapOf(mapOf(this@minus to 1u) to constantOne)) + else LabeledPolynomialAsIs( + toMutableMap() + .apply { + val degs = mapOf(this@minus to 1U) + + forEach { (degs, c) -> if(degs != degs) this[degs] = -c } + + this[degs] = constantOne - getOrElse(degs) { constantZero } + } + ) + } + /** + * Returns product of the variable represented as a monic monomial and the polynomial. + */ + public override operator fun Symbol.times(other: LabeledPolynomial): LabeledPolynomial = + LabeledPolynomialAsIs( + other.coefficients + .mapKeys { (degs, _) -> degs.toMutableMap().also{ it[this] = if (this in it) it[this]!! + 1U else 1U } } + ) + + /** + * Returns sum of the polynomial and the variable represented as a monic monomial. + */ + public override operator fun LabeledPolynomial.plus(other: Symbol): LabeledPolynomial = + with(coefficients) { + if (isEmpty()) LabeledPolynomialAsIs(mapOf(mapOf(other to 1u) to constantOne)) + else LabeledPolynomialAsIs( + toMutableMap() + .apply { + val degs = mapOf(other to 1U) + + this[degs] = constantOne + getOrElse(degs) { constantZero } + } + ) + } + /** + * Returns difference between the polynomial and the variable represented as a monic monomial. + */ + public override operator fun LabeledPolynomial.minus(other: Symbol): LabeledPolynomial = + with(coefficients) { + if (isEmpty()) LabeledPolynomialAsIs(mapOf(mapOf(other to 1u) to constantOne)) + else LabeledPolynomialAsIs( + toMutableMap() + .apply { + val degs = mapOf(other to 1U) + + this[degs] = constantOne - getOrElse(degs) { constantZero } + } + ) + } + /** + * Returns product of the polynomial and the variable represented as a monic monomial. + */ + public override operator fun LabeledPolynomial.times(other: Symbol): LabeledPolynomial = + LabeledPolynomialAsIs( + coefficients + .mapKeys { (degs, _) -> degs.toMutableMap().also{ it[other] = if (other in it) it[other]!! + 1U else 1U } } + ) + + /** + * Returns negation of the polynomial. + */ + override fun LabeledPolynomial.unaryMinus(): LabeledPolynomial = + LabeledPolynomialAsIs( + coefficients.mapValues { -it.value } + ) + /** + * Returns sum of the polynomials. + */ + override operator fun LabeledPolynomial.plus(other: LabeledPolynomial): LabeledPolynomial = + LabeledPolynomialAsIs( + buildMap(coefficients.size + other.coefficients.size) { + other.coefficients.mapValuesTo(this) { it.value } + other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! + value else value } + } + ) + /** + * Returns difference of the polynomials. + */ + override operator fun LabeledPolynomial.minus(other: LabeledPolynomial): LabeledPolynomial = + LabeledPolynomialAsIs( + buildMap(coefficients.size + other.coefficients.size) { + other.coefficients.mapValuesTo(this) { it.value } + other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! - value else -value } + } + ) + /** + * Returns product of the polynomials. + */ + override operator fun LabeledPolynomial.times(other: LabeledPolynomial): LabeledPolynomial = + LabeledPolynomialAsIs( + buildMap(coefficients.size * other.coefficients.size) { + for ((degs1, c1) in coefficients) for ((degs2, c2) in other.coefficients) { + val degs = degs1.toMutableMap() + degs2.mapValuesTo(degs) { (variable, deg) -> degs.getOrElse(variable) { 0u } + deg } + val c = c1 * c2 + this[degs] = if (degs in this) this[degs]!! + c else c + } + } + ) + + /** + * Instance of zero polynomial (zero of the polynomial ring). + */ + override val zero: LabeledPolynomial = LabeledPolynomialAsIs(mapOf(emptyMap() to constantZero)) + /** + * Instance of unit polynomial (unit of the polynomial ring). + */ + override val one: LabeledPolynomial = LabeledPolynomialAsIs(mapOf(emptyMap() to constantOne)) + + /** + * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is + * zero, degree is -1. + */ + override val LabeledPolynomial.degree: Int + get() = coefficients.entries.maxOfOrNull { (degs, _) -> degs.values.sum().toInt() } ?: -1 + /** + * Map that associates variables (that appear in the polynomial in positive exponents) with their most exponents + * in which they are appeared in the polynomial. + * + * As consequence all values in the map are positive integers. Also, if the polynomial is constant, the map is empty. + * And keys of the map is the same as in [variables]. + */ + public override val LabeledPolynomial.degrees: Map + get() = + buildMap { + coefficients.entries.forEach { (degs, _) -> + degs.mapValuesTo(this) { (variable, deg) -> + max(getOrElse(variable) { 0u }, deg) + } + } + } + /** + * Counts degree of the polynomial by the specified [variable]. + */ + public override fun LabeledPolynomial.degreeBy(variable: Symbol): UInt = + coefficients.entries.maxOfOrNull { (degs, _) -> degs.getOrElse(variable) { 0u } } ?: 0u + /** + * Counts degree of the polynomial by the specified [variables]. + */ + public override fun LabeledPolynomial.degreeBy(variables: Collection): UInt = + coefficients.entries.maxOfOrNull { (degs, _) -> degs.filterKeys { it in variables }.values.sum() } ?: 0u + /** + * Set of all variables that appear in the polynomial in positive exponents. + */ + public override val LabeledPolynomial.variables: Set + get() = + buildSet { + coefficients.entries.forEach { (degs, _) -> addAll(degs.keys) } + } + /** + * Count of all variables that appear in the polynomial in positive exponents. + */ + public override val LabeledPolynomial.countOfVariables: Int get() = variables.size + + // TODO: When context receivers will be ready move all of this substitutions and invocations to utilities with + // [ListPolynomialSpace] as a context receiver + /** + * Substitutes provided arguments [arguments] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun LabeledPolynomial.substitute(arguments: Map): LabeledPolynomial = substitute(ring, arguments) + /** + * Substitutes provided arguments [arguments] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + @JvmName("substitutePolynomial") + public inline fun LabeledPolynomial.substitute(arguments: Map>) : LabeledPolynomial = substitute(ring, arguments) +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt new file mode 100644 index 000000000..03f323813 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt @@ -0,0 +1,96 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.functions + +import space.kscience.kmath.expressions.Symbol +import space.kscience.kmath.operations.Ring +import kotlin.jvm.JvmName + + +/** + * Represents multivariate rational function that stores its numerator and denominator as [LabeledPolynomial]s. + */ +public class LabeledRationalFunction( + public override val numerator: LabeledPolynomial, + public override val denominator: LabeledPolynomial +) : RationalFunction> { + override fun toString(): String = "LabeledRationalFunction${numerator.coefficients}/${denominator.coefficients}" +} + +/** + * Arithmetic context for univariate rational functions with numerator and denominator represented as [LabeledPolynomial]s. + * + * @param C the type of constants. Polynomials have them a coefficients in their terms. + * @param A type of provided underlying ring of constants. It's [Ring] of [C]. + * @param ring underlying ring of constants of type [A]. + */ +public class LabeledRationalFunctionSpace>( + public val ring: A, +) : + MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSpace< + C, + Symbol, + LabeledPolynomial, + LabeledRationalFunction, + LabeledPolynomialSpace, + >, + MultivariatePolynomialSpaceOfFractions< + C, + Symbol, + LabeledPolynomial, + LabeledRationalFunction, + >() { + + /** + * Underlying polynomial ring. Its polynomial operations are inherited by local polynomial operations. + */ + override val polynomialRing : LabeledPolynomialSpace = LabeledPolynomialSpace(ring) + /** + * Constructor of rational functions (of type [LabeledRationalFunction]) from numerator and denominator (of type [LabeledPolynomial]). + */ + override fun constructRationalFunction( + numerator: LabeledPolynomial, + denominator: LabeledPolynomial + ): LabeledRationalFunction = + LabeledRationalFunction(numerator, denominator) + + // TODO: When context receivers will be ready move all of this substitutions and invocations to utilities with + // [ListPolynomialSpace] as a context receiver + /** + * Substitutes provided constant [argument] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun LabeledPolynomial.substitute(argument: Map): LabeledPolynomial = substitute(ring, argument) + /** + * Substitutes provided polynomial [argument] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + @JvmName("substitutePolynomial") + public inline fun LabeledPolynomial.substitute(argument: Map>): LabeledPolynomial = substitute(ring, argument) + /** + * Substitutes provided rational function [argument] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + @JvmName("substituteRationalFunction") + public inline fun LabeledPolynomial.substitute(argument: Map>): LabeledRationalFunction = substitute(ring, argument) + /** + * Substitutes provided constant [argument] into [this] rational function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun LabeledRationalFunction.substitute(argument: Map): LabeledRationalFunction = substitute(ring, argument) + /** + * Substitutes provided polynomial [argument] into [this] rational function. + */ + @Suppress("NOTHING_TO_INLINE") + @JvmName("substitutePolynomial") + public inline fun LabeledRationalFunction.substitute(argument: Map>): LabeledRationalFunction = substitute(ring, argument) + /** + * Substitutes provided rational function [argument] into [this] rational function. + */ + @Suppress("NOTHING_TO_INLINE") + @JvmName("substituteRationalFunction") + public inline fun LabeledRationalFunction.substitute(argument: Map>): LabeledRationalFunction = substitute(ring, argument) +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt index b3f1eb8f7..8db93cbb1 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt @@ -15,7 +15,7 @@ import kotlin.math.min /** * Represents univariate polynomial that stores its coefficients in a [List]. * - * @param coefficients constant is the leftmost coefficient. + * @param C the type of constants. */ public data class ListPolynomial( /** diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt index 02a3af683..eadeb68ab 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -12,7 +12,7 @@ import kotlin.math.max /** - * Represents univariate polynomial that stores its coefficients in a [Map] and terms' signatures in a [List]. + * Represents multivariate polynomial that stores its coefficients in a [Map] and terms' signatures in a [List]. * * @param C the type of constants. */ @@ -20,10 +20,11 @@ public data class NumberedPolynomial @PublishedApi internal constructor( /** - * Map that contains coefficients of the polynomial. Every monomial `a x_1^{d_1} ... x_n^{d_n}` is stored as pair - * "key-value" in the map, where the value is the coefficients `a` and the key is a list that associates index of - * every variable in the monomial with multiplicity of the variable occurring in the monomial. For example - * coefficients of a polynomial `5 x_1^2 x_3^3 - 6 x_2` can be represented as + * Map that contains coefficients of the polynomial. + * + * Every monomial `a x_1^{d_1} ... x_n^{d_n}` is stored as a pair "key-value" in the map, where the value is the + * coefficient `a` and the key is a list that associates index of every variable in the monomial with their degree + * in the monomial. For example, coefficients of a polynomial `5 x_1^2 x_3^3 - 6 x_2` can be represented as * ``` * mapOf( * listOf(2, 0, 3) to 5, // 5 x_1^2 x_3^3 + diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt new file mode 100644 index 000000000..47325c4bb --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt @@ -0,0 +1,518 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +@file:Suppress("FunctionName", "NOTHING_TO_INLINE") + +package space.kscience.kmath.functions + +import space.kscience.kmath.expressions.Symbol +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.Ring + + +/** + * Returns the same degrees' description of the monomial, but without zero degrees. + */ +internal fun Map.cleanUp() = filterValues { it > 0U } + +/** + * Constructs [LabeledPolynomial] with provided coefficients map [coefs]. The map is used as is. + */ +@PublishedApi +internal inline fun LabeledPolynomialAsIs(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs) + +/** + * Constructs [LabeledPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient". + * The collections will be transformed to map with [toMap] and then will be used as is. + */ +@PublishedApi +internal inline fun LabeledPolynomialAsIs(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs.toMap()) + +/** + * Constructs [LabeledPolynomial] with provided array of [pairs] of pairs "term's signature — term's coefficient". + * The array will be transformed to map with [toMap] and then will be used as is. + */ +@PublishedApi +internal inline fun LabeledPolynomialAsIs(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(pairs.toMap()) + +/** + * Constructs [LabeledPolynomial] with provided coefficients map [coefs]. The map is used as is. + * + * **Be sure you read description of [LabeledPolynomial.coefficients]. Otherwise, you may make a mistake that will + * cause wrong computation result or even runtime error.** + */ +@DelicatePolynomialAPI +public inline fun LabeledPolynomialWithoutCheck(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs) + +/** + * Constructs [LabeledPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient". + * The collections will be transformed to map with [toMap] and then will be used as is. + * + * **Be sure you read description of [LabeledPolynomial.coefficients]. Otherwise, you may make a mistake that will + * cause wrong computation result or even runtime error.** + */ +@DelicatePolynomialAPI +public inline fun LabeledPolynomialWithoutCheck(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs.toMap()) + +/** + * Constructs [LabeledPolynomial] with provided array of [pairs] of pairs "term's signature — term's coefficient". + * The array will be transformed to map with [toMap] and then will be used as is. + * + * **Be sure you read description of [LabeledPolynomial.coefficients]. Otherwise, you may make a mistake that will + * cause wrong computation result or even runtime error.** + */ +@DelicatePolynomialAPI +public inline fun LabeledPolynomialWithoutCheck(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(pairs.toMap()) + +/** + * Constructs [LabeledPolynomial] with provided coefficients map [coefs]. + * + * [coefs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [coefs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +public fun LabeledPolynomial(coefs: Map, C>, add: (C, C) -> C) : LabeledPolynomial { + val fixedCoefs = mutableMapOf, C>() + + for (entry in coefs) { + val key = entry.key.cleanUp() + val value = entry.value + fixedCoefs[key] = if (key in fixedCoefs) add(fixedCoefs[key]!!, value) else value + } + + return LabeledPolynomial(fixedCoefs) +} + +/** + * Constructs [LabeledPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient". + * + * [pairs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +public fun LabeledPolynomial(pairs: Collection, C>>, add: (C, C) -> C) : LabeledPolynomial { + val fixedCoefs = mutableMapOf, C>() + + for (entry in pairs) { + val key = entry.first.cleanUp() + val value = entry.second + fixedCoefs[key] = if (key in fixedCoefs) add(fixedCoefs[key]!!, value) else value + } + + return LabeledPolynomial(fixedCoefs) +} + +/** + * Constructs [LabeledPolynomial] with provided array [pairs] of pairs "term's signature — term's coefficient". + * + * [pairs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +public fun LabeledPolynomial(vararg pairs: Pair, C>, add: (C, C) -> C) : LabeledPolynomial { + val fixedCoefs = mutableMapOf, C>() + + for (entry in pairs) { + val key = entry.first.cleanUp() + val value = entry.second + fixedCoefs[key] = if (key in fixedCoefs) add(fixedCoefs[key]!!, value) else value + } + + return LabeledPolynomial(fixedCoefs) +} + +// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available + +/** + * Constructs [LabeledPolynomial] with provided coefficients map [coefs]. + * + * [coefs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [coefs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +public inline fun > A.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs, ::add) +/** + * Constructs [LabeledPolynomial] with provided coefficients map [coefs]. + * + * [coefs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [coefs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +public inline fun > LabeledPolynomialSpace.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs) { left: C, right: C -> left + right } + +/** + * Constructs [LabeledPolynomial] with provided coefficients map [coefs]. + * + * [coefs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [coefs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +public inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs) { left: C, right: C -> left + right } + +/** + * Constructs [LabeledPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient". + * + * [pairs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +public inline fun > A.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs, ::add) + +/** + * Constructs [LabeledPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient". + * + * [pairs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +public inline fun > LabeledPolynomialSpace.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs) { left: C, right: C -> left + right } +/** + * Constructs [LabeledPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient". + * + * [pairs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +public inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs) { left: C, right: C -> left + right } + +/** + * Constructs [LabeledPolynomial] with provided array [pairs] of pairs "term's signature — term's coefficient". + * + * [pairs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +public inline fun > A.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs) { left: C, right: C -> left + right } +/** + * Constructs [LabeledPolynomial] with provided array [pairs] of pairs "term's signature — term's coefficient". + * + * [pairs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +public inline fun > LabeledPolynomialSpace.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs) { left: C, right: C -> left + right } +/** + * Constructs [LabeledPolynomial] with provided array [pairs] of pairs "term's signature — term's coefficient". + * + * [pairs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +public inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs) { left: C, right: C -> left + right } + +/** + * Converts [this] constant to [LabeledPolynomial]. + */ +public inline fun C.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomialAsIs(mapOf(emptyMap() to this)) + +///** +//// * Converts [this] variable to [LabeledPolynomial]. +//// */ +//context(A) +//public inline fun > Symbol.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1u) to one)) +///** +// * Converts [this] variable to [LabeledPolynomial]. +// */ +//context(LabeledPolynomialSpace) +//public inline fun > Symbol.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1u) to constantOne)) +///** +// * Converts [this] variable to [LabeledPolynomial]. +// */ +//context(LabeledRationalFunctionSpace) +//public inline fun > Symbol.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1u) to constantOne)) + +/** + * Marks DSL that allows to more simply create [LabeledPolynomial]s with good performance. + * + * For example, polynomial `5 a^2 c^3 - 6 b` can be described as + * ``` + * Int.algebra { + * val numberedPolynomial : NumberedPolynomial = NumberedPolynomial { + * 5 { a inPowerOf 2u; c inPowerOf 3u } // 5 a^2 c^3 + + * (-6) { b inPowerOf 1u } // (-6) b^1 + * } + * } + * ``` + */ +@DslMarker +@UnstableKMathAPI +internal annotation class LabeledPolynomialConstructorDSL + +/** + * Builder of [LabeledPolynomial] signature. It should be used as an implicit context for lambdas that describe term signature. + */ +@UnstableKMathAPI +@LabeledPolynomialConstructorDSL +public class LabeledPolynomialTermSignatureBuilder { + /** + * Signature storage. Any declaration of any variable's power updates the storage by increasing corresponding value. + * Afterward the storage will be used as a resulting signature. + */ + private val signature: MutableMap = LinkedHashMap() + + /** + * Builds the resulting signature. + * + * In fact, it just returns [signature] as regular signature of type `List`. + */ + @PublishedApi + internal fun build(): Map = signature + + /** + * Declares power of [this] variable of degree [deg]. + * + * Declaring another power of the same variable will increase its degree by received degree. + */ + public infix fun Symbol.inPowerOf(deg: UInt) { + signature[this] = deg + } + /** + * Declares power of [this] variable of degree [deg]. + * + * Declaring another power of the same variable will increase its degree by received degree. + */ + @Suppress("NOTHING_TO_INLINE") + public inline infix fun Symbol.pow(deg: UInt): Unit = this inPowerOf deg + /** + * Declares power of [this] variable of degree [deg]. + * + * Declaring another power of the same variable will increase its degree by received degree. + */ + @Suppress("NOTHING_TO_INLINE") + public inline infix fun Symbol.`in`(deg: UInt): Unit = this inPowerOf deg + /** + * Declares power of [this] variable of degree [deg]. + * + * Declaring another power of the same variable will increase its degree by received degree. + */ + @Suppress("NOTHING_TO_INLINE") + public inline infix fun Symbol.of(deg: UInt): Unit = this inPowerOf deg +} + +/** + * Builder of [LabeledPolynomial]. It should be used as an implicit context for lambdas that describe [LabeledPolynomial]. + */ +@UnstableKMathAPI +public class LabeledPolynomialBuilder( + /** + * Summation operation that will be used to sum coefficients of monomials of same signatures. + */ + private val add: (C, C) -> C, + /** + * Initial capacity of coefficients map. + */ + initialCapacity: Int = 0 +) { + /** + * Coefficients storage. Any declaration of any monomial updates the storage. + * Afterward the storage will be used as a resulting coefficients map. + */ + private val coefficients: MutableMap, C> = LinkedHashMap(initialCapacity) + + /** + * Builds the resulting coefficients map. + * + * In fact, it just returns [coefficients] as regular coefficients map of type `Map, C>`. + */ + @PublishedApi + internal fun build(): LabeledPolynomial = LabeledPolynomial(coefficients) + + /** + * Declares monomial with [this] coefficient and provided [signature]. + * + * Declaring another monomial with the same signature will add [this] coefficient to existing one. If the sum of such + * coefficients is zero at any moment the monomial won't be removed but will be left as it is. + */ + public infix fun C.with(signature: Map) { + coefficients[signature] = if (signature in coefficients) add(coefficients[signature]!!, this@with) else this@with + } + /** + * Declares monomial with [this] coefficient and signature constructed by [block]. + * + * Declaring another monomial with the same signature will add [this] coefficient to existing one. If the sum of such + * coefficients is zero at any moment the monomial won't be removed but will be left as it is. + */ + @Suppress("NOTHING_TO_INLINE") + public inline infix fun C.with(noinline block: LabeledPolynomialTermSignatureBuilder.() -> Unit): Unit = this.invoke(block) + /** + * Declares monomial with [this] coefficient and signature constructed by [block]. + * + * Declaring another monomial with the same signature will add [this] coefficient to existing one. If the sum of such + * coefficients is zero at any moment the monomial won't be removed but will be left as it is. + */ + public inline operator fun C.invoke(block: LabeledPolynomialTermSignatureBuilder.() -> Unit): Unit = + this with LabeledPolynomialTermSignatureBuilder().apply(block).build() +} + +// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available + +///** +// * Creates [LabeledPolynomial] with lambda [block] in context of [this] ring of constants. +// * +// * For example, polynomial `5 x_1^2 x_3^3 - 6 x_2` can be described as +// * ``` +// * Int.algebra { +// * val LabeledPolynomial : LabeledPolynomial = LabeledPolynomial { +// * 5 { 1 inPowerOf 2u; 3 inPowerOf 3u } // 5 x_1^2 x_3^3 + +// * (-6) { 2 inPowerOf 1u } // (-6) x_2^1 +// * } +// * } +// * ``` +// */ +// FIXME: For now this fabric does not let next two fabrics work. (See KT-52803.) Possible feature solutions: +// 1. `LowPriorityInOverloadResolution` becomes public. Then it should be applied to this function. +// 2. Union types are implemented. Then all three functions should be rewritten +// as one with single union type as a (context) receiver. +//@UnstableKMathAPI +//public inline fun > A.LabeledPolynomial(initialCapacity: Int = 0, block: LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = LabeledPolynomialBuilder(::add, initialCapacity).apply(block).build() +/** + * Creates [LabeledPolynomial] with lambda [block] in context of [this] ring of [LabeledPolynomial]s. + * + * For example, polynomial `5 x_1^2 x_3^3 - 6 x_2` can be described as + * ``` + * Int.algebra { + * val LabeledPolynomial : LabeledPolynomial = LabeledPolynomial { + * 5 { 1 inPowerOf 2u; 3 inPowerOf 3u } // 5 x_1^2 x_3^3 + + * (-6) { 2 inPowerOf 1u } // (-6) x_2^1 + * } + * } + * ``` + */ +@UnstableKMathAPI +public inline fun > LabeledPolynomialSpace.LabeledPolynomial(initialCapacity: Int = 0, block: LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = LabeledPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() +/** + * Creates [LabeledPolynomial] with lambda [block] in context of [this] field of [LabeledRationalFunction]s. + * + * For example, polynomial `5 x_1^2 x_3^3 - 6 x_2` can be described as + * ``` + * Int.algebra { + * val LabeledPolynomial : LabeledPolynomial = LabeledPolynomial { + * 5 { 1 inPowerOf 2u; 3 inPowerOf 3u } // 5 x_1^2 x_3^3 + + * (-6) { 2 inPowerOf 1u } // (-6) x_2^1 + * } + * } + * ``` + */ +@UnstableKMathAPI +public inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(initialCapacity: Int = 0, block: LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = LabeledPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() + +// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available + +/** + * Constructs [LabeledRationalFunction] with provided coefficients maps [numeratorCoefficients] and [denominatorCoefficients]. + * + * The maps will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. the maps' keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +public fun > A.LabeledRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): LabeledRationalFunction = + LabeledRationalFunction( + LabeledPolynomial(numeratorCoefficients), + LabeledPolynomial(denominatorCoefficients) + ) +/** + * Constructs [LabeledRationalFunction] with provided coefficients maps [numeratorCoefficients] and [denominatorCoefficients]. + * + * The maps will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. the maps' keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +public fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): LabeledRationalFunction = + LabeledRationalFunction( + LabeledPolynomial(numeratorCoefficients), + LabeledPolynomial(denominatorCoefficients) + ) + +/** + * Constructs [LabeledRationalFunction] with provided [numerator] and unit denominator. + */ +public fun > A.LabeledRationalFunction(numerator: LabeledPolynomial): LabeledRationalFunction = + LabeledRationalFunction(numerator, LabeledPolynomial(mapOf(emptyMap() to one))) +/** + * Constructs [LabeledRationalFunction] with provided [numerator] and unit denominator. + */ +public fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numerator: LabeledPolynomial): LabeledRationalFunction = + LabeledRationalFunction(numerator, polynomialOne) + +/** + * Constructs [LabeledRationalFunction] with provided coefficients map [numeratorCoefficients] for numerator and unit + * denominator. + * + * [numeratorCoefficients] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [numeratorCoefficients]'s keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +public fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numeratorCoefficients: Map, C>): LabeledRationalFunction = + LabeledRationalFunction( + LabeledPolynomial(numeratorCoefficients), + polynomialOne + ) +/** + * Constructs [LabeledRationalFunction] with provided coefficients map [numeratorCoefficients] for numerator and unit + * denominator. + * + * [numeratorCoefficients] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [numeratorCoefficients]'s keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +public fun > A.LabeledRationalFunction(numeratorCoefficients: Map, C>): LabeledRationalFunction = + LabeledRationalFunction( + LabeledPolynomial(numeratorCoefficients), + LabeledPolynomialAsIs(mapOf(emptyMap() to one)) + ) + +///** +// * Converts [this] constant to [LabeledRationalFunction]. +// */ +//context(A) +//public fun > C.asLabeledRationalFunction() : LabeledRationalFunction = +// LabeledRationalFunction( +// LabeledPolynomialAsIs(mapOf(emptyMap() to this)), +// LabeledPolynomialAsIs(mapOf(emptyMap() to one)) +// ) +///** +// * Converts [this] constant to [LabeledRationalFunction]. +// */ +//context(LabeledRationalFunctionSpace) +//public fun > C.asLabeledRationalFunction() : LabeledRationalFunction = +// LabeledRationalFunction( +// LabeledPolynomialAsIs(mapOf(emptyMap() to this)), +// LabeledPolynomialAsIs(mapOf(emptyMap() to constantOne)) +// ) + +///** +// * Converts [this] variable to [LabeledRationalFunction]. +// */ +//context(A) +//public fun > Symbol.asLabeledRationalFunction() : LabeledRationalFunction = +// LabeledRationalFunction( +// LabeledPolynomialAsIs(mapOf(mapOf(this to 1u) to one)), +// LabeledPolynomialAsIs(mapOf(emptyMap() to one)) +// ) +///** +// * Converts [this] variable to [LabeledRationalFunction]. +// */ +//context(LabeledRationalFunctionSpace) +//public fun > Symbol.asLabeledRationalFunction() : LabeledRationalFunction = +// LabeledRationalFunction( +// LabeledPolynomialAsIs(mapOf(mapOf(this to 1u) to constantOne)), +// LabeledPolynomialAsIs(mapOf(emptyMap() to constantOne)) +// ) \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledUtil.kt new file mode 100644 index 000000000..39c781a14 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledUtil.kt @@ -0,0 +1,327 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.functions + +import space.kscience.kmath.expressions.Symbol +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.Field +import space.kscience.kmath.operations.invoke +import space.kscience.kmath.operations.Ring +import space.kscience.kmath.operations.algebra +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract +import kotlin.jvm.JvmName + + +/** + * Creates a [LabeledPolynomialSpace] over a received ring. + */ +public fun > A.labeledPolynomialSpace(): LabeledPolynomialSpace = + LabeledPolynomialSpace(this) + +/** + * Creates a [LabeledPolynomialSpace]'s scope over a received ring. + */ +public inline fun , R> A.labeledPolynomialSpace(block: LabeledPolynomialSpace.() -> R): R { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return LabeledPolynomialSpace(this).block() +} +/** + * Creates a [LabeledRationalFunctionSpace] over a received ring. + */ +public fun > A.labeledRationalFunctionSpace(): LabeledRationalFunctionSpace = + LabeledRationalFunctionSpace(this) + +/** + * Creates a [LabeledRationalFunctionSpace]'s scope over a received ring. + */ +public inline fun , R> A.labeledRationalFunctionSpace(block: LabeledRationalFunctionSpace.() -> R): R { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return LabeledRationalFunctionSpace(this).block() +} + +/** + * Substitutes provided Double arguments [args] into [this] Double polynomial. + */ +public fun LabeledPolynomial.substitute(args: Map): LabeledPolynomial = Double.algebra { + if (coefficients.isEmpty()) return this@substitute + LabeledPolynomial( + buildMap { + coefficients.forEach { (degs, c) -> + val newDegs = degs.filterKeys { it !in args } + val newC = args.entries.fold(c) { product, (variable, substitution) -> + val deg = degs.getOrElse(variable) { 0u } + if (deg == 0u) product else product * power(substitution, deg) + } + this[newDegs] = if (newDegs in this) this[newDegs]!! + newC else newC + } + } + ) +} + +/** + * Substitutes provided arguments [args] into [this] polynomial. + */ +public fun LabeledPolynomial.substitute(ring: Ring, args: Map): LabeledPolynomial = ring { + if (coefficients.isEmpty()) return this@substitute + LabeledPolynomial( + buildMap { + coefficients.forEach { (degs, c) -> + val newDegs = degs.filterKeys { it !in args } + val newC = args.entries.fold(c) { product, (variable, substitution) -> + val deg = degs.getOrElse(variable) { 0u } + if (deg == 0u) product else product * power(substitution, deg) + } + this[newDegs] = if (newDegs in this) this[newDegs]!! + newC else newC + } + } + ) +} + +/** + * Substitutes provided arguments [args] into [this] polynomial. + */ // TODO: To optimize boxing +@JvmName("substitutePolynomial") +public fun LabeledPolynomial.substitute(ring: Ring, args: Map>) : LabeledPolynomial = + ring.labeledPolynomialSpace { + coefficients.entries.fold(zero) { acc, (degs, c) -> + val newDegs = degs.filterKeys { it !in args } + acc + args.entries.fold(LabeledPolynomial(mapOf(newDegs to c))) { product, (variable, substitution) -> + val deg = degs.getOrElse(variable) { 0u } + if (deg == 0u) product else product * power(substitution, deg) + } + } + } + +/** + * Substitutes provided arguments [args] into [this] polynomial. + */ // TODO: To optimize boxing +@JvmName("substituteRationalFunction") +public fun LabeledPolynomial.substitute(ring: Ring, args: Map>) : LabeledRationalFunction = + ring.labeledRationalFunctionSpace { + coefficients.entries.fold(zero) { acc, (degs, c) -> + val newDegs = degs.filterKeys { it !in args } + acc + args.entries.fold(LabeledRationalFunction(LabeledPolynomial(mapOf(newDegs to c)))) { product, (variable, substitution) -> + val deg = degs.getOrElse(variable) { 0u } + if (deg == 0u) product else product * power(substitution, deg) + } + } + } + +/** + * Substitutes provided Double arguments [args] into [this] Double rational function. + */ +public fun LabeledRationalFunction.substitute(args: Map): LabeledRationalFunction = + LabeledRationalFunction(numerator.substitute(args), denominator.substitute(args)) + +/** + * Substitutes provided arguments [args] into [this] rational function. + */ +public fun LabeledRationalFunction.substitute(ring: Ring, args: Map): LabeledRationalFunction = + LabeledRationalFunction(numerator.substitute(ring, args), denominator.substitute(ring, args)) + +/** + * Substitutes provided arguments [args] into [this] rational function. + */ // TODO: To optimize calculation +@JvmName("substitutePolynomial") +public fun LabeledRationalFunction.substitute(ring: Ring, args: Map>) : LabeledRationalFunction = + LabeledRationalFunction(numerator.substitute(ring, args), denominator.substitute(ring, args)) + +/** + * Substitutes provided arguments [args] into [this] rational function. + */ // TODO: To optimize calculation +@JvmName("substituteRationalFunction") +public fun LabeledRationalFunction.substitute(ring: Ring, args: Map>) : LabeledRationalFunction = + ring.labeledRationalFunctionSpace { + numerator.substitute(ring, args) / denominator.substitute(ring, args) + } + +/** + * Returns algebraic derivative of received polynomial with respect to provided variable. + */ +@UnstableKMathAPI +public fun > LabeledPolynomial.derivativeWithRespectTo( + algebra: A, + variable: Symbol, +): LabeledPolynomial = algebra { + LabeledPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + if (variable !in degs) return@forEach + put( + buildMap { + degs.forEach { (vari, deg) -> + when { + vari != variable -> put(vari, deg) + deg > 1u -> put(vari, deg - 1u) + } + } + }, + multiplyByDoubling(c, degs[variable]!!) + ) + } + } + ) +} + +/** + * Returns algebraic derivative of received polynomial with respect to provided variable of specified order. + */ +@UnstableKMathAPI +public fun > LabeledPolynomial.nthDerivativeWithRespectTo( + algebra: A, + variable: Symbol, + order: UInt +): LabeledPolynomial = algebra { + if (order == 0u) return this@nthDerivativeWithRespectTo + LabeledPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + if (degs.getOrElse(variable) { 0u } < order) return@forEach + put( + buildMap { + degs.forEach { (vari, deg) -> + when { + vari != variable -> put(vari, deg) + deg > order -> put(vari, deg - order) + } + } + }, + degs[variable]!!.let { deg -> + (deg downTo deg - order + 1u) + .fold(c) { acc, ord -> multiplyByDoubling(acc, ord) } + } + ) + } + } + ) +} + +/** + * Returns algebraic derivative of received polynomial with respect to provided variables of specified orders. + */ +@UnstableKMathAPI +public fun > LabeledPolynomial.nthDerivativeWithRespectTo( + algebra: A, + variablesAndOrders: Map, +): LabeledPolynomial = algebra { + val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u } + if (filteredVariablesAndOrders.isEmpty()) return this@nthDerivativeWithRespectTo + LabeledPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + if (filteredVariablesAndOrders.any { (variable, order) -> degs.getOrElse(variable) { 0u } < order }) return@forEach + put( + buildMap { + degs.forEach { (vari, deg) -> + if (vari !in filteredVariablesAndOrders) put(vari, deg) + else { + val order = filteredVariablesAndOrders[vari]!! + if (deg > order) put(vari, deg - order) + } + } + }, + filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> + degs[index]!!.let { deg -> + (deg downTo deg - order + 1u) + .fold(acc1) { acc2, ord -> multiplyByDoubling(acc2, ord) } + } + } + ) + } + } + ) +} + +/** + * Returns algebraic antiderivative of received polynomial with respect to provided variable. + */ +@UnstableKMathAPI +public fun > LabeledPolynomial.antiderivativeWithRespectTo( + algebra: A, + variable: Symbol, +): LabeledPolynomial = algebra { + LabeledPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + val newDegs = buildMap(degs.size + 1) { + put(variable, 1u) + for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) + } + put( + newDegs, + c / multiplyByDoubling(one, newDegs[variable]!!) + ) + } + } + ) +} + +/** + * Returns algebraic antiderivative of received polynomial with respect to provided variable of specified order. + */ +@UnstableKMathAPI +public fun > LabeledPolynomial.nthAntiderivativeWithRespectTo( + algebra: A, + variable: Symbol, + order: UInt +): LabeledPolynomial = algebra { + if (order == 0u) return this@nthAntiderivativeWithRespectTo + LabeledPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + val newDegs = buildMap(degs.size + 1) { + put(variable, order) + for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) + } + put( + newDegs, + newDegs[variable]!!.let { deg -> + (deg downTo deg - order + 1u) + .fold(c) { acc, ord -> acc / multiplyByDoubling(one, ord) } + } + ) + } + } + ) +} + +/** + * Returns algebraic derivative of received polynomial with respect to provided variables of specified orders. + */ +@UnstableKMathAPI +public fun > LabeledPolynomial.nthAntiderivativeWithRespectTo( + algebra: A, + variablesAndOrders: Map, +): LabeledPolynomial = algebra { + val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u } + if (filteredVariablesAndOrders.isEmpty()) return this@nthAntiderivativeWithRespectTo + LabeledPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + val newDegs = buildMap(degs.size + 1) { + for ((variable, order) in filteredVariablesAndOrders) put(variable, order) + for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) + } + put( + newDegs, + filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> + newDegs[index]!!.let { deg -> + (deg downTo deg - order + 1u) + .fold(acc1) { acc2, ord -> acc2 / multiplyByDoubling(one, ord) } + } + } + ) + } + } + ) +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt index 37d5d7fb6..4850e6cec 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt @@ -3,6 +3,8 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ +@file:Suppress("FunctionName", "NOTHING_TO_INLINE") + package space.kscience.kmath.functions import space.kscience.kmath.misc.UnstableKMathAPI @@ -17,7 +19,6 @@ internal fun List.cleanUp() = subList(0, indexOfLast { it != 0U } + 1) /** * Constructs [NumberedPolynomial] with provided coefficients map [coefs]. The map is used as is. */ -@Suppress("FunctionName", "NOTHING_TO_INLINE") @PublishedApi internal inline fun NumberedPolynomialAsIs(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs) @@ -25,7 +26,6 @@ internal inline fun NumberedPolynomialAsIs(coefs: Map, C>) : Numb * Constructs [NumberedPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient". * The collections will be transformed to map with [toMap] and then will be used as is. */ -@Suppress("FunctionName", "NOTHING_TO_INLINE") @PublishedApi internal inline fun NumberedPolynomialAsIs(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs.toMap()) @@ -33,7 +33,6 @@ internal inline fun NumberedPolynomialAsIs(pairs: Collection * Constructs [NumberedPolynomial] with provided array of [pairs] of pairs "term's signature — term's coefficient". * The array will be transformed to map with [toMap] and then will be used as is. */ -@Suppress("FunctionName", "NOTHING_TO_INLINE") @PublishedApi internal inline fun NumberedPolynomialAsIs(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(pairs.toMap()) @@ -43,7 +42,6 @@ internal inline fun NumberedPolynomialAsIs(vararg pairs: Pair, C> * **Be sure you read description of [NumberedPolynomial.coefficients]. Otherwise, you may make a mistake that will * cause wrong computation result or even runtime error.** */ -@Suppress("FunctionName", "NOTHING_TO_INLINE") @DelicatePolynomialAPI public inline fun NumberedPolynomialWithoutCheck(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs) @@ -54,7 +52,6 @@ public inline fun NumberedPolynomialWithoutCheck(coefs: Map, C>) * **Be sure you read description of [NumberedPolynomial.coefficients]. Otherwise, you may make a mistake that will * cause wrong computation result or even runtime error.** */ -@Suppress("FunctionName", "NOTHING_TO_INLINE") @DelicatePolynomialAPI public inline fun NumberedPolynomialWithoutCheck(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs.toMap()) @@ -65,7 +62,6 @@ public inline fun NumberedPolynomialWithoutCheck(pairs: Collection NumberedPolynomialWithoutCheck(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(pairs.toMap()) @@ -77,7 +73,6 @@ public inline fun NumberedPolynomialWithoutCheck(vararg pairs: Pair NumberedPolynomial(coefs: Map, C>, add: (C, C) -> C) : NumberedPolynomial { val fixedCoefs = mutableMapOf, C>() @@ -98,7 +93,6 @@ public fun NumberedPolynomial(coefs: Map, C>, add: (C, C) -> C) : * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. */ -@Suppress("FunctionName") public fun NumberedPolynomial(pairs: Collection, C>>, add: (C, C) -> C) : NumberedPolynomial { val fixedCoefs = mutableMapOf, C>() @@ -119,7 +113,6 @@ public fun NumberedPolynomial(pairs: Collection, C>>, add: ( * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. */ -@Suppress("FunctionName") public fun NumberedPolynomial(vararg pairs: Pair, C>, add: (C, C) -> C) : NumberedPolynomial { val fixedCoefs = mutableMapOf, C>() @@ -142,7 +135,6 @@ public fun NumberedPolynomial(vararg pairs: Pair, C>, add: (C, C) * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. */ -@Suppress("FunctionName", "NOTHING_TO_INLINE") public inline fun > A.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, ::add) /** * Constructs [NumberedPolynomial] with provided coefficients map [coefs]. @@ -152,7 +144,6 @@ public inline fun > A.NumberedPolynomial(coefs: Map, C> * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. */ -@Suppress("FunctionName", "NOTHING_TO_INLINE") public inline fun > NumberedPolynomialSpace.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs) { left: C, right: C -> left + right } /** @@ -163,7 +154,6 @@ public inline fun > NumberedPolynomialSpace.NumberedPolynomi * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. */ -@Suppress("FunctionName", "NOTHING_TO_INLINE") public inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs) { left: C, right: C -> left + right } /** @@ -174,7 +164,6 @@ public inline fun > NumberedRationalFunctionSpace.NumberedPo * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. */ -@Suppress("FunctionName", "NOTHING_TO_INLINE") public inline fun > A.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, ::add) /** @@ -185,7 +174,6 @@ public inline fun > A.NumberedPolynomial(pairs: Collection> NumberedPolynomialSpace.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs) { left: C, right: C -> left + right } /** * Constructs [NumberedPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient". @@ -195,7 +183,6 @@ public inline fun > NumberedPolynomialSpace.NumberedPolynomi * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. */ -@Suppress("FunctionName", "NOTHING_TO_INLINE") public inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs) { left: C, right: C -> left + right } /** @@ -206,7 +193,6 @@ public inline fun > NumberedRationalFunctionSpace.NumberedPo * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. */ -@Suppress("FunctionName", "NOTHING_TO_INLINE") public inline fun > A.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs) { left: C, right: C -> left + right } /** * Constructs [NumberedPolynomial] with provided array [pairs] of pairs "term's signature — term's coefficient". @@ -216,7 +202,6 @@ public inline fun > A.NumberedPolynomial(vararg pairs: Pair> NumberedPolynomialSpace.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs) { left: C, right: C -> left + right } /** * Constructs [NumberedPolynomial] with provided array [pairs] of pairs "term's signature — term's coefficient". @@ -226,13 +211,11 @@ public inline fun > NumberedPolynomialSpace.NumberedPolynomi * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. */ -@Suppress("FunctionName", "NOTHING_TO_INLINE") public inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs) { left: C, right: C -> left + right } /** * Converts [this] constant to [NumberedPolynomial]. */ -@Suppress("NOTHING_TO_INLINE") public inline fun C.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomialAsIs(mapOf(emptyList() to this)) /** @@ -269,6 +252,7 @@ public class NumberedPolynomialTermSignatureBuilder { * * In fact, it just returns [signature] as regular signature of type `List`. */ + @PublishedApi internal fun build(): List = signature /** @@ -344,8 +328,7 @@ public class NumberedPolynomialBuilder( * coefficients is zero at any moment the monomial won't be removed but will be left as it is. */ public infix fun C.with(signature: List) { - if (signature in coefficients) coefficients[signature] = add(coefficients[signature]!!, this@with) - else coefficients[signature] = this@with + coefficients[signature] = if (signature in coefficients) add(coefficients[signature]!!, this@with) else this@with } /** * Declares monomial with [this] coefficient and signature constructed by [block]. @@ -361,7 +344,7 @@ public class NumberedPolynomialBuilder( * Declaring another monomial with the same signature will add [this] coefficient to existing one. If the sum of such * coefficients is zero at any moment the monomial won't be removed but will be left as it is. */ - public operator fun C.invoke(block: NumberedPolynomialTermSignatureBuilder.() -> Unit): Unit = + public inline operator fun C.invoke(block: NumberedPolynomialTermSignatureBuilder.() -> Unit): Unit = this with NumberedPolynomialTermSignatureBuilder().apply(block).build() } @@ -385,7 +368,6 @@ public class NumberedPolynomialBuilder( // 2. Union types are implemented. Then all three functions should be rewritten // as one with single union type as a (context) receiver. //@UnstableKMathAPI -//@Suppress("FunctionName") //public inline fun > A.NumberedPolynomial(initialCapacity: Int = 0, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder(::add, initialCapacity).apply(block).build() /** * Creates [NumberedPolynomial] with lambda [block] in context of [this] ring of [NumberedPolynomial]s. @@ -401,7 +383,6 @@ public class NumberedPolynomialBuilder( * ``` */ @UnstableKMathAPI -@Suppress("FunctionName") public inline fun > NumberedPolynomialSpace.NumberedPolynomial(initialCapacity: Int = 0, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() /** * Creates [NumberedPolynomial] with lambda [block] in context of [this] field of [NumberedRationalFunction]s. @@ -417,7 +398,6 @@ public inline fun > NumberedPolynomialSpace.NumberedPolynomi * ``` */ @UnstableKMathAPI -@Suppress("FunctionName") public inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(initialCapacity: Int = 0, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() // Waiting for context receivers :( FIXME: Replace with context receivers when they will be available @@ -430,7 +410,6 @@ public inline fun > NumberedRationalFunctionSpace.NumberedPo * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. */ -@Suppress("FunctionName") public fun > A.NumberedRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): NumberedRationalFunction = NumberedRationalFunction( NumberedPolynomial(numeratorCoefficients), @@ -444,7 +423,6 @@ public fun > A.NumberedRationalFunction(numeratorCoefficients: Map * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. */ -@Suppress("FunctionName") public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): NumberedRationalFunction = NumberedRationalFunction( NumberedPolynomial(numeratorCoefficients), @@ -454,13 +432,11 @@ public fun > NumberedRationalFunctionSpace.NumberedRationalF /** * Constructs [NumberedRationalFunction] with provided [numerator] and unit denominator. */ -@Suppress("FunctionName") public fun > A.NumberedRationalFunction(numerator: NumberedPolynomial): NumberedRationalFunction = NumberedRationalFunction(numerator, NumberedPolynomial(mapOf(emptyList() to one))) /** * Constructs [NumberedRationalFunction] with provided [numerator] and unit denominator. */ -@Suppress("FunctionName") public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numerator: NumberedPolynomial): NumberedRationalFunction = NumberedRationalFunction(numerator, polynomialOne) @@ -473,7 +449,6 @@ public fun > NumberedRationalFunctionSpace.NumberedRationalF * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. */ -@Suppress("FunctionName") public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numeratorCoefficients: Map, C>): NumberedRationalFunction = NumberedRationalFunction( NumberedPolynomial(numeratorCoefficients), @@ -488,7 +463,6 @@ public fun > NumberedRationalFunctionSpace.NumberedRationalF * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. */ -@Suppress("FunctionName") public fun > A.NumberedRationalFunction(numeratorCoefficients: Map, C>): NumberedRationalFunction = NumberedRationalFunction( NumberedPolynomial(numeratorCoefficients), @@ -496,7 +470,7 @@ public fun > A.NumberedRationalFunction(numeratorCoefficients: Map ) ///** -// * Converts [this] coefficient to [NumberedRationalFunction]. +// * Converts [this] constant to [NumberedRationalFunction]. // */ //context(A) //public fun > C.asNumberedRationalFunction() : NumberedRationalFunction = @@ -505,7 +479,7 @@ public fun > A.NumberedRationalFunction(numeratorCoefficients: Map // NumberedPolynomialAsIs(mapOf(emptyList() to one)) // ) ///** -// * Converts [this] coefficient to [NumberedRationalFunction]. +// * Converts [this] constant to [NumberedRationalFunction]. // */ //context(NumberedRationalFunctionSpace) //public fun > C.asNumberedRationalFunction() : NumberedRationalFunction = diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt index fca9a8ab8..06911feca 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt @@ -51,15 +51,14 @@ public inline fun , R> A.numberedRationalFunctionSpace(block: Num */ public fun NumberedPolynomial.substitute(args: Map): NumberedPolynomial = Double.algebra { NumberedPolynomial( - buildMap, Double>(coefficients.size) { + buildMap(coefficients.size) { for ((degs, c) in coefficients) { val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp() val newC = args.entries.fold(c) { product, (variable, substitution) -> val deg = degs.getOrElse(variable) { 0u } if (deg == 0u) product else product * substitution.pow(deg.toInt()) } - if (newDegs !in this) this[newDegs] = newC - else this[newDegs] = this[newDegs]!! + newC + this[newDegs] = if (newDegs !in this) newC else this[newDegs]!! + newC } } ) @@ -70,15 +69,14 @@ public fun NumberedPolynomial.substitute(args: Map): Number */ public fun NumberedPolynomial.substitute(ring: Ring, args: Map): NumberedPolynomial = ring { NumberedPolynomial( - buildMap, C>(coefficients.size) { + buildMap(coefficients.size) { for ((degs, c) in coefficients) { val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp() val newC = args.entries.fold(c) { product, (variable, substitution) -> val deg = degs.getOrElse(variable) { 0u } if (deg == 0u) product else product * power(substitution, deg) } - if (newDegs !in this) this[newDegs] = newC - else this[newDegs] = this[newDegs]!! + newC + this[newDegs] = if (newDegs !in this) newC else this[newDegs]!! + newC } } ) @@ -128,14 +126,14 @@ public fun NumberedRationalFunction.substitute(ring: Ring, args: Map NumberedRationalFunction.substitute(ring: Ring, args: Map>) : NumberedRationalFunction = NumberedRationalFunction(numerator.substitute(ring, args), denominator.substitute(ring, args)) /** * Substitutes provided arguments [args] into [this] rational function. - */ // TODO: To optimize boxing + */ // TODO: To optimize calculation @JvmName("substituteRationalFunction") public fun NumberedRationalFunction.substitute(ring: Ring, args: Map>) : NumberedRationalFunction = ring.numberedRationalFunctionSpace { @@ -250,14 +248,14 @@ public fun NumberedRationalFunction.substitute(ring: Ring, args: Buffe /** * Substitutes provided arguments [args] into [this] rational function. - */ // TODO: To optimize boxing + */ // TODO: To optimize calculation @JvmName("substitutePolynomial") public fun NumberedRationalFunction.substitute(ring: Ring, args: Buffer>) : NumberedRationalFunction = NumberedRationalFunction(numerator.substitute(ring, args), denominator.substitute(ring, args)) /** * Substitutes provided arguments [args] into [this] rational function. - */ // TODO: To optimize boxing + */ // TODO: To optimize calculation @JvmName("substituteRationalFunction") public fun NumberedRationalFunction.substitute(ring: Ring, args: Buffer>) : NumberedRationalFunction = ring.numberedRationalFunctionSpace {