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