Feature: Polynomials and rational functions #469
@ -91,6 +91,15 @@ public inline fun <T : Any, R> Buffer<T>.fold(initial: R, operation: (acc: R, T)
|
||||
return accumulator
|
||||
}
|
||||
|
||||
/**
|
||||
* Fold given buffer according to indexed [operation]
|
||||
*/
|
||||
public inline fun <T : Any, R> Buffer<T>.foldIndexed(initial: R, operation: (index: Int, acc: R, T) -> R): R {
|
||||
var accumulator = initial
|
||||
for (index in this.indices) accumulator = operation(index, accumulator, get(index))
|
||||
return accumulator
|
||||
}
|
||||
|
||||
/**
|
||||
* Zip two buffers using given [transform].
|
||||
*/
|
||||
|
@ -48,8 +48,8 @@ public data class ListPolynomial<C>(
|
||||
}
|
||||
|
||||
/**
|
||||
* Arithmetic context for univariate polynomials with coefficients stored as a [List] constructed with the given [ring]
|
||||
* of constants.
|
||||
* Arithmetic context for univariate polynomials with coefficients stored as a [List] constructed with the provided
|
||||
* [ring] of constants.
|
||||
*
|
||||
* @param C the type of constants. Polynomials have them a coefficients in their terms.
|
||||
* @param A type of provided underlying ring of constants. It's [Ring] of [C].
|
||||
@ -313,6 +313,10 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
|
||||
}
|
||||
)
|
||||
}
|
||||
/**
|
||||
* Raises [arg] to the integer power [exponent].
|
||||
*/ // TODO: To optimize boxing
|
||||
override fun power(arg: ListPolynomial<C>, exponent: UInt): ListPolynomial<C> = super.power(arg, exponent)
|
||||
|
||||
/**
|
||||
* Instance of zero polynomial (zero of the polynomial ring).
|
||||
@ -332,42 +336,42 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
|
||||
// TODO: When context receivers will be ready move all of this substitutions and invocations to utilities with
|
||||
// [ListPolynomialSpace] as a context receiver
|
||||
/**
|
||||
* Evaluates value of [this] polynomial on provided argument.
|
||||
* Evaluates value of [this] polynomial on provided [argument].
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun ListPolynomial<C>.substitute(argument: C): C = this.substitute(ring, argument)
|
||||
public inline fun ListPolynomial<C>.substitute(argument: C): C = substitute(ring, argument)
|
||||
/**
|
||||
* Substitutes provided polynomial [argument] into [this] polynomial.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun ListPolynomial<C>.substitute(argument: ListPolynomial<C>): ListPolynomial<C> = this.substitute(ring, argument)
|
||||
public inline fun ListPolynomial<C>.substitute(argument: ListPolynomial<C>): ListPolynomial<C> = substitute(ring, argument)
|
||||
|
||||
/**
|
||||
* Represent [this] polynomial as a regular context-less function.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun ListPolynomial<C>.asFunction(): (C) -> C = { this.substitute(ring, it) }
|
||||
public inline fun ListPolynomial<C>.asFunction(): (C) -> C = asFunctionOver(ring)
|
||||
/**
|
||||
* Represent [this] polynomial as a regular context-less function.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun ListPolynomial<C>.asFunctionOfConstant(): (C) -> C = { this.substitute(ring, it) }
|
||||
public inline fun ListPolynomial<C>.asFunctionOfConstant(): (C) -> C = asFunctionOfConstantOver(ring)
|
||||
/**
|
||||
* Represent [this] polynomial as a regular context-less function.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun ListPolynomial<C>.asFunctionOfPolynomial(): (ListPolynomial<C>) -> ListPolynomial<C> = { this.substitute(ring, it) }
|
||||
public inline fun ListPolynomial<C>.asFunctionOfPolynomial(): (ListPolynomial<C>) -> ListPolynomial<C> = asFunctionOfPolynomialOver(ring)
|
||||
|
||||
/**
|
||||
* Evaluates value of [this] polynomial on provided [argument].
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline operator fun ListPolynomial<C>.invoke(argument: C): C = this.substitute(ring, argument)
|
||||
public inline operator fun ListPolynomial<C>.invoke(argument: C): C = substitute(ring, argument)
|
||||
/**
|
||||
* Evaluates value of [this] polynomial on provided [argument].
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline operator fun ListPolynomial<C>.invoke(argument: ListPolynomial<C>): ListPolynomial<C> = this.substitute(ring, argument)
|
||||
public inline operator fun ListPolynomial<C>.invoke(argument: ListPolynomial<C>): ListPolynomial<C> = substitute(ring, argument)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -9,7 +9,7 @@ import space.kscience.kmath.operations.Ring
|
||||
|
||||
|
||||
/**
|
||||
* Represents rational function that stores its numerator and denominator as [ListPolynomial]s.
|
||||
* Represents univariate rational function that stores its numerator and denominator as [ListPolynomial]s.
|
||||
*/
|
||||
public data class ListRationalFunction<C>(
|
||||
public override val numerator: ListPolynomial<C>,
|
||||
@ -56,82 +56,82 @@ public class ListRationalFunctionSpace<C, A : Ring<C>> (
|
||||
* Evaluates value of [this] polynomial on provided argument.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun ListPolynomial<C>.substitute(argument: C): C = this.substitute(ring, argument)
|
||||
public inline fun ListPolynomial<C>.substitute(argument: C): C = substitute(ring, argument)
|
||||
/**
|
||||
* Substitutes provided polynomial [argument] into [this] polynomial.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun ListPolynomial<C>.substitute(argument: ListPolynomial<C>): ListPolynomial<C> = this.substitute(ring, argument)
|
||||
public inline fun ListPolynomial<C>.substitute(argument: ListPolynomial<C>): ListPolynomial<C> = substitute(ring, argument)
|
||||
/**
|
||||
* Substitutes provided rational function [argument] into [this] polynomial.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun ListPolynomial<C>.substitute(argument: ListRationalFunction<C>): ListRationalFunction<C> = this.substitute(ring, argument)
|
||||
public inline fun ListPolynomial<C>.substitute(argument: ListRationalFunction<C>): ListRationalFunction<C> = substitute(ring, argument)
|
||||
/**
|
||||
* Substitutes provided polynomial [argument] into [this] rational function.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun ListRationalFunction<C>.substitute(argument: ListPolynomial<C>): ListRationalFunction<C> = this.substitute(ring, argument)
|
||||
public inline fun ListRationalFunction<C>.substitute(argument: ListPolynomial<C>): ListRationalFunction<C> = substitute(ring, argument)
|
||||
/**
|
||||
* Substitutes provided rational function [argument] into [this] rational function.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun ListRationalFunction<C>.substitute(argument: ListRationalFunction<C>): ListRationalFunction<C> = this.substitute(ring, argument)
|
||||
public inline fun ListRationalFunction<C>.substitute(argument: ListRationalFunction<C>): ListRationalFunction<C> = substitute(ring, argument)
|
||||
|
||||
/**
|
||||
* Represent [this] polynomial as a regular context-less function.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun ListPolynomial<C>.asFunction(): (C) -> C = { this.substitute(ring, it) }
|
||||
public inline fun ListPolynomial<C>.asFunction(): (C) -> C = { substitute(ring, it) }
|
||||
/**
|
||||
* Represent [this] polynomial as a regular context-less function.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun ListPolynomial<C>.asFunctionOfConstant(): (C) -> C = { this.substitute(ring, it) }
|
||||
public inline fun ListPolynomial<C>.asFunctionOfConstant(): (C) -> C = { substitute(ring, it) }
|
||||
/**
|
||||
* Represent [this] polynomial as a regular context-less function.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun ListPolynomial<C>.asFunctionOfPolynomial(): (ListPolynomial<C>) -> ListPolynomial<C> = { this.substitute(ring, it) }
|
||||
public inline fun ListPolynomial<C>.asFunctionOfPolynomial(): (ListPolynomial<C>) -> ListPolynomial<C> = { substitute(ring, it) }
|
||||
/**
|
||||
* Represent [this] polynomial as a regular context-less function.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun ListPolynomial<C>.asFunctionOfRationalFunction(): (ListRationalFunction<C>) -> ListRationalFunction<C> = { this.substitute(ring, it) }
|
||||
public inline fun ListPolynomial<C>.asFunctionOfRationalFunction(): (ListRationalFunction<C>) -> ListRationalFunction<C> = { substitute(ring, it) }
|
||||
/**
|
||||
* Represent [this] rational function as a regular context-less function.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun ListRationalFunction<C>.asFunctionOfPolynomial(): (ListPolynomial<C>) -> ListRationalFunction<C> = { this.substitute(ring, it) }
|
||||
public inline fun ListRationalFunction<C>.asFunctionOfPolynomial(): (ListPolynomial<C>) -> ListRationalFunction<C> = { substitute(ring, it) }
|
||||
/**
|
||||
* Represent [this] rational function as a regular context-less function.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun ListRationalFunction<C>.asFunctionOfRationalFunction(): (ListRationalFunction<C>) -> ListRationalFunction<C> = { this.substitute(ring, it) }
|
||||
public inline fun ListRationalFunction<C>.asFunctionOfRationalFunction(): (ListRationalFunction<C>) -> ListRationalFunction<C> = { substitute(ring, it) }
|
||||
|
||||
/**
|
||||
* Evaluates value of [this] polynomial on provided argument.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline operator fun ListPolynomial<C>.invoke(argument: C): C = this.substitute(ring, argument)
|
||||
public inline operator fun ListPolynomial<C>.invoke(argument: C): C = substitute(ring, argument)
|
||||
/**
|
||||
* Evaluates value of [this] polynomial on provided argument.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline operator fun ListPolynomial<C>.invoke(argument: ListPolynomial<C>): ListPolynomial<C> = this.substitute(ring, argument)
|
||||
public inline operator fun ListPolynomial<C>.invoke(argument: ListPolynomial<C>): ListPolynomial<C> = substitute(ring, argument)
|
||||
/**
|
||||
* Evaluates value of [this] polynomial on provided argument.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline operator fun ListPolynomial<C>.invoke(argument: ListRationalFunction<C>): ListRationalFunction<C> = this.substitute(ring, argument)
|
||||
public inline operator fun ListPolynomial<C>.invoke(argument: ListRationalFunction<C>): ListRationalFunction<C> = substitute(ring, argument)
|
||||
/**
|
||||
* Evaluates value of [this] rational function on provided argument.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline operator fun ListRationalFunction<C>.invoke(argument: ListPolynomial<C>): ListRationalFunction<C> = this.substitute(ring, argument)
|
||||
public inline operator fun ListRationalFunction<C>.invoke(argument: ListPolynomial<C>): ListRationalFunction<C> = substitute(ring, argument)
|
||||
/**
|
||||
* Evaluates value of [this] rational function on provided argument.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline operator fun ListRationalFunction<C>.invoke(argument: ListRationalFunction<C>): ListRationalFunction<C> = this.substitute(ring, argument)
|
||||
public inline operator fun ListRationalFunction<C>.invoke(argument: ListRationalFunction<C>): ListRationalFunction<C> = substitute(ring, argument)
|
||||
}
|
@ -0,0 +1,429 @@
|
||||
/*
|
||||
* Copyright 2018-2021 KMath contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package space.kscience.kmath.functions
|
||||
|
||||
import space.kscience.kmath.operations.Ring
|
||||
import space.kscience.kmath.structures.Buffer
|
||||
import kotlin.jvm.JvmName
|
||||
import kotlin.math.max
|
||||
|
||||
|
||||
/**
|
||||
* Represents univariate polynomial that stores its coefficients in a [Map] and terms' signatures in a [List].
|
||||
*
|
||||
* @param C the type of constants.
|
||||
*/
|
||||
public data class NumberedPolynomial<C>
|
||||
@PublishedApi
|
||||
internal constructor(
|
||||
/**
|
||||
* Map that contains coefficients of the polynomial. Every monomial `a x_1^{d_1} ... x_n^{d_n}` is stored as pair
|
||||
* "key-value" in the map, where the value is the coefficients `a` and the key is a list that associates index of
|
||||
* every variable in the monomial with multiplicity of the variable occurring in the monomial. For example
|
||||
* coefficients of a polynomial `5 x_1^2 x_3^3 - 6 x_2` can be represented as
|
||||
* ```
|
||||
* mapOf(
|
||||
* listOf(2, 0, 3) to 5, // 5 x_1^2 x_3^3 +
|
||||
* listOf(0, 1) to (-6), // (-6) x_2^1
|
||||
* )
|
||||
* ```
|
||||
* and also as
|
||||
* ```
|
||||
* mapOf(
|
||||
* listOf(2, 0, 3) to 5, // 5 x_1^2 x_3^3 +
|
||||
* listOf(0, 1) to (-6), // (-6) x_2^1
|
||||
* listOf(0, 1, 1) to 0, // 0 x_2^1 x_3^1
|
||||
* )
|
||||
* ```
|
||||
* It is not prohibited to put extra zero monomials into the map (as for `0 x_2 x_3` in the example). But the
|
||||
* bigger the coefficients map the worse performance of arithmetical operations performed on it. Thus, it is
|
||||
* recommended not to put (or even to remove) extra (or useless) monomials in the coefficients map.
|
||||
*/
|
||||
public val coefficients: Map<List<UInt>, C>
|
||||
) : Polynomial<C> {
|
||||
override fun toString(): String = "NumberedPolynomial$coefficients"
|
||||
}
|
||||
|
||||
/**
|
||||
* Arithmetic context for multivariate polynomials with coefficients stored as a [Map] and terms' signatures stored as a
|
||||
* [List] constructed with the provided [ring] of constants.
|
||||
*
|
||||
* @param C the type of constants. Polynomials have them a coefficients in their terms.
|
||||
* @param A type of provided underlying ring of constants. It's [Ring] of [C].
|
||||
* @param ring underlying ring of constants of type [A].
|
||||
*/
|
||||
public class NumberedPolynomialSpace<C, A : Ring<C>>(
|
||||
public override val ring: A,
|
||||
) : PolynomialSpaceOverRing<C, NumberedPolynomial<C>, A> {
|
||||
/**
|
||||
* Returns sum of the polynomial and the integer represented as a polynomial.
|
||||
*
|
||||
* The operation is equivalent to adding [other] copies of unit polynomial to [this].
|
||||
*/
|
||||
public override operator fun NumberedPolynomial<C>.plus(other: Int): NumberedPolynomial<C> =
|
||||
if (other == 0) this
|
||||
else
|
||||
NumberedPolynomialAsIs(
|
||||
coefficients
|
||||
.toMutableMap()
|
||||
.apply {
|
||||
val degs = emptyList<UInt>()
|
||||
|
||||
this[degs] = getOrElse(degs) { constantZero } + other
|
||||
}
|
||||
)
|
||||
/**
|
||||
* Returns difference between the polynomial and the integer represented as a polynomial.
|
||||
*
|
||||
* The operation is equivalent to subtraction [other] copies of unit polynomial from [this].
|
||||
*/
|
||||
public override operator fun NumberedPolynomial<C>.minus(other: Int): NumberedPolynomial<C> =
|
||||
if (other == 0) this
|
||||
else
|
||||
NumberedPolynomialAsIs(
|
||||
coefficients
|
||||
.toMutableMap()
|
||||
.apply {
|
||||
val degs = emptyList<UInt>()
|
||||
|
||||
this[degs] = getOrElse(degs) { constantZero } - other
|
||||
}
|
||||
)
|
||||
/**
|
||||
* Returns product of the polynomial and the integer represented as a polynomial.
|
||||
*
|
||||
* The operation is equivalent to sum of [other] copies of [this].
|
||||
*/
|
||||
public override operator fun NumberedPolynomial<C>.times(other: Int): NumberedPolynomial<C> =
|
||||
if (other == 0) zero
|
||||
else NumberedPolynomialAsIs(
|
||||
coefficients
|
||||
.toMutableMap()
|
||||
.apply {
|
||||
for (degs in keys) this[degs] = this[degs]!! * other
|
||||
}
|
||||
)
|
||||
|
||||
/**
|
||||
* Returns sum of the integer represented as a polynomial and the polynomial.
|
||||
*
|
||||
* The operation is equivalent to adding [this] copies of unit polynomial to [other].
|
||||
*/
|
||||
public override operator fun Int.plus(other: NumberedPolynomial<C>): NumberedPolynomial<C> =
|
||||
if (this == 0) other
|
||||
else
|
||||
NumberedPolynomialAsIs(
|
||||
other.coefficients
|
||||
.toMutableMap()
|
||||
.apply {
|
||||
val degs = emptyList<UInt>()
|
||||
|
||||
this[degs] = this@plus + getOrElse(degs) { constantZero }
|
||||
}
|
||||
)
|
||||
/**
|
||||
* Returns difference between the integer represented as a polynomial and the polynomial.
|
||||
*
|
||||
* The operation is equivalent to subtraction [this] copies of unit polynomial from [other].
|
||||
*/
|
||||
public override operator fun Int.minus(other: NumberedPolynomial<C>): NumberedPolynomial<C> =
|
||||
if (this == 0) other
|
||||
else
|
||||
NumberedPolynomialAsIs(
|
||||
other.coefficients
|
||||
.toMutableMap()
|
||||
.apply {
|
||||
val degs = emptyList<UInt>()
|
||||
|
||||
this[degs] = this@minus - getOrElse(degs) { constantZero }
|
||||
}
|
||||
)
|
||||
/**
|
||||
* Returns product of the integer represented as a polynomial and the polynomial.
|
||||
*
|
||||
* The operation is equivalent to sum of [this] copies of [other].
|
||||
*/
|
||||
public override operator fun Int.times(other: NumberedPolynomial<C>): NumberedPolynomial<C> =
|
||||
if (this == 0) zero
|
||||
else NumberedPolynomialAsIs(
|
||||
other.coefficients
|
||||
.toMutableMap()
|
||||
.apply {
|
||||
for (degs in keys) this[degs] = this@times * this[degs]!!
|
||||
}
|
||||
)
|
||||
|
||||
/**
|
||||
* Converts the integer [value] to polynomial.
|
||||
*/
|
||||
public override fun number(value: Int): NumberedPolynomial<C> = number(constantNumber(value))
|
||||
|
||||
/**
|
||||
* Returns sum of the constant represented as a polynomial and the polynomial.
|
||||
*/
|
||||
override operator fun C.plus(other: NumberedPolynomial<C>): NumberedPolynomial<C> =
|
||||
with(other.coefficients) {
|
||||
if (isEmpty()) NumberedPolynomialAsIs(mapOf(emptyList<UInt>() to this@plus))
|
||||
else NumberedPolynomialAsIs(
|
||||
toMutableMap()
|
||||
.apply {
|
||||
val degs = emptyList<UInt>()
|
||||
|
||||
this[degs] = this@plus + getOrElse(degs) { constantZero }
|
||||
}
|
||||
)
|
||||
}
|
||||
/**
|
||||
* Returns difference between the constant represented as a polynomial and the polynomial.
|
||||
*/
|
||||
override operator fun C.minus(other: NumberedPolynomial<C>): NumberedPolynomial<C> =
|
||||
with(other.coefficients) {
|
||||
if (isEmpty()) NumberedPolynomialAsIs(mapOf(emptyList<UInt>() to this@minus))
|
||||
else NumberedPolynomialAsIs(
|
||||
toMutableMap()
|
||||
.apply {
|
||||
forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c }
|
||||
|
||||
val degs = emptyList<UInt>()
|
||||
|
||||
this[degs] = this@minus - getOrElse(degs) { constantZero }
|
||||
}
|
||||
)
|
||||
}
|
||||
/**
|
||||
* Returns product of the constant represented as a polynomial and the polynomial.
|
||||
*/
|
||||
override operator fun C.times(other: NumberedPolynomial<C>): NumberedPolynomial<C> =
|
||||
NumberedPolynomialAsIs(
|
||||
other.coefficients
|
||||
.toMutableMap()
|
||||
.apply {
|
||||
for (degs in keys) this[degs] = this@times * this[degs]!!
|
||||
}
|
||||
)
|
||||
|
||||
/**
|
||||
* Returns sum of the constant represented as a polynomial and the polynomial.
|
||||
*/
|
||||
override operator fun NumberedPolynomial<C>.plus(other: C): NumberedPolynomial<C> =
|
||||
with(coefficients) {
|
||||
if (isEmpty()) NumberedPolynomialAsIs(mapOf(emptyList<UInt>() to other))
|
||||
else NumberedPolynomialAsIs(
|
||||
toMutableMap()
|
||||
.apply {
|
||||
val degs = emptyList<UInt>()
|
||||
|
||||
this[degs] = getOrElse(degs) { constantZero } + other
|
||||
}
|
||||
)
|
||||
}
|
||||
/**
|
||||
* Returns difference between the constant represented as a polynomial and the polynomial.
|
||||
*/
|
||||
override operator fun NumberedPolynomial<C>.minus(other: C): NumberedPolynomial<C> =
|
||||
with(coefficients) {
|
||||
if (isEmpty()) NumberedPolynomialAsIs(mapOf(emptyList<UInt>() to other))
|
||||
else NumberedPolynomialAsIs(
|
||||
toMutableMap()
|
||||
.apply {
|
||||
val degs = emptyList<UInt>()
|
||||
|
||||
this[degs] = getOrElse(degs) { constantZero } - other
|
||||
}
|
||||
)
|
||||
}
|
||||
/**
|
||||
* Returns product of the constant represented as a polynomial and the polynomial.
|
||||
*/
|
||||
override operator fun NumberedPolynomial<C>.times(other: C): NumberedPolynomial<C> =
|
||||
NumberedPolynomialAsIs(
|
||||
coefficients
|
||||
.toMutableMap()
|
||||
.apply {
|
||||
for (degs in keys) this[degs] = this[degs]!! * other
|
||||
}
|
||||
)
|
||||
|
||||
/**
|
||||
* Converts the constant [value] to polynomial.
|
||||
*/
|
||||
public override fun number(value: C): NumberedPolynomial<C> =
|
||||
NumberedPolynomialAsIs(mapOf(emptyList<UInt>() to value))
|
||||
|
||||
/**
|
||||
* Returns negation of the polynomial.
|
||||
*/
|
||||
override fun NumberedPolynomial<C>.unaryMinus(): NumberedPolynomial<C> =
|
||||
NumberedPolynomialAsIs(
|
||||
coefficients.mapValues { -it.value }
|
||||
)
|
||||
/**
|
||||
* Returns sum of the polynomials.
|
||||
*/
|
||||
override operator fun NumberedPolynomial<C>.plus(other: NumberedPolynomial<C>): NumberedPolynomial<C> =
|
||||
NumberedPolynomialAsIs(
|
||||
buildMap(coefficients.size + other.coefficients.size) {
|
||||
other.coefficients.mapValuesTo(this) { it.value }
|
||||
other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! + value else value }
|
||||
}
|
||||
)
|
||||
/**
|
||||
* Returns difference of the polynomials.
|
||||
*/
|
||||
override operator fun NumberedPolynomial<C>.minus(other: NumberedPolynomial<C>): NumberedPolynomial<C> =
|
||||
NumberedPolynomialAsIs(
|
||||
buildMap(coefficients.size + other.coefficients.size) {
|
||||
other.coefficients.mapValuesTo(this) { it.value }
|
||||
other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! - value else -value }
|
||||
}
|
||||
)
|
||||
/**
|
||||
* Returns product of the polynomials.
|
||||
*/
|
||||
override operator fun NumberedPolynomial<C>.times(other: NumberedPolynomial<C>): NumberedPolynomial<C> =
|
||||
NumberedPolynomialAsIs(
|
||||
buildMap(coefficients.size * other.coefficients.size) {
|
||||
for ((degs1, c1) in coefficients) for ((degs2, c2) in other.coefficients) {
|
||||
val degs =
|
||||
(0..max(degs1.lastIndex, degs2.lastIndex))
|
||||
.map { degs1.getOrElse(it) { 0U } + degs2.getOrElse(it) { 0U } }
|
||||
val c = c1 * c2
|
||||
this[degs] = if (degs in this) this[degs]!! + c else c
|
||||
}
|
||||
}
|
||||
)
|
||||
/**
|
||||
* Raises [arg] to the integer power [exponent].
|
||||
*/ // TODO: To optimize boxing
|
||||
override fun power(arg: NumberedPolynomial<C>, exponent: UInt): NumberedPolynomial<C> = super.power(arg, exponent)
|
||||
|
||||
/**
|
||||
* Instance of zero polynomial (zero of the polynomial ring).
|
||||
*/
|
||||
override val zero: NumberedPolynomial<C> = NumberedPolynomialAsIs(emptyMap())
|
||||
/**
|
||||
* Instance of unit polynomial (unit of the polynomial ring).
|
||||
*/
|
||||
override val one: NumberedPolynomial<C> by lazy {
|
||||
NumberedPolynomialAsIs(
|
||||
mapOf(
|
||||
emptyList<UInt>() 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<C>.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<C>.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<C>.degrees: List<UInt>
|
||||
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<C>.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<C>.degreeBy(variables: Collection<Int>): 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<C>.countOfVariables: Int
|
||||
get() =
|
||||
MutableList(lastVariable + 1) { false }.apply {
|
||||
coefficients.entries.forEach { (degs, _) ->
|
||||
degs.forEachIndexed { index, deg ->
|
||||
if (deg != 0u) this[index] = true
|
||||
}
|
||||
}
|
||||
}.count { it }
|
||||
|
||||
// TODO: When context receivers will be ready move all of this substitutions and invocations to utilities with
|
||||
// [ListPolynomialSpace] as a context receiver
|
||||
/**
|
||||
* Substitutes provided arguments [arguments] into [this] polynomial.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun NumberedPolynomial<C>.substitute(arguments: Map<Int, C>): NumberedPolynomial<C> = substitute(ring, arguments)
|
||||
/**
|
||||
* Substitutes provided arguments [arguments] into [this] polynomial.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
@JvmName("substitutePolynomial")
|
||||
public inline fun NumberedPolynomial<C>.substitute(arguments: Map<Int, NumberedPolynomial<C>>) : NumberedPolynomial<C> = substitute(ring, arguments)
|
||||
/**
|
||||
* Substitutes provided arguments [arguments] into [this] polynomial.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun NumberedPolynomial<C>.substitute(arguments: Buffer<C>): NumberedPolynomial<C> = substitute(ring, arguments)
|
||||
/**
|
||||
* Substitutes provided arguments [arguments] into [this] polynomial.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
@JvmName("substitutePolynomial")
|
||||
public inline fun NumberedPolynomial<C>.substitute(arguments: Buffer<NumberedPolynomial<C>>) : NumberedPolynomial<C> = substitute(ring, arguments)
|
||||
/**
|
||||
* Substitutes provided arguments [arguments] into [this] polynomial.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun NumberedPolynomial<C>.substituteFully(arguments: Buffer<C>): C = this.substituteFully(ring, arguments)
|
||||
|
||||
/**
|
||||
* Represent [this] polynomial as a regular context-less function.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun NumberedPolynomial<C>.asFunction(): (Buffer<C>) -> C = asFunctionOver(ring)
|
||||
/**
|
||||
* Represent [this] polynomial as a regular context-less function.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun NumberedPolynomial<C>.asFunctionOfConstant(): (Buffer<C>) -> C = asFunctionOfConstantOver(ring)
|
||||
/**
|
||||
* Represent [this] polynomial as a regular context-less function.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun NumberedPolynomial<C>.asFunctionOfPolynomial(): (Buffer<NumberedPolynomial<C>>) -> NumberedPolynomial<C> = asFunctionOfPolynomialOver(ring)
|
||||
|
||||
/**
|
||||
* Evaluates value of [this] polynomial on provided [arguments].
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline operator fun NumberedPolynomial<C>.invoke(arguments: Buffer<C>): C = substituteFully(ring, arguments)
|
||||
/**
|
||||
* Substitutes provided [arguments] into [this] polynomial.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
@JvmName("invokePolynomial")
|
||||
public inline operator fun NumberedPolynomial<C>.invoke(arguments: Buffer<NumberedPolynomial<C>>): NumberedPolynomial<C> = substitute(ring, arguments)
|
||||
}
|
@ -0,0 +1,239 @@
|
||||
/*
|
||||
* Copyright 2018-2021 KMath contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package space.kscience.kmath.functions
|
||||
|
||||
import space.kscience.kmath.operations.Ring
|
||||
import space.kscience.kmath.operations.invoke
|
||||
import space.kscience.kmath.structures.Buffer
|
||||
import kotlin.jvm.JvmName
|
||||
import kotlin.math.max
|
||||
|
||||
|
||||
/**
|
||||
* Represents multivariate rational function that stores its numerator and denominator as [NumberedPolynomial]s.
|
||||
*/
|
||||
public class NumberedRationalFunction<C> internal constructor(
|
||||
public override val numerator: NumberedPolynomial<C>,
|
||||
public override val denominator: NumberedPolynomial<C>
|
||||
) : RationalFunction<C, NumberedPolynomial<C>> {
|
||||
override fun toString(): String = "NumberedRationalFunction${numerator.coefficients}/${denominator.coefficients}"
|
||||
}
|
||||
|
||||
/**
|
||||
* Arithmetic context for univariate rational functions with numerator and denominator represented as [NumberedPolynomial]s.
|
||||
*
|
||||
* @param C the type of constants. Polynomials have them a coefficients in their terms.
|
||||
* @param A type of provided underlying ring of constants. It's [Ring] of [C].
|
||||
* @param ring underlying ring of constants of type [A].
|
||||
*/
|
||||
public class NumberedRationalFunctionSpace<C, A: Ring<C>> (
|
||||
public val ring: A,
|
||||
) :
|
||||
RationalFunctionalSpaceOverPolynomialSpace<
|
||||
C,
|
||||
NumberedPolynomial<C>,
|
||||
NumberedRationalFunction<C>,
|
||||
NumberedPolynomialSpace<C, A>,
|
||||
>,
|
||||
PolynomialSpaceOfFractions<
|
||||
C,
|
||||
NumberedPolynomial<C>,
|
||||
NumberedRationalFunction<C>,
|
||||
>() {
|
||||
|
||||
/**
|
||||
* Underlying polynomial ring. Its polynomial operations are inherited by local polynomial operations.
|
||||
*/
|
||||
public override val polynomialRing : NumberedPolynomialSpace<C, A> = NumberedPolynomialSpace(ring)
|
||||
/**
|
||||
* Constructor of rational functions (of type [NumberedRationalFunction]) from numerator and denominator (of type [NumberedPolynomial]).
|
||||
*/
|
||||
protected override fun constructRationalFunction(
|
||||
numerator: NumberedPolynomial<C>,
|
||||
denominator: NumberedPolynomial<C>
|
||||
): NumberedRationalFunction<C> =
|
||||
NumberedRationalFunction(numerator, denominator)
|
||||
|
||||
/**
|
||||
* Maximal index (ID) of variable occurring in the polynomial with positive power. If there is no such variable,
|
||||
* the result is `-1`.
|
||||
*/
|
||||
public val NumberedPolynomial<C>.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<C>.degrees: List<UInt> get() = polynomialRing { degrees }
|
||||
/**
|
||||
* Counts degree of the polynomial by the specified [variable].
|
||||
*/
|
||||
public fun NumberedPolynomial<C>.degreeBy(variable: Int): UInt = polynomialRing { degreeBy(variable) }
|
||||
/**
|
||||
* Counts degree of the polynomial by the specified [variables].
|
||||
*/
|
||||
public fun NumberedPolynomial<C>.degreeBy(variables: Collection<Int>): 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<C>.countOfVariables: Int get() = polynomialRing { countOfVariables }
|
||||
|
||||
/**
|
||||
* Count of all variables that appear in the polynomial in positive exponents.
|
||||
*/
|
||||
public val NumberedRationalFunction<C>.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<C>.countOfVariables: Int
|
||||
get() =
|
||||
MutableList(lastVariable + 1) { false }.apply {
|
||||
numerator.coefficients.entries.forEach { (degs, _) ->
|
||||
degs.forEachIndexed { index, deg ->
|
||||
if (deg != 0u) this[index] = true
|
||||
}
|
||||
}
|
||||
denominator.coefficients.entries.forEach { (degs, _) ->
|
||||
degs.forEachIndexed { index, deg ->
|
||||
if (deg != 0u) this[index] = true
|
||||
}
|
||||
}
|
||||
}.count { it }
|
||||
|
||||
// TODO: When context receivers will be ready move all of this substitutions and invocations to utilities with
|
||||
// [ListPolynomialSpace] as a context receiver
|
||||
/**
|
||||
* Substitutes provided constant [argument] into [this] polynomial.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun NumberedPolynomial<C>.substitute(argument: Map<Int, C>): NumberedPolynomial<C> = substitute(ring, argument)
|
||||
/**
|
||||
* Substitutes provided polynomial [argument] into [this] polynomial.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun NumberedPolynomial<C>.substitute(argument: Map<Int, NumberedPolynomial<C>>): NumberedPolynomial<C> = substitute(ring, argument)
|
||||
/**
|
||||
* Substitutes provided rational function [argument] into [this] polynomial.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun NumberedPolynomial<C>.substitute(argument: Map<Int, NumberedRationalFunction<C>>): NumberedRationalFunction<C> = substitute(ring, argument)
|
||||
/**
|
||||
* Substitutes provided constant [argument] into [this] rational function.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun NumberedRationalFunction<C>.substitute(argument: Map<Int, C>): NumberedRationalFunction<C> = substitute(ring, argument)
|
||||
/**
|
||||
* Substitutes provided polynomial [argument] into [this] rational function.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun NumberedRationalFunction<C>.substitute(argument: Map<Int, NumberedPolynomial<C>>): NumberedRationalFunction<C> = substitute(ring, argument)
|
||||
/**
|
||||
* Substitutes provided rational function [argument] into [this] rational function.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun NumberedRationalFunction<C>.substitute(argument: Map<Int, NumberedRationalFunction<C>>): NumberedRationalFunction<C> = substitute(ring, argument)
|
||||
/**
|
||||
* Substitutes provided constant [argument] into [this] polynomial.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun NumberedPolynomial<C>.substitute(argument: Buffer<C>): NumberedPolynomial<C> = substitute(ring, argument)
|
||||
/**
|
||||
* Substitutes provided polynomial [argument] into [this] polynomial.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun NumberedPolynomial<C>.substitute(argument: Buffer<NumberedPolynomial<C>>): NumberedPolynomial<C> = substitute(ring, argument)
|
||||
/**
|
||||
* Substitutes provided rational function [argument] into [this] polynomial.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun NumberedPolynomial<C>.substitute(argument: Buffer<NumberedRationalFunction<C>>): NumberedRationalFunction<C> = substitute(ring, argument)
|
||||
/**
|
||||
* Substitutes provided constant [argument] into [this] rational function.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun NumberedRationalFunction<C>.substitute(argument: Buffer<C>): NumberedRationalFunction<C> = substitute(ring, argument)
|
||||
/**
|
||||
* Substitutes provided polynomial [arguments] into [this] rational function.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun NumberedRationalFunction<C>.substitute(arguments: Buffer<NumberedPolynomial<C>>): NumberedRationalFunction<C> = substitute(ring, arguments)
|
||||
/**
|
||||
* Substitutes provided rational function [arguments] into [this] rational function.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun NumberedRationalFunction<C>.substitute(arguments: Buffer<NumberedRationalFunction<C>>): NumberedRationalFunction<C> = substitute(ring, arguments)
|
||||
/**
|
||||
* Substitutes provided constant [arguments] into [this] polynomial.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun NumberedPolynomial<C>.substituteFully(arguments: Buffer<C>): C = substituteFully(ring, arguments)
|
||||
|
||||
/**
|
||||
* Represent [this] polynomial as a regular context-less function.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun NumberedPolynomial<C>.asFunction(): (Buffer<C>) -> C = asFunctionOver(ring)
|
||||
/**
|
||||
* Represent [this] polynomial as a regular context-less function.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun NumberedPolynomial<C>.asFunctionOfConstant(): (Buffer<C>) -> C = asFunctionOfConstantOver(ring)
|
||||
/**
|
||||
* Represent [this] polynomial as a regular context-less function.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun NumberedPolynomial<C>.asFunctionOfPolynomial(): (Buffer<NumberedPolynomial<C>>) -> NumberedPolynomial<C> = asFunctionOfPolynomialOver(ring)
|
||||
/**
|
||||
* Represent [this] polynomial as a regular context-less function.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun NumberedPolynomial<C>.asFunctionOfRationalFunction(): (Buffer<NumberedRationalFunction<C>>) -> NumberedRationalFunction<C> = asFunctionOfRationalFunctionOver(ring)
|
||||
/**
|
||||
* Represent [this] polynomial as a regular context-less function.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun NumberedRationalFunction<C>.asFunctionOfPolynomial(): (Buffer<NumberedPolynomial<C>>) -> NumberedRationalFunction<C> = asFunctionOfPolynomialOver(ring)
|
||||
/**
|
||||
* Represent [this] polynomial as a regular context-less function.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun NumberedRationalFunction<C>.asFunctionOfRationalFunction(): (Buffer<NumberedRationalFunction<C>>) -> NumberedRationalFunction<C> = asFunctionOfRationalFunctionOver(ring)
|
||||
|
||||
/**
|
||||
* Evaluates value of [this] polynomial on provided [arguments].
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline operator fun NumberedPolynomial<C>.invoke(arguments: Buffer<C>): C = substituteFully(ring, arguments)
|
||||
/**
|
||||
* Substitutes provided [arguments] into [this] polynomial.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
@JvmName("invokePolynomial")
|
||||
public inline operator fun NumberedPolynomial<C>.invoke(arguments: Buffer<NumberedPolynomial<C>>): NumberedPolynomial<C> = substitute(ring, arguments)
|
||||
/**
|
||||
* Substitutes provided [arguments] into [this] polynomial.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
@JvmName("invokePolynomial")
|
||||
public inline operator fun NumberedPolynomial<C>.invoke(arguments: Buffer<NumberedRationalFunction<C>>): NumberedRationalFunction<C> = substitute(ring, arguments)
|
||||
/**
|
||||
* Substitutes provided [arguments] into [this] rational function.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
@JvmName("invokePolynomial")
|
||||
public inline operator fun NumberedRationalFunction<C>.invoke(arguments: Buffer<NumberedPolynomial<C>>): NumberedRationalFunction<C> = substitute(ring, arguments)
|
||||
/**
|
||||
* Substitutes provided [arguments] into [this] rational function.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
@JvmName("invokePolynomial")
|
||||
public inline operator fun NumberedRationalFunction<C>.invoke(arguments: Buffer<NumberedRationalFunction<C>>): NumberedRationalFunction<C> = substitute(ring, arguments)
|
||||
}
|
@ -1076,6 +1076,14 @@ public abstract class PolynomialSpaceOfFractions<
|
||||
numerator * other.denominator,
|
||||
denominator * other.numerator
|
||||
)
|
||||
/**
|
||||
* Raises [arg] to the integer power [exponent].
|
||||
*/
|
||||
public override fun power(arg: R, exponent: UInt): R =
|
||||
constructRationalFunction(
|
||||
power(arg.numerator, exponent),
|
||||
power(arg.denominator, exponent),
|
||||
)
|
||||
|
||||
/**
|
||||
* Instance of zero rational function (zero of the rational functions ring).
|
||||
|
@ -147,12 +147,17 @@ public fun <C, A : Ring<C>> ListPolynomial<C>.asFunctionOver(ring: A): (C) -> C
|
||||
/**
|
||||
* Represent [this] polynomial as a regular context-less function.
|
||||
*/
|
||||
public fun <C, A : Ring<C>> ListPolynomial<C>.asPolynomialFunctionOver(ring: A): (ListPolynomial<C>) -> ListPolynomial<C> = { substitute(ring, it) }
|
||||
public fun <C, A : Ring<C>> ListPolynomial<C>.asFunctionOfConstantOver(ring: A): (C) -> C = { substitute(ring, it) }
|
||||
|
||||
/**
|
||||
* Represent [this] polynomial as a regular context-less function.
|
||||
*/
|
||||
public fun <C, A : Ring<C>> ListPolynomial<C>.asFunctionOfRationalFunctionOver(ring: A): (ListPolynomial<C>) -> ListPolynomial<C> = { substitute(ring, it) }
|
||||
public fun <C, A : Ring<C>> ListPolynomial<C>.asFunctionOfPolynomialOver(ring: A): (ListPolynomial<C>) -> ListPolynomial<C> = { substitute(ring, it) }
|
||||
|
||||
/**
|
||||
* Represent [this] polynomial as a regular context-less function.
|
||||
*/
|
||||
public fun <C, A : Ring<C>> ListPolynomial<C>.asFunctionOfRationalFunctionOver(ring: A): (ListRationalFunction<C>) -> ListRationalFunction<C> = { substitute(ring, it) }
|
||||
|
||||
/**
|
||||
* Represent [this] rational function as a regular context-less function.
|
||||
@ -162,12 +167,17 @@ public fun <C, A : Field<C>> ListRationalFunction<C>.asFunctionOver(ring: A): (C
|
||||
/**
|
||||
* Represent [this] rational function as a regular context-less function.
|
||||
*/
|
||||
public fun <C, A : Ring<C>> ListRationalFunction<C>.asPolynomialFunctionOver(ring: A): (ListPolynomial<C>) -> ListRationalFunction<C> = { substitute(ring, it) }
|
||||
public fun <C, A : Field<C>> ListRationalFunction<C>.asFunctionOfConstantOver(ring: A): (C) -> C = { substitute(ring, it) }
|
||||
|
||||
/**
|
||||
* Represent [this] rational function as a regular context-less function.
|
||||
*/
|
||||
public fun <C, A : Ring<C>> ListRationalFunction<C>.asFunctionOfRationalFunctionOver(ring: A): (ListPolynomial<C>) -> ListRationalFunction<C> = { substitute(ring, it) }
|
||||
public fun <C, A : Ring<C>> ListRationalFunction<C>.asFunctionOfPolynomialOver(ring: A): (ListPolynomial<C>) -> ListRationalFunction<C> = { substitute(ring, it) }
|
||||
|
||||
/**
|
||||
* Represent [this] rational function as a regular context-less function.
|
||||
*/
|
||||
public fun <C, A : Ring<C>> ListRationalFunction<C>.asFunctionOfRationalFunctionOver(ring: A): (ListRationalFunction<C>) -> ListRationalFunction<C> = { substitute(ring, it) }
|
||||
|
||||
/**
|
||||
* Returns algebraic derivative of received polynomial.
|
||||
@ -242,27 +252,4 @@ public fun <C : Comparable<C>> ListPolynomial<C>.integrate(
|
||||
): C = ring {
|
||||
val antiderivative = antiderivative(ring)
|
||||
antiderivative.substitute(ring, range.endInclusive) - antiderivative.substitute(ring, range.start)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns algebraic derivative of received rational function.
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public fun <C, A> ListRationalFunction<C>.derivative(
|
||||
ring: A,
|
||||
): ListRationalFunction<C> where A : Ring<C>, A : NumericAlgebra<C> = ring.listRationalFunctionSpace {
|
||||
ListRationalFunction(
|
||||
numerator.derivative(ring) * denominator - numerator * denominator.derivative(ring),
|
||||
denominator * denominator
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns algebraic derivative of received rational function of specified [order]. The [order] should be non-negative integer.
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public tailrec fun <C, A> ListRationalFunction<C>.nthDerivative(
|
||||
ring: A,
|
||||
order: Int,
|
||||
): ListRationalFunction<C> where A : Ring<C>, A : NumericAlgebra<C> =
|
||||
if (order == 0) this else derivative(ring).nthDerivative(ring, order - 1)
|
||||
}
|
@ -0,0 +1,478 @@
|
||||
/*
|
||||
* Copyright 2018-2021 KMath contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package space.kscience.kmath.functions
|
||||
|
||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||
import space.kscience.kmath.operations.Ring
|
||||
|
||||
|
||||
/**
|
||||
* Returns the same degrees' description of the monomial, but without extra zero degrees on the end.
|
||||
*/
|
||||
internal fun List<UInt>.cleanUp() = subList(0, indexOfLast { it != 0U } + 1)
|
||||
|
||||
/**
|
||||
* Constructs [NumberedPolynomial] with provided coefficients map [coefs]. The map is used as is.
|
||||
*/
|
||||
@Suppress("FunctionName", "NOTHING_TO_INLINE")
|
||||
@PublishedApi
|
||||
internal inline fun <C> NumberedPolynomialAsIs(coefs: Map<List<UInt>, C>) : NumberedPolynomial<C> = NumberedPolynomial<C>(coefs)
|
||||
|
||||
/**
|
||||
* Constructs [NumberedPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient".
|
||||
* The collections will be transformed to map with [toMap] and then will be used as is.
|
||||
*/
|
||||
@Suppress("FunctionName", "NOTHING_TO_INLINE")
|
||||
@PublishedApi
|
||||
internal inline fun <C> NumberedPolynomialAsIs(pairs: Collection<Pair<List<UInt>, C>>) : NumberedPolynomial<C> = NumberedPolynomial<C>(pairs.toMap())
|
||||
|
||||
/**
|
||||
* Constructs [NumberedPolynomial] with provided array of [pairs] of pairs "term's signature — term's coefficient".
|
||||
* The array will be transformed to map with [toMap] and then will be used as is.
|
||||
*/
|
||||
@Suppress("FunctionName", "NOTHING_TO_INLINE")
|
||||
@PublishedApi
|
||||
internal inline fun <C> NumberedPolynomialAsIs(vararg pairs: Pair<List<UInt>, C>) : NumberedPolynomial<C> = NumberedPolynomial<C>(pairs.toMap())
|
||||
|
||||
/**
|
||||
* Constructs [NumberedPolynomial] with provided coefficients map [coefs].
|
||||
*
|
||||
* [coefs] will be "cleaned up":
|
||||
* 1. Zeros at the ends of terms' signatures (e.g. [coefs] keys) will be removed. (See [cleanUp].)
|
||||
* 1. Terms that happen to have the same signature will be summed up.
|
||||
* 1. New map will be formed of resulting terms.
|
||||
*/
|
||||
@Suppress("FunctionName")
|
||||
public fun <C> NumberedPolynomial(coefs: Map<List<UInt>, C>, add: (C, C) -> C) : NumberedPolynomial<C> {
|
||||
val fixedCoefs = mutableMapOf<List<UInt>, C>()
|
||||
|
||||
for (entry in coefs) {
|
||||
val key = entry.key.cleanUp()
|
||||
val value = entry.value
|
||||
fixedCoefs[key] = if (key in fixedCoefs) add(fixedCoefs[key]!!, value) else value
|
||||
}
|
||||
|
||||
return NumberedPolynomial<C>(fixedCoefs)
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs [NumberedPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient".
|
||||
*
|
||||
* [pairs] will be "cleaned up":
|
||||
* 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].)
|
||||
* 1. Terms that happen to have the same signature will be summed up.
|
||||
* 1. New map will be formed of resulting terms.
|
||||
*/
|
||||
@Suppress("FunctionName")
|
||||
public fun <C> NumberedPolynomial(pairs: Collection<Pair<List<UInt>, C>>, add: (C, C) -> C) : NumberedPolynomial<C> {
|
||||
val fixedCoefs = mutableMapOf<List<UInt>, C>()
|
||||
|
||||
for (entry in pairs) {
|
||||
val key = entry.first.cleanUp()
|
||||
val value = entry.second
|
||||
fixedCoefs[key] = if (key in fixedCoefs) add(fixedCoefs[key]!!, value) else value
|
||||
}
|
||||
|
||||
return NumberedPolynomial<C>(fixedCoefs)
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs [NumberedPolynomial] with provided array [pairs] of pairs "term's signature — term's coefficient".
|
||||
*
|
||||
* [pairs] will be "cleaned up":
|
||||
* 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].)
|
||||
* 1. Terms that happen to have the same signature will be summed up.
|
||||
* 1. New map will be formed of resulting terms.
|
||||
*/
|
||||
@Suppress("FunctionName")
|
||||
public fun <C> NumberedPolynomial(vararg pairs: Pair<List<UInt>, C>, add: (C, C) -> C) : NumberedPolynomial<C> {
|
||||
val fixedCoefs = mutableMapOf<List<UInt>, C>()
|
||||
|
||||
for (entry in pairs) {
|
||||
val key = entry.first.cleanUp()
|
||||
val value = entry.second
|
||||
fixedCoefs[key] = if (key in fixedCoefs) add(fixedCoefs[key]!!, value) else value
|
||||
}
|
||||
|
||||
return NumberedPolynomial<C>(fixedCoefs)
|
||||
}
|
||||
|
||||
// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available
|
||||
|
||||
/**
|
||||
* Constructs [NumberedPolynomial] with provided coefficients map [coefs].
|
||||
*
|
||||
* [coefs] will be "cleaned up":
|
||||
* 1. Zeros at the ends of terms' signatures (e.g. [coefs] keys) will be removed. (See [cleanUp].)
|
||||
* 1. Terms that happen to have the same signature will be summed up.
|
||||
* 1. New map will be formed of resulting terms.
|
||||
*/
|
||||
@Suppress("FunctionName", "NOTHING_TO_INLINE")
|
||||
public inline fun <C, A: Ring<C>> A.NumberedPolynomial(coefs: Map<List<UInt>, C>) : NumberedPolynomial<C> = NumberedPolynomial(coefs, ::add)
|
||||
/**
|
||||
* Constructs [NumberedPolynomial] with provided coefficients map [coefs].
|
||||
*
|
||||
* [coefs] will be "cleaned up":
|
||||
* 1. Zeros at the ends of terms' signatures (e.g. [coefs] keys) will be removed. (See [cleanUp].)
|
||||
* 1. Terms that happen to have the same signature will be summed up.
|
||||
* 1. New map will be formed of resulting terms.
|
||||
*/
|
||||
@Suppress("FunctionName", "NOTHING_TO_INLINE")
|
||||
public inline fun <C, A: Ring<C>> NumberedPolynomialSpace<C, A>.NumberedPolynomial(coefs: Map<List<UInt>, C>) : NumberedPolynomial<C> = NumberedPolynomial(coefs) { left: C, right: C -> left + right }
|
||||
|
||||
/**
|
||||
* Constructs [NumberedPolynomial] with provided coefficients map [coefs].
|
||||
*
|
||||
* [coefs] will be "cleaned up":
|
||||
* 1. Zeros at the ends of terms' signatures (e.g. [coefs] keys) will be removed. (See [cleanUp].)
|
||||
* 1. Terms that happen to have the same signature will be summed up.
|
||||
* 1. New map will be formed of resulting terms.
|
||||
*/
|
||||
@Suppress("FunctionName", "NOTHING_TO_INLINE")
|
||||
public inline fun <C, A: Ring<C>> NumberedRationalFunctionSpace<C, A>.NumberedPolynomial(coefs: Map<List<UInt>, C>) : NumberedPolynomial<C> = NumberedPolynomial(coefs) { left: C, right: C -> left + right }
|
||||
|
||||
/**
|
||||
* Constructs [NumberedPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient".
|
||||
*
|
||||
* [pairs] will be "cleaned up":
|
||||
* 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].)
|
||||
* 1. Terms that happen to have the same signature will be summed up.
|
||||
* 1. New map will be formed of resulting terms.
|
||||
*/
|
||||
@Suppress("FunctionName", "NOTHING_TO_INLINE")
|
||||
public inline fun <C, A: Ring<C>> A.NumberedPolynomial(pairs: Collection<Pair<List<UInt>, C>>) : NumberedPolynomial<C> = NumberedPolynomial(pairs, ::add)
|
||||
|
||||
/**
|
||||
* Constructs [NumberedPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient".
|
||||
*
|
||||
* [pairs] will be "cleaned up":
|
||||
* 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].)
|
||||
* 1. Terms that happen to have the same signature will be summed up.
|
||||
* 1. New map will be formed of resulting terms.
|
||||
*/
|
||||
@Suppress("FunctionName", "NOTHING_TO_INLINE")
|
||||
public inline fun <C, A: Ring<C>> NumberedPolynomialSpace<C, A>.NumberedPolynomial(pairs: Collection<Pair<List<UInt>, C>>) : NumberedPolynomial<C> = NumberedPolynomial(pairs) { left: C, right: C -> left + right }
|
||||
/**
|
||||
* Constructs [NumberedPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient".
|
||||
*
|
||||
* [pairs] will be "cleaned up":
|
||||
* 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].)
|
||||
* 1. Terms that happen to have the same signature will be summed up.
|
||||
* 1. New map will be formed of resulting terms.
|
||||
*/
|
||||
@Suppress("FunctionName", "NOTHING_TO_INLINE")
|
||||
public inline fun <C, A: Ring<C>> NumberedRationalFunctionSpace<C, A>.NumberedPolynomial(pairs: Collection<Pair<List<UInt>, C>>) : NumberedPolynomial<C> = NumberedPolynomial(pairs) { left: C, right: C -> left + right }
|
||||
|
||||
/**
|
||||
* Constructs [NumberedPolynomial] with provided array [pairs] of pairs "term's signature — term's coefficient".
|
||||
*
|
||||
* [pairs] will be "cleaned up":
|
||||
* 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].)
|
||||
* 1. Terms that happen to have the same signature will be summed up.
|
||||
* 1. New map will be formed of resulting terms.
|
||||
*/
|
||||
@Suppress("FunctionName", "NOTHING_TO_INLINE")
|
||||
public inline fun <C, A: Ring<C>> A.NumberedPolynomial(vararg pairs: Pair<List<UInt>, C>) : NumberedPolynomial<C> = NumberedPolynomial(*pairs) { left: C, right: C -> left + right }
|
||||
/**
|
||||
* Constructs [NumberedPolynomial] with provided array [pairs] of pairs "term's signature — term's coefficient".
|
||||
*
|
||||
* [pairs] will be "cleaned up":
|
||||
* 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].)
|
||||
* 1. Terms that happen to have the same signature will be summed up.
|
||||
* 1. New map will be formed of resulting terms.
|
||||
*/
|
||||
@Suppress("FunctionName", "NOTHING_TO_INLINE")
|
||||
public inline fun <C, A: Ring<C>> NumberedPolynomialSpace<C, A>.NumberedPolynomial(vararg pairs: Pair<List<UInt>, C>) : NumberedPolynomial<C> = NumberedPolynomial(*pairs) { left: C, right: C -> left + right }
|
||||
/**
|
||||
* Constructs [NumberedPolynomial] with provided array [pairs] of pairs "term's signature — term's coefficient".
|
||||
*
|
||||
* [pairs] will be "cleaned up":
|
||||
* 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].)
|
||||
* 1. Terms that happen to have the same signature will be summed up.
|
||||
* 1. New map will be formed of resulting terms.
|
||||
*/
|
||||
@Suppress("FunctionName", "NOTHING_TO_INLINE")
|
||||
public inline fun <C, A: Ring<C>> NumberedRationalFunctionSpace<C, A>.NumberedPolynomial(vararg pairs: Pair<List<UInt>, C>) : NumberedPolynomial<C> = NumberedPolynomial(*pairs) { left: C, right: C -> left + right }
|
||||
|
||||
/**
|
||||
* Converts [this] constant to [NumberedPolynomial].
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun <C> C.asNumberedPolynomial() : NumberedPolynomial<C> = NumberedPolynomialAsIs(mapOf(emptyList<UInt>() to this))
|
||||
|
||||
/**
|
||||
* Marks DSL that allows to more simply create [NumberedPolynomial]s with good performance.
|
||||
*
|
||||
* For example, polynomial `5 x_1^2 x_3^3 - 6 x_2` can be described as
|
||||
* ```
|
||||
* Int.algebra {
|
||||
* val numberedPolynomial : NumberedPolynomial<Int> = NumberedPolynomial {
|
||||
* 5 { 1 inPowerOf 2u; 3 inPowerOf 3u } // 5 x_1^2 x_3^3 +
|
||||
* (-6) { 2 inPowerOf 1u } // (-6) x_2^1
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
@DslMarker
|
||||
@UnstableKMathAPI
|
||||
internal annotation class NumberedPolynomialConstructorDSL
|
||||
|
||||
/**
|
||||
* Builder of [NumberedPolynomial] signature. It should be used as an implicit context for lambdas that describe term signature.
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
@NumberedPolynomialConstructorDSL
|
||||
public class NumberedPolynomialTermSignatureBuilder {
|
||||
/**
|
||||
* Signature storage. Any declaration of any variable's power updates the storage by increasing corresponding value.
|
||||
* Afterward the storage will be used as a resulting signature.
|
||||
*/
|
||||
private val signature: MutableList<UInt> = ArrayList()
|
||||
|
||||
/**
|
||||
* Builds the resulting signature.
|
||||
*
|
||||
* In fact, it just returns [signature] as regular signature of type `List<UInt>`.
|
||||
*/
|
||||
internal fun build(): List<UInt> = signature
|
||||
|
||||
/**
|
||||
* Declares power of variable #[this] of degree [deg].
|
||||
*
|
||||
* Declaring another power of the same variable will increase its degree by received degree.
|
||||
*/
|
||||
public infix fun Int.inPowerOf(deg: UInt) {
|
||||
if (this > signature.lastIndex) {
|
||||
signature.addAll(List(this - signature.lastIndex - 1) { 0u })
|
||||
signature.add(deg)
|
||||
} else {
|
||||
signature[this] += deg
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Declares power of variable #[this] of degree [deg].
|
||||
*
|
||||
* Declaring another power of the same variable will increase its degree by received degree.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline infix fun Int.pow(deg: UInt): Unit = this inPowerOf deg
|
||||
/**
|
||||
* Declares power of variable #[this] of degree [deg].
|
||||
*
|
||||
* Declaring another power of the same variable will increase its degree by received degree.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline infix fun Int.`in`(deg: UInt): Unit = this inPowerOf deg
|
||||
/**
|
||||
* Declares power of variable #[this] of degree [deg].
|
||||
*
|
||||
* Declaring another power of the same variable will increase its degree by received degree.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline infix fun Int.of(deg: UInt): Unit = this inPowerOf deg
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder of [NumberedPolynomial]. It should be used as an implicit context for lambdas that describe [NumberedPolynomial].
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
@NumberedPolynomialConstructorDSL
|
||||
public class NumberedPolynomialBuilder<C>(
|
||||
/**
|
||||
* Summation operation that will be used to sum coefficients of monomials of same signatures.
|
||||
*/
|
||||
private val add: (C, C) -> C,
|
||||
/**
|
||||
* Initial capacity of coefficients map.
|
||||
*/
|
||||
initialCapacity: Int = 0
|
||||
) {
|
||||
/**
|
||||
* Coefficients storage. Any declaration of any monomial updates the storage.
|
||||
* Afterward the storage will be used as a resulting coefficients map.
|
||||
*/
|
||||
private val coefficients: MutableMap<List<UInt>, C> = LinkedHashMap(initialCapacity)
|
||||
|
||||
/**
|
||||
* Builds the resulting coefficients map.
|
||||
*
|
||||
* In fact, it just returns [coefficients] as regular coefficients map of type `Map<List<UInt>, C>`.
|
||||
*/
|
||||
@PublishedApi
|
||||
internal fun build(): NumberedPolynomial<C> = NumberedPolynomial<C>(coefficients)
|
||||
|
||||
/**
|
||||
* Declares monomial with [this] coefficient and provided [signature].
|
||||
*
|
||||
* Declaring another monomial with the same signature will add [this] coefficient to existing one. If the sum of such
|
||||
* coefficients is zero at any moment the monomial won't be removed but will be left as it is.
|
||||
*/
|
||||
public infix fun C.with(signature: List<UInt>) {
|
||||
if (signature in coefficients) coefficients[signature] = add(coefficients[signature]!!, this@with)
|
||||
else coefficients[signature] = this@with
|
||||
}
|
||||
/**
|
||||
* Declares monomial with [this] coefficient and signature constructed by [block].
|
||||
*
|
||||
* Declaring another monomial with the same signature will add [this] coefficient to existing one. If the sum of such
|
||||
* coefficients is zero at any moment the monomial won't be removed but will be left as it is.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline infix fun C.with(noinline block: NumberedPolynomialTermSignatureBuilder.() -> Unit): Unit = this.invoke(block)
|
||||
/**
|
||||
* Declares monomial with [this] coefficient and signature constructed by [block].
|
||||
*
|
||||
* Declaring another monomial with the same signature will add [this] coefficient to existing one. If the sum of such
|
||||
* coefficients is zero at any moment the monomial won't be removed but will be left as it is.
|
||||
*/
|
||||
public operator fun C.invoke(block: NumberedPolynomialTermSignatureBuilder.() -> Unit): Unit =
|
||||
this with NumberedPolynomialTermSignatureBuilder().apply(block).build()
|
||||
}
|
||||
|
||||
// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available
|
||||
|
||||
/**
|
||||
* Creates [NumberedPolynomial] with lambda [block] in context of [this] ring of constants.
|
||||
*
|
||||
* For example, polynomial `5 x_1^2 x_3^3 - 6 x_2` can be described as
|
||||
* ```
|
||||
* Int.algebra {
|
||||
* val numberedPolynomial : NumberedPolynomial<Int> = NumberedPolynomial {
|
||||
* 5 { 1 inPowerOf 2u; 3 inPowerOf 3u } // 5 x_1^2 x_3^3 +
|
||||
* (-6) { 2 inPowerOf 1u } // (-6) x_2^1
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
@Suppress("FunctionName")
|
||||
public inline fun <C, A: Ring<C>> A.NumberedPolynomial(initialCapacity: Int = 0, block: NumberedPolynomialBuilder<C>.() -> Unit) : NumberedPolynomial<C> = NumberedPolynomialBuilder(::add, initialCapacity).apply(block).build()
|
||||
/**
|
||||
* Creates [NumberedPolynomial] with lambda [block] in context of [this] ring of [NumberedPolynomial]s.
|
||||
*
|
||||
* For example, polynomial `5 x_1^2 x_3^3 - 6 x_2` can be described as
|
||||
* ```
|
||||
* Int.algebra {
|
||||
* val numberedPolynomial : NumberedPolynomial<Int> = NumberedPolynomial {
|
||||
* 5 { 1 inPowerOf 2u; 3 inPowerOf 3u } // 5 x_1^2 x_3^3 +
|
||||
* (-6) { 2 inPowerOf 1u } // (-6) x_2^1
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
@Suppress("FunctionName")
|
||||
public inline fun <C, A: Ring<C>> NumberedPolynomialSpace<C, A>.NumberedPolynomial(initialCapacity: Int, block: NumberedPolynomialBuilder<C>.() -> Unit) : NumberedPolynomial<C> = NumberedPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build()
|
||||
/**
|
||||
* Creates [NumberedPolynomial] with lambda [block] in context of [this] field of [NumberedRationalFunction]s.
|
||||
*
|
||||
* For example, polynomial `5 x_1^2 x_3^3 - 6 x_2` can be described as
|
||||
* ```
|
||||
* Int.algebra {
|
||||
* val numberedPolynomial : NumberedPolynomial<Int> = NumberedPolynomial {
|
||||
* 5 { 1 inPowerOf 2u; 3 inPowerOf 3u } // 5 x_1^2 x_3^3 +
|
||||
* (-6) { 2 inPowerOf 1u } // (-6) x_2^1
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
@Suppress("FunctionName")
|
||||
public inline fun <C, A: Ring<C>> NumberedRationalFunctionSpace<C, A>.NumberedPolynomial(initialCapacity: Int, block: NumberedPolynomialBuilder<C>.() -> Unit) : NumberedPolynomial<C> = NumberedPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build()
|
||||
|
||||
// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available
|
||||
|
||||
/**
|
||||
* Constructs [NumberedRationalFunction] with provided coefficients maps [numeratorCoefficients] and [denominatorCoefficients].
|
||||
*
|
||||
* The maps will be "cleaned up":
|
||||
* 1. Zeros at the ends of terms' signatures (e.g. the maps' keys) will be removed. (See [cleanUp].)
|
||||
* 1. Terms that happen to have the same signature will be summed up.
|
||||
* 1. New map will be formed of resulting terms.
|
||||
*/
|
||||
@Suppress("FunctionName")
|
||||
public fun <C, A: Ring<C>> A.NumberedRationalFunction(numeratorCoefficients: Map<List<UInt>, C>, denominatorCoefficients: Map<List<UInt>, C>): NumberedRationalFunction<C> =
|
||||
NumberedRationalFunction<C>(
|
||||
NumberedPolynomial(numeratorCoefficients),
|
||||
NumberedPolynomial(denominatorCoefficients)
|
||||
)
|
||||
/**
|
||||
* Constructs [NumberedRationalFunction] with provided coefficients maps [numeratorCoefficients] and [denominatorCoefficients].
|
||||
*
|
||||
* The maps will be "cleaned up":
|
||||
* 1. Zeros at the ends of terms' signatures (e.g. the maps' keys) will be removed. (See [cleanUp].)
|
||||
* 1. Terms that happen to have the same signature will be summed up.
|
||||
* 1. New map will be formed of resulting terms.
|
||||
*/
|
||||
@Suppress("FunctionName")
|
||||
public fun <C, A: Ring<C>> NumberedRationalFunctionSpace<C, A>.NumberedRationalFunction(numeratorCoefficients: Map<List<UInt>, C>, denominatorCoefficients: Map<List<UInt>, C>): NumberedRationalFunction<C> =
|
||||
NumberedRationalFunction<C>(
|
||||
NumberedPolynomial(numeratorCoefficients),
|
||||
NumberedPolynomial(denominatorCoefficients)
|
||||
)
|
||||
|
||||
/**
|
||||
* Constructs [NumberedRationalFunction] with provided [numerator] and unit denominator.
|
||||
*/
|
||||
@Suppress("FunctionName")
|
||||
public fun <C, A: Ring<C>> A.NumberedRationalFunction(numerator: NumberedPolynomial<C>): NumberedRationalFunction<C> =
|
||||
NumberedRationalFunction<C>(numerator, NumberedPolynomial(mapOf(emptyList<UInt>() to one)))
|
||||
/**
|
||||
* Constructs [NumberedRationalFunction] with provided [numerator] and unit denominator.
|
||||
*/
|
||||
@Suppress("FunctionName")
|
||||
public fun <C, A: Ring<C>> NumberedRationalFunctionSpace<C, A>.NumberedRationalFunction(numerator: NumberedPolynomial<C>): NumberedRationalFunction<C> =
|
||||
NumberedRationalFunction<C>(numerator, polynomialOne)
|
||||
|
||||
/**
|
||||
* Constructs [NumberedRationalFunction] with provided coefficients map [numeratorCoefficients] for numerator and unit
|
||||
* denominator.
|
||||
*
|
||||
* [numeratorCoefficients] will be "cleaned up":
|
||||
* 1. Zeros at the ends of terms' signatures (e.g. [numeratorCoefficients]'s keys) will be removed. (See [cleanUp].)
|
||||
* 1. Terms that happen to have the same signature will be summed up.
|
||||
* 1. New map will be formed of resulting terms.
|
||||
*/
|
||||
@Suppress("FunctionName")
|
||||
public fun <C, A: Ring<C>> NumberedRationalFunctionSpace<C, A>.NumberedRationalFunction(numeratorCoefficients: Map<List<UInt>, C>): NumberedRationalFunction<C> =
|
||||
NumberedRationalFunction<C>(
|
||||
NumberedPolynomial(numeratorCoefficients),
|
||||
polynomialOne
|
||||
)
|
||||
/**
|
||||
* Constructs [NumberedRationalFunction] with provided coefficients map [numeratorCoefficients] for numerator and unit
|
||||
* denominator.
|
||||
*
|
||||
* [numeratorCoefficients] will be "cleaned up":
|
||||
* 1. Zeros at the ends of terms' signatures (e.g. [numeratorCoefficients]'s keys) will be removed. (See [cleanUp].)
|
||||
* 1. Terms that happen to have the same signature will be summed up.
|
||||
* 1. New map will be formed of resulting terms.
|
||||
*/
|
||||
@Suppress("FunctionName")
|
||||
public fun <C, A: Ring<C>> A.NumberedRationalFunction(numeratorCoefficients: Map<List<UInt>, C>): NumberedRationalFunction<C> =
|
||||
NumberedRationalFunction<C>(
|
||||
NumberedPolynomial(numeratorCoefficients),
|
||||
NumberedPolynomialAsIs(mapOf(emptyList<UInt>() to one))
|
||||
)
|
||||
|
||||
///**
|
||||
// * Converts [this] coefficient to [NumberedRationalFunction].
|
||||
// */
|
||||
//context(A)
|
||||
//public fun <C, A: Ring<C>> C.asNumberedRationalFunction() : NumberedRationalFunction<C> =
|
||||
// NumberedRationalFunction(
|
||||
// NumberedPolynomialAsIs(mapOf(emptyList<UInt>() to this)),
|
||||
// NumberedPolynomialAsIs(mapOf(emptyList<UInt>() to one))
|
||||
// )
|
||||
///**
|
||||
// * Converts [this] coefficient to [NumberedRationalFunction].
|
||||
// */
|
||||
//context(NumberedRationalFunctionSpace<C, A>)
|
||||
//public fun <C, A: Ring<C>> C.asNumberedRationalFunction() : NumberedRationalFunction<C> =
|
||||
// NumberedRationalFunction(
|
||||
// NumberedPolynomialAsIs(mapOf(emptyList<UInt>() to this)),
|
||||
// NumberedPolynomialAsIs(mapOf(emptyList<UInt>() to constantOne))
|
||||
// )
|
@ -0,0 +1,515 @@
|
||||
/*
|
||||
* Copyright 2018-2021 KMath contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package space.kscience.kmath.functions
|
||||
|
||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||
import space.kscience.kmath.operations.Field
|
||||
import space.kscience.kmath.operations.Ring
|
||||
import space.kscience.kmath.operations.algebra
|
||||
import space.kscience.kmath.operations.invoke
|
||||
import space.kscience.kmath.structures.Buffer
|
||||
import kotlin.contracts.InvocationKind
|
||||
import kotlin.contracts.contract
|
||||
import kotlin.jvm.JvmName
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
|
||||
/**
|
||||
* Creates a [NumberedPolynomialSpace] over a received ring.
|
||||
*/
|
||||
public fun <C, A : Ring<C>> A.numberedPolynomialSpace(): NumberedPolynomialSpace<C, A> =
|
||||
NumberedPolynomialSpace(this)
|
||||
|
||||
/**
|
||||
* Creates a [NumberedPolynomialSpace]'s scope over a received ring.
|
||||
*/
|
||||
public inline fun <C, A : Ring<C>, R> A.numberedPolynomialSpace(block: NumberedPolynomialSpace<C, A>.() -> R): R {
|
||||
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
|
||||
return NumberedPolynomialSpace(this).block()
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a [NumberedRationalFunctionSpace] over a received ring.
|
||||
*/
|
||||
public fun <C, A : Ring<C>> A.numberedRationalFunctionSpace(): NumberedRationalFunctionSpace<C, A> =
|
||||
NumberedRationalFunctionSpace(this)
|
||||
|
||||
/**
|
||||
* Creates a [NumberedRationalFunctionSpace]'s scope over a received ring.
|
||||
*/
|
||||
public inline fun <C, A : Ring<C>, R> A.numberedRationalFunctionSpace(block: NumberedRationalFunctionSpace<C, A>.() -> R): R {
|
||||
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
|
||||
return NumberedRationalFunctionSpace(this).block()
|
||||
}
|
||||
|
||||
/**
|
||||
* Substitutes provided Double arguments [args] into [this] Double polynomial.
|
||||
*/
|
||||
public fun NumberedPolynomial<Double>.substitute(args: Map<Int, Double>): NumberedPolynomial<Double> = Double.algebra {
|
||||
NumberedPolynomial<Double>(
|
||||
buildMap<List<UInt>, Double>(coefficients.size) {
|
||||
for ((degs, c) in coefficients) {
|
||||
val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp()
|
||||
val newC = args.entries.fold(c) { product, (variable, substitution) ->
|
||||
val deg = degs.getOrElse(variable) { 0u }
|
||||
if (deg == 0u) product else product * substitution.pow(deg.toInt())
|
||||
}
|
||||
if (newDegs !in this) this[newDegs] = newC
|
||||
else this[newDegs] = this[newDegs]!! + newC
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Substitutes provided arguments [args] into [this] polynomial.
|
||||
*/
|
||||
public fun <C> NumberedPolynomial<C>.substitute(ring: Ring<C>, args: Map<Int, C>): NumberedPolynomial<C> = ring {
|
||||
NumberedPolynomial<C>(
|
||||
buildMap<List<UInt>, C>(coefficients.size) {
|
||||
for ((degs, c) in coefficients) {
|
||||
val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp()
|
||||
val newC = args.entries.fold(c) { product, (variable, substitution) ->
|
||||
val deg = degs.getOrElse(variable) { 0u }
|
||||
if (deg == 0u) product else product * power(substitution, deg)
|
||||
}
|
||||
if (newDegs !in this) this[newDegs] = newC
|
||||
else this[newDegs] = this[newDegs]!! + newC
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Substitutes provided arguments [args] into [this] polynomial.
|
||||
*/ // TODO: To optimize boxing
|
||||
@JvmName("substitutePolynomial")
|
||||
public fun <C> NumberedPolynomial<C>.substitute(ring: Ring<C>, args: Map<Int, NumberedPolynomial<C>>) : NumberedPolynomial<C> =
|
||||
ring.numberedPolynomialSpace {
|
||||
coefficients.entries.fold(zero) { acc, (degs, c) ->
|
||||
val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp()
|
||||
acc + args.entries.fold(NumberedPolynomial<C>(mapOf(newDegs to c))) { product, (variable, substitution) ->
|
||||
val deg = degs.getOrElse(variable) { 0u }
|
||||
if (deg == 0u) product else product * power(substitution, deg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Substitutes provided arguments [args] into [this] polynomial.
|
||||
*/ // TODO: To optimize boxing
|
||||
@JvmName("substituteRationalFunction")
|
||||
public fun <C> NumberedPolynomial<C>.substitute(ring: Ring<C>, args: Map<Int, NumberedRationalFunction<C>>) : NumberedRationalFunction<C> =
|
||||
ring.numberedRationalFunctionSpace {
|
||||
coefficients.entries.fold(zero) { acc, (degs, c) ->
|
||||
val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp()
|
||||
acc + args.entries.fold(NumberedRationalFunction(NumberedPolynomial<C>(mapOf(newDegs to c)))) { product, (variable, substitution) ->
|
||||
val deg = degs.getOrElse(variable) { 0u }
|
||||
if (deg == 0u) product else product * power(substitution, deg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Substitutes provided Double arguments [args] into [this] Double rational function.
|
||||
*/
|
||||
public fun NumberedRationalFunction<Double>.substitute(args: Map<Int, Double>): NumberedRationalFunction<Double> =
|
||||
NumberedRationalFunction(numerator.substitute(args), denominator.substitute(args))
|
||||
|
||||
/**
|
||||
* Substitutes provided arguments [args] into [this] rational function.
|
||||
*/
|
||||
public fun <C> NumberedRationalFunction<C>.substitute(ring: Ring<C>, args: Map<Int, C>): NumberedRationalFunction<C> =
|
||||
NumberedRationalFunction(numerator.substitute(ring, args), denominator.substitute(ring, args))
|
||||
|
||||
/**
|
||||
* Substitutes provided arguments [args] into [this] rational function.
|
||||
*/ // TODO: To optimize boxing
|
||||
@JvmName("substitutePolynomial")
|
||||
public fun <C> NumberedRationalFunction<C>.substitute(ring: Ring<C>, args: Map<Int, NumberedPolynomial<C>>) : NumberedRationalFunction<C> =
|
||||
NumberedRationalFunction(numerator.substitute(ring, args), denominator.substitute(ring, args))
|
||||
|
||||
/**
|
||||
* Substitutes provided arguments [args] into [this] rational function.
|
||||
*/ // TODO: To optimize boxing
|
||||
@JvmName("substituteRationalFunction")
|
||||
public fun <C> NumberedRationalFunction<C>.substitute(ring: Ring<C>, args: Map<Int, NumberedRationalFunction<C>>) : NumberedRationalFunction<C> =
|
||||
ring.numberedRationalFunctionSpace {
|
||||
numerator.substitute(ring, args) / denominator.substitute(ring, args)
|
||||
}
|
||||
|
||||
/**
|
||||
* Substitutes provided Double arguments [args] into [this] Double polynomial.
|
||||
*/
|
||||
public fun NumberedPolynomial<Double>.substitute(args: Buffer<Double>): NumberedPolynomial<Double> = Double.algebra {
|
||||
val lastSubstitutionVariable = args.size - 1
|
||||
NumberedPolynomial<Double>(
|
||||
buildMap(coefficients.size) {
|
||||
for ((degs, c) in coefficients) {
|
||||
val lastDegsIndex = degs.lastIndex
|
||||
val newDegs =
|
||||
if (lastDegsIndex <= lastSubstitutionVariable) emptyList()
|
||||
else degs.toMutableList().apply {
|
||||
for (i in 0..lastSubstitutionVariable) this[i] = 0u
|
||||
}
|
||||
val newC = (0..min(lastDegsIndex, lastSubstitutionVariable)).fold(c) { product, variable ->
|
||||
val deg = degs[variable]
|
||||
if (deg == 0u) product else product * args[variable].pow(deg.toInt())
|
||||
}
|
||||
if (newDegs !in this) this[newDegs] = newC
|
||||
else this[newDegs] = this[newDegs]!! + newC
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Substitutes provided arguments [args] into [this] polynomial.
|
||||
*/
|
||||
public fun <C> NumberedPolynomial<C>.substitute(ring: Ring<C>, args: Buffer<C>): NumberedPolynomial<C> = ring {
|
||||
val lastSubstitutionVariable = args.size - 1
|
||||
NumberedPolynomial<C>(
|
||||
buildMap<List<UInt>, C>(coefficients.size) {
|
||||
for ((degs, c) in coefficients) {
|
||||
val lastDegsIndex = degs.lastIndex
|
||||
val newDegs =
|
||||
if (lastDegsIndex <= lastSubstitutionVariable) emptyList()
|
||||
else degs.toMutableList().apply {
|
||||
for (i in 0..lastSubstitutionVariable) this[i] = 0u
|
||||
}
|
||||
val newC = (0..min(lastDegsIndex, lastSubstitutionVariable)).fold(c) { product, variable ->
|
||||
val deg = degs[variable]
|
||||
if (deg == 0u) product else product * power(args[variable], deg)
|
||||
}
|
||||
if (newDegs !in this) this[newDegs] = newC
|
||||
else this[newDegs] = this[newDegs]!! + newC
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Substitutes provided arguments [args] into [this] polynomial.
|
||||
*/ // TODO: To optimize boxing
|
||||
@JvmName("substitutePolynomial")
|
||||
public fun <C> NumberedPolynomial<C>.substitute(ring: Ring<C>, args: Buffer<NumberedPolynomial<C>>) : NumberedPolynomial<C> =
|
||||
ring.numberedPolynomialSpace {
|
||||
val lastSubstitutionVariable = args.size - 1
|
||||
coefficients.entries.fold(zero) { acc, (degs, c) ->
|
||||
val lastDegsIndex = degs.lastIndex
|
||||
val newDegs =
|
||||
if (lastDegsIndex <= lastSubstitutionVariable) emptyList()
|
||||
else degs.toMutableList().apply {
|
||||
for (i in 0..lastSubstitutionVariable) this[i] = 0u
|
||||
}
|
||||
acc + (0..min(lastDegsIndex, lastSubstitutionVariable))
|
||||
.fold(NumberedPolynomial<C>(mapOf(newDegs to c))) { product, variable ->
|
||||
val deg = degs[variable]
|
||||
if (deg == 0u) product else product * power(args[variable], deg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Substitutes provided arguments [args] into [this] polynomial.
|
||||
*/ // TODO: To optimize boxing
|
||||
@JvmName("substituteRationalFunction")
|
||||
public fun <C> NumberedPolynomial<C>.substitute(ring: Ring<C>, args: Buffer<NumberedRationalFunction<C>>) : NumberedRationalFunction<C> =
|
||||
ring.numberedRationalFunctionSpace {
|
||||
val lastSubstitutionVariable = args.size - 1
|
||||
coefficients.entries.fold(zero) { acc, (degs, c) ->
|
||||
val lastDegsIndex = degs.lastIndex
|
||||
val newDegs =
|
||||
if (lastDegsIndex <= lastSubstitutionVariable) emptyList()
|
||||
else degs.toMutableList().apply {
|
||||
for (i in 0..lastSubstitutionVariable) this[i] = 0u
|
||||
}
|
||||
acc + (0..min(lastDegsIndex, lastSubstitutionVariable))
|
||||
.fold(NumberedRationalFunction(NumberedPolynomial<C>(mapOf(newDegs to c)))) { product, variable ->
|
||||
val deg = degs[variable]
|
||||
if (deg == 0u) product else product * power(args[variable], deg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Substitutes provided Double arguments [args] into [this] Double rational function.
|
||||
*/
|
||||
public fun NumberedRationalFunction<Double>.substitute(args: Buffer<Double>): NumberedRationalFunction<Double> =
|
||||
NumberedRationalFunction(numerator.substitute(args), denominator.substitute(args))
|
||||
|
||||
/**
|
||||
* Substitutes provided arguments [args] into [this] rational function.
|
||||
*/
|
||||
public fun <C> NumberedRationalFunction<C>.substitute(ring: Ring<C>, args: Buffer<C>): NumberedRationalFunction<C> =
|
||||
NumberedRationalFunction(numerator.substitute(ring, args), denominator.substitute(ring, args))
|
||||
|
||||
/**
|
||||
* Substitutes provided arguments [args] into [this] rational function.
|
||||
*/ // TODO: To optimize boxing
|
||||
@JvmName("substitutePolynomial")
|
||||
public fun <C> NumberedRationalFunction<C>.substitute(ring: Ring<C>, args: Buffer<NumberedPolynomial<C>>) : NumberedRationalFunction<C> =
|
||||
NumberedRationalFunction(numerator.substitute(ring, args), denominator.substitute(ring, args))
|
||||
|
||||
/**
|
||||
* Substitutes provided arguments [args] into [this] rational function.
|
||||
*/ // TODO: To optimize boxing
|
||||
@JvmName("substituteRationalFunction")
|
||||
public fun <C> NumberedRationalFunction<C>.substitute(ring: Ring<C>, args: Buffer<NumberedRationalFunction<C>>) : NumberedRationalFunction<C> =
|
||||
ring.numberedRationalFunctionSpace {
|
||||
numerator.substitute(ring, args) / denominator.substitute(ring, args)
|
||||
}
|
||||
|
||||
/**
|
||||
* Substitutes provided Double arguments [args] into [this] Double polynomial.
|
||||
*/
|
||||
public fun NumberedPolynomial<Double>.substituteFully(args: Buffer<Double>): Double = Double.algebra {
|
||||
val lastSubstitutionVariable = args.size - 1
|
||||
require(coefficients.keys.all { it.lastIndex <= lastSubstitutionVariable }) { "Fully substituting buffer should cover all variables of the polynomial." }
|
||||
coefficients.entries.fold(.0) { acc, (degs, c) ->
|
||||
acc + degs.foldIndexed(c) { variable, product, deg ->
|
||||
if (deg == 0u) product else product * args[variable].pow(deg.toInt())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Substitutes provided arguments [args] into [this] polynomial.
|
||||
*/
|
||||
public fun <C> NumberedPolynomial<C>.substituteFully(ring: Ring<C>, args: Buffer<C>): C = ring {
|
||||
val lastSubstitutionVariable = args.size - 1
|
||||
require(coefficients.keys.all { it.lastIndex <= lastSubstitutionVariable }) { "Fully substituting buffer should cover all variables of the polynomial." }
|
||||
coefficients.entries.fold(zero) { acc, (degs, c) ->
|
||||
acc + degs.foldIndexed(c) { variable, product, deg ->
|
||||
if (deg == 0u) product else product * power(args[variable], deg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Substitutes provided Double arguments [args] into [this] Double rational function.
|
||||
*/
|
||||
public fun NumberedRationalFunction<Double>.substituteFully(args: Buffer<Double>): Double =
|
||||
numerator.substituteFully(args) / denominator.substituteFully(args)
|
||||
|
||||
/**
|
||||
* Substitutes provided arguments [args] into [this] rational function.
|
||||
*/
|
||||
public fun <C> NumberedRationalFunction<C>.substituteFully(ring: Field<C>, args: Buffer<C>): C = ring {
|
||||
numerator.substituteFully(ring, args) / denominator.substituteFully(ring, args)
|
||||
}
|
||||
|
||||
/**
|
||||
* Represent [this] polynomial as a regular context-less function.
|
||||
*/
|
||||
public fun <C, A : Ring<C>> NumberedPolynomial<C>.asFunctionOver(ring: A): (Buffer<C>) -> C = { substituteFully(ring, it) }
|
||||
|
||||
/**
|
||||
* Represent [this] polynomial as a regular context-less function.
|
||||
*/
|
||||
public fun <C, A : Ring<C>> NumberedPolynomial<C>.asFunctionOfConstantOver(ring: A): (Buffer<C>) -> C = { substituteFully(ring, it) }
|
||||
|
||||
/**
|
||||
* Represent [this] polynomial as a regular context-less function.
|
||||
*/
|
||||
public fun <C, A : Ring<C>> NumberedPolynomial<C>.asFunctionOfPolynomialOver(ring: A): (Buffer<NumberedPolynomial<C>>) -> NumberedPolynomial<C> = { substitute(ring, it) }
|
||||
|
||||
/**
|
||||
* Represent [this] polynomial as a regular context-less function.
|
||||
*/
|
||||
public fun <C, A : Ring<C>> NumberedPolynomial<C>.asFunctionOfRationalFunctionOver(ring: A): (Buffer<NumberedRationalFunction<C>>) -> NumberedRationalFunction<C> = { substitute(ring, it) }
|
||||
|
||||
/**
|
||||
* Represent [this] rational function as a regular context-less function.
|
||||
*/
|
||||
public fun <C, A : Field<C>> NumberedRationalFunction<C>.asFunctionOver(ring: A): (Buffer<C>) -> C = { substituteFully(ring, it) }
|
||||
|
||||
/**
|
||||
* Represent [this] rational function as a regular context-less function.
|
||||
*/
|
||||
public fun <C, A : Field<C>> NumberedRationalFunction<C>.asFunctionOfConstantOver(ring: A): (Buffer<C>) -> C = { substituteFully(ring, it) }
|
||||
|
||||
/**
|
||||
* Represent [this] rational function as a regular context-less function.
|
||||
*/
|
||||
public fun <C, A : Ring<C>> NumberedRationalFunction<C>.asFunctionOfPolynomialOver(ring: A): (Buffer<NumberedPolynomial<C>>) -> NumberedRationalFunction<C> = { substitute(ring, it) }
|
||||
|
||||
/**
|
||||
* Represent [this] rational function as a regular context-less function.
|
||||
*/
|
||||
public fun <C, A : Ring<C>> NumberedRationalFunction<C>.asFunctionOfRationalFunctionOver(ring: A): (Buffer<NumberedRationalFunction<C>>) -> NumberedRationalFunction<C> = { substitute(ring, it) }
|
||||
|
||||
/**
|
||||
* Returns algebraic derivative of received polynomial with respect to provided variable.
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public fun <C, A : Ring<C>> NumberedPolynomial<C>.derivativeWithRespectTo(
|
||||
ring: A,
|
||||
variable: Int,
|
||||
): NumberedPolynomial<C> = ring {
|
||||
NumberedPolynomial<C>(
|
||||
buildMap(coefficients.size) {
|
||||
coefficients
|
||||
.forEach { (degs, c) ->
|
||||
if (degs.size > variable) return@forEach
|
||||
put(
|
||||
degs.mapIndexed { index, deg ->
|
||||
when {
|
||||
index != variable -> deg
|
||||
deg > 0u -> deg - 1u
|
||||
else -> return@forEach
|
||||
}
|
||||
}.cleanUp(),
|
||||
multiplyByDoubling(c, degs[variable])
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns algebraic derivative of received polynomial with respect to provided variable of specified order.
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public fun <C, A : Ring<C>> NumberedPolynomial<C>.nthDerivativeWithRespectTo(
|
||||
ring: A,
|
||||
variable: Int,
|
||||
order: UInt
|
||||
): NumberedPolynomial<C> = ring {
|
||||
if (order == 0u) return this@nthDerivativeWithRespectTo
|
||||
NumberedPolynomial<C>(
|
||||
buildMap(coefficients.size) {
|
||||
coefficients
|
||||
.forEach { (degs, c) ->
|
||||
if (degs.size > variable) return@forEach
|
||||
put(
|
||||
degs.mapIndexed { index, deg ->
|
||||
when {
|
||||
index != variable -> deg
|
||||
deg >= order -> deg - order
|
||||
else -> return@forEach
|
||||
}
|
||||
}.cleanUp(),
|
||||
degs[variable].let { deg ->
|
||||
(deg downTo deg - order + 1u)
|
||||
.fold(c) { acc, ord -> multiplyByDoubling(acc, ord) }
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns algebraic derivative of received polynomial with respect to provided variables of specified orders.
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public fun <C, A : Ring<C>> NumberedPolynomial<C>.nthDerivativeWithRespectTo(
|
||||
ring: A,
|
||||
variablesAndOrders: Map<Int, UInt>,
|
||||
): NumberedPolynomial<C> = ring {
|
||||
val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u }
|
||||
if (filteredVariablesAndOrders.isEmpty()) return this@nthDerivativeWithRespectTo
|
||||
val maxRespectedVariable = filteredVariablesAndOrders.keys.maxOrNull()!!
|
||||
NumberedPolynomial<C>(
|
||||
buildMap(coefficients.size) {
|
||||
coefficients
|
||||
.forEach { (degs, c) ->
|
||||
if (degs.size > maxRespectedVariable) return@forEach
|
||||
put(
|
||||
degs.mapIndexed { index, deg ->
|
||||
if (index !in filteredVariablesAndOrders) return@mapIndexed deg
|
||||
val order = filteredVariablesAndOrders[index]!!
|
||||
if (deg >= order) deg - order else return@forEach
|
||||
}.cleanUp(),
|
||||
filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) ->
|
||||
degs[index].let { deg ->
|
||||
(deg downTo deg - order + 1u)
|
||||
.fold(acc1) { acc2, ord -> multiplyByDoubling(acc2, ord) }
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns algebraic antiderivative of received polynomial with respect to provided variable.
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public fun <C, A : Field<C>> NumberedPolynomial<C>.antiderivativeWithRespectTo(
|
||||
ring: A,
|
||||
variable: Int,
|
||||
): NumberedPolynomial<C> = ring {
|
||||
NumberedPolynomial<C>(
|
||||
buildMap(coefficients.size) {
|
||||
coefficients
|
||||
.forEach { (degs, c) ->
|
||||
put(
|
||||
List(max(variable + 1, degs.size)) { if (it != variable) degs[it] else degs[it] + 1u },
|
||||
c / multiplyByDoubling(one, degs[variable])
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns algebraic antiderivative of received polynomial with respect to provided variable of specified order.
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public fun <C, A : Field<C>> NumberedPolynomial<C>.nthAntiderivativeWithRespectTo(
|
||||
ring: A,
|
||||
variable: Int,
|
||||
order: UInt
|
||||
): NumberedPolynomial<C> = ring {
|
||||
if (order == 0u) return this@nthAntiderivativeWithRespectTo
|
||||
NumberedPolynomial<C>(
|
||||
buildMap(coefficients.size) {
|
||||
coefficients
|
||||
.forEach { (degs, c) ->
|
||||
put(
|
||||
List(max(variable + 1, degs.size)) { if (it != variable) degs[it] else degs[it] + order },
|
||||
degs[variable].let { deg ->
|
||||
(deg downTo deg - order + 1u)
|
||||
.fold(c) { acc, ord -> acc / multiplyByDoubling(one, ord) }
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns algebraic derivative of received polynomial with respect to provided variables of specified orders.
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public fun <C, A : Field<C>> NumberedPolynomial<C>.nthAntiderivativeWithRespectTo(
|
||||
ring: A,
|
||||
variablesAndOrders: Map<Int, UInt>,
|
||||
): NumberedPolynomial<C> = ring {
|
||||
val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u }
|
||||
if (filteredVariablesAndOrders.isEmpty()) return this@nthAntiderivativeWithRespectTo
|
||||
val maxRespectedVariable = filteredVariablesAndOrders.keys.maxOrNull()!!
|
||||
NumberedPolynomial<C>(
|
||||
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) }
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
Loading…
Reference in New Issue
Block a user