Feature: Polynomials and rational functions #469
@ -0,0 +1,621 @@
|
||||
/*
|
||||
* Copyright 2018-2021 KMath contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package space.kscience.kmath.functions
|
||||
|
||||
import space.kscience.kmath.expressions.Symbol
|
||||
import space.kscience.kmath.operations.Ring
|
||||
import kotlin.jvm.JvmName
|
||||
import kotlin.math.max
|
||||
|
||||
|
||||
/**
|
||||
* Represents multivariate polynomial that stores its coefficients in a [Map] and terms' signatures in a [Map] that
|
||||
* associates variables (of type [Symbol]) with their degree.
|
||||
*
|
||||
* @param C the type of constants.
|
||||
*/
|
||||
public data class LabeledPolynomial<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 a pair "key-value" in the map, where the value is the
|
||||
* coefficient `a` and the key is a map that associates variables in the monomial with their degree in the monomial.
|
||||
* For example, coefficients of a polynomial `5 a^2 c^3 - 6 b` can be represented as
|
||||
* ```
|
||||
* mapOf(
|
||||
* mapOf(
|
||||
* a to 2,
|
||||
* c to 3
|
||||
* ) to 5,
|
||||
* mapOf(
|
||||
* b to 1
|
||||
* ) to (-6)
|
||||
* )
|
||||
* ```
|
||||
* and also as
|
||||
* ```
|
||||
* mapOf(
|
||||
* mapOf(
|
||||
* a to 2,
|
||||
* c to 3
|
||||
* ) to 5,
|
||||
* mapOf(
|
||||
* b to 1
|
||||
* ) to (-6),
|
||||
* mapOf(
|
||||
* b to 1,
|
||||
* c to 1
|
||||
* ) to 0
|
||||
* )
|
||||
* ```
|
||||
* where `a`, `b` and `c` are corresponding [Symbol] objects.
|
||||
*/
|
||||
public val coefficients: Map<Map<Symbol, UInt>, C>
|
||||
) : Polynomial<C> {
|
||||
override fun toString(): String = "LabeledPolynomial$coefficients"
|
||||
}
|
||||
|
||||
/**
|
||||
* Arithmetic context for multivariate polynomials with coefficients stored as a [Map] and terms' signatures stored as a
|
||||
* [Map] constructed with the provided [ring] of constants.
|
||||
*
|
||||
* @param C the type of constants. Polynomials have them a coefficients in their terms.
|
||||
* @param A type of provided underlying ring of constants. It's [Ring] of [C].
|
||||
* @param ring underlying ring of constants of type [A].
|
||||
*/
|
||||
public class LabeledPolynomialSpace<C, A : Ring<C>>(
|
||||
public override val ring: A,
|
||||
) : MultivariatePolynomialSpace<C, Symbol, LabeledPolynomial<C>>, PolynomialSpaceOverRing<C, LabeledPolynomial<C>, A> {
|
||||
/**
|
||||
* Returns sum of the variable represented as a monic monomial and the integer represented as a constant polynomial.
|
||||
*/
|
||||
public override operator fun Symbol.plus(other: Int): LabeledPolynomial<C> =
|
||||
if (other == 0) LabeledPolynomialAsIs(mapOf(
|
||||
mapOf(this@plus to 1U) to constantOne,
|
||||
))
|
||||
else LabeledPolynomialAsIs(mapOf(
|
||||
mapOf(this@plus to 1U) to constantOne,
|
||||
emptyMap<Symbol, UInt>() to constantOne * other,
|
||||
))
|
||||
/**
|
||||
* Returns difference between the variable represented as a monic monomial and the integer represented as a constant polynomial.
|
||||
*/
|
||||
public override operator fun Symbol.minus(other: Int): LabeledPolynomial<C> =
|
||||
if (other == 0) LabeledPolynomialAsIs(mapOf(
|
||||
mapOf(this@minus to 1U) to -constantOne,
|
||||
))
|
||||
else LabeledPolynomialAsIs(mapOf(
|
||||
mapOf(this@minus to 1U) to -constantOne,
|
||||
emptyMap<Symbol, UInt>() to constantOne * other,
|
||||
))
|
||||
/**
|
||||
* Returns product of the variable represented as a monic monomial and the integer represented as a constant polynomial.
|
||||
*/
|
||||
public override operator fun Symbol.times(other: Int): LabeledPolynomial<C> =
|
||||
if (other == 0) zero
|
||||
else LabeledPolynomialAsIs(mapOf(
|
||||
mapOf(this to 1U) to constantOne * other,
|
||||
))
|
||||
|
||||
/**
|
||||
* Returns sum of the integer represented as a constant polynomial and the variable represented as a monic monomial.
|
||||
*/
|
||||
public override operator fun Int.plus(other: Symbol): LabeledPolynomial<C> =
|
||||
if (this == 0) LabeledPolynomialAsIs(mapOf(
|
||||
mapOf(other to 1U) to constantOne,
|
||||
))
|
||||
else LabeledPolynomialAsIs(mapOf(
|
||||
mapOf(other to 1U) to constantOne,
|
||||
emptyMap<Symbol, UInt>() to constantOne * this@plus,
|
||||
))
|
||||
/**
|
||||
* Returns difference between the integer represented as a constant polynomial and the variable represented as a monic monomial.
|
||||
*/
|
||||
public override operator fun Int.minus(other: Symbol): LabeledPolynomial<C> =
|
||||
if (this == 0) LabeledPolynomialAsIs(mapOf(
|
||||
mapOf(other to 1U) to -constantOne,
|
||||
))
|
||||
else LabeledPolynomialAsIs(mapOf(
|
||||
mapOf(other to 1U) to -constantOne,
|
||||
emptyMap<Symbol, UInt>() to constantOne * this@minus,
|
||||
))
|
||||
/**
|
||||
* Returns product of the integer represented as a constant polynomial and the variable represented as a monic monomial.
|
||||
*/
|
||||
public override operator fun Int.times(other: Symbol): LabeledPolynomial<C> =
|
||||
if (this == 0) zero
|
||||
else LabeledPolynomialAsIs(mapOf(
|
||||
mapOf(other to 1U) to constantOne * this@times,
|
||||
))
|
||||
|
||||
/**
|
||||
* Returns sum of the polynomial and the integer represented as a polynomial.
|
||||
*
|
||||
* The operation is equivalent to adding [other] copies of unit polynomial to [this].
|
||||
*/
|
||||
public override operator fun LabeledPolynomial<C>.plus(other: Int): LabeledPolynomial<C> =
|
||||
if (other == 0) this
|
||||
else with(coefficients) {
|
||||
if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap<Symbol, UInt>() to other.asConstant()))
|
||||
else LabeledPolynomialAsIs(
|
||||
toMutableMap()
|
||||
.apply {
|
||||
val degs = emptyMap<Symbol, 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 LabeledPolynomial<C>.minus(other: Int): LabeledPolynomial<C> =
|
||||
if (other == 0) this
|
||||
else with(coefficients) {
|
||||
if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap<Symbol, UInt>() to (-other).asConstant()))
|
||||
else LabeledPolynomialAsIs(
|
||||
toMutableMap()
|
||||
.apply {
|
||||
val degs = emptyMap<Symbol, 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 LabeledPolynomial<C>.times(other: Int): LabeledPolynomial<C> =
|
||||
if (other == 0) zero
|
||||
else LabeledPolynomial(
|
||||
coefficients
|
||||
.toMutableMap()
|
||||
.apply {
|
||||
for (degs in keys) this[degs] = this[degs]!! * other
|
||||
}
|
||||
)
|
||||
|
||||
/**
|
||||
* Returns sum of the integer represented as a polynomial and the polynomial.
|
||||
*
|
||||
* The operation is equivalent to adding [this] copies of unit polynomial to [other].
|
||||
*/
|
||||
public override operator fun Int.plus(other: LabeledPolynomial<C>): LabeledPolynomial<C> =
|
||||
if (this == 0) other
|
||||
else with(other.coefficients) {
|
||||
if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap<Symbol, UInt>() to this@plus.asConstant()))
|
||||
else LabeledPolynomialAsIs(
|
||||
toMutableMap()
|
||||
.apply {
|
||||
val degs = emptyMap<Symbol, 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: LabeledPolynomial<C>): LabeledPolynomial<C> =
|
||||
if (this == 0) other
|
||||
else with(other.coefficients) {
|
||||
if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap<Symbol, UInt>() to this@minus.asConstant()))
|
||||
else LabeledPolynomialAsIs(
|
||||
toMutableMap()
|
||||
.apply {
|
||||
forEach { (key, value) -> if (key.isNotEmpty()) this[key] = -value }
|
||||
|
||||
val degs = emptyMap<Symbol, 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: LabeledPolynomial<C>): LabeledPolynomial<C> =
|
||||
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<C> = number(constantNumber(value))
|
||||
|
||||
/**
|
||||
* Returns sum of the variable represented as a monic monomial and the constant represented as a constant polynomial.
|
||||
*/
|
||||
public override operator fun Symbol.plus(other: C): LabeledPolynomial<C> =
|
||||
LabeledPolynomialAsIs(mapOf(
|
||||
mapOf(this@plus to 1U) to constantOne,
|
||||
emptyMap<Symbol, UInt>() to other,
|
||||
))
|
||||
/**
|
||||
* Returns difference between the variable represented as a monic monomial and the constant represented as a constant polynomial.
|
||||
*/
|
||||
public override operator fun Symbol.minus(other: C): LabeledPolynomial<C> =
|
||||
LabeledPolynomialAsIs(mapOf(
|
||||
mapOf(this@minus to 1U) to -constantOne,
|
||||
emptyMap<Symbol, UInt>() to other,
|
||||
))
|
||||
/**
|
||||
* Returns product of the variable represented as a monic monomial and the constant represented as a constant polynomial.
|
||||
*/
|
||||
public override operator fun Symbol.times(other: C): LabeledPolynomial<C> =
|
||||
LabeledPolynomialAsIs(mapOf(
|
||||
mapOf(this@times to 1U) to other,
|
||||
))
|
||||
|
||||
/**
|
||||
* Returns sum of the constant represented as a constant polynomial and the variable represented as a monic monomial.
|
||||
*/
|
||||
public override operator fun C.plus(other: Symbol): LabeledPolynomial<C> =
|
||||
LabeledPolynomialAsIs(mapOf(
|
||||
mapOf(other to 1U) to constantOne,
|
||||
emptyMap<Symbol, UInt>() to this@plus,
|
||||
))
|
||||
/**
|
||||
* Returns difference between the constant represented as a constant polynomial and the variable represented as a monic monomial.
|
||||
*/
|
||||
public override operator fun C.minus(other: Symbol): LabeledPolynomial<C> =
|
||||
LabeledPolynomialAsIs(mapOf(
|
||||
mapOf(other to 1U) to -constantOne,
|
||||
emptyMap<Symbol, UInt>() to this@minus,
|
||||
))
|
||||
/**
|
||||
* Returns product of the constant represented as a constant polynomial and the variable represented as a monic monomial.
|
||||
*/
|
||||
public override operator fun C.times(other: Symbol): LabeledPolynomial<C> =
|
||||
LabeledPolynomialAsIs(mapOf(
|
||||
mapOf(other to 1U) to this@times,
|
||||
))
|
||||
|
||||
/**
|
||||
* Returns sum of the constant represented as a polynomial and the polynomial.
|
||||
*/
|
||||
override operator fun C.plus(other: LabeledPolynomial<C>): LabeledPolynomial<C> =
|
||||
with(other.coefficients) {
|
||||
if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap<Symbol, UInt>() to this@plus))
|
||||
else LabeledPolynomialAsIs(
|
||||
toMutableMap()
|
||||
.apply {
|
||||
val degs = emptyMap<Symbol, 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: LabeledPolynomial<C>): LabeledPolynomial<C> =
|
||||
with(other.coefficients) {
|
||||
if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap<Symbol, UInt>() to this@minus))
|
||||
else LabeledPolynomialAsIs(
|
||||
toMutableMap()
|
||||
.apply {
|
||||
forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c }
|
||||
|
||||
val degs = emptyMap<Symbol, 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: LabeledPolynomial<C>): LabeledPolynomial<C> =
|
||||
LabeledPolynomialAsIs(
|
||||
other.coefficients
|
||||
.toMutableMap()
|
||||
.apply {
|
||||
for (degs in keys) this[degs] = this@times * this[degs]!!
|
||||
}
|
||||
)
|
||||
|
||||
/**
|
||||
* Returns sum of the constant represented as a polynomial and the polynomial.
|
||||
*/
|
||||
override operator fun LabeledPolynomial<C>.plus(other: C): LabeledPolynomial<C> =
|
||||
with(coefficients) {
|
||||
if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap<Symbol, UInt>() to other))
|
||||
else LabeledPolynomialAsIs(
|
||||
toMutableMap()
|
||||
.apply {
|
||||
val degs = emptyMap<Symbol, UInt>()
|
||||
|
||||
this[degs] = getOrElse(degs) { constantZero } + other
|
||||
}
|
||||
)
|
||||
}
|
||||
/**
|
||||
* Returns difference between the constant represented as a polynomial and the polynomial.
|
||||
*/
|
||||
override operator fun LabeledPolynomial<C>.minus(other: C): LabeledPolynomial<C> =
|
||||
with(coefficients) {
|
||||
if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap<Symbol, UInt>() to other))
|
||||
else LabeledPolynomialAsIs(
|
||||
toMutableMap()
|
||||
.apply {
|
||||
forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c }
|
||||
|
||||
val degs = emptyMap<Symbol, UInt>()
|
||||
|
||||
this[degs] = getOrElse(degs) { constantZero } - other
|
||||
}
|
||||
)
|
||||
}
|
||||
/**
|
||||
* Returns product of the constant represented as a polynomial and the polynomial.
|
||||
*/
|
||||
override operator fun LabeledPolynomial<C>.times(other: C): LabeledPolynomial<C> =
|
||||
LabeledPolynomialAsIs(
|
||||
coefficients
|
||||
.toMutableMap()
|
||||
.apply {
|
||||
for (degs in keys) this[degs] = this[degs]!! * other
|
||||
}
|
||||
)
|
||||
|
||||
/**
|
||||
* Converts the constant [value] to polynomial.
|
||||
*/
|
||||
public override fun number(value: C): LabeledPolynomial<C> =
|
||||
LabeledPolynomial(mapOf(emptyMap<Symbol, UInt>() to value))
|
||||
|
||||
/**
|
||||
* Represents the variable as a monic monomial.
|
||||
*/
|
||||
public override operator fun Symbol.unaryPlus(): LabeledPolynomial<C> =
|
||||
LabeledPolynomialAsIs(mapOf(
|
||||
mapOf(this to 1U) to constantOne,
|
||||
))
|
||||
/**
|
||||
* Returns negation of representation of the variable as a monic monomial.
|
||||
*/
|
||||
public override operator fun Symbol.unaryMinus(): LabeledPolynomial<C> =
|
||||
LabeledPolynomialAsIs(mapOf(
|
||||
mapOf(this to 1U) to -constantOne,
|
||||
))
|
||||
/**
|
||||
* Returns sum of the variables represented as monic monomials.
|
||||
*/
|
||||
public override operator fun Symbol.plus(other: Symbol): LabeledPolynomial<C> =
|
||||
if (this == other) LabeledPolynomialAsIs(mapOf(
|
||||
mapOf(this to 1U) to constantOne * 2
|
||||
))
|
||||
else LabeledPolynomialAsIs(mapOf(
|
||||
mapOf(this to 1U) to constantOne,
|
||||
mapOf(other to 1U) to constantOne,
|
||||
))
|
||||
/**
|
||||
* Returns difference between the variables represented as monic monomials.
|
||||
*/
|
||||
public override operator fun Symbol.minus(other: Symbol): LabeledPolynomial<C> =
|
||||
if (this == other) zero
|
||||
else LabeledPolynomialAsIs(mapOf(
|
||||
mapOf(this to 1U) to constantOne,
|
||||
mapOf(other to 1U) to -constantOne,
|
||||
))
|
||||
/**
|
||||
* Returns product of the variables represented as monic monomials.
|
||||
*/
|
||||
public override operator fun Symbol.times(other: Symbol): LabeledPolynomial<C> =
|
||||
if (this == other) LabeledPolynomialAsIs(mapOf(
|
||||
mapOf(this to 2U) to constantOne
|
||||
))
|
||||
else LabeledPolynomialAsIs(mapOf(
|
||||
mapOf(this to 1U, other to 1U) to constantOne,
|
||||
))
|
||||
|
||||
/**
|
||||
* Returns sum of the variable represented as a monic monomial and the polynomial.
|
||||
*/
|
||||
public override operator fun Symbol.plus(other: LabeledPolynomial<C>): LabeledPolynomial<C> =
|
||||
with(other.coefficients) {
|
||||
if (isEmpty()) LabeledPolynomialAsIs(mapOf(mapOf(this@plus to 1u) to constantOne))
|
||||
else LabeledPolynomialAsIs(
|
||||
toMutableMap()
|
||||
.apply {
|
||||
val degs = mapOf(this@plus to 1U)
|
||||
|
||||
this[degs] = constantOne + getOrElse(degs) { constantZero }
|
||||
}
|
||||
)
|
||||
}
|
||||
/**
|
||||
* Returns difference between the variable represented as a monic monomial and the polynomial.
|
||||
*/
|
||||
public override operator fun Symbol.minus(other: LabeledPolynomial<C>): LabeledPolynomial<C> =
|
||||
with(other.coefficients) {
|
||||
if (isEmpty()) LabeledPolynomialAsIs(mapOf(mapOf(this@minus to 1u) to constantOne))
|
||||
else LabeledPolynomialAsIs(
|
||||
toMutableMap()
|
||||
.apply {
|
||||
val degs = mapOf(this@minus to 1U)
|
||||
|
||||
forEach { (degs, c) -> if(degs != degs) this[degs] = -c }
|
||||
|
||||
this[degs] = constantOne - getOrElse(degs) { constantZero }
|
||||
}
|
||||
)
|
||||
}
|
||||
/**
|
||||
* Returns product of the variable represented as a monic monomial and the polynomial.
|
||||
*/
|
||||
public override operator fun Symbol.times(other: LabeledPolynomial<C>): LabeledPolynomial<C> =
|
||||
LabeledPolynomialAsIs(
|
||||
other.coefficients
|
||||
.mapKeys { (degs, _) -> degs.toMutableMap().also{ it[this] = if (this in it) it[this]!! + 1U else 1U } }
|
||||
)
|
||||
|
||||
/**
|
||||
* Returns sum of the polynomial and the variable represented as a monic monomial.
|
||||
*/
|
||||
public override operator fun LabeledPolynomial<C>.plus(other: Symbol): LabeledPolynomial<C> =
|
||||
with(coefficients) {
|
||||
if (isEmpty()) LabeledPolynomialAsIs(mapOf(mapOf(other to 1u) to constantOne))
|
||||
else LabeledPolynomialAsIs(
|
||||
toMutableMap()
|
||||
.apply {
|
||||
val degs = mapOf(other to 1U)
|
||||
|
||||
this[degs] = constantOne + getOrElse(degs) { constantZero }
|
||||
}
|
||||
)
|
||||
}
|
||||
/**
|
||||
* Returns difference between the polynomial and the variable represented as a monic monomial.
|
||||
*/
|
||||
public override operator fun LabeledPolynomial<C>.minus(other: Symbol): LabeledPolynomial<C> =
|
||||
with(coefficients) {
|
||||
if (isEmpty()) LabeledPolynomialAsIs(mapOf(mapOf(other to 1u) to constantOne))
|
||||
else LabeledPolynomialAsIs(
|
||||
toMutableMap()
|
||||
.apply {
|
||||
val degs = mapOf(other to 1U)
|
||||
|
||||
this[degs] = constantOne - getOrElse(degs) { constantZero }
|
||||
}
|
||||
)
|
||||
}
|
||||
/**
|
||||
* Returns product of the polynomial and the variable represented as a monic monomial.
|
||||
*/
|
||||
public override operator fun LabeledPolynomial<C>.times(other: Symbol): LabeledPolynomial<C> =
|
||||
LabeledPolynomialAsIs(
|
||||
coefficients
|
||||
.mapKeys { (degs, _) -> degs.toMutableMap().also{ it[other] = if (other in it) it[other]!! + 1U else 1U } }
|
||||
)
|
||||
|
||||
/**
|
||||
* Returns negation of the polynomial.
|
||||
*/
|
||||
override fun LabeledPolynomial<C>.unaryMinus(): LabeledPolynomial<C> =
|
||||
LabeledPolynomialAsIs(
|
||||
coefficients.mapValues { -it.value }
|
||||
)
|
||||
/**
|
||||
* Returns sum of the polynomials.
|
||||
*/
|
||||
override operator fun LabeledPolynomial<C>.plus(other: LabeledPolynomial<C>): LabeledPolynomial<C> =
|
||||
LabeledPolynomialAsIs(
|
||||
buildMap(coefficients.size + other.coefficients.size) {
|
||||
other.coefficients.mapValuesTo(this) { it.value }
|
||||
other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! + value else value }
|
||||
}
|
||||
)
|
||||
/**
|
||||
* Returns difference of the polynomials.
|
||||
*/
|
||||
override operator fun LabeledPolynomial<C>.minus(other: LabeledPolynomial<C>): LabeledPolynomial<C> =
|
||||
LabeledPolynomialAsIs(
|
||||
buildMap(coefficients.size + other.coefficients.size) {
|
||||
other.coefficients.mapValuesTo(this) { it.value }
|
||||
other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! - value else -value }
|
||||
}
|
||||
)
|
||||
/**
|
||||
* Returns product of the polynomials.
|
||||
*/
|
||||
override operator fun LabeledPolynomial<C>.times(other: LabeledPolynomial<C>): LabeledPolynomial<C> =
|
||||
LabeledPolynomialAsIs(
|
||||
buildMap(coefficients.size * other.coefficients.size) {
|
||||
for ((degs1, c1) in coefficients) for ((degs2, c2) in other.coefficients) {
|
||||
val degs = degs1.toMutableMap()
|
||||
degs2.mapValuesTo(degs) { (variable, deg) -> degs.getOrElse(variable) { 0u } + deg }
|
||||
val c = c1 * c2
|
||||
this[degs] = if (degs in this) this[degs]!! + c else c
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
/**
|
||||
* Instance of zero polynomial (zero of the polynomial ring).
|
||||
*/
|
||||
override val zero: LabeledPolynomial<C> = LabeledPolynomialAsIs(mapOf(emptyMap<Symbol, UInt>() to constantZero))
|
||||
/**
|
||||
* Instance of unit polynomial (unit of the polynomial ring).
|
||||
*/
|
||||
override val one: LabeledPolynomial<C> = LabeledPolynomialAsIs(mapOf(emptyMap<Symbol, UInt>() 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<C>.degree: Int
|
||||
get() = coefficients.entries.maxOfOrNull { (degs, _) -> degs.values.sum().toInt() } ?: -1
|
||||
/**
|
||||
* Map that associates variables (that appear in the polynomial in positive exponents) with their most exponents
|
||||
* in which they are appeared in the polynomial.
|
||||
*
|
||||
* As consequence all values in the map are positive integers. Also, if the polynomial is constant, the map is empty.
|
||||
* And keys of the map is the same as in [variables].
|
||||
*/
|
||||
public override val LabeledPolynomial<C>.degrees: Map<Symbol, UInt>
|
||||
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<C>.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<C>.degreeBy(variables: Collection<Symbol>): 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<C>.variables: Set<Symbol>
|
||||
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<C>.countOfVariables: Int get() = variables.size
|
||||
|
||||
// TODO: When context receivers will be ready move all of this substitutions and invocations to utilities with
|
||||
// [ListPolynomialSpace] as a context receiver
|
||||
/**
|
||||
* Substitutes provided arguments [arguments] into [this] polynomial.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun LabeledPolynomial<C>.substitute(arguments: Map<Symbol, C>): LabeledPolynomial<C> = substitute(ring, arguments)
|
||||
/**
|
||||
* Substitutes provided arguments [arguments] into [this] polynomial.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
@JvmName("substitutePolynomial")
|
||||
public inline fun LabeledPolynomial<C>.substitute(arguments: Map<Symbol, LabeledPolynomial<C>>) : LabeledPolynomial<C> = substitute(ring, arguments)
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright 2018-2021 KMath contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package space.kscience.kmath.functions
|
||||
|
||||
import space.kscience.kmath.expressions.Symbol
|
||||
import space.kscience.kmath.operations.Ring
|
||||
import kotlin.jvm.JvmName
|
||||
|
||||
|
||||
/**
|
||||
* Represents multivariate rational function that stores its numerator and denominator as [LabeledPolynomial]s.
|
||||
*/
|
||||
public class LabeledRationalFunction<C>(
|
||||
public override val numerator: LabeledPolynomial<C>,
|
||||
public override val denominator: LabeledPolynomial<C>
|
||||
) : RationalFunction<C, LabeledPolynomial<C>> {
|
||||
override fun toString(): String = "LabeledRationalFunction${numerator.coefficients}/${denominator.coefficients}"
|
||||
}
|
||||
|
||||
/**
|
||||
* Arithmetic context for univariate rational functions with numerator and denominator represented as [LabeledPolynomial]s.
|
||||
*
|
||||
* @param C the type of constants. Polynomials have them a coefficients in their terms.
|
||||
* @param A type of provided underlying ring of constants. It's [Ring] of [C].
|
||||
* @param ring underlying ring of constants of type [A].
|
||||
*/
|
||||
public class LabeledRationalFunctionSpace<C, A: Ring<C>>(
|
||||
public val ring: A,
|
||||
) :
|
||||
MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSpace<
|
||||
C,
|
||||
Symbol,
|
||||
LabeledPolynomial<C>,
|
||||
LabeledRationalFunction<C>,
|
||||
LabeledPolynomialSpace<C, A>,
|
||||
>,
|
||||
MultivariatePolynomialSpaceOfFractions<
|
||||
C,
|
||||
Symbol,
|
||||
LabeledPolynomial<C>,
|
||||
LabeledRationalFunction<C>,
|
||||
>() {
|
||||
|
||||
/**
|
||||
* Underlying polynomial ring. Its polynomial operations are inherited by local polynomial operations.
|
||||
*/
|
||||
override val polynomialRing : LabeledPolynomialSpace<C, A> = LabeledPolynomialSpace(ring)
|
||||
/**
|
||||
* Constructor of rational functions (of type [LabeledRationalFunction]) from numerator and denominator (of type [LabeledPolynomial]).
|
||||
*/
|
||||
override fun constructRationalFunction(
|
||||
numerator: LabeledPolynomial<C>,
|
||||
denominator: LabeledPolynomial<C>
|
||||
): LabeledRationalFunction<C> =
|
||||
LabeledRationalFunction<C>(numerator, denominator)
|
||||
|
||||
// TODO: When context receivers will be ready move all of this substitutions and invocations to utilities with
|
||||
// [ListPolynomialSpace] as a context receiver
|
||||
/**
|
||||
* Substitutes provided constant [argument] into [this] polynomial.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun LabeledPolynomial<C>.substitute(argument: Map<Symbol, C>): LabeledPolynomial<C> = substitute(ring, argument)
|
||||
/**
|
||||
* Substitutes provided polynomial [argument] into [this] polynomial.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
@JvmName("substitutePolynomial")
|
||||
public inline fun LabeledPolynomial<C>.substitute(argument: Map<Symbol, LabeledPolynomial<C>>): LabeledPolynomial<C> = substitute(ring, argument)
|
||||
/**
|
||||
* Substitutes provided rational function [argument] into [this] polynomial.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
@JvmName("substituteRationalFunction")
|
||||
public inline fun LabeledPolynomial<C>.substitute(argument: Map<Symbol, LabeledRationalFunction<C>>): LabeledRationalFunction<C> = substitute(ring, argument)
|
||||
/**
|
||||
* Substitutes provided constant [argument] into [this] rational function.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun LabeledRationalFunction<C>.substitute(argument: Map<Symbol, C>): LabeledRationalFunction<C> = substitute(ring, argument)
|
||||
/**
|
||||
* Substitutes provided polynomial [argument] into [this] rational function.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
@JvmName("substitutePolynomial")
|
||||
public inline fun LabeledRationalFunction<C>.substitute(argument: Map<Symbol, LabeledPolynomial<C>>): LabeledRationalFunction<C> = substitute(ring, argument)
|
||||
/**
|
||||
* Substitutes provided rational function [argument] into [this] rational function.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
@JvmName("substituteRationalFunction")
|
||||
public inline fun LabeledRationalFunction<C>.substitute(argument: Map<Symbol, LabeledRationalFunction<C>>): LabeledRationalFunction<C> = substitute(ring, argument)
|
||||
}
|
@ -15,7 +15,7 @@ import kotlin.math.min
|
||||
/**
|
||||
* Represents univariate polynomial that stores its coefficients in a [List].
|
||||
*
|
||||
* @param coefficients constant is the leftmost coefficient.
|
||||
* @param C the type of constants.
|
||||
*/
|
||||
public data class ListPolynomial<C>(
|
||||
/**
|
||||
|
@ -12,7 +12,7 @@ import kotlin.math.max
|
||||
|
||||
|
||||
/**
|
||||
* Represents univariate polynomial that stores its coefficients in a [Map] and terms' signatures in a [List].
|
||||
* Represents multivariate polynomial that stores its coefficients in a [Map] and terms' signatures in a [List].
|
||||
*
|
||||
* @param C the type of constants.
|
||||
*/
|
||||
@ -20,10 +20,11 @@ public data class NumberedPolynomial<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
|
||||
* Map that contains coefficients of the polynomial.
|
||||
*
|
||||
* Every monomial `a x_1^{d_1} ... x_n^{d_n}` is stored as a pair "key-value" in the map, where the value is the
|
||||
* coefficient `a` and the key is a list that associates index of every variable in the monomial with their degree
|
||||
* in the monomial. For example, coefficients of a polynomial `5 x_1^2 x_3^3 - 6 x_2` can be represented as
|
||||
* ```
|
||||
* mapOf(
|
||||
* listOf(2, 0, 3) to 5, // 5 x_1^2 x_3^3 +
|
||||
|
@ -0,0 +1,518 @@
|
||||
/*
|
||||
* Copyright 2018-2021 KMath contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@file:Suppress("FunctionName", "NOTHING_TO_INLINE")
|
||||
|
||||
package space.kscience.kmath.functions
|
||||
|
||||
import space.kscience.kmath.expressions.Symbol
|
||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||
import space.kscience.kmath.operations.Ring
|
||||
|
||||
|
||||
/**
|
||||
* Returns the same degrees' description of the monomial, but without zero degrees.
|
||||
*/
|
||||
internal fun Map<Symbol, UInt>.cleanUp() = filterValues { it > 0U }
|
||||
|
||||
/**
|
||||
* Constructs [LabeledPolynomial] with provided coefficients map [coefs]. The map is used as is.
|
||||
*/
|
||||
@PublishedApi
|
||||
internal inline fun <C> LabeledPolynomialAsIs(coefs: Map<Map<Symbol, UInt>, C>) : LabeledPolynomial<C> = LabeledPolynomial<C>(coefs)
|
||||
|
||||
/**
|
||||
* Constructs [LabeledPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient".
|
||||
* The collections will be transformed to map with [toMap] and then will be used as is.
|
||||
*/
|
||||
@PublishedApi
|
||||
internal inline fun <C> LabeledPolynomialAsIs(pairs: Collection<Pair<Map<Symbol, UInt>, C>>) : LabeledPolynomial<C> = LabeledPolynomial<C>(pairs.toMap())
|
||||
|
||||
/**
|
||||
* Constructs [LabeledPolynomial] with provided array of [pairs] of pairs "term's signature — term's coefficient".
|
||||
* The array will be transformed to map with [toMap] and then will be used as is.
|
||||
*/
|
||||
@PublishedApi
|
||||
internal inline fun <C> LabeledPolynomialAsIs(vararg pairs: Pair<Map<Symbol, UInt>, C>) : LabeledPolynomial<C> = LabeledPolynomial<C>(pairs.toMap())
|
||||
|
||||
/**
|
||||
* Constructs [LabeledPolynomial] with provided coefficients map [coefs]. The map is used as is.
|
||||
*
|
||||
* **Be sure you read description of [LabeledPolynomial.coefficients]. Otherwise, you may make a mistake that will
|
||||
* cause wrong computation result or even runtime error.**
|
||||
*/
|
||||
@DelicatePolynomialAPI
|
||||
public inline fun <C> LabeledPolynomialWithoutCheck(coefs: Map<Map<Symbol, UInt>, C>) : LabeledPolynomial<C> = LabeledPolynomial<C>(coefs)
|
||||
|
||||
/**
|
||||
* Constructs [LabeledPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient".
|
||||
* The collections will be transformed to map with [toMap] and then will be used as is.
|
||||
*
|
||||
* **Be sure you read description of [LabeledPolynomial.coefficients]. Otherwise, you may make a mistake that will
|
||||
* cause wrong computation result or even runtime error.**
|
||||
*/
|
||||
@DelicatePolynomialAPI
|
||||
public inline fun <C> LabeledPolynomialWithoutCheck(pairs: Collection<Pair<Map<Symbol, UInt>, C>>) : LabeledPolynomial<C> = LabeledPolynomial<C>(pairs.toMap())
|
||||
|
||||
/**
|
||||
* Constructs [LabeledPolynomial] with provided array of [pairs] of pairs "term's signature — term's coefficient".
|
||||
* The array will be transformed to map with [toMap] and then will be used as is.
|
||||
*
|
||||
* **Be sure you read description of [LabeledPolynomial.coefficients]. Otherwise, you may make a mistake that will
|
||||
* cause wrong computation result or even runtime error.**
|
||||
*/
|
||||
@DelicatePolynomialAPI
|
||||
public inline fun <C> LabeledPolynomialWithoutCheck(vararg pairs: Pair<Map<Symbol, UInt>, C>) : LabeledPolynomial<C> = LabeledPolynomial<C>(pairs.toMap())
|
||||
|
||||
/**
|
||||
* Constructs [LabeledPolynomial] with provided coefficients map [coefs].
|
||||
*
|
||||
* [coefs] will be "cleaned up":
|
||||
* 1. Zeros at the ends of terms' signatures (e.g. [coefs] keys) will be removed. (See [cleanUp].)
|
||||
* 1. Terms that happen to have the same signature will be summed up.
|
||||
* 1. New map will be formed of resulting terms.
|
||||
*/
|
||||
public fun <C> LabeledPolynomial(coefs: Map<Map<Symbol, UInt>, C>, add: (C, C) -> C) : LabeledPolynomial<C> {
|
||||
val fixedCoefs = mutableMapOf<Map<Symbol, 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 LabeledPolynomial<C>(fixedCoefs)
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs [LabeledPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient".
|
||||
*
|
||||
* [pairs] will be "cleaned up":
|
||||
* 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].)
|
||||
* 1. Terms that happen to have the same signature will be summed up.
|
||||
* 1. New map will be formed of resulting terms.
|
||||
*/
|
||||
public fun <C> LabeledPolynomial(pairs: Collection<Pair<Map<Symbol, UInt>, C>>, add: (C, C) -> C) : LabeledPolynomial<C> {
|
||||
val fixedCoefs = mutableMapOf<Map<Symbol, 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 LabeledPolynomial<C>(fixedCoefs)
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs [LabeledPolynomial] with provided array [pairs] of pairs "term's signature — term's coefficient".
|
||||
*
|
||||
* [pairs] will be "cleaned up":
|
||||
* 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].)
|
||||
* 1. Terms that happen to have the same signature will be summed up.
|
||||
* 1. New map will be formed of resulting terms.
|
||||
*/
|
||||
public fun <C> LabeledPolynomial(vararg pairs: Pair<Map<Symbol, UInt>, C>, add: (C, C) -> C) : LabeledPolynomial<C> {
|
||||
val fixedCoefs = mutableMapOf<Map<Symbol, 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 LabeledPolynomial<C>(fixedCoefs)
|
||||
}
|
||||
|
||||
// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available
|
||||
|
||||
/**
|
||||
* Constructs [LabeledPolynomial] with provided coefficients map [coefs].
|
||||
*
|
||||
* [coefs] will be "cleaned up":
|
||||
* 1. Zeros at the ends of terms' signatures (e.g. [coefs] keys) will be removed. (See [cleanUp].)
|
||||
* 1. Terms that happen to have the same signature will be summed up.
|
||||
* 1. New map will be formed of resulting terms.
|
||||
*/
|
||||
public inline fun <C, A: Ring<C>> A.LabeledPolynomial(coefs: Map<Map<Symbol, UInt>, C>) : LabeledPolynomial<C> = LabeledPolynomial(coefs, ::add)
|
||||
/**
|
||||
* Constructs [LabeledPolynomial] with provided coefficients map [coefs].
|
||||
*
|
||||
* [coefs] will be "cleaned up":
|
||||
* 1. Zeros at the ends of terms' signatures (e.g. [coefs] keys) will be removed. (See [cleanUp].)
|
||||
* 1. Terms that happen to have the same signature will be summed up.
|
||||
* 1. New map will be formed of resulting terms.
|
||||
*/
|
||||
public inline fun <C, A: Ring<C>> LabeledPolynomialSpace<C, A>.LabeledPolynomial(coefs: Map<Map<Symbol, UInt>, C>) : LabeledPolynomial<C> = LabeledPolynomial(coefs) { left: C, right: C -> left + right }
|
||||
|
||||
/**
|
||||
* Constructs [LabeledPolynomial] with provided coefficients map [coefs].
|
||||
*
|
||||
* [coefs] will be "cleaned up":
|
||||
* 1. Zeros at the ends of terms' signatures (e.g. [coefs] keys) will be removed. (See [cleanUp].)
|
||||
* 1. Terms that happen to have the same signature will be summed up.
|
||||
* 1. New map will be formed of resulting terms.
|
||||
*/
|
||||
public inline fun <C, A: Ring<C>> LabeledRationalFunctionSpace<C, A>.LabeledPolynomial(coefs: Map<Map<Symbol, UInt>, C>) : LabeledPolynomial<C> = LabeledPolynomial(coefs) { left: C, right: C -> left + right }
|
||||
|
||||
/**
|
||||
* Constructs [LabeledPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient".
|
||||
*
|
||||
* [pairs] will be "cleaned up":
|
||||
* 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].)
|
||||
* 1. Terms that happen to have the same signature will be summed up.
|
||||
* 1. New map will be formed of resulting terms.
|
||||
*/
|
||||
public inline fun <C, A: Ring<C>> A.LabeledPolynomial(pairs: Collection<Pair<Map<Symbol, UInt>, C>>) : LabeledPolynomial<C> = LabeledPolynomial(pairs, ::add)
|
||||
|
||||
/**
|
||||
* Constructs [LabeledPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient".
|
||||
*
|
||||
* [pairs] will be "cleaned up":
|
||||
* 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].)
|
||||
* 1. Terms that happen to have the same signature will be summed up.
|
||||
* 1. New map will be formed of resulting terms.
|
||||
*/
|
||||
public inline fun <C, A: Ring<C>> LabeledPolynomialSpace<C, A>.LabeledPolynomial(pairs: Collection<Pair<Map<Symbol, UInt>, C>>) : LabeledPolynomial<C> = LabeledPolynomial(pairs) { left: C, right: C -> left + right }
|
||||
/**
|
||||
* Constructs [LabeledPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient".
|
||||
*
|
||||
* [pairs] will be "cleaned up":
|
||||
* 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].)
|
||||
* 1. Terms that happen to have the same signature will be summed up.
|
||||
* 1. New map will be formed of resulting terms.
|
||||
*/
|
||||
public inline fun <C, A: Ring<C>> LabeledRationalFunctionSpace<C, A>.LabeledPolynomial(pairs: Collection<Pair<Map<Symbol, UInt>, C>>) : LabeledPolynomial<C> = LabeledPolynomial(pairs) { left: C, right: C -> left + right }
|
||||
|
||||
/**
|
||||
* Constructs [LabeledPolynomial] with provided array [pairs] of pairs "term's signature — term's coefficient".
|
||||
*
|
||||
* [pairs] will be "cleaned up":
|
||||
* 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].)
|
||||
* 1. Terms that happen to have the same signature will be summed up.
|
||||
* 1. New map will be formed of resulting terms.
|
||||
*/
|
||||
public inline fun <C, A: Ring<C>> A.LabeledPolynomial(vararg pairs: Pair<Map<Symbol, UInt>, C>) : LabeledPolynomial<C> = LabeledPolynomial(*pairs) { left: C, right: C -> left + right }
|
||||
/**
|
||||
* Constructs [LabeledPolynomial] with provided array [pairs] of pairs "term's signature — term's coefficient".
|
||||
*
|
||||
* [pairs] will be "cleaned up":
|
||||
* 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].)
|
||||
* 1. Terms that happen to have the same signature will be summed up.
|
||||
* 1. New map will be formed of resulting terms.
|
||||
*/
|
||||
public inline fun <C, A: Ring<C>> LabeledPolynomialSpace<C, A>.LabeledPolynomial(vararg pairs: Pair<Map<Symbol, UInt>, C>) : LabeledPolynomial<C> = LabeledPolynomial(*pairs) { left: C, right: C -> left + right }
|
||||
/**
|
||||
* Constructs [LabeledPolynomial] with provided array [pairs] of pairs "term's signature — term's coefficient".
|
||||
*
|
||||
* [pairs] will be "cleaned up":
|
||||
* 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].)
|
||||
* 1. Terms that happen to have the same signature will be summed up.
|
||||
* 1. New map will be formed of resulting terms.
|
||||
*/
|
||||
public inline fun <C, A: Ring<C>> LabeledRationalFunctionSpace<C, A>.LabeledPolynomial(vararg pairs: Pair<Map<Symbol, UInt>, C>) : LabeledPolynomial<C> = LabeledPolynomial(*pairs) { left: C, right: C -> left + right }
|
||||
|
||||
/**
|
||||
* Converts [this] constant to [LabeledPolynomial].
|
||||
*/
|
||||
public inline fun <C> C.asLabeledPolynomial() : LabeledPolynomial<C> = LabeledPolynomialAsIs(mapOf(emptyMap<Symbol, UInt>() to this))
|
||||
|
||||
///**
|
||||
//// * Converts [this] variable to [LabeledPolynomial].
|
||||
//// */
|
||||
//context(A)
|
||||
//public inline fun <C, A: Ring<C>> Symbol.asLabeledPolynomial() : LabeledPolynomial<C> = LabeledPolynomial<C>(mapOf(mapOf(this to 1u) to one))
|
||||
///**
|
||||
// * Converts [this] variable to [LabeledPolynomial].
|
||||
// */
|
||||
//context(LabeledPolynomialSpace<C, A>)
|
||||
//public inline fun <C, A: Ring<C>> Symbol.asLabeledPolynomial() : LabeledPolynomial<C> = LabeledPolynomial<C>(mapOf(mapOf(this to 1u) to constantOne))
|
||||
///**
|
||||
// * Converts [this] variable to [LabeledPolynomial].
|
||||
// */
|
||||
//context(LabeledRationalFunctionSpace<C, A>)
|
||||
//public inline fun <C, A: Ring<C>> Symbol.asLabeledPolynomial() : LabeledPolynomial<C> = LabeledPolynomial<C>(mapOf(mapOf(this to 1u) to constantOne))
|
||||
|
||||
/**
|
||||
* Marks DSL that allows to more simply create [LabeledPolynomial]s with good performance.
|
||||
*
|
||||
* For example, polynomial `5 a^2 c^3 - 6 b` can be described as
|
||||
* ```
|
||||
* Int.algebra {
|
||||
* val numberedPolynomial : NumberedPolynomial<Int> = NumberedPolynomial {
|
||||
* 5 { a inPowerOf 2u; c inPowerOf 3u } // 5 a^2 c^3 +
|
||||
* (-6) { b inPowerOf 1u } // (-6) b^1
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
@DslMarker
|
||||
@UnstableKMathAPI
|
||||
internal annotation class LabeledPolynomialConstructorDSL
|
||||
|
||||
/**
|
||||
* Builder of [LabeledPolynomial] signature. It should be used as an implicit context for lambdas that describe term signature.
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
@LabeledPolynomialConstructorDSL
|
||||
public class LabeledPolynomialTermSignatureBuilder {
|
||||
/**
|
||||
* Signature storage. Any declaration of any variable's power updates the storage by increasing corresponding value.
|
||||
* Afterward the storage will be used as a resulting signature.
|
||||
*/
|
||||
private val signature: MutableMap<Symbol, UInt> = LinkedHashMap()
|
||||
|
||||
/**
|
||||
* Builds the resulting signature.
|
||||
*
|
||||
* In fact, it just returns [signature] as regular signature of type `List<UInt>`.
|
||||
*/
|
||||
@PublishedApi
|
||||
internal fun build(): Map<Symbol, UInt> = signature
|
||||
|
||||
/**
|
||||
* Declares power of [this] variable of degree [deg].
|
||||
*
|
||||
* Declaring another power of the same variable will increase its degree by received degree.
|
||||
*/
|
||||
public infix fun Symbol.inPowerOf(deg: UInt) {
|
||||
signature[this] = deg
|
||||
}
|
||||
/**
|
||||
* Declares power of [this] variable of degree [deg].
|
||||
*
|
||||
* Declaring another power of the same variable will increase its degree by received degree.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline infix fun Symbol.pow(deg: UInt): Unit = this inPowerOf deg
|
||||
/**
|
||||
* Declares power of [this] variable of degree [deg].
|
||||
*
|
||||
* Declaring another power of the same variable will increase its degree by received degree.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline infix fun Symbol.`in`(deg: UInt): Unit = this inPowerOf deg
|
||||
/**
|
||||
* Declares power of [this] variable of degree [deg].
|
||||
*
|
||||
* Declaring another power of the same variable will increase its degree by received degree.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline infix fun Symbol.of(deg: UInt): Unit = this inPowerOf deg
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder of [LabeledPolynomial]. It should be used as an implicit context for lambdas that describe [LabeledPolynomial].
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public class LabeledPolynomialBuilder<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<Map<Symbol, 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(): LabeledPolynomial<C> = LabeledPolynomial<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: Map<Symbol, UInt>) {
|
||||
coefficients[signature] = if (signature in coefficients) add(coefficients[signature]!!, this@with) else this@with
|
||||
}
|
||||
/**
|
||||
* Declares monomial with [this] coefficient and signature constructed by [block].
|
||||
*
|
||||
* Declaring another monomial with the same signature will add [this] coefficient to existing one. If the sum of such
|
||||
* coefficients is zero at any moment the monomial won't be removed but will be left as it is.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline infix fun C.with(noinline block: LabeledPolynomialTermSignatureBuilder.() -> Unit): Unit = this.invoke(block)
|
||||
/**
|
||||
* Declares monomial with [this] coefficient and signature constructed by [block].
|
||||
*
|
||||
* Declaring another monomial with the same signature will add [this] coefficient to existing one. If the sum of such
|
||||
* coefficients is zero at any moment the monomial won't be removed but will be left as it is.
|
||||
*/
|
||||
public inline operator fun C.invoke(block: LabeledPolynomialTermSignatureBuilder.() -> Unit): Unit =
|
||||
this with LabeledPolynomialTermSignatureBuilder().apply(block).build()
|
||||
}
|
||||
|
||||
// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available
|
||||
|
||||
///**
|
||||
// * Creates [LabeledPolynomial] with lambda [block] in context of [this] ring of constants.
|
||||
// *
|
||||
// * For example, polynomial `5 x_1^2 x_3^3 - 6 x_2` can be described as
|
||||
// * ```
|
||||
// * Int.algebra {
|
||||
// * val LabeledPolynomial : LabeledPolynomial<Int> = LabeledPolynomial {
|
||||
// * 5 { 1 inPowerOf 2u; 3 inPowerOf 3u } // 5 x_1^2 x_3^3 +
|
||||
// * (-6) { 2 inPowerOf 1u } // (-6) x_2^1
|
||||
// * }
|
||||
// * }
|
||||
// * ```
|
||||
// */
|
||||
// FIXME: For now this fabric does not let next two fabrics work. (See KT-52803.) Possible feature solutions:
|
||||
// 1. `LowPriorityInOverloadResolution` becomes public. Then it should be applied to this function.
|
||||
// 2. Union types are implemented. Then all three functions should be rewritten
|
||||
// as one with single union type as a (context) receiver.
|
||||
//@UnstableKMathAPI
|
||||
//public inline fun <C, A: Ring<C>> A.LabeledPolynomial(initialCapacity: Int = 0, block: LabeledPolynomialBuilder<C>.() -> Unit) : LabeledPolynomial<C> = LabeledPolynomialBuilder(::add, initialCapacity).apply(block).build()
|
||||
/**
|
||||
* Creates [LabeledPolynomial] with lambda [block] in context of [this] ring of [LabeledPolynomial]s.
|
||||
*
|
||||
* For example, polynomial `5 x_1^2 x_3^3 - 6 x_2` can be described as
|
||||
* ```
|
||||
* Int.algebra {
|
||||
* val LabeledPolynomial : LabeledPolynomial<Int> = LabeledPolynomial {
|
||||
* 5 { 1 inPowerOf 2u; 3 inPowerOf 3u } // 5 x_1^2 x_3^3 +
|
||||
* (-6) { 2 inPowerOf 1u } // (-6) x_2^1
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public inline fun <C, A: Ring<C>> LabeledPolynomialSpace<C, A>.LabeledPolynomial(initialCapacity: Int = 0, block: LabeledPolynomialBuilder<C>.() -> Unit) : LabeledPolynomial<C> = LabeledPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build()
|
||||
/**
|
||||
* Creates [LabeledPolynomial] with lambda [block] in context of [this] field of [LabeledRationalFunction]s.
|
||||
*
|
||||
* For example, polynomial `5 x_1^2 x_3^3 - 6 x_2` can be described as
|
||||
* ```
|
||||
* Int.algebra {
|
||||
* val LabeledPolynomial : LabeledPolynomial<Int> = LabeledPolynomial {
|
||||
* 5 { 1 inPowerOf 2u; 3 inPowerOf 3u } // 5 x_1^2 x_3^3 +
|
||||
* (-6) { 2 inPowerOf 1u } // (-6) x_2^1
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public inline fun <C, A: Ring<C>> LabeledRationalFunctionSpace<C, A>.LabeledPolynomial(initialCapacity: Int = 0, block: LabeledPolynomialBuilder<C>.() -> Unit) : LabeledPolynomial<C> = LabeledPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build()
|
||||
|
||||
// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available
|
||||
|
||||
/**
|
||||
* Constructs [LabeledRationalFunction] with provided coefficients maps [numeratorCoefficients] and [denominatorCoefficients].
|
||||
*
|
||||
* The maps will be "cleaned up":
|
||||
* 1. Zeros at the ends of terms' signatures (e.g. the maps' keys) will be removed. (See [cleanUp].)
|
||||
* 1. Terms that happen to have the same signature will be summed up.
|
||||
* 1. New map will be formed of resulting terms.
|
||||
*/
|
||||
public fun <C, A: Ring<C>> A.LabeledRationalFunction(numeratorCoefficients: Map<Map<Symbol, UInt>, C>, denominatorCoefficients: Map<Map<Symbol, UInt>, C>): LabeledRationalFunction<C> =
|
||||
LabeledRationalFunction<C>(
|
||||
LabeledPolynomial(numeratorCoefficients),
|
||||
LabeledPolynomial(denominatorCoefficients)
|
||||
)
|
||||
/**
|
||||
* Constructs [LabeledRationalFunction] with provided coefficients maps [numeratorCoefficients] and [denominatorCoefficients].
|
||||
*
|
||||
* The maps will be "cleaned up":
|
||||
* 1. Zeros at the ends of terms' signatures (e.g. the maps' keys) will be removed. (See [cleanUp].)
|
||||
* 1. Terms that happen to have the same signature will be summed up.
|
||||
* 1. New map will be formed of resulting terms.
|
||||
*/
|
||||
public fun <C, A: Ring<C>> LabeledRationalFunctionSpace<C, A>.LabeledRationalFunction(numeratorCoefficients: Map<Map<Symbol, UInt>, C>, denominatorCoefficients: Map<Map<Symbol, UInt>, C>): LabeledRationalFunction<C> =
|
||||
LabeledRationalFunction<C>(
|
||||
LabeledPolynomial(numeratorCoefficients),
|
||||
LabeledPolynomial(denominatorCoefficients)
|
||||
)
|
||||
|
||||
/**
|
||||
* Constructs [LabeledRationalFunction] with provided [numerator] and unit denominator.
|
||||
*/
|
||||
public fun <C, A: Ring<C>> A.LabeledRationalFunction(numerator: LabeledPolynomial<C>): LabeledRationalFunction<C> =
|
||||
LabeledRationalFunction<C>(numerator, LabeledPolynomial(mapOf(emptyMap<Symbol, UInt>() to one)))
|
||||
/**
|
||||
* Constructs [LabeledRationalFunction] with provided [numerator] and unit denominator.
|
||||
*/
|
||||
public fun <C, A: Ring<C>> LabeledRationalFunctionSpace<C, A>.LabeledRationalFunction(numerator: LabeledPolynomial<C>): LabeledRationalFunction<C> =
|
||||
LabeledRationalFunction<C>(numerator, polynomialOne)
|
||||
|
||||
/**
|
||||
* Constructs [LabeledRationalFunction] with provided coefficients map [numeratorCoefficients] for numerator and unit
|
||||
* denominator.
|
||||
*
|
||||
* [numeratorCoefficients] will be "cleaned up":
|
||||
* 1. Zeros at the ends of terms' signatures (e.g. [numeratorCoefficients]'s keys) will be removed. (See [cleanUp].)
|
||||
* 1. Terms that happen to have the same signature will be summed up.
|
||||
* 1. New map will be formed of resulting terms.
|
||||
*/
|
||||
public fun <C, A: Ring<C>> LabeledRationalFunctionSpace<C, A>.LabeledRationalFunction(numeratorCoefficients: Map<Map<Symbol, UInt>, C>): LabeledRationalFunction<C> =
|
||||
LabeledRationalFunction<C>(
|
||||
LabeledPolynomial(numeratorCoefficients),
|
||||
polynomialOne
|
||||
)
|
||||
/**
|
||||
* Constructs [LabeledRationalFunction] with provided coefficients map [numeratorCoefficients] for numerator and unit
|
||||
* denominator.
|
||||
*
|
||||
* [numeratorCoefficients] will be "cleaned up":
|
||||
* 1. Zeros at the ends of terms' signatures (e.g. [numeratorCoefficients]'s keys) will be removed. (See [cleanUp].)
|
||||
* 1. Terms that happen to have the same signature will be summed up.
|
||||
* 1. New map will be formed of resulting terms.
|
||||
*/
|
||||
public fun <C, A: Ring<C>> A.LabeledRationalFunction(numeratorCoefficients: Map<Map<Symbol, UInt>, C>): LabeledRationalFunction<C> =
|
||||
LabeledRationalFunction<C>(
|
||||
LabeledPolynomial(numeratorCoefficients),
|
||||
LabeledPolynomialAsIs(mapOf(emptyMap<Symbol, UInt>() to one))
|
||||
)
|
||||
|
||||
///**
|
||||
// * Converts [this] constant to [LabeledRationalFunction].
|
||||
// */
|
||||
//context(A)
|
||||
//public fun <C, A: Ring<C>> C.asLabeledRationalFunction() : LabeledRationalFunction<C> =
|
||||
// LabeledRationalFunction(
|
||||
// LabeledPolynomialAsIs(mapOf(emptyMap<Symbol, UInt>() to this)),
|
||||
// LabeledPolynomialAsIs(mapOf(emptyMap<Symbol, UInt>() to one))
|
||||
// )
|
||||
///**
|
||||
// * Converts [this] constant to [LabeledRationalFunction].
|
||||
// */
|
||||
//context(LabeledRationalFunctionSpace<C, A>)
|
||||
//public fun <C, A: Ring<C>> C.asLabeledRationalFunction() : LabeledRationalFunction<C> =
|
||||
// LabeledRationalFunction(
|
||||
// LabeledPolynomialAsIs(mapOf(emptyMap<Symbol, UInt>() to this)),
|
||||
// LabeledPolynomialAsIs(mapOf(emptyMap<Symbol, UInt>() to constantOne))
|
||||
// )
|
||||
|
||||
///**
|
||||
// * Converts [this] variable to [LabeledRationalFunction].
|
||||
// */
|
||||
//context(A)
|
||||
//public fun <C, A: Ring<C>> Symbol.asLabeledRationalFunction() : LabeledRationalFunction<C> =
|
||||
// LabeledRationalFunction(
|
||||
// LabeledPolynomialAsIs(mapOf(mapOf(this to 1u) to one)),
|
||||
// LabeledPolynomialAsIs(mapOf(emptyMap<Symbol, UInt>() to one))
|
||||
// )
|
||||
///**
|
||||
// * Converts [this] variable to [LabeledRationalFunction].
|
||||
// */
|
||||
//context(LabeledRationalFunctionSpace<C, A>)
|
||||
//public fun <C, A: Ring<C>> Symbol.asLabeledRationalFunction() : LabeledRationalFunction<C> =
|
||||
// LabeledRationalFunction(
|
||||
// LabeledPolynomialAsIs(mapOf(mapOf(this to 1u) to constantOne)),
|
||||
// LabeledPolynomialAsIs(mapOf(emptyMap<Symbol, UInt>() to constantOne))
|
||||
// )
|
@ -0,0 +1,327 @@
|
||||
/*
|
||||
* Copyright 2018-2021 KMath contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package space.kscience.kmath.functions
|
||||
|
||||
import space.kscience.kmath.expressions.Symbol
|
||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||
import space.kscience.kmath.operations.Field
|
||||
import space.kscience.kmath.operations.invoke
|
||||
import space.kscience.kmath.operations.Ring
|
||||
import space.kscience.kmath.operations.algebra
|
||||
import kotlin.contracts.InvocationKind
|
||||
import kotlin.contracts.contract
|
||||
import kotlin.jvm.JvmName
|
||||
|
||||
|
||||
/**
|
||||
* Creates a [LabeledPolynomialSpace] over a received ring.
|
||||
*/
|
||||
public fun <C, A : Ring<C>> A.labeledPolynomialSpace(): LabeledPolynomialSpace<C, A> =
|
||||
LabeledPolynomialSpace(this)
|
||||
|
||||
/**
|
||||
* Creates a [LabeledPolynomialSpace]'s scope over a received ring.
|
||||
*/
|
||||
public inline fun <C, A : Ring<C>, R> A.labeledPolynomialSpace(block: LabeledPolynomialSpace<C, A>.() -> R): R {
|
||||
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
|
||||
return LabeledPolynomialSpace(this).block()
|
||||
}
|
||||
/**
|
||||
* Creates a [LabeledRationalFunctionSpace] over a received ring.
|
||||
*/
|
||||
public fun <C, A : Ring<C>> A.labeledRationalFunctionSpace(): LabeledRationalFunctionSpace<C, A> =
|
||||
LabeledRationalFunctionSpace(this)
|
||||
|
||||
/**
|
||||
* Creates a [LabeledRationalFunctionSpace]'s scope over a received ring.
|
||||
*/
|
||||
public inline fun <C, A : Ring<C>, R> A.labeledRationalFunctionSpace(block: LabeledRationalFunctionSpace<C, A>.() -> R): R {
|
||||
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
|
||||
return LabeledRationalFunctionSpace(this).block()
|
||||
}
|
||||
|
||||
/**
|
||||
* Substitutes provided Double arguments [args] into [this] Double polynomial.
|
||||
*/
|
||||
public fun LabeledPolynomial<Double>.substitute(args: Map<Symbol, Double>): LabeledPolynomial<Double> = Double.algebra {
|
||||
if (coefficients.isEmpty()) return this@substitute
|
||||
LabeledPolynomial<Double>(
|
||||
buildMap {
|
||||
coefficients.forEach { (degs, c) ->
|
||||
val newDegs = degs.filterKeys { it !in args }
|
||||
val newC = args.entries.fold(c) { product, (variable, substitution) ->
|
||||
val deg = degs.getOrElse(variable) { 0u }
|
||||
if (deg == 0u) product else product * power(substitution, deg)
|
||||
}
|
||||
this[newDegs] = if (newDegs in this) this[newDegs]!! + newC else newC
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Substitutes provided arguments [args] into [this] polynomial.
|
||||
*/
|
||||
public fun <C> LabeledPolynomial<C>.substitute(ring: Ring<C>, args: Map<Symbol, C>): LabeledPolynomial<C> = ring {
|
||||
if (coefficients.isEmpty()) return this@substitute
|
||||
LabeledPolynomial<C>(
|
||||
buildMap {
|
||||
coefficients.forEach { (degs, c) ->
|
||||
val newDegs = degs.filterKeys { it !in args }
|
||||
val newC = args.entries.fold(c) { product, (variable, substitution) ->
|
||||
val deg = degs.getOrElse(variable) { 0u }
|
||||
if (deg == 0u) product else product * power(substitution, deg)
|
||||
}
|
||||
this[newDegs] = if (newDegs in this) this[newDegs]!! + newC else newC
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Substitutes provided arguments [args] into [this] polynomial.
|
||||
*/ // TODO: To optimize boxing
|
||||
@JvmName("substitutePolynomial")
|
||||
public fun <C> LabeledPolynomial<C>.substitute(ring: Ring<C>, args: Map<Symbol, LabeledPolynomial<C>>) : LabeledPolynomial<C> =
|
||||
ring.labeledPolynomialSpace {
|
||||
coefficients.entries.fold(zero) { acc, (degs, c) ->
|
||||
val newDegs = degs.filterKeys { it !in args }
|
||||
acc + args.entries.fold(LabeledPolynomial<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> LabeledPolynomial<C>.substitute(ring: Ring<C>, args: Map<Symbol, LabeledRationalFunction<C>>) : LabeledRationalFunction<C> =
|
||||
ring.labeledRationalFunctionSpace {
|
||||
coefficients.entries.fold(zero) { acc, (degs, c) ->
|
||||
val newDegs = degs.filterKeys { it !in args }
|
||||
acc + args.entries.fold(LabeledRationalFunction(LabeledPolynomial<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 LabeledRationalFunction<Double>.substitute(args: Map<Symbol, Double>): LabeledRationalFunction<Double> =
|
||||
LabeledRationalFunction(numerator.substitute(args), denominator.substitute(args))
|
||||
|
||||
/**
|
||||
* Substitutes provided arguments [args] into [this] rational function.
|
||||
*/
|
||||
public fun <C> LabeledRationalFunction<C>.substitute(ring: Ring<C>, args: Map<Symbol, C>): LabeledRationalFunction<C> =
|
||||
LabeledRationalFunction(numerator.substitute(ring, args), denominator.substitute(ring, args))
|
||||
|
||||
/**
|
||||
* Substitutes provided arguments [args] into [this] rational function.
|
||||
*/ // TODO: To optimize calculation
|
||||
@JvmName("substitutePolynomial")
|
||||
public fun <C> LabeledRationalFunction<C>.substitute(ring: Ring<C>, args: Map<Symbol, LabeledPolynomial<C>>) : LabeledRationalFunction<C> =
|
||||
LabeledRationalFunction(numerator.substitute(ring, args), denominator.substitute(ring, args))
|
||||
|
||||
/**
|
||||
* Substitutes provided arguments [args] into [this] rational function.
|
||||
*/ // TODO: To optimize calculation
|
||||
@JvmName("substituteRationalFunction")
|
||||
public fun <C> LabeledRationalFunction<C>.substitute(ring: Ring<C>, args: Map<Symbol, LabeledRationalFunction<C>>) : LabeledRationalFunction<C> =
|
||||
ring.labeledRationalFunctionSpace {
|
||||
numerator.substitute(ring, args) / denominator.substitute(ring, args)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns algebraic derivative of received polynomial with respect to provided variable.
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public fun <C, A : Ring<C>> LabeledPolynomial<C>.derivativeWithRespectTo(
|
||||
algebra: A,
|
||||
variable: Symbol,
|
||||
): LabeledPolynomial<C> = algebra {
|
||||
LabeledPolynomial<C>(
|
||||
buildMap(coefficients.size) {
|
||||
coefficients
|
||||
.forEach { (degs, c) ->
|
||||
if (variable !in degs) return@forEach
|
||||
put(
|
||||
buildMap {
|
||||
degs.forEach { (vari, deg) ->
|
||||
when {
|
||||
vari != variable -> put(vari, deg)
|
||||
deg > 1u -> put(vari, deg - 1u)
|
||||
}
|
||||
}
|
||||
},
|
||||
multiplyByDoubling(c, degs[variable]!!)
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns algebraic derivative of received polynomial with respect to provided variable of specified order.
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public fun <C, A : Ring<C>> LabeledPolynomial<C>.nthDerivativeWithRespectTo(
|
||||
algebra: A,
|
||||
variable: Symbol,
|
||||
order: UInt
|
||||
): LabeledPolynomial<C> = algebra {
|
||||
if (order == 0u) return this@nthDerivativeWithRespectTo
|
||||
LabeledPolynomial<C>(
|
||||
buildMap(coefficients.size) {
|
||||
coefficients
|
||||
.forEach { (degs, c) ->
|
||||
if (degs.getOrElse(variable) { 0u } < order) return@forEach
|
||||
put(
|
||||
buildMap {
|
||||
degs.forEach { (vari, deg) ->
|
||||
when {
|
||||
vari != variable -> put(vari, deg)
|
||||
deg > order -> put(vari, deg - order)
|
||||
}
|
||||
}
|
||||
},
|
||||
degs[variable]!!.let { deg ->
|
||||
(deg downTo deg - order + 1u)
|
||||
.fold(c) { acc, ord -> multiplyByDoubling(acc, ord) }
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns algebraic derivative of received polynomial with respect to provided variables of specified orders.
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public fun <C, A : Ring<C>> LabeledPolynomial<C>.nthDerivativeWithRespectTo(
|
||||
algebra: A,
|
||||
variablesAndOrders: Map<Symbol, UInt>,
|
||||
): LabeledPolynomial<C> = algebra {
|
||||
val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u }
|
||||
if (filteredVariablesAndOrders.isEmpty()) return this@nthDerivativeWithRespectTo
|
||||
LabeledPolynomial<C>(
|
||||
buildMap(coefficients.size) {
|
||||
coefficients
|
||||
.forEach { (degs, c) ->
|
||||
if (filteredVariablesAndOrders.any { (variable, order) -> degs.getOrElse(variable) { 0u } < order }) return@forEach
|
||||
put(
|
||||
buildMap {
|
||||
degs.forEach { (vari, deg) ->
|
||||
if (vari !in filteredVariablesAndOrders) put(vari, deg)
|
||||
else {
|
||||
val order = filteredVariablesAndOrders[vari]!!
|
||||
if (deg > order) put(vari, deg - order)
|
||||
}
|
||||
}
|
||||
},
|
||||
filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) ->
|
||||
degs[index]!!.let { deg ->
|
||||
(deg downTo deg - order + 1u)
|
||||
.fold(acc1) { acc2, ord -> multiplyByDoubling(acc2, ord) }
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns algebraic antiderivative of received polynomial with respect to provided variable.
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public fun <C, A : Field<C>> LabeledPolynomial<C>.antiderivativeWithRespectTo(
|
||||
algebra: A,
|
||||
variable: Symbol,
|
||||
): LabeledPolynomial<C> = algebra {
|
||||
LabeledPolynomial<C>(
|
||||
buildMap(coefficients.size) {
|
||||
coefficients
|
||||
.forEach { (degs, c) ->
|
||||
val newDegs = buildMap<Symbol, UInt>(degs.size + 1) {
|
||||
put(variable, 1u)
|
||||
for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u })
|
||||
}
|
||||
put(
|
||||
newDegs,
|
||||
c / multiplyByDoubling(one, newDegs[variable]!!)
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns algebraic antiderivative of received polynomial with respect to provided variable of specified order.
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public fun <C, A : Field<C>> LabeledPolynomial<C>.nthAntiderivativeWithRespectTo(
|
||||
algebra: A,
|
||||
variable: Symbol,
|
||||
order: UInt
|
||||
): LabeledPolynomial<C> = algebra {
|
||||
if (order == 0u) return this@nthAntiderivativeWithRespectTo
|
||||
LabeledPolynomial<C>(
|
||||
buildMap(coefficients.size) {
|
||||
coefficients
|
||||
.forEach { (degs, c) ->
|
||||
val newDegs = buildMap<Symbol, UInt>(degs.size + 1) {
|
||||
put(variable, order)
|
||||
for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u })
|
||||
}
|
||||
put(
|
||||
newDegs,
|
||||
newDegs[variable]!!.let { deg ->
|
||||
(deg downTo deg - order + 1u)
|
||||
.fold(c) { acc, ord -> acc / multiplyByDoubling(one, ord) }
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns algebraic derivative of received polynomial with respect to provided variables of specified orders.
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public fun <C, A : Field<C>> LabeledPolynomial<C>.nthAntiderivativeWithRespectTo(
|
||||
algebra: A,
|
||||
variablesAndOrders: Map<Symbol, UInt>,
|
||||
): LabeledPolynomial<C> = algebra {
|
||||
val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u }
|
||||
if (filteredVariablesAndOrders.isEmpty()) return this@nthAntiderivativeWithRespectTo
|
||||
LabeledPolynomial<C>(
|
||||
buildMap(coefficients.size) {
|
||||
coefficients
|
||||
.forEach { (degs, c) ->
|
||||
val newDegs = buildMap<Symbol, UInt>(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) }
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
@ -3,6 +3,8 @@
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@file:Suppress("FunctionName", "NOTHING_TO_INLINE")
|
||||
|
||||
package space.kscience.kmath.functions
|
||||
|
||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||
@ -17,7 +19,6 @@ internal fun List<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)
|
||||
|
||||
@ -25,7 +26,6 @@ internal inline fun <C> NumberedPolynomialAsIs(coefs: Map<List<UInt>, C>) : Numb
|
||||
* Constructs [NumberedPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient".
|
||||
* The collections will be transformed to map with [toMap] and then will be used as is.
|
||||
*/
|
||||
@Suppress("FunctionName", "NOTHING_TO_INLINE")
|
||||
@PublishedApi
|
||||
internal inline fun <C> NumberedPolynomialAsIs(pairs: Collection<Pair<List<UInt>, C>>) : NumberedPolynomial<C> = NumberedPolynomial<C>(pairs.toMap())
|
||||
|
||||
@ -33,7 +33,6 @@ internal inline fun <C> NumberedPolynomialAsIs(pairs: Collection<Pair<List<UInt>
|
||||
* 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())
|
||||
|
||||
@ -43,7 +42,6 @@ internal inline fun <C> NumberedPolynomialAsIs(vararg pairs: Pair<List<UInt>, C>
|
||||
* **Be sure you read description of [NumberedPolynomial.coefficients]. Otherwise, you may make a mistake that will
|
||||
* cause wrong computation result or even runtime error.**
|
||||
*/
|
||||
@Suppress("FunctionName", "NOTHING_TO_INLINE")
|
||||
@DelicatePolynomialAPI
|
||||
public inline fun <C> NumberedPolynomialWithoutCheck(coefs: Map<List<UInt>, C>) : NumberedPolynomial<C> = NumberedPolynomial<C>(coefs)
|
||||
|
||||
@ -54,7 +52,6 @@ public inline fun <C> NumberedPolynomialWithoutCheck(coefs: Map<List<UInt>, C>)
|
||||
* **Be sure you read description of [NumberedPolynomial.coefficients]. Otherwise, you may make a mistake that will
|
||||
* cause wrong computation result or even runtime error.**
|
||||
*/
|
||||
@Suppress("FunctionName", "NOTHING_TO_INLINE")
|
||||
@DelicatePolynomialAPI
|
||||
public inline fun <C> NumberedPolynomialWithoutCheck(pairs: Collection<Pair<List<UInt>, C>>) : NumberedPolynomial<C> = NumberedPolynomial<C>(pairs.toMap())
|
||||
|
||||
@ -65,7 +62,6 @@ public inline fun <C> NumberedPolynomialWithoutCheck(pairs: Collection<Pair<List
|
||||
* **Be sure you read description of [NumberedPolynomial.coefficients]. Otherwise, you may make a mistake that will
|
||||
* cause wrong computation result or even runtime error.**
|
||||
*/
|
||||
@Suppress("FunctionName", "NOTHING_TO_INLINE")
|
||||
@DelicatePolynomialAPI
|
||||
public inline fun <C> NumberedPolynomialWithoutCheck(vararg pairs: Pair<List<UInt>, C>) : NumberedPolynomial<C> = NumberedPolynomial<C>(pairs.toMap())
|
||||
|
||||
@ -77,7 +73,6 @@ public inline fun <C> NumberedPolynomialWithoutCheck(vararg pairs: Pair<List<UIn
|
||||
* 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>()
|
||||
|
||||
@ -98,7 +93,6 @@ public fun <C> NumberedPolynomial(coefs: Map<List<UInt>, C>, add: (C, C) -> C) :
|
||||
* 1. Terms that happen to have the same signature will be summed up.
|
||||
* 1. New map will be formed of resulting terms.
|
||||
*/
|
||||
@Suppress("FunctionName")
|
||||
public fun <C> NumberedPolynomial(pairs: Collection<Pair<List<UInt>, C>>, add: (C, C) -> C) : NumberedPolynomial<C> {
|
||||
val fixedCoefs = mutableMapOf<List<UInt>, C>()
|
||||
|
||||
@ -119,7 +113,6 @@ public fun <C> NumberedPolynomial(pairs: Collection<Pair<List<UInt>, C>>, add: (
|
||||
* 1. Terms that happen to have the same signature will be summed up.
|
||||
* 1. New map will be formed of resulting terms.
|
||||
*/
|
||||
@Suppress("FunctionName")
|
||||
public fun <C> NumberedPolynomial(vararg pairs: Pair<List<UInt>, C>, add: (C, C) -> C) : NumberedPolynomial<C> {
|
||||
val fixedCoefs = mutableMapOf<List<UInt>, C>()
|
||||
|
||||
@ -142,7 +135,6 @@ public fun <C> NumberedPolynomial(vararg pairs: Pair<List<UInt>, C>, add: (C, C)
|
||||
* 1. Terms that happen to have the same signature will be summed up.
|
||||
* 1. New map will be formed of resulting terms.
|
||||
*/
|
||||
@Suppress("FunctionName", "NOTHING_TO_INLINE")
|
||||
public inline fun <C, A: Ring<C>> A.NumberedPolynomial(coefs: Map<List<UInt>, C>) : NumberedPolynomial<C> = NumberedPolynomial(coefs, ::add)
|
||||
/**
|
||||
* Constructs [NumberedPolynomial] with provided coefficients map [coefs].
|
||||
@ -152,7 +144,6 @@ public inline fun <C, A: Ring<C>> A.NumberedPolynomial(coefs: Map<List<UInt>, C>
|
||||
* 1. Terms that happen to have the same signature will be summed up.
|
||||
* 1. New map will be formed of resulting terms.
|
||||
*/
|
||||
@Suppress("FunctionName", "NOTHING_TO_INLINE")
|
||||
public inline fun <C, A: Ring<C>> NumberedPolynomialSpace<C, A>.NumberedPolynomial(coefs: Map<List<UInt>, C>) : NumberedPolynomial<C> = NumberedPolynomial(coefs) { left: C, right: C -> left + right }
|
||||
|
||||
/**
|
||||
@ -163,7 +154,6 @@ public inline fun <C, A: Ring<C>> NumberedPolynomialSpace<C, A>.NumberedPolynomi
|
||||
* 1. Terms that happen to have the same signature will be summed up.
|
||||
* 1. New map will be formed of resulting terms.
|
||||
*/
|
||||
@Suppress("FunctionName", "NOTHING_TO_INLINE")
|
||||
public inline fun <C, A: Ring<C>> NumberedRationalFunctionSpace<C, A>.NumberedPolynomial(coefs: Map<List<UInt>, C>) : NumberedPolynomial<C> = NumberedPolynomial(coefs) { left: C, right: C -> left + right }
|
||||
|
||||
/**
|
||||
@ -174,7 +164,6 @@ public inline fun <C, A: Ring<C>> NumberedRationalFunctionSpace<C, A>.NumberedPo
|
||||
* 1. Terms that happen to have the same signature will be summed up.
|
||||
* 1. New map will be formed of resulting terms.
|
||||
*/
|
||||
@Suppress("FunctionName", "NOTHING_TO_INLINE")
|
||||
public inline fun <C, A: Ring<C>> A.NumberedPolynomial(pairs: Collection<Pair<List<UInt>, C>>) : NumberedPolynomial<C> = NumberedPolynomial(pairs, ::add)
|
||||
|
||||
/**
|
||||
@ -185,7 +174,6 @@ public inline fun <C, A: Ring<C>> A.NumberedPolynomial(pairs: Collection<Pair<Li
|
||||
* 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".
|
||||
@ -195,7 +183,6 @@ public inline fun <C, A: Ring<C>> NumberedPolynomialSpace<C, A>.NumberedPolynomi
|
||||
* 1. Terms that happen to have the same signature will be summed up.
|
||||
* 1. New map will be formed of resulting terms.
|
||||
*/
|
||||
@Suppress("FunctionName", "NOTHING_TO_INLINE")
|
||||
public inline fun <C, A: Ring<C>> NumberedRationalFunctionSpace<C, A>.NumberedPolynomial(pairs: Collection<Pair<List<UInt>, C>>) : NumberedPolynomial<C> = NumberedPolynomial(pairs) { left: C, right: C -> left + right }
|
||||
|
||||
/**
|
||||
@ -206,7 +193,6 @@ public inline fun <C, A: Ring<C>> NumberedRationalFunctionSpace<C, A>.NumberedPo
|
||||
* 1. Terms that happen to have the same signature will be summed up.
|
||||
* 1. New map will be formed of resulting terms.
|
||||
*/
|
||||
@Suppress("FunctionName", "NOTHING_TO_INLINE")
|
||||
public inline fun <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".
|
||||
@ -216,7 +202,6 @@ public inline fun <C, A: Ring<C>> A.NumberedPolynomial(vararg pairs: Pair<List<U
|
||||
* 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".
|
||||
@ -226,13 +211,11 @@ public inline fun <C, A: Ring<C>> NumberedPolynomialSpace<C, A>.NumberedPolynomi
|
||||
* 1. Terms that happen to have the same signature will be summed up.
|
||||
* 1. New map will be formed of resulting terms.
|
||||
*/
|
||||
@Suppress("FunctionName", "NOTHING_TO_INLINE")
|
||||
public inline fun <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))
|
||||
|
||||
/**
|
||||
@ -269,6 +252,7 @@ public class NumberedPolynomialTermSignatureBuilder {
|
||||
*
|
||||
* In fact, it just returns [signature] as regular signature of type `List<UInt>`.
|
||||
*/
|
||||
@PublishedApi
|
||||
internal fun build(): List<UInt> = signature
|
||||
|
||||
/**
|
||||
@ -344,8 +328,7 @@ public class NumberedPolynomialBuilder<C>(
|
||||
* 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
|
||||
coefficients[signature] = if (signature in coefficients) add(coefficients[signature]!!, this@with) else this@with
|
||||
}
|
||||
/**
|
||||
* Declares monomial with [this] coefficient and signature constructed by [block].
|
||||
@ -361,7 +344,7 @@ public class NumberedPolynomialBuilder<C>(
|
||||
* Declaring another monomial with the same signature will add [this] coefficient to existing one. If the sum of such
|
||||
* coefficients is zero at any moment the monomial won't be removed but will be left as it is.
|
||||
*/
|
||||
public operator fun C.invoke(block: NumberedPolynomialTermSignatureBuilder.() -> Unit): Unit =
|
||||
public inline operator fun C.invoke(block: NumberedPolynomialTermSignatureBuilder.() -> Unit): Unit =
|
||||
this with NumberedPolynomialTermSignatureBuilder().apply(block).build()
|
||||
}
|
||||
|
||||
@ -385,7 +368,6 @@ public class NumberedPolynomialBuilder<C>(
|
||||
// 2. Union types are implemented. Then all three functions should be rewritten
|
||||
// as one with single union type as a (context) receiver.
|
||||
//@UnstableKMathAPI
|
||||
//@Suppress("FunctionName")
|
||||
//public inline fun <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.
|
||||
@ -401,7 +383,6 @@ public class NumberedPolynomialBuilder<C>(
|
||||
* ```
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
@Suppress("FunctionName")
|
||||
public inline fun <C, A: Ring<C>> NumberedPolynomialSpace<C, A>.NumberedPolynomial(initialCapacity: Int = 0, 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.
|
||||
@ -417,7 +398,6 @@ public inline fun <C, A: Ring<C>> NumberedPolynomialSpace<C, A>.NumberedPolynomi
|
||||
* ```
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
@Suppress("FunctionName")
|
||||
public inline fun <C, A: Ring<C>> NumberedRationalFunctionSpace<C, A>.NumberedPolynomial(initialCapacity: Int = 0, 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
|
||||
@ -430,7 +410,6 @@ public inline fun <C, A: Ring<C>> NumberedRationalFunctionSpace<C, A>.NumberedPo
|
||||
* 1. Terms that happen to have the same signature will be summed up.
|
||||
* 1. New map will be formed of resulting terms.
|
||||
*/
|
||||
@Suppress("FunctionName")
|
||||
public fun <C, A: Ring<C>> A.NumberedRationalFunction(numeratorCoefficients: Map<List<UInt>, C>, denominatorCoefficients: Map<List<UInt>, C>): NumberedRationalFunction<C> =
|
||||
NumberedRationalFunction<C>(
|
||||
NumberedPolynomial(numeratorCoefficients),
|
||||
@ -444,7 +423,6 @@ public fun <C, A: Ring<C>> A.NumberedRationalFunction(numeratorCoefficients: Map
|
||||
* 1. Terms that happen to have the same signature will be summed up.
|
||||
* 1. New map will be formed of resulting terms.
|
||||
*/
|
||||
@Suppress("FunctionName")
|
||||
public fun <C, A: Ring<C>> NumberedRationalFunctionSpace<C, A>.NumberedRationalFunction(numeratorCoefficients: Map<List<UInt>, C>, denominatorCoefficients: Map<List<UInt>, C>): NumberedRationalFunction<C> =
|
||||
NumberedRationalFunction<C>(
|
||||
NumberedPolynomial(numeratorCoefficients),
|
||||
@ -454,13 +432,11 @@ public fun <C, A: Ring<C>> NumberedRationalFunctionSpace<C, A>.NumberedRationalF
|
||||
/**
|
||||
* 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)
|
||||
|
||||
@ -473,7 +449,6 @@ public fun <C, A: Ring<C>> NumberedRationalFunctionSpace<C, A>.NumberedRationalF
|
||||
* 1. Terms that happen to have the same signature will be summed up.
|
||||
* 1. New map will be formed of resulting terms.
|
||||
*/
|
||||
@Suppress("FunctionName")
|
||||
public fun <C, A: Ring<C>> NumberedRationalFunctionSpace<C, A>.NumberedRationalFunction(numeratorCoefficients: Map<List<UInt>, C>): NumberedRationalFunction<C> =
|
||||
NumberedRationalFunction<C>(
|
||||
NumberedPolynomial(numeratorCoefficients),
|
||||
@ -488,7 +463,6 @@ public fun <C, A: Ring<C>> NumberedRationalFunctionSpace<C, A>.NumberedRationalF
|
||||
* 1. Terms that happen to have the same signature will be summed up.
|
||||
* 1. New map will be formed of resulting terms.
|
||||
*/
|
||||
@Suppress("FunctionName")
|
||||
public fun <C, A: Ring<C>> A.NumberedRationalFunction(numeratorCoefficients: Map<List<UInt>, C>): NumberedRationalFunction<C> =
|
||||
NumberedRationalFunction<C>(
|
||||
NumberedPolynomial(numeratorCoefficients),
|
||||
@ -496,7 +470,7 @@ public fun <C, A: Ring<C>> A.NumberedRationalFunction(numeratorCoefficients: Map
|
||||
)
|
||||
|
||||
///**
|
||||
// * Converts [this] coefficient to [NumberedRationalFunction].
|
||||
// * Converts [this] constant to [NumberedRationalFunction].
|
||||
// */
|
||||
//context(A)
|
||||
//public fun <C, A: Ring<C>> C.asNumberedRationalFunction() : NumberedRationalFunction<C> =
|
||||
@ -505,7 +479,7 @@ public fun <C, A: Ring<C>> A.NumberedRationalFunction(numeratorCoefficients: Map
|
||||
// NumberedPolynomialAsIs(mapOf(emptyList<UInt>() to one))
|
||||
// )
|
||||
///**
|
||||
// * Converts [this] coefficient to [NumberedRationalFunction].
|
||||
// * Converts [this] constant to [NumberedRationalFunction].
|
||||
// */
|
||||
//context(NumberedRationalFunctionSpace<C, A>)
|
||||
//public fun <C, A: Ring<C>> C.asNumberedRationalFunction() : NumberedRationalFunction<C> =
|
||||
|
@ -51,15 +51,14 @@ public inline fun <C, A : Ring<C>, R> A.numberedRationalFunctionSpace(block: Num
|
||||
*/
|
||||
public fun NumberedPolynomial<Double>.substitute(args: Map<Int, Double>): NumberedPolynomial<Double> = Double.algebra {
|
||||
NumberedPolynomial<Double>(
|
||||
buildMap<List<UInt>, Double>(coefficients.size) {
|
||||
buildMap(coefficients.size) {
|
||||
for ((degs, c) in coefficients) {
|
||||
val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp()
|
||||
val newC = args.entries.fold(c) { product, (variable, substitution) ->
|
||||
val deg = degs.getOrElse(variable) { 0u }
|
||||
if (deg == 0u) product else product * substitution.pow(deg.toInt())
|
||||
}
|
||||
if (newDegs !in this) this[newDegs] = newC
|
||||
else this[newDegs] = this[newDegs]!! + newC
|
||||
this[newDegs] = if (newDegs !in this) newC else this[newDegs]!! + newC
|
||||
}
|
||||
}
|
||||
)
|
||||
@ -70,15 +69,14 @@ public fun NumberedPolynomial<Double>.substitute(args: Map<Int, Double>): Number
|
||||
*/
|
||||
public fun <C> NumberedPolynomial<C>.substitute(ring: Ring<C>, args: Map<Int, C>): NumberedPolynomial<C> = ring {
|
||||
NumberedPolynomial<C>(
|
||||
buildMap<List<UInt>, C>(coefficients.size) {
|
||||
buildMap(coefficients.size) {
|
||||
for ((degs, c) in coefficients) {
|
||||
val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp()
|
||||
val newC = args.entries.fold(c) { product, (variable, substitution) ->
|
||||
val deg = degs.getOrElse(variable) { 0u }
|
||||
if (deg == 0u) product else product * power(substitution, deg)
|
||||
}
|
||||
if (newDegs !in this) this[newDegs] = newC
|
||||
else this[newDegs] = this[newDegs]!! + newC
|
||||
this[newDegs] = if (newDegs !in this) newC else this[newDegs]!! + newC
|
||||
}
|
||||
}
|
||||
)
|
||||
@ -128,14 +126,14 @@ public fun <C> NumberedRationalFunction<C>.substitute(ring: Ring<C>, args: Map<I
|
||||
|
||||
/**
|
||||
* Substitutes provided arguments [args] into [this] rational function.
|
||||
*/ // TODO: To optimize boxing
|
||||
*/ // TODO: To optimize calculation
|
||||
@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
|
||||
*/ // TODO: To optimize calculation
|
||||
@JvmName("substituteRationalFunction")
|
||||
public fun <C> NumberedRationalFunction<C>.substitute(ring: Ring<C>, args: Map<Int, NumberedRationalFunction<C>>) : NumberedRationalFunction<C> =
|
||||
ring.numberedRationalFunctionSpace {
|
||||
@ -250,14 +248,14 @@ public fun <C> NumberedRationalFunction<C>.substitute(ring: Ring<C>, args: Buffe
|
||||
|
||||
/**
|
||||
* Substitutes provided arguments [args] into [this] rational function.
|
||||
*/ // TODO: To optimize boxing
|
||||
*/ // TODO: To optimize calculation
|
||||
@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
|
||||
*/ // TODO: To optimize calculation
|
||||
@JvmName("substituteRationalFunction")
|
||||
public fun <C> NumberedRationalFunction<C>.substitute(ring: Ring<C>, args: Buffer<NumberedRationalFunction<C>>) : NumberedRationalFunction<C> =
|
||||
ring.numberedRationalFunctionSpace {
|
||||
|
Loading…
Reference in New Issue
Block a user