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].
|
||||
*/
|
||||
|
@ -7,26 +7,25 @@ package space.kscience.kmath.functions
|
||||
|
||||
import space.kscience.kmath.expressions.Symbol
|
||||
import space.kscience.kmath.operations.Ring
|
||||
import space.kscience.kmath.operations.ScaleOperations
|
||||
import kotlin.jvm.JvmName
|
||||
import kotlin.math.max
|
||||
|
||||
|
||||
/**
|
||||
* Represents multivariate polynomials with labeled variables.
|
||||
* 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 Ring in which the polynomial is considered.
|
||||
* @param C the type of constants.
|
||||
*/
|
||||
public data class LabeledPolynomial<C>
|
||||
@PublishedApi
|
||||
internal constructor(
|
||||
/**
|
||||
* Map that collects coefficients of the polynomial. Every non-zero monomial
|
||||
* `a x_1^{d_1} ... x_n^{d_n}` is represented as pair "key-value" in the map, where value is coefficients `a` and
|
||||
* key is map that associates variables in the monomial with multiplicity of them occurring in the monomial.
|
||||
* For example polynomial
|
||||
* ```
|
||||
* 5 a^2 c^3 - 6 b + 0 b c
|
||||
* ```
|
||||
* has coefficients represented as
|
||||
* 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(
|
||||
@ -38,6 +37,22 @@ internal constructor(
|
||||
* ) 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>
|
||||
@ -46,69 +61,88 @@ internal constructor(
|
||||
}
|
||||
|
||||
/**
|
||||
* Space of polynomials.
|
||||
* 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 operated polynomials.
|
||||
* @param A the intersection of [Ring] of [C] and [ScaleOperations] of [C].
|
||||
* @param ring the [A] instance.
|
||||
* @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) LabeledPolynomial<C>(mapOf(
|
||||
if (other == 0) LabeledPolynomialAsIs(mapOf(
|
||||
mapOf(this@plus to 1U) to constantOne,
|
||||
))
|
||||
else LabeledPolynomial<C>(mapOf(
|
||||
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) LabeledPolynomial<C>(mapOf(
|
||||
if (other == 0) LabeledPolynomialAsIs(mapOf(
|
||||
mapOf(this@minus to 1U) to -constantOne,
|
||||
))
|
||||
else LabeledPolynomial<C>(mapOf(
|
||||
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 LabeledPolynomial<C>(mapOf(
|
||||
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) LabeledPolynomial<C>(mapOf(
|
||||
if (this == 0) LabeledPolynomialAsIs(mapOf(
|
||||
mapOf(other to 1U) to constantOne,
|
||||
))
|
||||
else LabeledPolynomial<C>(mapOf(
|
||||
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) LabeledPolynomial<C>(mapOf(
|
||||
if (this == 0) LabeledPolynomialAsIs(mapOf(
|
||||
mapOf(other to 1U) to -constantOne,
|
||||
))
|
||||
else LabeledPolynomial<C>(mapOf(
|
||||
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 LabeledPolynomial<C>(mapOf(
|
||||
else LabeledPolynomialAsIs(mapOf(
|
||||
mapOf(other to 1U) to constantOne * this@times,
|
||||
))
|
||||
|
||||
/**
|
||||
* Returns sum of the polynomial and the integer represented as polynomial.
|
||||
* Returns sum of the polynomial and the integer represented as a polynomial.
|
||||
*
|
||||
* The operation is equivalent to adding [other] copies of unit polynomial to [this].
|
||||
*/
|
||||
public override operator fun LabeledPolynomial<C>.plus(other: Int): LabeledPolynomial<C> =
|
||||
if (other == 0) this
|
||||
else with(coefficients) {
|
||||
if (isEmpty()) LabeledPolynomial<C>(mapOf(emptyMap<Symbol, UInt>() to other.asConstant()))
|
||||
else LabeledPolynomial<C>(
|
||||
if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap<Symbol, UInt>() to other.asConstant()))
|
||||
else LabeledPolynomialAsIs(
|
||||
toMutableMap()
|
||||
.apply {
|
||||
val degs = emptyMap<Symbol, UInt>()
|
||||
@ -118,15 +152,15 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
|
||||
)
|
||||
}
|
||||
/**
|
||||
* Returns difference between the polynomial and the integer represented as polynomial.
|
||||
* Returns difference between the polynomial and the integer represented as a polynomial.
|
||||
*
|
||||
* The operation is equivalent to subtraction [other] copies of unit polynomial from [this].
|
||||
*/
|
||||
public override operator fun LabeledPolynomial<C>.minus(other: Int): LabeledPolynomial<C> =
|
||||
if (other == 0) this
|
||||
else with(coefficients) {
|
||||
if (isEmpty()) LabeledPolynomial<C>(mapOf(emptyMap<Symbol, UInt>() to (-other).asConstant()))
|
||||
else LabeledPolynomial<C>(
|
||||
if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap<Symbol, UInt>() to (-other).asConstant()))
|
||||
else LabeledPolynomialAsIs(
|
||||
toMutableMap()
|
||||
.apply {
|
||||
val degs = emptyMap<Symbol, UInt>()
|
||||
@ -136,7 +170,7 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
|
||||
)
|
||||
}
|
||||
/**
|
||||
* Returns product of the polynomial and the integer represented as polynomial.
|
||||
* Returns product of the polynomial and the integer represented as a polynomial.
|
||||
*
|
||||
* The operation is equivalent to sum of [other] copies of [this].
|
||||
*/
|
||||
@ -151,15 +185,15 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
|
||||
)
|
||||
|
||||
/**
|
||||
* Returns sum of the integer represented as polynomial and the polynomial.
|
||||
* Returns sum of the integer represented as a polynomial and the polynomial.
|
||||
*
|
||||
* The operation is equivalent to adding [this] copies of unit polynomial to [other].
|
||||
*/
|
||||
public override operator fun Int.plus(other: LabeledPolynomial<C>): LabeledPolynomial<C> =
|
||||
if (this == 0) other
|
||||
else with(other.coefficients) {
|
||||
if (isEmpty()) LabeledPolynomial<C>(mapOf(emptyMap<Symbol, UInt>() to this@plus.asConstant()))
|
||||
else LabeledPolynomial<C>(
|
||||
if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap<Symbol, UInt>() to this@plus.asConstant()))
|
||||
else LabeledPolynomialAsIs(
|
||||
toMutableMap()
|
||||
.apply {
|
||||
val degs = emptyMap<Symbol, UInt>()
|
||||
@ -169,17 +203,19 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
|
||||
)
|
||||
}
|
||||
/**
|
||||
* Returns difference between the integer represented as polynomial and the polynomial.
|
||||
* Returns difference between the integer represented as a polynomial and the polynomial.
|
||||
*
|
||||
* The operation is equivalent to subtraction [this] copies of unit polynomial from [other].
|
||||
*/
|
||||
public override operator fun Int.minus(other: LabeledPolynomial<C>): LabeledPolynomial<C> =
|
||||
if (this == 0) other
|
||||
else with(other.coefficients) {
|
||||
if (isEmpty()) LabeledPolynomial<C>(mapOf(emptyMap<Symbol, UInt>() to this@minus.asConstant()))
|
||||
else LabeledPolynomial<C>(
|
||||
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 }
|
||||
@ -187,7 +223,7 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
|
||||
)
|
||||
}
|
||||
/**
|
||||
* Returns product of the integer represented as polynomial and the polynomial.
|
||||
* Returns product of the integer represented as a polynomial and the polynomial.
|
||||
*
|
||||
* The operation is equivalent to sum of [this] copies of [other].
|
||||
*/
|
||||
@ -206,43 +242,61 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
|
||||
*/
|
||||
public override fun number(value: Int): LabeledPolynomial<C> = number(constantNumber(value))
|
||||
|
||||
public override operator fun C.plus(other: Symbol): LabeledPolynomial<C> =
|
||||
LabeledPolynomial<C>(mapOf(
|
||||
mapOf(other to 1U) to constantOne,
|
||||
emptyMap<Symbol, UInt>() to this@plus,
|
||||
))
|
||||
public override operator fun C.minus(other: Symbol): LabeledPolynomial<C> =
|
||||
LabeledPolynomial<C>(mapOf(
|
||||
mapOf(other to 1U) to -constantOne,
|
||||
emptyMap<Symbol, UInt>() to this@minus,
|
||||
))
|
||||
public override operator fun C.times(other: Symbol): LabeledPolynomial<C> =
|
||||
LabeledPolynomial<C>(mapOf(
|
||||
mapOf(other to 1U) to this@times,
|
||||
))
|
||||
|
||||
/**
|
||||
* 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> =
|
||||
LabeledPolynomial<C>(mapOf(
|
||||
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> =
|
||||
LabeledPolynomial<C>(mapOf(
|
||||
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> =
|
||||
LabeledPolynomial<C>(mapOf(
|
||||
LabeledPolynomialAsIs(mapOf(
|
||||
mapOf(this@times to 1U) to other,
|
||||
))
|
||||
|
||||
/**
|
||||
* Returns sum of the constant represented as polynomial and the polynomial.
|
||||
* 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()) LabeledPolynomial<C>(mapOf(emptyMap<Symbol, UInt>() to this@plus))
|
||||
else LabeledPolynomial<C>(
|
||||
if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap<Symbol, UInt>() to this@plus))
|
||||
else LabeledPolynomialAsIs(
|
||||
toMutableMap()
|
||||
.apply {
|
||||
val degs = emptyMap<Symbol, UInt>()
|
||||
@ -252,12 +306,12 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
|
||||
)
|
||||
}
|
||||
/**
|
||||
* Returns difference between the constant represented as polynomial and the polynomial.
|
||||
* 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()) LabeledPolynomial<C>(mapOf(emptyMap<Symbol, UInt>() to this@minus))
|
||||
else LabeledPolynomial<C>(
|
||||
if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap<Symbol, UInt>() to this@minus))
|
||||
else LabeledPolynomialAsIs(
|
||||
toMutableMap()
|
||||
.apply {
|
||||
forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c }
|
||||
@ -269,10 +323,10 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
|
||||
)
|
||||
}
|
||||
/**
|
||||
* Returns product of the constant represented as polynomial and the polynomial.
|
||||
* Returns product of the constant represented as a polynomial and the polynomial.
|
||||
*/
|
||||
override operator fun C.times(other: LabeledPolynomial<C>): LabeledPolynomial<C> =
|
||||
LabeledPolynomial<C>(
|
||||
LabeledPolynomialAsIs(
|
||||
other.coefficients
|
||||
.toMutableMap()
|
||||
.apply {
|
||||
@ -281,12 +335,12 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
|
||||
)
|
||||
|
||||
/**
|
||||
* Returns sum of the constant represented as polynomial and the polynomial.
|
||||
* 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()) LabeledPolynomial<C>(mapOf(emptyMap<Symbol, UInt>() to other))
|
||||
else LabeledPolynomial<C>(
|
||||
if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap<Symbol, UInt>() to other))
|
||||
else LabeledPolynomialAsIs(
|
||||
toMutableMap()
|
||||
.apply {
|
||||
val degs = emptyMap<Symbol, UInt>()
|
||||
@ -296,12 +350,12 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
|
||||
)
|
||||
}
|
||||
/**
|
||||
* Returns difference between the constant represented as polynomial and the polynomial.
|
||||
* 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()) LabeledPolynomial<C>(mapOf(emptyMap<Symbol, UInt>() to other))
|
||||
else LabeledPolynomial<C>(
|
||||
if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap<Symbol, UInt>() to other))
|
||||
else LabeledPolynomialAsIs(
|
||||
toMutableMap()
|
||||
.apply {
|
||||
forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c }
|
||||
@ -313,10 +367,10 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
|
||||
)
|
||||
}
|
||||
/**
|
||||
* Returns product of the constant represented as polynomial and the polynomial.
|
||||
* Returns product of the constant represented as a polynomial and the polynomial.
|
||||
*/
|
||||
override operator fun LabeledPolynomial<C>.times(other: C): LabeledPolynomial<C> =
|
||||
LabeledPolynomial<C>(
|
||||
LabeledPolynomialAsIs(
|
||||
coefficients
|
||||
.toMutableMap()
|
||||
.apply {
|
||||
@ -330,40 +384,58 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
|
||||
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> =
|
||||
LabeledPolynomial<C>(mapOf(
|
||||
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> =
|
||||
LabeledPolynomial<C>(mapOf(
|
||||
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) LabeledPolynomial<C>(mapOf(
|
||||
if (this == other) LabeledPolynomialAsIs(mapOf(
|
||||
mapOf(this to 1U) to constantOne * 2
|
||||
))
|
||||
else LabeledPolynomial<C>(mapOf(
|
||||
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 LabeledPolynomial<C>(mapOf(
|
||||
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) LabeledPolynomial<C>(mapOf(
|
||||
if (this == other) LabeledPolynomialAsIs(mapOf(
|
||||
mapOf(this to 2U) to constantOne
|
||||
))
|
||||
else LabeledPolynomial<C>(mapOf(
|
||||
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()) LabeledPolynomial<C>(mapOf(mapOf(this@plus to 1u) to constantOne))
|
||||
else LabeledPolynomial<C>(
|
||||
if (isEmpty()) LabeledPolynomialAsIs(mapOf(mapOf(this@plus to 1u) to constantOne))
|
||||
else LabeledPolynomialAsIs(
|
||||
toMutableMap()
|
||||
.apply {
|
||||
val degs = mapOf(this@plus to 1U)
|
||||
@ -372,30 +444,39 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
|
||||
}
|
||||
)
|
||||
}
|
||||
/**
|
||||
* 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()) LabeledPolynomial<C>(mapOf(mapOf(this@minus to 1u) to constantOne))
|
||||
else LabeledPolynomial<C>(
|
||||
if (isEmpty()) LabeledPolynomialAsIs(mapOf(mapOf(this@minus to 1u) to constantOne))
|
||||
else LabeledPolynomialAsIs(
|
||||
toMutableMap()
|
||||
.apply {
|
||||
forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c }
|
||||
|
||||
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> =
|
||||
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()) LabeledPolynomial<C>(mapOf(mapOf(other to 1u) to constantOne))
|
||||
else LabeledPolynomial<C>(
|
||||
if (isEmpty()) LabeledPolynomialAsIs(mapOf(mapOf(other to 1u) to constantOne))
|
||||
else LabeledPolynomialAsIs(
|
||||
toMutableMap()
|
||||
.apply {
|
||||
val degs = mapOf(other to 1U)
|
||||
@ -404,10 +485,13 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
|
||||
}
|
||||
)
|
||||
}
|
||||
/**
|
||||
* 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()) LabeledPolynomial<C>(mapOf(mapOf(other to 1u) to constantOne))
|
||||
else LabeledPolynomial<C>(
|
||||
if (isEmpty()) LabeledPolynomialAsIs(mapOf(mapOf(other to 1u) to constantOne))
|
||||
else LabeledPolynomialAsIs(
|
||||
toMutableMap()
|
||||
.apply {
|
||||
val degs = mapOf(other to 1U)
|
||||
@ -416,8 +500,11 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
|
||||
}
|
||||
)
|
||||
}
|
||||
/**
|
||||
* Returns product of the polynomial and the variable represented as a monic monomial.
|
||||
*/
|
||||
public override operator fun LabeledPolynomial<C>.times(other: Symbol): LabeledPolynomial<C> =
|
||||
LabeledPolynomial<C>(
|
||||
LabeledPolynomialAsIs(
|
||||
coefficients
|
||||
.mapKeys { (degs, _) -> degs.toMutableMap().also{ it[other] = if (other in it) it[other]!! + 1U else 1U } }
|
||||
)
|
||||
@ -426,14 +513,14 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
|
||||
* Returns negation of the polynomial.
|
||||
*/
|
||||
override fun LabeledPolynomial<C>.unaryMinus(): LabeledPolynomial<C> =
|
||||
LabeledPolynomial<C>(
|
||||
LabeledPolynomialAsIs(
|
||||
coefficients.mapValues { -it.value }
|
||||
)
|
||||
/**
|
||||
* Returns sum of the polynomials.
|
||||
*/
|
||||
override operator fun LabeledPolynomial<C>.plus(other: LabeledPolynomial<C>): 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 }
|
||||
@ -443,7 +530,7 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
|
||||
* Returns difference of the polynomials.
|
||||
*/
|
||||
override operator fun LabeledPolynomial<C>.minus(other: LabeledPolynomial<C>): 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 }
|
||||
@ -453,7 +540,7 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
|
||||
* Returns product of the polynomials.
|
||||
*/
|
||||
override operator fun LabeledPolynomial<C>.times(other: LabeledPolynomial<C>): 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()
|
||||
@ -467,18 +554,18 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
|
||||
/**
|
||||
* Instance of zero polynomial (zero of the polynomial ring).
|
||||
*/
|
||||
override val zero: LabeledPolynomial<C> = LabeledPolynomial<C>(mapOf(emptyMap<Symbol, UInt>() to constantZero))
|
||||
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> = LabeledPolynomial<C>(mapOf(emptyMap<Symbol, UInt>() to constantOne))
|
||||
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, c) -> degs.values.sum().toInt() } ?: -1
|
||||
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.
|
||||
@ -518,22 +605,17 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
|
||||
*/
|
||||
public override val LabeledPolynomial<C>.countOfVariables: Int get() = variables.size
|
||||
|
||||
// @Suppress("NOTHING_TO_INLINE")
|
||||
// public inline fun LabeledPolynomial<C>.substitute(argument: Map<Symbol, C>): LabeledPolynomial<C> = this.substitute(ring, argument)
|
||||
// @Suppress("NOTHING_TO_INLINE")
|
||||
// @JvmName("substitutePolynomial")
|
||||
// public inline fun LabeledPolynomial<C>.substitute(argument: Map<Symbol, LabeledPolynomial<C>>): LabeledPolynomial<C> = this.substitute(ring, argument)
|
||||
//
|
||||
// @Suppress("NOTHING_TO_INLINE")
|
||||
// public inline fun LabeledPolynomial<C>.asFunction(): (Map<Symbol, C>) -> LabeledPolynomial<C> = { this.substitute(ring, it) }
|
||||
// @Suppress("NOTHING_TO_INLINE")
|
||||
// public inline fun LabeledPolynomial<C>.asFunctionOnConstants(): (Map<Symbol, C>) -> LabeledPolynomial<C> = { this.substitute(ring, it) }
|
||||
// @Suppress("NOTHING_TO_INLINE")
|
||||
// public inline fun LabeledPolynomial<C>.asFunctionOnPolynomials(): (Map<Symbol, LabeledPolynomial<C>>) -> LabeledPolynomial<C> = { this.substitute(ring, it) }
|
||||
//
|
||||
// @Suppress("NOTHING_TO_INLINE")
|
||||
// public inline operator fun LabeledPolynomial<C>.invoke(argument: Map<Symbol, C>): LabeledPolynomial<C> = this.substitute(ring, argument)
|
||||
// @Suppress("NOTHING_TO_INLINE")
|
||||
// @JvmName("invokePolynomial")
|
||||
// public inline operator fun LabeledPolynomial<C>.invoke(argument: Map<Symbol, LabeledPolynomial<C>>): LabeledPolynomial<C> = this.substitute(ring, argument)
|
||||
// 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)
|
||||
}
|
@ -7,9 +7,12 @@ package space.kscience.kmath.functions
|
||||
|
||||
import space.kscience.kmath.expressions.Symbol
|
||||
import space.kscience.kmath.operations.Ring
|
||||
import space.kscience.kmath.operations.invoke
|
||||
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>
|
||||
@ -17,6 +20,13 @@ public class LabeledRationalFunction<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,
|
||||
) :
|
||||
@ -34,106 +44,53 @@ public class LabeledRationalFunctionSpace<C, A: Ring<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
|
||||
/**
|
||||
* Instance of zero rational function (zero of the rational functions ring).
|
||||
* Substitutes provided constant [argument] into [this] polynomial.
|
||||
*/
|
||||
public override val zero: LabeledRationalFunction<C> = LabeledRationalFunction<C>(polynomialZero, polynomialOne)
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun LabeledPolynomial<C>.substitute(argument: Map<Symbol, C>): LabeledPolynomial<C> = substitute(ring, argument)
|
||||
/**
|
||||
* Instance of unit polynomial (unit of the rational functions ring).
|
||||
* Substitutes provided polynomial [argument] into [this] polynomial.
|
||||
*/
|
||||
public override val one: LabeledRationalFunction<C> = LabeledRationalFunction<C>(polynomialOne, polynomialOne)
|
||||
|
||||
// TODO: Разобрать
|
||||
|
||||
// operator fun invoke(arg: Map<Symbol, C>): LabeledRationalFunction<C> =
|
||||
// LabeledRationalFunction(
|
||||
// numerator(arg),
|
||||
// denominator(arg)
|
||||
// )
|
||||
//
|
||||
// @JvmName("invokeLabeledPolynomial")
|
||||
// operator fun invoke(arg: Map<Symbol, LabeledPolynomial<C>>): LabeledRationalFunction<C> =
|
||||
// LabeledRationalFunction(
|
||||
// numerator(arg),
|
||||
// denominator(arg)
|
||||
// )
|
||||
//
|
||||
// @JvmName("invokeLabeledRationalFunction")
|
||||
// operator fun invoke(arg: Map<Symbol, LabeledRationalFunction<C>>): LabeledRationalFunction<C> {
|
||||
// var num = numerator invokeRFTakeNumerator arg
|
||||
// var den = denominator invokeRFTakeNumerator arg
|
||||
// for (variable in variables) if (variable in arg) {
|
||||
// val degreeDif = degrees[variable]!!
|
||||
// if (degreeDif > 0)
|
||||
// den = multiplyByPower(den, arg[variable]!!.denominator, degreeDif)
|
||||
// else
|
||||
// num = multiplyByPower(num, arg[variable]!!.denominator, -degreeDif)
|
||||
// }
|
||||
// return LabeledRationalFunction(num, den)
|
||||
// }
|
||||
//
|
||||
// override fun toString(): String = toString(emptyMap())
|
||||
//
|
||||
// fun toString(names: Map<Symbol, String> = emptyMap()): String =
|
||||
// when (true) {
|
||||
// numerator.isZero() -> "0"
|
||||
// denominator.isOne() -> numerator.toString(names)
|
||||
// else -> "${numerator.toStringWithBrackets(names)}/${denominator.toStringWithBrackets(names)}"
|
||||
// }
|
||||
//
|
||||
// fun toString(namer: (Symbol) -> String): String =
|
||||
// when (true) {
|
||||
// numerator.isZero() -> "0"
|
||||
// denominator.isOne() -> numerator.toString(namer)
|
||||
// else -> "${numerator.toStringWithBrackets(namer)}/${denominator.toStringWithBrackets(namer)}"
|
||||
// }
|
||||
//
|
||||
// fun toStringWithBrackets(names: Map<Symbol, String> = emptyMap()): String =
|
||||
// when (true) {
|
||||
// numerator.isZero() -> "0"
|
||||
// denominator.isOne() -> numerator.toStringWithBrackets(names)
|
||||
// else -> "(${numerator.toStringWithBrackets(names)}/${denominator.toStringWithBrackets(names)})"
|
||||
// }
|
||||
//
|
||||
// fun toStringWithBrackets(namer: (Symbol) -> String): String =
|
||||
// when (true) {
|
||||
// numerator.isZero() -> "0"
|
||||
// denominator.isOne() -> numerator.toStringWithBrackets(namer)
|
||||
// else -> "(${numerator.toStringWithBrackets(namer)}/${denominator.toStringWithBrackets(namer)})"
|
||||
// }
|
||||
//
|
||||
// fun toReversedString(names: Map<Symbol, String> = emptyMap()): String =
|
||||
// when (true) {
|
||||
// numerator.isZero() -> "0"
|
||||
// denominator.isOne() -> numerator.toReversedString(names)
|
||||
// else -> "${numerator.toReversedStringWithBrackets(names)}/${denominator.toReversedStringWithBrackets(names)}"
|
||||
// }
|
||||
//
|
||||
// fun toReversedString(namer: (Symbol) -> String): String =
|
||||
// when (true) {
|
||||
// numerator.isZero() -> "0"
|
||||
// denominator.isOne() -> numerator.toReversedString(namer)
|
||||
// else -> "${numerator.toReversedStringWithBrackets(namer)}/${denominator.toReversedStringWithBrackets(namer)}"
|
||||
// }
|
||||
//
|
||||
// fun toReversedStringWithBrackets(names: Map<Symbol, String> = emptyMap()): String =
|
||||
// when (true) {
|
||||
// numerator.isZero() -> "0"
|
||||
// denominator.isOne() -> numerator.toReversedStringWithBrackets(names)
|
||||
// else -> "(${numerator.toReversedStringWithBrackets(names)}/${denominator.toReversedStringWithBrackets(names)})"
|
||||
// }
|
||||
//
|
||||
// fun toReversedStringWithBrackets(namer: (Symbol) -> String): String =
|
||||
// when (true) {
|
||||
// numerator.isZero() -> "0"
|
||||
// denominator.isOne() -> numerator.toReversedStringWithBrackets(namer)
|
||||
// else -> "(${numerator.toReversedStringWithBrackets(namer)}/${denominator.toReversedStringWithBrackets(namer)})"
|
||||
// }
|
||||
@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)
|
||||
}
|
@ -8,23 +8,19 @@ package space.kscience.kmath.functions
|
||||
import space.kscience.kmath.operations.Ring
|
||||
import space.kscience.kmath.operations.ScaleOperations
|
||||
import space.kscience.kmath.operations.invoke
|
||||
import kotlin.contracts.InvocationKind
|
||||
import kotlin.contracts.contract
|
||||
import kotlin.experimental.ExperimentalTypeInference
|
||||
import kotlin.jvm.JvmName
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
|
||||
/**
|
||||
* Polynomial model without fixation on specific context they are applied to.
|
||||
* Represents univariate polynomial that stores its coefficients in a [List].
|
||||
*
|
||||
* @param coefficients constant is the leftmost coefficient.
|
||||
* @param C the type of constants.
|
||||
*/
|
||||
public data class ListPolynomial<C>(
|
||||
/**
|
||||
* List that collects coefficients of the polynomial. Every monomial `a x^d` is represented as a coefficients
|
||||
* `a` placed into the list with index `d`. For example coefficients of polynomial `5 x^2 - 6` can be represented as
|
||||
* List that contains coefficients of the polynomial. Every monomial `a x^d` is stored as a coefficient `a` placed
|
||||
* into the list at index `d`. For example, coefficients of a polynomial `5 x^2 - 6` can be represented as
|
||||
* ```
|
||||
* listOf(
|
||||
* -6, // -6 +
|
||||
@ -42,26 +38,28 @@ public data class ListPolynomial<C>(
|
||||
* 0, // 0 x^4
|
||||
* )
|
||||
* ```
|
||||
* It is recommended not to put extra zeros at end of the list (as for `0x^3` and `0x^4` in the example), but is not
|
||||
* prohibited.
|
||||
* It is not prohibited to put extra zeros at end of the list (as for `0x^3` and `0x^4` in the example). But the
|
||||
* longer the coefficients list the worse performance of arithmetical operations performed on it. Thus, it is
|
||||
* recommended not to put (or even to remove) extra (or useless) coefficients at the end of the coefficients list.
|
||||
*/
|
||||
public val coefficients: List<C>
|
||||
) : Polynomial<C> {
|
||||
override fun toString(): String = "Polynomial$coefficients"
|
||||
override fun toString(): String = "ListPolynomial$coefficients"
|
||||
}
|
||||
|
||||
/**
|
||||
* Space of univariate polynomials constructed over ring.
|
||||
* Arithmetic context for univariate polynomials with coefficients stored as a [List] constructed with the provided
|
||||
* [ring] of constants.
|
||||
*
|
||||
* @param C the type of constants. Polynomials have them as a coefficients in their terms.
|
||||
* @param A type of underlying ring of constants. It's [Ring] of [C].
|
||||
* @param C the type of constants. Polynomials have them a coefficients in their terms.
|
||||
* @param A type of provided underlying ring of constants. It's [Ring] of [C].
|
||||
* @param ring underlying ring of constants of type [A].
|
||||
*/
|
||||
public open class ListPolynomialSpace<C, A : Ring<C>>(
|
||||
public override val ring: A,
|
||||
) : PolynomialSpaceOverRing<C, ListPolynomial<C>, A> {
|
||||
/**
|
||||
* Returns sum of the polynomial and the integer represented as polynomial.
|
||||
* Returns sum of the polynomial and the integer represented as a polynomial.
|
||||
*
|
||||
* The operation is equivalent to adding [other] copies of unit polynomial to [this].
|
||||
*/
|
||||
@ -79,7 +77,7 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
|
||||
}
|
||||
)
|
||||
/**
|
||||
* Returns difference between the polynomial and the integer represented as polynomial.
|
||||
* Returns difference between the polynomial and the integer represented as a polynomial.
|
||||
*
|
||||
* The operation is equivalent to subtraction [other] copies of unit polynomial from [this].
|
||||
*/
|
||||
@ -97,22 +95,25 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
|
||||
}
|
||||
)
|
||||
/**
|
||||
* Returns product of the polynomial and the integer represented as polynomial.
|
||||
* Returns product of the polynomial and the integer represented as a polynomial.
|
||||
*
|
||||
* The operation is equivalent to sum of [other] copies of [this].
|
||||
*/
|
||||
public override operator fun ListPolynomial<C>.times(other: Int): ListPolynomial<C> =
|
||||
if (other == 0) zero
|
||||
else ListPolynomial(
|
||||
coefficients
|
||||
.toMutableList()
|
||||
.apply {
|
||||
for (deg in indices) this[deg] = this[deg] * other
|
||||
}
|
||||
)
|
||||
when (other) {
|
||||
0 -> zero
|
||||
1 -> this
|
||||
else -> ListPolynomial(
|
||||
coefficients
|
||||
.toMutableList()
|
||||
.apply {
|
||||
for (deg in indices) this[deg] = this[deg] * other
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns sum of the integer represented as polynomial and the polynomial.
|
||||
* Returns sum of the integer represented as a polynomial and the polynomial.
|
||||
*
|
||||
* The operation is equivalent to adding [this] copies of unit polynomial to [other].
|
||||
*/
|
||||
@ -130,39 +131,44 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
|
||||
}
|
||||
)
|
||||
/**
|
||||
* Returns difference between the integer represented as polynomial and the polynomial.
|
||||
* Returns difference between the integer represented as a polynomial and the polynomial.
|
||||
*
|
||||
* The operation is equivalent to subtraction [this] copies of unit polynomial from [other].
|
||||
*/
|
||||
public override operator fun Int.minus(other: ListPolynomial<C>): ListPolynomial<C> =
|
||||
if (this == 0) other
|
||||
else
|
||||
ListPolynomial(
|
||||
other.coefficients
|
||||
.toMutableList()
|
||||
.apply {
|
||||
forEachIndexed { index, c -> if (index != 0) this[index] = -c }
|
||||
ListPolynomial(
|
||||
other.coefficients
|
||||
.toMutableList()
|
||||
.apply {
|
||||
if (this@minus == 0) {
|
||||
indices.forEach { this[it] = -this[it] }
|
||||
} else {
|
||||
(1..lastIndex).forEach { this[it] = -this[it] }
|
||||
|
||||
val result = this@minus - getOrElse(0) { constantZero }
|
||||
|
||||
if(size == 0) add(result)
|
||||
if (size == 0) add(result)
|
||||
else this[0] = result
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
/**
|
||||
* Returns product of the integer represented as polynomial and the polynomial.
|
||||
* Returns product of the integer represented as a polynomial and the polynomial.
|
||||
*
|
||||
* The operation is equivalent to sum of [this] copies of [other].
|
||||
*/
|
||||
public override operator fun Int.times(other: ListPolynomial<C>): ListPolynomial<C> =
|
||||
if (this == 0) zero
|
||||
else ListPolynomial(
|
||||
other.coefficients
|
||||
.toMutableList()
|
||||
.apply {
|
||||
for (deg in indices) this[deg] = this@times * this[deg]
|
||||
}
|
||||
)
|
||||
when (this) {
|
||||
0 -> zero
|
||||
1 -> other
|
||||
else -> ListPolynomial(
|
||||
other.coefficients
|
||||
.toMutableList()
|
||||
.apply {
|
||||
for (deg in indices) this[deg] = this@times * this[deg]
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the integer [value] to polynomial.
|
||||
@ -170,7 +176,7 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
|
||||
public override fun number(value: Int): ListPolynomial<C> = number(constantNumber(value))
|
||||
|
||||
/**
|
||||
* Returns sum of the constant represented as polynomial and the polynomial.
|
||||
* Returns sum of the constant represented as a polynomial and the polynomial.
|
||||
*/
|
||||
public override operator fun C.plus(other: ListPolynomial<C>): ListPolynomial<C> =
|
||||
with(other.coefficients) {
|
||||
@ -186,7 +192,7 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
|
||||
)
|
||||
}
|
||||
/**
|
||||
* Returns difference between the constant represented as polynomial and the polynomial.
|
||||
* Returns difference between the constant represented as a polynomial and the polynomial.
|
||||
*/
|
||||
public override operator fun C.minus(other: ListPolynomial<C>): ListPolynomial<C> =
|
||||
with(other.coefficients) {
|
||||
@ -194,7 +200,7 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
|
||||
else ListPolynomial(
|
||||
toMutableList()
|
||||
.apply {
|
||||
forEachIndexed { index, c -> if (index != 0) this[index] = -c }
|
||||
(1 .. lastIndex).forEach { this[it] = -this[it] }
|
||||
|
||||
val result = if (size == 0) this@minus else this@minus - get(0)
|
||||
|
||||
@ -204,7 +210,7 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
|
||||
)
|
||||
}
|
||||
/**
|
||||
* Returns product of the constant represented as polynomial and the polynomial.
|
||||
* Returns product of the constant represented as a polynomial and the polynomial.
|
||||
*/
|
||||
public override operator fun C.times(other: ListPolynomial<C>): ListPolynomial<C> =
|
||||
ListPolynomial(
|
||||
@ -216,7 +222,7 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
|
||||
)
|
||||
|
||||
/**
|
||||
* Returns sum of the constant represented as polynomial and the polynomial.
|
||||
* Returns sum of the constant represented as a polynomial and the polynomial.
|
||||
*/
|
||||
public override operator fun ListPolynomial<C>.plus(other: C): ListPolynomial<C> =
|
||||
with(coefficients) {
|
||||
@ -232,7 +238,7 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
|
||||
)
|
||||
}
|
||||
/**
|
||||
* Returns difference between the constant represented as polynomial and the polynomial.
|
||||
* Returns difference between the constant represented as a polynomial and the polynomial.
|
||||
*/
|
||||
public override operator fun ListPolynomial<C>.minus(other: C): ListPolynomial<C> =
|
||||
with(coefficients) {
|
||||
@ -248,7 +254,7 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
|
||||
)
|
||||
}
|
||||
/**
|
||||
* Returns product of the constant represented as polynomial and the polynomial.
|
||||
* Returns product of the constant represented as a polynomial and the polynomial.
|
||||
*/
|
||||
public override operator fun ListPolynomial<C>.times(other: C): ListPolynomial<C> =
|
||||
ListPolynomial(
|
||||
@ -262,7 +268,7 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
|
||||
/**
|
||||
* Converts the constant [value] to polynomial.
|
||||
*/
|
||||
public override fun number(value: C): ListPolynomial<C> = ListPolynomial(value)
|
||||
public override fun number(value: C): ListPolynomial<C> = ListPolynomial(listOf(value))
|
||||
|
||||
/**
|
||||
* Returns negation of the polynomial.
|
||||
@ -315,15 +321,19 @@ 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).
|
||||
*/
|
||||
override val zero: ListPolynomial<C> = ListPolynomial(emptyList())
|
||||
/**
|
||||
* Instance of unit constant (unit of the underlying ring).
|
||||
* Instance of unit polynomial (unit of the polynomial ring).
|
||||
*/
|
||||
override val one: ListPolynomial<C> = ListPolynomial(listOf(constantOne))
|
||||
override val one: ListPolynomial<C> by lazy { ListPolynomial(listOf(constantOne)) }
|
||||
|
||||
/**
|
||||
* Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is
|
||||
@ -331,25 +341,45 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
|
||||
*/
|
||||
public override val ListPolynomial<C>.degree: Int get() = coefficients.lastIndex
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun ListPolynomial<C>.substitute(argument: C): C = this.substitute(ring, argument)
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun ListPolynomial<C>.substitute(argument: ListPolynomial<C>): ListPolynomial<C> = this.substitute(ring, argument)
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun ListPolynomial<C>.asFunction(): (C) -> C = { this.substitute(ring, it) }
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun ListPolynomial<C>.asFunctionOnConstants(): (C) -> C = { this.substitute(ring, it) }
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun ListPolynomial<C>.asFunctionOnPolynomials(): (ListPolynomial<C>) -> ListPolynomial<C> = { this.substitute(ring, it) }
|
||||
|
||||
// TODO: When context receivers will be ready move all of this substitutions and invocations to utilities with
|
||||
// [ListPolynomialSpace] as a context receiver
|
||||
/**
|
||||
* Evaluates the polynomial for the given value [argument].
|
||||
* Evaluates value of [this] polynomial on provided [argument].
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline operator fun ListPolynomial<C>.invoke(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 operator fun ListPolynomial<C>.invoke(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 = asFunctionOver(ring)
|
||||
/**
|
||||
* Represent [this] polynomial as a regular context-less function.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
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> = asFunctionOfPolynomialOver(ring)
|
||||
|
||||
/**
|
||||
* Evaluates value of [this] polynomial on provided [argument].
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
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> = substitute(ring, argument)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -8,13 +8,23 @@ package space.kscience.kmath.functions
|
||||
import space.kscience.kmath.operations.Ring
|
||||
|
||||
|
||||
/**
|
||||
* Represents univariate rational function that stores its numerator and denominator as [ListPolynomial]s.
|
||||
*/
|
||||
public data class ListRationalFunction<C>(
|
||||
public override val numerator: ListPolynomial<C>,
|
||||
public override val denominator: ListPolynomial<C>
|
||||
) : RationalFunction<C, ListPolynomial<C>> {
|
||||
override fun toString(): String = "RationalFunction${numerator.coefficients}/${denominator.coefficients}"
|
||||
override fun toString(): String = "ListRationalFunction${numerator.coefficients}/${denominator.coefficients}"
|
||||
}
|
||||
|
||||
/**
|
||||
* Arithmetic context for univariate rational functions with numerator and denominator represented as [ListPolynomial]s.
|
||||
*
|
||||
* @param C the type of constants. Polynomials have them a coefficients in their terms.
|
||||
* @param A type of provided underlying ring of constants. It's [Ring] of [C].
|
||||
* @param ring underlying ring of constants of type [A].
|
||||
*/
|
||||
public class ListRationalFunctionSpace<C, A : Ring<C>> (
|
||||
public val ring: A,
|
||||
) :
|
||||
@ -30,76 +40,98 @@ public class ListRationalFunctionSpace<C, A : Ring<C>> (
|
||||
ListRationalFunction<C>,
|
||||
>() {
|
||||
|
||||
/**
|
||||
* Underlying polynomial ring. Its polynomial operations are inherited by local polynomial operations.
|
||||
*/
|
||||
override val polynomialRing : ListPolynomialSpace<C, A> = ListPolynomialSpace(ring)
|
||||
/**
|
||||
* Constructor of [ListRationalFunction] from numerator and denominator [ListPolynomial].
|
||||
*/
|
||||
override fun constructRationalFunction(numerator: ListPolynomial<C>, denominator: ListPolynomial<C>): ListRationalFunction<C> =
|
||||
ListRationalFunction(numerator, denominator)
|
||||
|
||||
// TODO: When context receivers will be ready move all of this substitutions and invocations to utilities with
|
||||
// [ListPolynomialSpace] as a context receiver
|
||||
/**
|
||||
* Instance of zero rational function (zero of the rational functions ring).
|
||||
* Evaluates value of [this] polynomial on provided argument.
|
||||
*/
|
||||
public override val zero: ListRationalFunction<C> = ListRationalFunction(polynomialZero, polynomialOne)
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun ListPolynomial<C>.substitute(argument: C): C = substitute(ring, argument)
|
||||
/**
|
||||
* Instance of unit polynomial (unit of the rational functions ring).
|
||||
* Substitutes provided polynomial [argument] into [this] polynomial.
|
||||
*/
|
||||
public override val one: ListRationalFunction<C> = ListRationalFunction(polynomialOne, polynomialOne)
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
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> = 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> = 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> = substitute(ring, argument)
|
||||
|
||||
// TODO: Разобрать
|
||||
/**
|
||||
* Represent [this] polynomial as a regular context-less function.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
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 = { 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> = { 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> = { 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> = { 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> = { substitute(ring, it) }
|
||||
|
||||
// operator fun invoke(arg: UnivariatePolynomial<T>): RationalFunction<T> =
|
||||
// RationalFunction(
|
||||
// numerator(arg),
|
||||
// denominator(arg)
|
||||
// )
|
||||
//
|
||||
// operator fun invoke(arg: RationalFunction<T>): RationalFunction<T> {
|
||||
// val num = numerator invokeRFTakeNumerator arg
|
||||
// val den = denominator invokeRFTakeNumerator arg
|
||||
// val degreeDif = numeratorDegree - denominatorDegree
|
||||
// return if (degreeDif > 0)
|
||||
// RationalFunction(
|
||||
// num,
|
||||
// multiplyByPower(den, arg.denominator, degreeDif)
|
||||
// )
|
||||
// else
|
||||
// RationalFunction(
|
||||
// multiplyByPower(num, arg.denominator, -degreeDif),
|
||||
// den
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// override fun toString(): String = toString(UnivariatePolynomial.variableName)
|
||||
//
|
||||
// fun toString(withVariableName: String = UnivariatePolynomial.variableName): String =
|
||||
// when(true) {
|
||||
// numerator.isZero() -> "0"
|
||||
// denominator.isOne() -> numerator.toString(withVariableName)
|
||||
// else -> "${numerator.toStringWithBrackets(withVariableName)}/${denominator.toStringWithBrackets(withVariableName)}"
|
||||
// }
|
||||
//
|
||||
// fun toStringWithBrackets(withVariableName: String = UnivariatePolynomial.variableName): String =
|
||||
// when(true) {
|
||||
// numerator.isZero() -> "0"
|
||||
// denominator.isOne() -> numerator.toStringWithBrackets(withVariableName)
|
||||
// else -> "(${numerator.toStringWithBrackets(withVariableName)}/${denominator.toStringWithBrackets(withVariableName)})"
|
||||
// }
|
||||
//
|
||||
// fun toReversedString(withVariableName: String = UnivariatePolynomial.variableName): String =
|
||||
// when(true) {
|
||||
// numerator.isZero() -> "0"
|
||||
// denominator.isOne() -> numerator.toReversedString(withVariableName)
|
||||
// else -> "${numerator.toReversedStringWithBrackets(withVariableName)}/${denominator.toReversedStringWithBrackets(withVariableName)}"
|
||||
// }
|
||||
//
|
||||
// fun toReversedStringWithBrackets(withVariableName: String = UnivariatePolynomial.variableName): String =
|
||||
// when(true) {
|
||||
// numerator.isZero() -> "0"
|
||||
// denominator.isOne() -> numerator.toReversedStringWithBrackets(withVariableName)
|
||||
// else -> "(${numerator.toReversedStringWithBrackets(withVariableName)}/${denominator.toReversedStringWithBrackets(withVariableName)})"
|
||||
// }
|
||||
//
|
||||
// fun removeZeros() =
|
||||
// RationalFunction(
|
||||
// numerator.removeZeros(),
|
||||
// denominator.removeZeros()
|
||||
// )
|
||||
/**
|
||||
* Evaluates value of [this] polynomial on provided argument.
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline operator fun ListPolynomial<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> = 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> = 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> = 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> = substitute(ring, argument)
|
||||
}
|
@ -5,44 +5,43 @@
|
||||
|
||||
package space.kscience.kmath.functions
|
||||
|
||||
import space.kscience.kmath.operations.invoke
|
||||
import space.kscience.kmath.operations.Ring
|
||||
import space.kscience.kmath.operations.ScaleOperations
|
||||
import kotlin.contracts.InvocationKind
|
||||
import kotlin.contracts.contract
|
||||
import kotlin.experimental.ExperimentalTypeInference
|
||||
import space.kscience.kmath.structures.Buffer
|
||||
import kotlin.jvm.JvmName
|
||||
import kotlin.math.max
|
||||
|
||||
|
||||
/**
|
||||
* Polynomial model without fixation on specific context they are applied to.
|
||||
* Represents multivariate 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 collects coefficients of the polynomial. Every monomial `a x_1^{d_1} ... x_n^{d_n}` is represented as
|
||||
* pair "key-value" in the map, where value is coefficients `a` and
|
||||
* key is list that associates index of every variable in the monomial with multiplicity of the variable occurring
|
||||
* in the monomial. For example coefficients of polynomial `5 x_1^2 x_3^3 - 6 x_2` can be represented as
|
||||
* 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,
|
||||
* listOf(0, 1) to (-6),
|
||||
* 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,
|
||||
* listOf(0, 1) to (-6),
|
||||
* listOf(0, 1, 1) to 0,
|
||||
* 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 recommended not to put zero monomials into the map, but is not prohibited. Lists of degrees always do not
|
||||
* contain any zeros on end, but can contain zeros on start or anywhere in middle.
|
||||
* 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> {
|
||||
@ -50,24 +49,25 @@ internal constructor(
|
||||
}
|
||||
|
||||
/**
|
||||
* Space of polynomials.
|
||||
* 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 operated polynomials.
|
||||
* @param A the intersection of [Ring] of [C] and [ScaleOperations] of [C].
|
||||
* @param ring the [A] instance.
|
||||
* @param C the type of constants. Polynomials have them a coefficients in their terms.
|
||||
* @param A type of provided underlying ring of constants. It's [Ring] of [C].
|
||||
* @param ring underlying ring of constants of type [A].
|
||||
*/
|
||||
public open class NumberedPolynomialSpace<C, A : Ring<C>>(
|
||||
public final override val ring: 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 polynomial.
|
||||
* Returns sum of the polynomial and the integer represented as a polynomial.
|
||||
*
|
||||
* The operation is equivalent to adding [other] copies of unit polynomial to [this].
|
||||
*/
|
||||
public override operator fun NumberedPolynomial<C>.plus(other: Int): NumberedPolynomial<C> =
|
||||
if (other == 0) this
|
||||
else
|
||||
NumberedPolynomial(
|
||||
NumberedPolynomialAsIs(
|
||||
coefficients
|
||||
.toMutableMap()
|
||||
.apply {
|
||||
@ -77,14 +77,14 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
|
||||
}
|
||||
)
|
||||
/**
|
||||
* Returns difference between the polynomial and the integer represented as polynomial.
|
||||
* Returns difference between the polynomial and the integer represented as a polynomial.
|
||||
*
|
||||
* The operation is equivalent to subtraction [other] copies of unit polynomial from [this].
|
||||
*/
|
||||
public override operator fun NumberedPolynomial<C>.minus(other: Int): NumberedPolynomial<C> =
|
||||
if (other == 0) this
|
||||
else
|
||||
NumberedPolynomial(
|
||||
NumberedPolynomialAsIs(
|
||||
coefficients
|
||||
.toMutableMap()
|
||||
.apply {
|
||||
@ -94,29 +94,32 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
|
||||
}
|
||||
)
|
||||
/**
|
||||
* Returns product of the polynomial and the integer represented as polynomial.
|
||||
* Returns product of the polynomial and the integer represented as a polynomial.
|
||||
*
|
||||
* The operation is equivalent to sum of [other] copies of [this].
|
||||
*/
|
||||
public override operator fun NumberedPolynomial<C>.times(other: Int): NumberedPolynomial<C> =
|
||||
if (other == 0) zero
|
||||
else NumberedPolynomial<C>(
|
||||
coefficients
|
||||
.toMutableMap()
|
||||
.apply {
|
||||
for (degs in keys) this[degs] = this[degs]!! * other
|
||||
}
|
||||
)
|
||||
when (other) {
|
||||
0 -> zero
|
||||
1 -> this
|
||||
else -> NumberedPolynomialAsIs(
|
||||
coefficients
|
||||
.toMutableMap()
|
||||
.apply {
|
||||
for (degs in keys) this[degs] = this[degs]!! * other
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns sum of the integer represented as polynomial and the polynomial.
|
||||
* Returns sum of the integer represented as a polynomial and the polynomial.
|
||||
*
|
||||
* The operation is equivalent to adding [this] copies of unit polynomial to [other].
|
||||
*/
|
||||
public override operator fun Int.plus(other: NumberedPolynomial<C>): NumberedPolynomial<C> =
|
||||
if (this == 0) other
|
||||
else
|
||||
NumberedPolynomial(
|
||||
NumberedPolynomialAsIs(
|
||||
other.coefficients
|
||||
.toMutableMap()
|
||||
.apply {
|
||||
@ -126,36 +129,43 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
|
||||
}
|
||||
)
|
||||
/**
|
||||
* Returns difference between the integer represented as polynomial and the polynomial.
|
||||
* Returns difference between the integer represented as a polynomial and the polynomial.
|
||||
*
|
||||
* The operation is equivalent to subtraction [this] copies of unit polynomial from [other].
|
||||
*/
|
||||
public override operator fun Int.minus(other: NumberedPolynomial<C>): NumberedPolynomial<C> =
|
||||
if (this == 0) other
|
||||
else
|
||||
NumberedPolynomial(
|
||||
other.coefficients
|
||||
.toMutableMap()
|
||||
.apply {
|
||||
NumberedPolynomialAsIs(
|
||||
other.coefficients
|
||||
.toMutableMap()
|
||||
.apply {
|
||||
if (this@minus == 0) {
|
||||
forEach { (key, value) -> this[key] = -value }
|
||||
} else {
|
||||
forEach { (key, value) -> if (key.isNotEmpty()) this[key] = -value }
|
||||
|
||||
val degs = emptyList<UInt>()
|
||||
|
||||
this[degs] = this@minus - getOrElse(degs) { constantZero }
|
||||
}
|
||||
}
|
||||
)
|
||||
/**
|
||||
* Returns product of the integer represented as polynomial and the polynomial.
|
||||
* Returns product of the integer represented as a polynomial and the polynomial.
|
||||
*
|
||||
* The operation is equivalent to sum of [this] copies of [other].
|
||||
*/
|
||||
public override operator fun Int.times(other: NumberedPolynomial<C>): NumberedPolynomial<C> =
|
||||
if (this == 0) zero
|
||||
else NumberedPolynomial(
|
||||
other.coefficients
|
||||
.toMutableMap()
|
||||
.apply {
|
||||
for (degs in keys) this[degs] = this@times * this[degs]!!
|
||||
}
|
||||
)
|
||||
when (this) {
|
||||
0 -> zero
|
||||
1 -> other
|
||||
else -> NumberedPolynomialAsIs(
|
||||
other.coefficients
|
||||
.toMutableMap()
|
||||
.apply {
|
||||
for (degs in keys) this[degs] = this@times * this[degs]!!
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the integer [value] to polynomial.
|
||||
@ -163,12 +173,12 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
|
||||
public override fun number(value: Int): NumberedPolynomial<C> = number(constantNumber(value))
|
||||
|
||||
/**
|
||||
* Returns sum of the constant represented as polynomial and the polynomial.
|
||||
* Returns sum of the constant represented as a polynomial and the polynomial.
|
||||
*/
|
||||
override operator fun C.plus(other: NumberedPolynomial<C>): NumberedPolynomial<C> =
|
||||
with(other.coefficients) {
|
||||
if (isEmpty()) NumberedPolynomial<C>(mapOf(emptyList<UInt>() to this@plus))
|
||||
else NumberedPolynomial<C>(
|
||||
if (isEmpty()) NumberedPolynomialAsIs(mapOf(emptyList<UInt>() to this@plus))
|
||||
else NumberedPolynomialAsIs(
|
||||
toMutableMap()
|
||||
.apply {
|
||||
val degs = emptyList<UInt>()
|
||||
@ -178,15 +188,15 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
|
||||
)
|
||||
}
|
||||
/**
|
||||
* Returns difference between the constant represented as polynomial and the polynomial.
|
||||
* 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()) NumberedPolynomial<C>(mapOf(emptyList<UInt>() to this@minus))
|
||||
else NumberedPolynomial<C>(
|
||||
if (isEmpty()) NumberedPolynomialAsIs(mapOf(emptyList<UInt>() to this@minus))
|
||||
else NumberedPolynomialAsIs(
|
||||
toMutableMap()
|
||||
.apply {
|
||||
forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c }
|
||||
forEach { (degs, c) -> if (degs.isNotEmpty()) this[degs] = -c }
|
||||
|
||||
val degs = emptyList<UInt>()
|
||||
|
||||
@ -195,10 +205,10 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
|
||||
)
|
||||
}
|
||||
/**
|
||||
* Returns product of the constant represented as polynomial and the polynomial.
|
||||
* Returns product of the constant represented as a polynomial and the polynomial.
|
||||
*/
|
||||
override operator fun C.times(other: NumberedPolynomial<C>): NumberedPolynomial<C> =
|
||||
NumberedPolynomial<C>(
|
||||
NumberedPolynomialAsIs(
|
||||
other.coefficients
|
||||
.toMutableMap()
|
||||
.apply {
|
||||
@ -207,12 +217,12 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
|
||||
)
|
||||
|
||||
/**
|
||||
* Returns sum of the constant represented as polynomial and the polynomial.
|
||||
* 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()) NumberedPolynomial<C>(mapOf(emptyList<UInt>() to other))
|
||||
else NumberedPolynomial<C>(
|
||||
if (isEmpty()) NumberedPolynomialAsIs(mapOf(emptyList<UInt>() to other))
|
||||
else NumberedPolynomialAsIs(
|
||||
toMutableMap()
|
||||
.apply {
|
||||
val degs = emptyList<UInt>()
|
||||
@ -222,12 +232,12 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
|
||||
)
|
||||
}
|
||||
/**
|
||||
* Returns difference between the constant represented as polynomial and the polynomial.
|
||||
* 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()) NumberedPolynomial<C>(mapOf(emptyList<UInt>() to other))
|
||||
else NumberedPolynomial<C>(
|
||||
if (isEmpty()) NumberedPolynomialAsIs(mapOf(emptyList<UInt>() to other))
|
||||
else NumberedPolynomialAsIs(
|
||||
toMutableMap()
|
||||
.apply {
|
||||
val degs = emptyList<UInt>()
|
||||
@ -237,10 +247,10 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
|
||||
)
|
||||
}
|
||||
/**
|
||||
* Returns product of the constant represented as polynomial and the polynomial.
|
||||
* Returns product of the constant represented as a polynomial and the polynomial.
|
||||
*/
|
||||
override operator fun NumberedPolynomial<C>.times(other: C): NumberedPolynomial<C> =
|
||||
NumberedPolynomial<C>(
|
||||
NumberedPolynomialAsIs(
|
||||
coefficients
|
||||
.toMutableMap()
|
||||
.apply {
|
||||
@ -252,22 +262,22 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
|
||||
* Converts the constant [value] to polynomial.
|
||||
*/
|
||||
public override fun number(value: C): NumberedPolynomial<C> =
|
||||
NumberedPolynomial(mapOf(emptyList<UInt>() to value))
|
||||
NumberedPolynomialAsIs(mapOf(emptyList<UInt>() to value))
|
||||
|
||||
/**
|
||||
* Returns negation of the polynomial.
|
||||
*/
|
||||
override fun NumberedPolynomial<C>.unaryMinus(): NumberedPolynomial<C> =
|
||||
NumberedPolynomial<C>(
|
||||
NumberedPolynomialAsIs(
|
||||
coefficients.mapValues { -it.value }
|
||||
)
|
||||
/**
|
||||
* Returns sum of the polynomials.
|
||||
*/
|
||||
override operator fun NumberedPolynomial<C>.plus(other: NumberedPolynomial<C>): NumberedPolynomial<C> =
|
||||
NumberedPolynomial<C>(
|
||||
NumberedPolynomialAsIs(
|
||||
buildMap(coefficients.size + other.coefficients.size) {
|
||||
other.coefficients.mapValuesTo(this) { it.value }
|
||||
coefficients.mapValuesTo(this) { it.value }
|
||||
other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! + value else value }
|
||||
}
|
||||
)
|
||||
@ -275,9 +285,9 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
|
||||
* Returns difference of the polynomials.
|
||||
*/
|
||||
override operator fun NumberedPolynomial<C>.minus(other: NumberedPolynomial<C>): NumberedPolynomial<C> =
|
||||
NumberedPolynomial<C>(
|
||||
NumberedPolynomialAsIs(
|
||||
buildMap(coefficients.size + other.coefficients.size) {
|
||||
other.coefficients.mapValuesTo(this) { it.value }
|
||||
coefficients.mapValuesTo(this) { it.value }
|
||||
other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! - value else -value }
|
||||
}
|
||||
)
|
||||
@ -285,7 +295,7 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
|
||||
* Returns product of the polynomials.
|
||||
*/
|
||||
override operator fun NumberedPolynomial<C>.times(other: NumberedPolynomial<C>): NumberedPolynomial<C> =
|
||||
NumberedPolynomial<C>(
|
||||
NumberedPolynomialAsIs(
|
||||
buildMap(coefficients.size * other.coefficients.size) {
|
||||
for ((degs1, c1) in coefficients) for ((degs2, c2) in other.coefficients) {
|
||||
val degs =
|
||||
@ -296,20 +306,25 @@ public open class NumberedPolynomialSpace<C, A : Ring<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> = NumberedPolynomial<C>(emptyMap())
|
||||
override val zero: NumberedPolynomial<C> = NumberedPolynomialAsIs(emptyMap())
|
||||
/**
|
||||
* Instance of unit polynomial (unit of the polynomial ring).
|
||||
*/
|
||||
override val one: NumberedPolynomial<C> =
|
||||
NumberedPolynomial<C>(
|
||||
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,
|
||||
@ -365,25 +380,61 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
|
||||
}
|
||||
}.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(argument: Map<Int, C>): NumberedPolynomial<C> = this.substitute(ring, argument)
|
||||
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(argument: Map<Int, NumberedPolynomial<C>>): NumberedPolynomial<C> = this.substitute(ring, argument)
|
||||
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(): (Map<Int, C>) -> NumberedPolynomial<C> = { this.substitute(ring, it) }
|
||||
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>.asFunctionOnConstants(): (Map<Int, C>) -> NumberedPolynomial<C> = { this.substitute(ring, it) }
|
||||
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>.asFunctionOnPolynomials(): (Map<Int, NumberedPolynomial<C>>) -> NumberedPolynomial<C> = { this.substitute(ring, it) }
|
||||
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(argument: Map<Int, C>): NumberedPolynomial<C> = this.substitute(ring, argument)
|
||||
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(argument: Map<Int, NumberedPolynomial<C>>): NumberedPolynomial<C> = this.substitute(ring, argument)
|
||||
|
||||
// FIXME: Move to other constructors with context receiver
|
||||
public fun C.asNumberedPolynomial() : NumberedPolynomial<C> = NumberedPolynomial<C>(mapOf(emptyList<UInt>() to this))
|
||||
public inline operator fun NumberedPolynomial<C>.invoke(arguments: Buffer<NumberedPolynomial<C>>): NumberedPolynomial<C> = substitute(ring, arguments)
|
||||
}
|
@ -7,9 +7,14 @@ 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>
|
||||
@ -17,6 +22,13 @@ public class NumberedRationalFunction<C> internal constructor(
|
||||
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,
|
||||
) :
|
||||
@ -32,22 +44,19 @@ public class NumberedRationalFunctionSpace<C, A: Ring<C>> (
|
||||
NumberedRationalFunction<C>,
|
||||
>() {
|
||||
|
||||
override val polynomialRing : NumberedPolynomialSpace<C, A> = NumberedPolynomialSpace(ring)
|
||||
override fun constructRationalFunction(
|
||||
/**
|
||||
* 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)
|
||||
|
||||
/**
|
||||
* Instance of zero rational function (zero of the rational functions ring).
|
||||
*/
|
||||
public override val zero: NumberedRationalFunction<C> = NumberedRationalFunction(polynomialZero, polynomialOne)
|
||||
/**
|
||||
* Instance of unit polynomial (unit of the rational functions ring).
|
||||
*/
|
||||
public override val one: NumberedRationalFunction<C> = NumberedRationalFunction(polynomialOne, polynomialOne)
|
||||
|
||||
/**
|
||||
* Maximal index (ID) of variable occurring in the polynomial with positive power. If there is no such variable,
|
||||
* the result is `-1`.
|
||||
@ -99,90 +108,140 @@ public class NumberedRationalFunctionSpace<C, A: Ring<C>> (
|
||||
}
|
||||
}.count { it }
|
||||
|
||||
// TODO: Разобрать
|
||||
// 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")
|
||||
@JvmName("substitutePolynomial")
|
||||
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")
|
||||
@JvmName("substituteRationalFunction")
|
||||
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")
|
||||
@JvmName("substitutePolynomial")
|
||||
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")
|
||||
@JvmName("substituteRationalFunction")
|
||||
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")
|
||||
@JvmName("substitutePolynomial")
|
||||
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")
|
||||
@JvmName("substituteRationalFunction")
|
||||
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")
|
||||
@JvmName("substitutePolynomial")
|
||||
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")
|
||||
@JvmName("substituteRationalFunction")
|
||||
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)
|
||||
|
||||
// operator fun invoke(arg: Map<Int, C>): NumberedRationalFunction<C> =
|
||||
// NumberedRationalFunction(
|
||||
// numerator(arg),
|
||||
// denominator(arg)
|
||||
// )
|
||||
//
|
||||
// @JvmName("invokePolynomial")
|
||||
// operator fun invoke(arg: Map<Int, Polynomial<C>>): NumberedRationalFunction<C> =
|
||||
// NumberedRationalFunction(
|
||||
// numerator(arg),
|
||||
// denominator(arg)
|
||||
// )
|
||||
//
|
||||
// @JvmName("invokeRationalFunction")
|
||||
// operator fun invoke(arg: Map<Int, NumberedRationalFunction<C>>): NumberedRationalFunction<C> {
|
||||
// var num = numerator invokeRFTakeNumerator arg
|
||||
// var den = denominator invokeRFTakeNumerator arg
|
||||
// for (variable in 0 until max(numerator.countOfVariables, denominator.countOfVariables)) if (variable in arg) {
|
||||
// val degreeDif = numerator.degrees.getOrElse(variable) { 0 } - denominator.degrees.getOrElse(variable) { 0 }
|
||||
// if (degreeDif > 0)
|
||||
// den = multiplyByPower(den, arg[variable]!!.denominator, degreeDif)
|
||||
// else
|
||||
// num = multiplyByPower(num, arg[variable]!!.denominator, -degreeDif)
|
||||
// }
|
||||
// return NumberedRationalFunction(num, den)
|
||||
// }
|
||||
//
|
||||
// override fun toString(): String = toString(Polynomial.variableName)
|
||||
//
|
||||
// fun toString(withVariableName: String = Polynomial.variableName): String =
|
||||
// when(true) {
|
||||
// numerator.isZero() -> "0"
|
||||
// denominator.isOne() -> numerator.toString(withVariableName)
|
||||
// else -> "${numerator.toStringWithBrackets(withVariableName)}/${denominator.toStringWithBrackets(withVariableName)}"
|
||||
// }
|
||||
//
|
||||
// fun toString(namer: (Int) -> String): String =
|
||||
// when(true) {
|
||||
// numerator.isZero() -> "0"
|
||||
// denominator.isOne() -> numerator.toString(namer)
|
||||
// else -> "${numerator.toStringWithBrackets(namer)}/${denominator.toStringWithBrackets(namer)}"
|
||||
// }
|
||||
//
|
||||
// fun toStringWithBrackets(withVariableName: String = Polynomial.variableName): String =
|
||||
// when(true) {
|
||||
// numerator.isZero() -> "0"
|
||||
// denominator.isOne() -> numerator.toStringWithBrackets(withVariableName)
|
||||
// else -> "(${numerator.toStringWithBrackets(withVariableName)}/${denominator.toStringWithBrackets(withVariableName)})"
|
||||
// }
|
||||
//
|
||||
// fun toStringWithBrackets(namer: (Int) -> String): String =
|
||||
// when(true) {
|
||||
// numerator.isZero() -> "0"
|
||||
// denominator.isOne() -> numerator.toStringWithBrackets(namer)
|
||||
// else -> "(${numerator.toStringWithBrackets(namer)}/${denominator.toStringWithBrackets(namer)})"
|
||||
// }
|
||||
//
|
||||
// fun toReversedString(withVariableName: String = Polynomial.variableName): String =
|
||||
// when(true) {
|
||||
// numerator.isZero() -> "0"
|
||||
// denominator.isOne() -> numerator.toReversedString(withVariableName)
|
||||
// else -> "${numerator.toReversedStringWithBrackets(withVariableName)}/${denominator.toReversedStringWithBrackets(withVariableName)}"
|
||||
// }
|
||||
//
|
||||
// fun toReversedString(namer: (Int) -> String): String =
|
||||
// when(true) {
|
||||
// numerator.isZero() -> "0"
|
||||
// denominator.isOne() -> numerator.toReversedString(namer)
|
||||
// else -> "${numerator.toReversedStringWithBrackets(namer)}/${denominator.toReversedStringWithBrackets(namer)}"
|
||||
// }
|
||||
//
|
||||
// fun toReversedStringWithBrackets(withVariableName: String = Polynomial.variableName): String =
|
||||
// when(true) {
|
||||
// numerator.isZero() -> "0"
|
||||
// denominator.isOne() -> numerator.toReversedStringWithBrackets(withVariableName)
|
||||
// else -> "(${numerator.toReversedStringWithBrackets(withVariableName)}/${denominator.toReversedStringWithBrackets(withVariableName)})"
|
||||
// }
|
||||
//
|
||||
// fun toReversedStringWithBrackets(namer: (Int) -> String): String =
|
||||
// when(true) {
|
||||
// numerator.isZero() -> "0"
|
||||
// denominator.isOne() -> numerator.toReversedStringWithBrackets(namer)
|
||||
// else -> "(${numerator.toReversedStringWithBrackets(namer)}/${denominator.toReversedStringWithBrackets(namer)})"
|
||||
// }
|
||||
/**
|
||||
* 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("invokeRationalFunction")
|
||||
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("invokeRationalFunction")
|
||||
public inline operator fun NumberedRationalFunction<C>.invoke(arguments: Buffer<NumberedRationalFunction<C>>): NumberedRationalFunction<C> = substitute(ring, arguments)
|
||||
}
|
@ -25,38 +25,38 @@ public interface Polynomial<C>
|
||||
@Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") // FIXME: Waiting for KT-31420
|
||||
public interface PolynomialSpace<C, P: Polynomial<C>> : Ring<P> {
|
||||
/**
|
||||
* Returns sum of the constant and the integer represented as constant (member of underlying ring).
|
||||
* Returns sum of the constant and the integer represented as a constant (member of underlying ring).
|
||||
*
|
||||
* The operation is equivalent to adding [other] copies of unit of underlying ring to [this].
|
||||
*/
|
||||
public operator fun C.plus(other: Int): C
|
||||
/**
|
||||
* Returns difference between the constant and the integer represented as constant (member of underlying ring).
|
||||
* Returns difference between the constant and the integer represented as a constant (member of underlying ring).
|
||||
*
|
||||
* The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this].
|
||||
*/
|
||||
public operator fun C.minus(other: Int): C
|
||||
/**
|
||||
* Returns product of the constant and the integer represented as constant (member of underlying ring).
|
||||
* Returns product of the constant and the integer represented as a constant (member of underlying ring).
|
||||
*
|
||||
* The operation is equivalent to sum of [other] copies of [this].
|
||||
*/
|
||||
public operator fun C.times(other: Int): C
|
||||
|
||||
/**
|
||||
* Returns sum of the integer represented as constant (member of underlying ring) and the constant.
|
||||
* Returns sum of the integer represented as a constant (member of underlying ring) and the constant.
|
||||
*
|
||||
* The operation is equivalent to adding [this] copies of unit of underlying ring to [other].
|
||||
*/
|
||||
public operator fun Int.plus(other: C): C
|
||||
/**
|
||||
* Returns difference between the integer represented as constant (member of underlying ring) and the constant.
|
||||
* Returns difference between the integer represented as a constant (member of underlying ring) and the constant.
|
||||
*
|
||||
* The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other].
|
||||
*/
|
||||
public operator fun Int.minus(other: C): C
|
||||
/**
|
||||
* Returns product of the integer represented as constant (member of underlying ring) and the constant.
|
||||
* Returns product of the integer represented as a constant (member of underlying ring) and the constant.
|
||||
*
|
||||
* The operation is equivalent to sum of [this] copies of [other].
|
||||
*/
|
||||
@ -72,38 +72,38 @@ public interface PolynomialSpace<C, P: Polynomial<C>> : Ring<P> {
|
||||
public fun Int.asConstant(): C = constantNumber(this)
|
||||
|
||||
/**
|
||||
* Returns sum of the polynomial and the integer represented as polynomial.
|
||||
* Returns sum of the polynomial and the integer represented as a polynomial.
|
||||
*
|
||||
* The operation is equivalent to adding [other] copies of unit polynomial to [this].
|
||||
*/
|
||||
public operator fun P.plus(other: Int): P = addMultipliedByDoubling(this, one, other)
|
||||
/**
|
||||
* Returns difference between the polynomial and the integer represented as polynomial.
|
||||
* Returns difference between the polynomial and the integer represented as a polynomial.
|
||||
*
|
||||
* The operation is equivalent to subtraction [other] copies of unit polynomial from [this].
|
||||
*/
|
||||
public operator fun P.minus(other: Int): P = addMultipliedByDoubling(this, one, -other)
|
||||
/**
|
||||
* Returns product of the polynomial and the integer represented as polynomial.
|
||||
* Returns product of the polynomial and the integer represented as a polynomial.
|
||||
*
|
||||
* The operation is equivalent to sum of [other] copies of [this].
|
||||
*/
|
||||
public operator fun P.times(other: Int): P = multiplyByDoubling(this, other)
|
||||
|
||||
/**
|
||||
* Returns sum of the integer represented as polynomial and the polynomial.
|
||||
* Returns sum of the integer represented as a polynomial and the polynomial.
|
||||
*
|
||||
* The operation is equivalent to adding [this] copies of unit polynomial to [other].
|
||||
*/
|
||||
public operator fun Int.plus(other: P): P = addMultipliedByDoubling(other, one, this)
|
||||
/**
|
||||
* Returns difference between the integer represented as polynomial and the polynomial.
|
||||
* Returns difference between the integer represented as a polynomial and the polynomial.
|
||||
*
|
||||
* The operation is equivalent to subtraction [this] copies of unit polynomial from [other].
|
||||
*/
|
||||
public operator fun Int.minus(other: P): P = addMultipliedByDoubling(-other, one, this)
|
||||
/**
|
||||
* Returns product of the integer represented as polynomial and the polynomial.
|
||||
* Returns product of the integer represented as a polynomial and the polynomial.
|
||||
*
|
||||
* The operation is equivalent to sum of [this] copies of [other].
|
||||
*/
|
||||
@ -165,28 +165,28 @@ public interface PolynomialSpace<C, P: Polynomial<C>> : Ring<P> {
|
||||
public val constantOne: C
|
||||
|
||||
/**
|
||||
* Returns sum of the constant represented as polynomial and the polynomial.
|
||||
* Returns sum of the constant represented as a polynomial and the polynomial.
|
||||
*/
|
||||
public operator fun C.plus(other: P): P
|
||||
/**
|
||||
* Returns difference between the constant represented as polynomial and the polynomial.
|
||||
* Returns difference between the constant represented as a polynomial and the polynomial.
|
||||
*/
|
||||
public operator fun C.minus(other: P): P
|
||||
/**
|
||||
* Returns product of the constant represented as polynomial and the polynomial.
|
||||
* Returns product of the constant represented as a polynomial and the polynomial.
|
||||
*/
|
||||
public operator fun C.times(other: P): P
|
||||
|
||||
/**
|
||||
* Returns sum of the constant represented as polynomial and the polynomial.
|
||||
* Returns sum of the constant represented as a polynomial and the polynomial.
|
||||
*/
|
||||
public operator fun P.plus(other: C): P
|
||||
/**
|
||||
* Returns difference between the constant represented as polynomial and the polynomial.
|
||||
* Returns difference between the constant represented as a polynomial and the polynomial.
|
||||
*/
|
||||
public operator fun P.minus(other: C): P
|
||||
/**
|
||||
* Returns product of the constant represented as polynomial and the polynomial.
|
||||
* Returns product of the constant represented as a polynomial and the polynomial.
|
||||
*/
|
||||
public operator fun P.times(other: C): P
|
||||
|
||||
@ -254,41 +254,44 @@ public interface PolynomialSpace<C, P: Polynomial<C>> : Ring<P> {
|
||||
@Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420
|
||||
public interface PolynomialSpaceOverRing<C, P: Polynomial<C>, A: Ring<C>> : PolynomialSpace<C, P> {
|
||||
|
||||
/**
|
||||
* Underlying ring of constants. Its operations on constants are inherited by local operations on constants.
|
||||
*/
|
||||
public val ring: A
|
||||
|
||||
/**
|
||||
* Returns sum of the constant and the integer represented as constant (member of underlying ring).
|
||||
* Returns sum of the constant and the integer represented as a constant (member of underlying ring).
|
||||
*
|
||||
* The operation is equivalent to adding [other] copies of unit of underlying ring to [this].
|
||||
*/
|
||||
public override operator fun C.plus(other: Int): C = ring { addMultipliedByDoubling(this@plus, one, other) }
|
||||
/**
|
||||
* Returns difference between the constant and the integer represented as constant (member of underlying ring).
|
||||
* Returns difference between the constant and the integer represented as a constant (member of underlying ring).
|
||||
*
|
||||
* The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this].
|
||||
*/
|
||||
public override operator fun C.minus(other: Int): C = ring { addMultipliedByDoubling(this@minus, one, -other) }
|
||||
/**
|
||||
* Returns product of the constant and the integer represented as constant (member of underlying ring).
|
||||
* Returns product of the constant and the integer represented as a constant (member of underlying ring).
|
||||
*
|
||||
* The operation is equivalent to sum of [other] copies of [this].
|
||||
*/
|
||||
public override operator fun C.times(other: Int): C = ring { multiplyByDoubling(this@times, other) }
|
||||
|
||||
/**
|
||||
* Returns sum of the integer represented as constant (member of underlying ring) and the constant.
|
||||
* Returns sum of the integer represented as a constant (member of underlying ring) and the constant.
|
||||
*
|
||||
* The operation is equivalent to adding [this] copies of unit of underlying ring to [other].
|
||||
*/
|
||||
public override operator fun Int.plus(other: C): C = ring { addMultipliedByDoubling(other, one, this@plus) }
|
||||
/**
|
||||
* Returns difference between the integer represented as constant (member of underlying ring) and the constant.
|
||||
* Returns difference between the integer represented as a constant (member of underlying ring) and the constant.
|
||||
*
|
||||
* The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other].
|
||||
*/
|
||||
public override operator fun Int.minus(other: C): C = ring { addMultipliedByDoubling(-other, one, this@minus) }
|
||||
/**
|
||||
* Returns product of the integer represented as constant (member of underlying ring) and the constant.
|
||||
* Returns product of the integer represented as a constant (member of underlying ring) and the constant.
|
||||
*
|
||||
* The operation is equivalent to sum of [this] copies of [other].
|
||||
*/
|
||||
@ -330,58 +333,145 @@ public interface PolynomialSpaceOverRing<C, P: Polynomial<C>, A: Ring<C>> : Poly
|
||||
public override val constantOne: C get() = ring.one
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstraction of ring of polynomials of type [P] of variables of type [V] and over ring of constants of type [C].
|
||||
*
|
||||
* @param C the type of constants. Polynomials have them as coefficients in their terms.
|
||||
* @param V the type of variables. Polynomials have them in representations of terms.
|
||||
* @param P the type of polynomials.
|
||||
*/
|
||||
@Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420
|
||||
public interface MultivariatePolynomialSpace<C, V, P: Polynomial<C>>: PolynomialSpace<C, P> {
|
||||
/**
|
||||
* Returns sum of the variable represented as a monic monomial and the integer represented as a constant polynomial.
|
||||
*/
|
||||
@JvmName("plusVariableInt")
|
||||
public operator fun V.plus(other: Int): P
|
||||
/**
|
||||
* Returns difference between the variable represented as a monic monomial and the integer represented as a constant polynomial.
|
||||
*/
|
||||
@JvmName("minusVariableInt")
|
||||
public operator fun V.minus(other: Int): P
|
||||
/**
|
||||
* Returns product of the variable represented as a monic monomial and the integer represented as a constant polynomial.
|
||||
*/
|
||||
@JvmName("timesVariableInt")
|
||||
public operator fun V.times(other: Int): P
|
||||
|
||||
/**
|
||||
* Returns sum of the integer represented as a constant polynomial and the variable represented as a monic monomial.
|
||||
*/
|
||||
@JvmName("plusIntVariable")
|
||||
public operator fun Int.plus(other: V): P
|
||||
/**
|
||||
* Returns difference between the integer represented as a constant polynomial and the variable represented as a monic monomial.
|
||||
*/
|
||||
@JvmName("minusIntVariable")
|
||||
public operator fun Int.minus(other: V): P
|
||||
/**
|
||||
* Returns product of the integer represented as a constant polynomial and the variable represented as a monic monomial.
|
||||
*/
|
||||
@JvmName("timesIntVariable")
|
||||
public operator fun Int.times(other: V): P
|
||||
|
||||
@JvmName("plusConstantVariable")
|
||||
public operator fun C.plus(other: V): P
|
||||
@JvmName("minusConstantVariable")
|
||||
public operator fun C.minus(other: V): P
|
||||
@JvmName("timesConstantVariable")
|
||||
public operator fun C.times(other: V): P
|
||||
|
||||
/**
|
||||
* Returns sum of the variable represented as a monic monomial and the constant represented as a constant polynomial.
|
||||
*/
|
||||
@JvmName("plusVariableConstant")
|
||||
public operator fun V.plus(other: C): P
|
||||
/**
|
||||
* Returns difference between the variable represented as a monic monomial and the constant represented as a constant polynomial.
|
||||
*/
|
||||
@JvmName("minusVariableConstant")
|
||||
public operator fun V.minus(other: C): P
|
||||
/**
|
||||
* Returns product of the variable represented as a monic monomial and the constant represented as a constant polynomial.
|
||||
*/
|
||||
@JvmName("timesVariableConstant")
|
||||
public operator fun V.times(other: C): P
|
||||
|
||||
/**
|
||||
* Returns sum of the constant represented as a constant polynomial and the variable represented as a monic monomial.
|
||||
*/
|
||||
@JvmName("plusConstantVariable")
|
||||
public operator fun C.plus(other: V): P
|
||||
/**
|
||||
* Returns difference between the constant represented as a constant polynomial and the variable represented as a monic monomial.
|
||||
*/
|
||||
@JvmName("minusConstantVariable")
|
||||
public operator fun C.minus(other: V): P
|
||||
/**
|
||||
* Returns product of the constant represented as a constant polynomial and the variable represented as a monic monomial.
|
||||
*/
|
||||
@JvmName("timesConstantVariable")
|
||||
public operator fun C.times(other: V): P
|
||||
|
||||
/**
|
||||
* Represents the variable as a monic monomial.
|
||||
*/
|
||||
@JvmName("unaryPlusVariable")
|
||||
public operator fun V.unaryPlus(): P
|
||||
/**
|
||||
* Returns negation of representation of the variable as a monic monomial.
|
||||
*/
|
||||
@JvmName("unaryMinusVariable")
|
||||
public operator fun V.unaryMinus(): P
|
||||
/**
|
||||
* Returns sum of the variables represented as monic monomials.
|
||||
*/
|
||||
@JvmName("plusVariableVariable")
|
||||
public operator fun V.plus(other: V): P
|
||||
/**
|
||||
* Returns difference between the variables represented as monic monomials.
|
||||
*/
|
||||
@JvmName("minusVariableVariable")
|
||||
public operator fun V.minus(other: V): P
|
||||
/**
|
||||
* Returns product of the variables represented as monic monomials.
|
||||
*/
|
||||
@JvmName("timesVariableVariable")
|
||||
public operator fun V.times(other: V): P
|
||||
|
||||
/**
|
||||
* Represents the [variable] as a monic monomial.
|
||||
*/
|
||||
@JvmName("numberVariable")
|
||||
public fun number(variable: V): P = +variable
|
||||
/**
|
||||
* Represents the variable as a monic monomial.
|
||||
*/
|
||||
@JvmName("asPolynomialVariable")
|
||||
public fun V.asPolynomial(): P = number(this)
|
||||
|
||||
/**
|
||||
* Returns sum of the variable represented as a monic monomial and the polynomial.
|
||||
*/
|
||||
@JvmName("plusVariablePolynomial")
|
||||
public operator fun V.plus(other: P): P
|
||||
/**
|
||||
* Returns difference between the variable represented as a monic monomial and the polynomial.
|
||||
*/
|
||||
@JvmName("minusVariablePolynomial")
|
||||
public operator fun V.minus(other: P): P
|
||||
/**
|
||||
* Returns product of the variable represented as a monic monomial and the polynomial.
|
||||
*/
|
||||
@JvmName("timesVariablePolynomial")
|
||||
public operator fun V.times(other: P): P
|
||||
|
||||
/**
|
||||
* Returns sum of the polynomial and the variable represented as a monic monomial.
|
||||
*/
|
||||
@JvmName("plusPolynomialVariable")
|
||||
public operator fun P.plus(other: V): P
|
||||
/**
|
||||
* Returns difference between the polynomial and the variable represented as a monic monomial.
|
||||
*/
|
||||
@JvmName("minusPolynomialVariable")
|
||||
public operator fun P.minus(other: V): P
|
||||
/**
|
||||
* Returns product of the polynomial and the variable represented as a monic monomial.
|
||||
*/
|
||||
@JvmName("timesPolynomialVariable")
|
||||
public operator fun P.times(other: V): P
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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.expressions.Symbol
|
||||
@ -15,189 +17,502 @@ import space.kscience.kmath.operations.Ring
|
||||
*/
|
||||
internal fun Map<Symbol, UInt>.cleanUp() = filterValues { it > 0U }
|
||||
|
||||
// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available
|
||||
/**
|
||||
* 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)
|
||||
|
||||
@Suppress("FunctionName", "NOTHING_TO_INLINE")
|
||||
internal inline fun <C, A: Ring<C>> LabeledPolynomialSpace<C, A>.LabeledPolynomial(coefs: Map<Map<Symbol, UInt>, C>, toCheckInput: Boolean = true) : LabeledPolynomial<C> = ring.LabeledPolynomial(coefs, toCheckInput)
|
||||
@Suppress("FunctionName", "NOTHING_TO_INLINE")
|
||||
internal inline fun <C, A: Ring<C>> LabeledRationalFunctionSpace<C, A>.LabeledPolynomial(coefs: Map<Map<Symbol, UInt>, C>, toCheckInput: Boolean = true) : LabeledPolynomial<C> = ring.LabeledPolynomial(coefs, toCheckInput)
|
||||
@Suppress("FunctionName")
|
||||
internal fun <C, A: Ring<C>> A.LabeledPolynomial(coefs: Map<Map<Symbol, UInt>, C>, toCheckInput: Boolean = true) : LabeledPolynomial<C> {
|
||||
if (!toCheckInput) return 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())
|
||||
|
||||
val fixedCoefs = LinkedHashMap<Map<Symbol, UInt>, C>(coefs.size)
|
||||
/**
|
||||
* 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) fixedCoefs[key]!! + value else value
|
||||
fixedCoefs[key] = if (key in fixedCoefs) add(fixedCoefs[key]!!, value) else value
|
||||
}
|
||||
|
||||
return LabeledPolynomial<C>(fixedCoefs)
|
||||
}
|
||||
|
||||
@Suppress("FunctionName", "NOTHING_TO_INLINE")
|
||||
internal inline fun <C, A: Ring<C>> LabeledPolynomialSpace<C, A>.LabeledPolynomial(pairs: Collection<Pair<Map<Symbol, UInt>, C>>, toCheckInput: Boolean = true) : LabeledPolynomial<C> = ring.LabeledPolynomial(pairs, toCheckInput)
|
||||
@Suppress("FunctionName", "NOTHING_TO_INLINE")
|
||||
internal inline fun <C, A: Ring<C>> LabeledRationalFunctionSpace<C, A>.LabeledPolynomial(pairs: Collection<Pair<Map<Symbol, UInt>, C>>, toCheckInput: Boolean = true) : LabeledPolynomial<C> = ring.LabeledPolynomial(pairs, toCheckInput)
|
||||
@Suppress("FunctionName")
|
||||
internal fun <C, A: Ring<C>> A.LabeledPolynomial(pairs: Collection<Pair<Map<Symbol, UInt>, C>>, toCheckInput: Boolean = true) : LabeledPolynomial<C> {
|
||||
if (!toCheckInput) return LabeledPolynomial<C>(pairs.toMap())
|
||||
|
||||
val fixedCoefs = LinkedHashMap<Map<Symbol, UInt>, C>(pairs.size)
|
||||
/**
|
||||
* 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) fixedCoefs[key]!! + value else value
|
||||
fixedCoefs[key] = if (key in fixedCoefs) add(fixedCoefs[key]!!, value) else value
|
||||
}
|
||||
|
||||
return LabeledPolynomial<C>(fixedCoefs)
|
||||
}
|
||||
|
||||
@Suppress("FunctionName", "NOTHING_TO_INLINE")
|
||||
internal inline fun <C, A: Ring<C>> LabeledPolynomialSpace<C, A>.LabeledPolynomial(vararg pairs: Pair<Map<Symbol, UInt>, C>, toCheckInput: Boolean = true) : LabeledPolynomial<C> = ring.LabeledPolynomial(pairs = pairs, toCheckInput = toCheckInput)
|
||||
@Suppress("FunctionName", "NOTHING_TO_INLINE")
|
||||
internal inline fun <C, A: Ring<C>> LabeledRationalFunctionSpace<C, A>.LabeledPolynomial(vararg pairs: Pair<Map<Symbol, UInt>, C>, toCheckInput: Boolean = true) : LabeledPolynomial<C> = ring.LabeledPolynomial(pairs = pairs, toCheckInput = toCheckInput)
|
||||
@Suppress("FunctionName")
|
||||
internal fun <C, A: Ring<C>> A.LabeledPolynomial(vararg pairs: Pair<Map<Symbol, UInt>, C>, toCheckInput: Boolean = true) : LabeledPolynomial<C> {
|
||||
if (!toCheckInput) return LabeledPolynomial<C>(pairs.toMap())
|
||||
|
||||
val fixedCoefs = LinkedHashMap<Map<Symbol, UInt>, C>(pairs.size)
|
||||
/**
|
||||
* 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) fixedCoefs[key]!! + value else value
|
||||
fixedCoefs[key] = if (key in fixedCoefs) add(fixedCoefs[key]!!, value) else value
|
||||
}
|
||||
|
||||
return LabeledPolynomial<C>(fixedCoefs)
|
||||
}
|
||||
|
||||
@Suppress("FunctionName")
|
||||
public fun <C, A: Ring<C>> A.LabeledPolynomial(coefs: Map<Map<Symbol, UInt>, C>) : LabeledPolynomial<C> = LabeledPolynomial(coefs, toCheckInput = true)
|
||||
@Suppress("FunctionName")
|
||||
public fun <C, A: Ring<C>> LabeledPolynomialSpace<C, A>.LabeledPolynomial(coefs: Map<Map<Symbol, UInt>, C>) : LabeledPolynomial<C> = LabeledPolynomial(coefs, toCheckInput = true)
|
||||
@Suppress("FunctionName")
|
||||
public fun <C, A: Ring<C>> LabeledRationalFunctionSpace<C, A>.LabeledPolynomial(coefs: Map<Map<Symbol, UInt>, C>) : LabeledPolynomial<C> = LabeledPolynomial(coefs, toCheckInput = true)
|
||||
// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available
|
||||
|
||||
@Suppress("FunctionName")
|
||||
public fun <C, A: Ring<C>> A.LabeledPolynomial(pairs: Collection<Pair<Map<Symbol, UInt>, C>>) : LabeledPolynomial<C> = LabeledPolynomial(pairs, toCheckInput = true)
|
||||
@Suppress("FunctionName")
|
||||
public fun <C, A: Ring<C>> LabeledPolynomialSpace<C, A>.LabeledPolynomial(pairs: Collection<Pair<Map<Symbol, UInt>, C>>) : LabeledPolynomial<C> = LabeledPolynomial(pairs, toCheckInput = true)
|
||||
@Suppress("FunctionName")
|
||||
public fun <C, A: Ring<C>> LabeledRationalFunctionSpace<C, A>.LabeledPolynomial(pairs: Collection<Pair<Map<Symbol, UInt>, C>>) : LabeledPolynomial<C> = LabeledPolynomial(pairs, toCheckInput = true)
|
||||
/**
|
||||
* 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 }
|
||||
|
||||
@Suppress("FunctionName")
|
||||
public fun <C, A: Ring<C>> A.LabeledPolynomial(vararg pairs: Pair<Map<Symbol, UInt>, C>) : LabeledPolynomial<C> = LabeledPolynomial(*pairs, toCheckInput = true)
|
||||
@Suppress("FunctionName")
|
||||
public fun <C, A: Ring<C>> LabeledPolynomialSpace<C, A>.LabeledPolynomial(vararg pairs: Pair<Map<Symbol, UInt>, C>) : LabeledPolynomial<C> = LabeledPolynomial(*pairs, toCheckInput = true)
|
||||
@Suppress("FunctionName")
|
||||
public fun <C, A: Ring<C>> LabeledRationalFunctionSpace<C, A>.LabeledPolynomial(vararg pairs: Pair<Map<Symbol, UInt>, C>) : LabeledPolynomial<C> = LabeledPolynomial(*pairs, toCheckInput = true)
|
||||
/**
|
||||
* 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 fun <C, A: Ring<C>> Symbol.asLabeledPolynomial() : LabeledPolynomial<C> = LabeledPolynomial<C>(mapOf(mapOf(this to 1u) to one))
|
||||
//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 fun <C, A: Ring<C>> Symbol.asLabeledPolynomial() : LabeledPolynomial<C> = LabeledPolynomial<C>(mapOf(mapOf(this to 1u) to constantOne))
|
||||
//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 fun <C, A: Ring<C>> Symbol.asLabeledPolynomial() : LabeledPolynomial<C> = LabeledPolynomial<C>(mapOf(mapOf(this to 1u) to constantOne))
|
||||
|
||||
public fun <C> C.asLabeledPolynomial() : LabeledPolynomial<C> = LabeledPolynomial<C>(mapOf(emptyMap<Symbol, UInt>() to this))
|
||||
//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()
|
||||
public fun build(): Map<Symbol, UInt> = signature
|
||||
|
||||
/**
|
||||
* 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>(private val zero: C, private val add: (C, C) -> C, capacity: Int = 0) {
|
||||
private val coefficients: MutableMap<Map<Symbol, UInt>, C> = LinkedHashMap(capacity)
|
||||
public fun build(): LabeledPolynomial<C> = LabeledPolynomial<C>(coefficients)
|
||||
public operator fun C.invoke(block: LabeledPolynomialTermSignatureBuilder.() -> Unit) {
|
||||
val signature = LabeledPolynomialTermSignatureBuilder().apply(block).build()
|
||||
coefficients[signature] = add(coefficients.getOrElse(signature) { zero }, this@invoke)
|
||||
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)
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline infix fun (LabeledPolynomialTermSignatureBuilder.() -> Unit).with(coef: C): Unit = coef.invoke(this)
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public infix fun sig(block: LabeledPolynomialTermSignatureBuilder.() -> Unit): LabeledPolynomialTermSignatureBuilder.() -> Unit = block
|
||||
/**
|
||||
* 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
|
||||
@LabeledPolynomialConstructorDSL
|
||||
@Suppress("FunctionName")
|
||||
public inline fun <C, A: Ring<C>> A.LabeledPolynomial(block: LabeledPolynomialBuilder<C>.() -> Unit) : LabeledPolynomial<C> = LabeledPolynomialBuilder(zero, ::add).apply(block).build()
|
||||
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
|
||||
@LabeledPolynomialConstructorDSL
|
||||
@Suppress("FunctionName")
|
||||
public inline fun <C, A: Ring<C>> A.LabeledPolynomial(capacity: Int, block: LabeledPolynomialBuilder<C>.() -> Unit) : LabeledPolynomial<C> = LabeledPolynomialBuilder(zero, ::add, capacity).apply(block).build()
|
||||
@UnstableKMathAPI
|
||||
@LabeledPolynomialConstructorDSL
|
||||
@Suppress("FunctionName")
|
||||
public inline fun <C, A: Ring<C>> LabeledPolynomialSpace<C, A>.LabeledPolynomial(block: LabeledPolynomialBuilder<C>.() -> Unit) : LabeledPolynomial<C> = LabeledPolynomialBuilder(constantZero, { left: C, right: C -> left + right}).apply(block).build()
|
||||
@UnstableKMathAPI
|
||||
@LabeledPolynomialConstructorDSL
|
||||
@Suppress("FunctionName")
|
||||
public inline fun <C, A: Ring<C>> LabeledPolynomialSpace<C, A>.LabeledPolynomial(capacity: Int, block: LabeledPolynomialBuilder<C>.() -> Unit) : LabeledPolynomial<C> = LabeledPolynomialBuilder(constantZero, { left: C, right: C -> left + right}, capacity).apply(block).build()
|
||||
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
|
||||
|
||||
@Suppress("FunctionName")
|
||||
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, toCheckInput = true),
|
||||
LabeledPolynomial(denominatorCoefficients, toCheckInput = true)
|
||||
)
|
||||
@Suppress("FunctionName")
|
||||
/**
|
||||
* 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, toCheckInput = true),
|
||||
LabeledPolynomial(denominatorCoefficients, toCheckInput = true)
|
||||
LabeledPolynomial(numeratorCoefficients),
|
||||
LabeledPolynomial(denominatorCoefficients)
|
||||
)
|
||||
@Suppress("FunctionName")
|
||||
/**
|
||||
* 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)
|
||||
@Suppress("FunctionName")
|
||||
public fun <C, A: Ring<C>> A.LabeledRationalFunction(numerator: LabeledPolynomial<C>): LabeledRationalFunction<C> =
|
||||
LabeledRationalFunction<C>(numerator, LabeledPolynomial(mapOf(emptyMap<Symbol, UInt>() to one), toCheckInput = false))
|
||||
@Suppress("FunctionName")
|
||||
|
||||
/**
|
||||
* 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, toCheckInput = true),
|
||||
LabeledPolynomial(numeratorCoefficients),
|
||||
polynomialOne
|
||||
)
|
||||
@Suppress("FunctionName")
|
||||
/**
|
||||
* 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, toCheckInput = true),
|
||||
LabeledPolynomial(mapOf(emptyMap<Symbol, UInt>() to one), toCheckInput = false)
|
||||
LabeledPolynomial(numeratorCoefficients),
|
||||
LabeledPolynomialAsIs(mapOf(emptyMap<Symbol, UInt>() to one))
|
||||
)
|
||||
|
||||
///**
|
||||
// * Converts [this] constant to [LabeledRationalFunction].
|
||||
// */
|
||||
//context(A)
|
||||
//public fun <C, A: Ring<C>> Symbol.asLabeledRationalFunction() : LabeledRationalFunction<C> = LabeledRationalFunction(asLabeledPolynomial())
|
||||
//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>> Symbol.asLabeledRationalFunction() : LabeledRationalFunction<C> = LabeledRationalFunction(asLabeledPolynomial())
|
||||
//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>> C.asLabeledRationalFunction() : LabeledRationalFunction<C> = LabeledRationalFunction(asLabeledPolynomial())
|
||||
//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>> C.asLabeledRationalFunction() : LabeledRationalFunction<C> = LabeledRationalFunction(asLabeledPolynomial())
|
||||
//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))
|
||||
// )
|
@ -1,495 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018-2021 KMath contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package space.kscience.kmath.functions
|
||||
|
||||
import space.kscience.kmath.expressions.Symbol
|
||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||
import space.kscience.kmath.operations.Field
|
||||
import space.kscience.kmath.operations.Ring
|
||||
import space.kscience.kmath.operations.invoke
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
import kotlin.contracts.InvocationKind
|
||||
import kotlin.contracts.contract
|
||||
|
||||
|
||||
// TODO: Docs
|
||||
|
||||
/**
|
||||
* Creates a [LabeledPolynomialSpace] over a received ring.
|
||||
*/
|
||||
public fun <C, A : Ring<C>> A.labeledPolynomial(): LabeledPolynomialSpace<C, A> =
|
||||
LabeledPolynomialSpace(this)
|
||||
|
||||
/**
|
||||
* Creates a [LabeledPolynomialSpace]'s scope over a received ring.
|
||||
*/
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
public inline fun <C, A : Ring<C>, R> A.labeledPolynomial(block: LabeledPolynomialSpace<C, A>.() -> R): R {
|
||||
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
|
||||
return LabeledPolynomialSpace(this).block()
|
||||
}
|
||||
|
||||
///**
|
||||
// * Represents the polynomial as a [String] with names of variables substituted with names from [names].
|
||||
// * Consider that monomials are sorted in lexicographic order.
|
||||
// */
|
||||
//context(LabeledPolynomialSpace<C, A>)
|
||||
//fun <C, A: Ring<C>> LabeledPolynomial<C>.represent(names: Map<Symbol, String> = emptyMap()): String =
|
||||
// coefficients.entries
|
||||
// .sortedWith { o1, o2 -> LabeledPolynomial.monomialComparator.compare(o1.key, o2.key) }
|
||||
// .asSequence()
|
||||
// .map { (degs, t) ->
|
||||
// if (degs.isEmpty()) "$t"
|
||||
// else {
|
||||
// when {
|
||||
// t.isOne() -> ""
|
||||
// t.isMinusOne() -> "-"
|
||||
// else -> "$t "
|
||||
// } +
|
||||
// degs
|
||||
// .toSortedMap()
|
||||
// .filter { it.value > 0U }
|
||||
// .map { (variable, deg) ->
|
||||
// val variableName = names.getOrDefault(variable, variable.toString())
|
||||
// when (deg) {
|
||||
// 1U -> variableName
|
||||
// else -> "$variableName^$deg"
|
||||
// }
|
||||
// }
|
||||
// .joinToString(separator = " ") { it }
|
||||
// }
|
||||
// }
|
||||
// .joinToString(separator = " + ") { it }
|
||||
// .ifEmpty { "0" }
|
||||
//
|
||||
///**
|
||||
// * Represents the polynomial as a [String] naming variables by [namer].
|
||||
// * Consider that monomials are sorted in lexicographic order.
|
||||
// */
|
||||
//context(LabeledPolynomialSpace<C, A>)
|
||||
//fun <C, A: Ring<C>> LabeledPolynomial<C>.represent(namer: (Symbol) -> String): String =
|
||||
// coefficients.entries
|
||||
// .sortedWith { o1, o2 -> LabeledPolynomial.monomialComparator.compare(o1.key, o2.key) }
|
||||
// .asSequence()
|
||||
// .map { (degs, t) ->
|
||||
// if (degs.isEmpty()) "$t"
|
||||
// else {
|
||||
// when {
|
||||
// t.isOne() -> ""
|
||||
// t.isMinusOne() -> "-"
|
||||
// else -> "$t "
|
||||
// } +
|
||||
// degs
|
||||
// .toSortedMap()
|
||||
// .filter { it.value > 0U }
|
||||
// .map { (variable, deg) ->
|
||||
// when (deg) {
|
||||
// 1U -> namer(variable)
|
||||
// else -> "${namer(variable)}^$deg"
|
||||
// }
|
||||
// }
|
||||
// .joinToString(separator = " ") { it }
|
||||
// }
|
||||
// }
|
||||
// .joinToString(separator = " + ") { it }
|
||||
// .ifEmpty { "0" }
|
||||
//
|
||||
///**
|
||||
// * Represents the polynomial as a [String] with names of variables substituted with names from [names] and with
|
||||
// * brackets around the string if needed (i.e. when there are at least two addends in the representation).
|
||||
// * Consider that monomials are sorted in lexicographic order.
|
||||
// */
|
||||
//context(LabeledPolynomialSpace<C, A>)
|
||||
//fun <C, A: Ring<C>> LabeledPolynomial<C>.representWithBrackets(names: Map<Symbol, String> = emptyMap()): String =
|
||||
// with(represent(names)) { if (coefficients.count() == 1) this else "($this)" }
|
||||
//
|
||||
///**
|
||||
// * Represents the polynomial as a [String] naming variables by [namer] and with brackets around the string if needed
|
||||
// * (i.e. when there are at least two addends in the representation).
|
||||
// * Consider that monomials are sorted in lexicographic order.
|
||||
// */
|
||||
//context(LabeledPolynomialSpace<C, A>)
|
||||
//fun <C, A: Ring<C>> LabeledPolynomial<C>.representWithBrackets(namer: (Symbol) -> String): String =
|
||||
// with(represent(namer)) { if (coefficients.count() == 1) this else "($this)" }
|
||||
//
|
||||
///**
|
||||
// * Represents the polynomial as a [String] with names of variables substituted with names from [names].
|
||||
// * Consider that monomials are sorted in **reversed** lexicographic order.
|
||||
// */
|
||||
//context(LabeledPolynomialSpace<C, A>)
|
||||
//fun <C, A: Ring<C>> LabeledPolynomial<C>.representReversed(names: Map<Symbol, String> = emptyMap()): String =
|
||||
// coefficients.entries
|
||||
// .sortedWith { o1, o2 -> -LabeledPolynomial.monomialComparator.compare(o1.key, o2.key) }
|
||||
// .asSequence()
|
||||
// .map { (degs, t) ->
|
||||
// if (degs.isEmpty()) "$t"
|
||||
// else {
|
||||
// when {
|
||||
// t.isOne() -> ""
|
||||
// t.isMinusOne() -> "-"
|
||||
// else -> "$t "
|
||||
// } +
|
||||
// degs
|
||||
// .toSortedMap()
|
||||
// .filter { it.value > 0U }
|
||||
// .map { (variable, deg) ->
|
||||
// val variableName = names.getOrDefault(variable, variable.toString())
|
||||
// when (deg) {
|
||||
// 1U -> variableName
|
||||
// else -> "$variableName^$deg"
|
||||
// }
|
||||
// }
|
||||
// .joinToString(separator = " ") { it }
|
||||
// }
|
||||
// }
|
||||
// .joinToString(separator = " + ") { it }
|
||||
// .ifEmpty { "0" }
|
||||
//
|
||||
///**
|
||||
// * Represents the polynomial as a [String] naming variables by [namer].
|
||||
// * Consider that monomials are sorted in **reversed** lexicographic order.
|
||||
// */
|
||||
//context(LabeledPolynomialSpace<C, A>)
|
||||
//fun <C, A: Ring<C>> LabeledPolynomial<C>.representReversed(namer: (Symbol) -> String): String =
|
||||
// coefficients.entries
|
||||
// .sortedWith { o1, o2 -> -LabeledPolynomial.monomialComparator.compare(o1.key, o2.key) }
|
||||
// .asSequence()
|
||||
// .map { (degs, t) ->
|
||||
// if (degs.isEmpty()) "$t"
|
||||
// else {
|
||||
// when {
|
||||
// t.isOne() -> ""
|
||||
// t.isMinusOne() -> "-"
|
||||
// else -> "$t "
|
||||
// } +
|
||||
// degs
|
||||
// .toSortedMap()
|
||||
// .filter { it.value > 0U }
|
||||
// .map { (variable, deg) ->
|
||||
// when (deg) {
|
||||
// 1U -> namer(variable)
|
||||
// else -> "${namer(variable)}^$deg"
|
||||
// }
|
||||
// }
|
||||
// .joinToString(separator = " ") { it }
|
||||
// }
|
||||
// }
|
||||
// .joinToString(separator = " + ") { it }
|
||||
// .ifEmpty { "0" }
|
||||
//
|
||||
///**
|
||||
// * Represents the polynomial as a [String] with names of variables substituted with names from [names] and with
|
||||
// * brackets around the string if needed (i.e. when there are at least two addends in the representation).
|
||||
// * Consider that monomials are sorted in **reversed** lexicographic order.
|
||||
// */
|
||||
//context(LabeledPolynomialSpace<C, A>)
|
||||
//fun <C, A: Ring<C>> LabeledPolynomial<C>.representReversedWithBrackets(names: Map<Symbol, String> = emptyMap()): String =
|
||||
// with(representReversed(names)) { if (coefficients.count() == 1) this else "($this)" }
|
||||
//
|
||||
///**
|
||||
// * Represents the polynomial as a [String] naming variables by [namer] and with brackets around the string if needed
|
||||
// * (i.e. when there are at least two addends in the representation).
|
||||
// * Consider that monomials are sorted in **reversed** lexicographic order.
|
||||
// */
|
||||
//context(LabeledPolynomialSpace<C, A>)
|
||||
//fun <C, A: Ring<C>> LabeledPolynomial<C>.representReversedWithBrackets(namer: (Symbol) -> String): String =
|
||||
// with(representReversed(namer)) { if (coefficients.count() == 1) this else "($this)" }
|
||||
|
||||
//operator fun <T: Field<T>> Polynomial<T>.div(other: T): Polynomial<T> =
|
||||
// if (other.isZero()) throw ArithmeticException("/ by zero")
|
||||
// else
|
||||
// Polynomial(
|
||||
// coefficients
|
||||
// .mapValues { it.value / other },
|
||||
// toCheckInput = false
|
||||
// )
|
||||
|
||||
//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 = degs.entries.asSequence().filter { it.key in args }.fold(c) { acc, (variable, deg) ->
|
||||
// multiplyWithPower(acc, args[variable]!!, deg)
|
||||
// }
|
||||
// this[newDegs] = if (newDegs in this) this[newDegs]!! + newC else newC
|
||||
// }
|
||||
// }
|
||||
// )
|
||||
//}
|
||||
//
|
||||
//// TODO: Replace with optimisation: the [result] may be unboxed, and all operations may be performed as soon as
|
||||
//// possible on it
|
||||
//@JvmName("substitutePolynomial")
|
||||
//fun <C> LabeledPolynomial<C>.substitute(ring: Ring<C>, arg: Map<Symbol, LabeledPolynomial<C>>) : LabeledPolynomial<C> =
|
||||
// ring.labeledPolynomial {
|
||||
// if (coefficients.isEmpty()) return zero
|
||||
// coefficients
|
||||
// .asSequence()
|
||||
// .map { (degs, c) ->
|
||||
// degs.entries
|
||||
// .asSequence()
|
||||
// .filter { it.key in arg }
|
||||
// .fold(LabeledPolynomial(mapOf(degs.filterKeys { it !in arg } to c))) { acc, (index, deg) ->
|
||||
// multiplyWithPower(acc, arg[index]!!, deg)
|
||||
// }
|
||||
// }
|
||||
// .reduce { acc, polynomial -> acc + polynomial } // TODO: Rewrite. Might be slow.
|
||||
// }
|
||||
//
|
||||
//// TODO: Substitute rational function
|
||||
//
|
||||
//fun <C, A : Ring<C>> LabeledPolynomial<C>.asFunctionOver(ring: A): (Map<Symbol, C>) -> LabeledPolynomial<C> =
|
||||
// { substitute(ring, it) }
|
||||
//
|
||||
//fun <C, A : Ring<C>> LabeledPolynomial<C>.asPolynomialFunctionOver(ring: A): (Map<Symbol, LabeledPolynomial<C>>) -> LabeledPolynomial<C> =
|
||||
// { substitute(ring, it) }
|
||||
|
||||
/**
|
||||
* Returns algebraic derivative of received polynomial.
|
||||
*/
|
||||
@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.
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public fun <C, A : Ring<C>> LabeledPolynomial<C>.derivativeWithRespectTo(
|
||||
algebra: A,
|
||||
variables: Collection<Symbol>,
|
||||
): LabeledPolynomial<C> = algebra {
|
||||
val cleanedVariables = variables.toSet()
|
||||
if (cleanedVariables.isEmpty()) return this@derivativeWithRespectTo
|
||||
LabeledPolynomial<C>(
|
||||
buildMap(coefficients.size) {
|
||||
coefficients
|
||||
.forEach { (degs, c) ->
|
||||
if (!degs.keys.containsAll(cleanedVariables)) return@forEach
|
||||
put(
|
||||
buildMap {
|
||||
degs.forEach { (vari, deg) ->
|
||||
when {
|
||||
vari !in cleanedVariables -> put(vari, deg)
|
||||
deg > 1u -> put(vari, deg - 1u)
|
||||
}
|
||||
}
|
||||
},
|
||||
cleanedVariables.fold(c) { acc, variable -> multiplyByDoubling(acc, degs[variable]!!) }
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns algebraic derivative of received polynomial.
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public fun <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.
|
||||
*/
|
||||
@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.
|
||||
*/
|
||||
@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.
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public fun <C, A : Field<C>> LabeledPolynomial<C>.antiderivativeWithRespectTo(
|
||||
algebra: A,
|
||||
variables: Collection<Symbol>,
|
||||
): LabeledPolynomial<C> = algebra {
|
||||
val cleanedVariables = variables.toSet()
|
||||
if (cleanedVariables.isEmpty()) return this@antiderivativeWithRespectTo
|
||||
LabeledPolynomial<C>(
|
||||
buildMap(coefficients.size) {
|
||||
coefficients
|
||||
.forEach { (degs, c) ->
|
||||
val newDegs = buildMap<Symbol, UInt>(degs.size + 1) {
|
||||
for (variable in cleanedVariables) put(variable, 1u)
|
||||
for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u })
|
||||
}
|
||||
put(
|
||||
newDegs,
|
||||
cleanedVariables.fold(c) { acc, variable -> acc / multiplyByDoubling(one, newDegs[variable]!!) }
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns algebraic derivative of received polynomial.
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public fun <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.
|
||||
*/
|
||||
@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) }
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018-2021 KMath contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package space.kscience.kmath.functions
|
||||
|
||||
import space.kscience.kmath.operations.Ring
|
||||
import kotlin.contracts.InvocationKind
|
||||
import kotlin.contracts.contract
|
||||
|
||||
|
||||
/**
|
||||
* Creates a [LabeledRationalFunctionSpace] over a received ring.
|
||||
*/
|
||||
public fun <C, A : Ring<C>> A.labeledRationalFunction(): LabeledRationalFunctionSpace<C, A> =
|
||||
LabeledRationalFunctionSpace(this)
|
||||
|
||||
/**
|
||||
* Creates a [LabeledRationalFunctionSpace]'s scope over a received ring.
|
||||
*/
|
||||
public inline fun <C, A : Ring<C>, R> A.labeledRationalFunction(block: LabeledRationalFunctionSpace<C, A>.() -> R): R {
|
||||
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
|
||||
return LabeledRationalFunctionSpace(this).block()
|
||||
}
|
||||
|
||||
//fun <T: Field<T>> LabeledRationalFunction<T>.reduced(): LabeledRationalFunction<T> {
|
||||
// val greatestCommonDivider = polynomialGCD(numerator, denominator)
|
||||
// return LabeledRationalFunction(
|
||||
// numerator / greatestCommonDivider,
|
||||
// denominator / greatestCommonDivider
|
||||
// )
|
||||
//}
|
@ -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,58 +3,95 @@
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2018-2021 KMath contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package space.kscience.kmath.functions
|
||||
|
||||
import space.kscience.kmath.operations.Ring
|
||||
|
||||
|
||||
/**
|
||||
* Returns a [ListPolynomial] instance with given [coefficients]. The collection of coefficients will be reversed if
|
||||
* [reverse] parameter is true.
|
||||
* Constructs a [ListPolynomial] instance with provided [coefficients]. The collection of coefficients will be reversed
|
||||
* if [reverse] parameter is true.
|
||||
*/
|
||||
@Suppress("FunctionName")
|
||||
public fun <C> ListPolynomial(coefficients: List<C>, reverse: Boolean = false): ListPolynomial<C> =
|
||||
ListPolynomial(with(coefficients) { if (reverse) reversed() else this })
|
||||
|
||||
/**
|
||||
* Returns a [ListPolynomial] instance with given [coefficients]. The collection of coefficients will be reversed if
|
||||
* [reverse] parameter is true.
|
||||
* Constructs a [ListPolynomial] instance with provided [coefficients]. The collection of coefficients will be reversed
|
||||
* if [reverse] parameter is true.
|
||||
*/
|
||||
@Suppress("FunctionName")
|
||||
public fun <C> ListPolynomial(vararg coefficients: C, reverse: Boolean = false): ListPolynomial<C> =
|
||||
ListPolynomial(with(coefficients) { if (reverse) reversed() else toList() })
|
||||
|
||||
/**
|
||||
* Represents [this] constant as a [ListPolynomial].
|
||||
*/
|
||||
public fun <C> C.asListPolynomial() : ListPolynomial<C> = ListPolynomial(listOf(this))
|
||||
|
||||
|
||||
// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available
|
||||
|
||||
/**
|
||||
* Constructs [ListRationalFunction] instance with numerator and denominator constructed with provided
|
||||
* [numeratorCoefficients] and [denominatorCoefficients]. The both collections of coefficients will be reversed if
|
||||
* [reverse] parameter is true.
|
||||
*/
|
||||
@Suppress("FunctionName")
|
||||
public fun <C> ListRationalFunction(numeratorCoefficients: List<C>, denominatorCoefficients: List<C>, reverse: Boolean = false): ListRationalFunction<C> =
|
||||
ListRationalFunction<C>(
|
||||
ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ),
|
||||
ListPolynomial( with(denominatorCoefficients) { if (reverse) reversed() else this } )
|
||||
)
|
||||
@Suppress("FunctionName")
|
||||
public fun <C, A: Ring<C>> ListRationalFunctionSpace<C, A>.ListRationalFunction(numerator: ListPolynomial<C>): ListRationalFunction<C> =
|
||||
ListRationalFunction<C>(numerator, polynomialOne)
|
||||
/**
|
||||
* Constructs [ListRationalFunction] instance with provided [numerator] and unit denominator.
|
||||
*/
|
||||
@Suppress("FunctionName")
|
||||
public fun <C, A: Ring<C>> A.ListRationalFunction(numerator: ListPolynomial<C>): ListRationalFunction<C> =
|
||||
ListRationalFunction<C>(numerator, ListPolynomial(listOf(one)))
|
||||
/**
|
||||
* Constructs [ListRationalFunction] instance with provided [numerator] and unit denominator.
|
||||
*/
|
||||
@Suppress("FunctionName")
|
||||
public fun <C, A: Ring<C>> ListRationalFunctionSpace<C, A>.ListRationalFunction(numeratorCoefficients: List<C>, reverse: Boolean = false): ListRationalFunction<C> =
|
||||
ListRationalFunction<C>(
|
||||
ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ),
|
||||
polynomialOne
|
||||
)
|
||||
public fun <C, A: Ring<C>> ListRationalFunctionSpace<C, A>.ListRationalFunction(numerator: ListPolynomial<C>): ListRationalFunction<C> =
|
||||
ListRationalFunction<C>(numerator, polynomialOne)
|
||||
/**
|
||||
* Constructs [ListRationalFunction] instance with numerator constructed with provided [numeratorCoefficients] and unit
|
||||
* denominator. The collection of numerator coefficients will be reversed if [reverse] parameter is true.
|
||||
*/
|
||||
@Suppress("FunctionName")
|
||||
public fun <C, A: Ring<C>> A.ListRationalFunction(numeratorCoefficients: List<C>, reverse: Boolean = false): ListRationalFunction<C> =
|
||||
ListRationalFunction<C>(
|
||||
ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ),
|
||||
ListPolynomial(listOf(one))
|
||||
)
|
||||
/**
|
||||
* Constructs [ListRationalFunction] instance with numerator constructed with provided [numeratorCoefficients] and unit
|
||||
* denominator. The collection of numerator coefficients will be reversed if [reverse] parameter is true.
|
||||
*/
|
||||
@Suppress("FunctionName")
|
||||
public fun <C, A: Ring<C>> ListRationalFunctionSpace<C, A>.ListRationalFunction(numeratorCoefficients: List<C>, reverse: Boolean = false): ListRationalFunction<C> =
|
||||
ListRationalFunction<C>(
|
||||
ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ),
|
||||
polynomialOne
|
||||
)
|
||||
|
||||
/**
|
||||
* Represents [this] constant as a rational function.
|
||||
*/ // FIXME: When context receivers will be ready, delete this function and uncomment the following two
|
||||
public fun <C, A: Ring<C>> C.asListRationalFunction(ring: A) : ListRationalFunction<C> = ring.ListRationalFunction(asListPolynomial())
|
||||
///**
|
||||
// * Represents [this] constant as a rational function.
|
||||
// */
|
||||
//context(A)
|
||||
//public fun <C, A: Ring<C>> C.asListRationalFunction() : ListRationalFunction<C> = ListRationalFunction(asListPolynomial())
|
||||
///**
|
||||
// * Represents [this] constant as a rational function.
|
||||
// */
|
||||
//context(ListRationalFunctionSpace<C, A>)
|
||||
//public fun <C, A: Ring<C>> C.asListRationalFunction() : ListRationalFunction<C> = ListRationalFunction(asListPolynomial())
|
@ -1,233 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018-2021 KMath contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package space.kscience.kmath.functions
|
||||
|
||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||
import space.kscience.kmath.operations.*
|
||||
import kotlin.contracts.InvocationKind
|
||||
import kotlin.contracts.contract
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
import kotlin.math.pow
|
||||
|
||||
|
||||
/**
|
||||
* Removes zeros on the end of the coefficient list of polynomial.
|
||||
*/
|
||||
//context(PolynomialSpace<C, A>)
|
||||
//fun <C, A: Ring<C>> Polynomial<C>.removeZeros() : Polynomial<C> =
|
||||
// if (degree > -1) Polynomial(coefficients.subList(0, degree + 1)) else zero
|
||||
|
||||
/**
|
||||
* Creates a [ListPolynomialSpace] over a received ring.
|
||||
*/
|
||||
public fun <C, A : Ring<C>> A.listPolynomial(): ListPolynomialSpace<C, A> =
|
||||
ListPolynomialSpace(this)
|
||||
|
||||
/**
|
||||
* Creates a [ListPolynomialSpace]'s scope over a received ring.
|
||||
*/
|
||||
public inline fun <C, A : Ring<C>, R> A.listPolynomial(block: ListPolynomialSpace<C, A>.() -> R): R {
|
||||
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
|
||||
return ListPolynomialSpace(this).block()
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a [ScalableListPolynomialSpace] over a received scalable ring.
|
||||
*/
|
||||
public fun <C, A> A.scalableListPolynomial(): ScalableListPolynomialSpace<C, A> where A : Ring<C>, A : ScaleOperations<C> =
|
||||
ScalableListPolynomialSpace(this)
|
||||
|
||||
/**
|
||||
* Creates a [ScalableListPolynomialSpace]'s scope over a received scalable ring.
|
||||
*/
|
||||
public inline fun <C, A, R> A.scalableListPolynomial(block: ScalableListPolynomialSpace<C, A>.() -> R): R where A : Ring<C>, A : ScaleOperations<C> {
|
||||
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
|
||||
return ScalableListPolynomialSpace(this).block()
|
||||
}
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
internal inline fun <C> copyTo(
|
||||
origin: List<C>,
|
||||
originDegree: Int,
|
||||
target: MutableList<C>,
|
||||
) {
|
||||
for (deg in 0 .. originDegree) target[deg] = origin[deg]
|
||||
}
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
internal inline fun <C> multiplyAddingToUpdater(
|
||||
ring: Ring<C>,
|
||||
multiplicand: MutableList<C>,
|
||||
multiplicandDegree: Int,
|
||||
multiplier: List<C>,
|
||||
multiplierDegree: Int,
|
||||
updater: MutableList<C>,
|
||||
zero: C,
|
||||
) {
|
||||
multiplyAddingTo(
|
||||
ring = ring,
|
||||
multiplicand = multiplicand,
|
||||
multiplicandDegree = multiplicandDegree,
|
||||
multiplier = multiplier,
|
||||
multiplierDegree = multiplierDegree,
|
||||
target = updater
|
||||
)
|
||||
for (updateDeg in 0 .. multiplicandDegree + multiplierDegree) {
|
||||
multiplicand[updateDeg] = updater[updateDeg]
|
||||
updater[updateDeg] = zero
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
internal inline fun <C> multiplyAddingTo(
|
||||
ring: Ring<C>,
|
||||
multiplicand: List<C>,
|
||||
multiplicandDegree: Int,
|
||||
multiplier: List<C>,
|
||||
multiplierDegree: Int,
|
||||
target: MutableList<C>
|
||||
) = ring {
|
||||
for (d in 0 .. multiplicandDegree + multiplierDegree)
|
||||
for (k in max(0, d - multiplierDegree)..min(multiplicandDegree, d))
|
||||
target[d] += multiplicand[k] * multiplier[d - k]
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates the value of the given double polynomial for given double argument.
|
||||
*/
|
||||
public fun ListPolynomial<Double>.substitute(arg: Double): Double =
|
||||
coefficients.reduceIndexedOrNull { index, acc, c ->
|
||||
acc + c * arg.pow(index)
|
||||
} ?: .0
|
||||
|
||||
/**
|
||||
* Evaluates the value of the given polynomial for given argument.
|
||||
*
|
||||
* It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method).
|
||||
*/
|
||||
public fun <C> ListPolynomial<C>.substitute(ring: Ring<C>, arg: C): C = ring {
|
||||
if (coefficients.isEmpty()) return@ring zero
|
||||
var result: C = coefficients.last()
|
||||
for (j in coefficients.size - 2 downTo 0) {
|
||||
result = (arg * result) + coefficients[j]
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
public fun <C> ListPolynomial<C>.substitute(ring: Ring<C>, arg: ListPolynomial<C>) : ListPolynomial<C> = ring {
|
||||
if (coefficients.isEmpty()) return ListPolynomial(emptyList())
|
||||
|
||||
val thisDegree = coefficients.lastIndex
|
||||
if (thisDegree == -1) return ListPolynomial(emptyList())
|
||||
val argDegree = arg.coefficients.lastIndex
|
||||
if (argDegree == -1) return coefficients[0].asListPolynomial()
|
||||
val constantZero = zero
|
||||
val resultCoefs: MutableList<C> = MutableList(thisDegree * argDegree + 1) { constantZero }
|
||||
resultCoefs[0] = coefficients[thisDegree]
|
||||
val resultCoefsUpdate: MutableList<C> = MutableList(thisDegree * argDegree + 1) { constantZero }
|
||||
var resultDegree = 0
|
||||
for (deg in thisDegree - 1 downTo 0) {
|
||||
resultCoefsUpdate[0] = coefficients[deg]
|
||||
multiplyAddingToUpdater(
|
||||
ring = ring,
|
||||
multiplicand = resultCoefs,
|
||||
multiplicandDegree = resultDegree,
|
||||
multiplier = arg.coefficients,
|
||||
multiplierDegree = argDegree,
|
||||
updater = resultCoefsUpdate,
|
||||
zero = constantZero
|
||||
)
|
||||
resultDegree += argDegree
|
||||
}
|
||||
|
||||
return ListPolynomial<C>(resultCoefs)
|
||||
}
|
||||
|
||||
/**
|
||||
* Represent the polynomial as a regular context-less function.
|
||||
*/
|
||||
public fun <C, A : Ring<C>> ListPolynomial<C>.asFunction(ring: A): (C) -> C = { substitute(ring, it) }
|
||||
|
||||
/**
|
||||
* Represent the 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) }
|
||||
|
||||
/**
|
||||
* Returns algebraic derivative of received polynomial.
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public fun <C, A> ListPolynomial<C>.derivative(
|
||||
algebra: A,
|
||||
): ListPolynomial<C> where A : Ring<C>, A : NumericAlgebra<C> = algebra {
|
||||
ListPolynomial(
|
||||
buildList(max(0, coefficients.size - 1)) {
|
||||
for (deg in 1 .. coefficients.lastIndex) add(number(deg) * coefficients[deg])
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns algebraic derivative of received polynomial.
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public fun <C, A> ListPolynomial<C>.nthDerivative(
|
||||
algebra: A,
|
||||
order: Int,
|
||||
): ListPolynomial<C> where A : Ring<C>, A : NumericAlgebra<C> = algebra {
|
||||
require(order >= 0) { "Order of derivative must be non-negative" }
|
||||
ListPolynomial(
|
||||
buildList(max(0, coefficients.size - order)) {
|
||||
for (deg in order.. coefficients.lastIndex)
|
||||
add((deg - order + 1 .. deg).fold(coefficients[deg]) { acc, d -> acc * number(d) })
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns algebraic antiderivative of received polynomial.
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public fun <C, A> ListPolynomial<C>.antiderivative(
|
||||
algebra: A,
|
||||
): ListPolynomial<C> where A : Field<C>, A : NumericAlgebra<C> = algebra {
|
||||
ListPolynomial(
|
||||
buildList(coefficients.size + 1) {
|
||||
add(zero)
|
||||
coefficients.mapIndexedTo(this) { index, t -> t / number(index + 1) }
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns algebraic antiderivative of received polynomial.
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public fun <C, A> ListPolynomial<C>.nthAntiderivative(
|
||||
algebra: A,
|
||||
order: Int,
|
||||
): ListPolynomial<C> where A : Field<C>, A : NumericAlgebra<C> = algebra {
|
||||
require(order >= 0) { "Order of antiderivative must be non-negative" }
|
||||
ListPolynomial(
|
||||
buildList(coefficients.size + order) {
|
||||
repeat(order) { add(zero) }
|
||||
coefficients.mapIndexedTo(this) { index, c -> (1..order).fold(c) { acc, i -> acc / number(index + i) } }
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute a definite integral of a given polynomial in a [range]
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public fun <C : Comparable<C>> ListPolynomial<C>.integrate(
|
||||
algebra: Field<C>,
|
||||
range: ClosedRange<C>,
|
||||
): C = algebra {
|
||||
val integral = antiderivative(algebra)
|
||||
integral.substitute(algebra, range.endInclusive) - integral.substitute(algebra, range.start)
|
||||
}
|
@ -0,0 +1,255 @@
|
||||
/*
|
||||
* Copyright 2018-2021 KMath contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package space.kscience.kmath.functions
|
||||
|
||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||
import space.kscience.kmath.operations.*
|
||||
import kotlin.contracts.InvocationKind
|
||||
import kotlin.contracts.contract
|
||||
import kotlin.math.max
|
||||
import kotlin.math.pow
|
||||
|
||||
|
||||
/**
|
||||
* Creates a [ListPolynomialSpace] over a received ring.
|
||||
*/
|
||||
public fun <C, A : Ring<C>> A.listPolynomialSpace(): ListPolynomialSpace<C, A> =
|
||||
ListPolynomialSpace(this)
|
||||
|
||||
/**
|
||||
* Creates a [ListPolynomialSpace]'s scope over a received ring.
|
||||
*/ // TODO: When context will be ready move [ListPolynomialSpace] and add [A] to context receivers of [block]
|
||||
public inline fun <C, A : Ring<C>, R> A.listPolynomialSpace(block: ListPolynomialSpace<C, A>.() -> R): R {
|
||||
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
|
||||
return ListPolynomialSpace(this).block()
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a [ScalableListPolynomialSpace] over a received scalable ring.
|
||||
*/
|
||||
public fun <C, A> A.scalableListPolynomialSpace(): ScalableListPolynomialSpace<C, A> where A : Ring<C>, A : ScaleOperations<C> =
|
||||
ScalableListPolynomialSpace(this)
|
||||
|
||||
/**
|
||||
* Creates a [ScalableListPolynomialSpace]'s scope over a received scalable ring.
|
||||
*/ // TODO: When context will be ready move [ListPolynomialSpace] and add [A] to context receivers of [block]
|
||||
public inline fun <C, A, R> A.scalableListPolynomialSpace(block: ScalableListPolynomialSpace<C, A>.() -> R): R where A : Ring<C>, A : ScaleOperations<C> {
|
||||
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
|
||||
return ScalableListPolynomialSpace(this).block()
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a [ListRationalFunctionSpace] over a received ring.
|
||||
*/
|
||||
public fun <C, A : Ring<C>> A.listRationalFunctionSpace(): ListRationalFunctionSpace<C, A> =
|
||||
ListRationalFunctionSpace(this)
|
||||
|
||||
/**
|
||||
* Creates a [ListRationalFunctionSpace]'s scope over a received ring.
|
||||
*/ // TODO: When context will be ready move [ListRationalFunctionSpace] and add [A] to context receivers of [block]
|
||||
public inline fun <C, A : Ring<C>, R> A.listRationalFunctionSpace(block: ListRationalFunctionSpace<C, A>.() -> R): R {
|
||||
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
|
||||
return ListRationalFunctionSpace(this).block()
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Evaluates value of [this] Double polynomial on provided Double argument.
|
||||
*/
|
||||
public fun ListPolynomial<Double>.substitute(arg: Double): Double =
|
||||
coefficients.reduceIndexedOrNull { index, acc, c ->
|
||||
acc + c * arg.pow(index)
|
||||
} ?: .0
|
||||
|
||||
/**
|
||||
* Evaluates value of [this] polynomial on provided argument.
|
||||
*
|
||||
* It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method).
|
||||
*/
|
||||
public fun <C> ListPolynomial<C>.substitute(ring: Ring<C>, arg: C): C = ring {
|
||||
if (coefficients.isEmpty()) return zero
|
||||
var result: C = coefficients.last()
|
||||
for (j in coefficients.size - 2 downTo 0) {
|
||||
result = (arg * result) + coefficients[j]
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Substitutes provided polynomial [arg] into [this] polynomial.
|
||||
*
|
||||
* It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method).
|
||||
*/ // TODO: To optimize boxing
|
||||
public fun <C> ListPolynomial<C>.substitute(ring: Ring<C>, arg: ListPolynomial<C>) : ListPolynomial<C> =
|
||||
ring.listPolynomialSpace {
|
||||
if (coefficients.isEmpty()) return zero
|
||||
var result: ListPolynomial<C> = coefficients.last().asPolynomial()
|
||||
for (j in coefficients.size - 2 downTo 0) {
|
||||
result = (arg * result) + coefficients[j]
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Substitutes provided rational function [arg] into [this] polynomial.
|
||||
*
|
||||
* It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method).
|
||||
*/ // TODO: To optimize boxing
|
||||
public fun <C> ListPolynomial<C>.substitute(ring: Ring<C>, arg: ListRationalFunction<C>) : ListRationalFunction<C> =
|
||||
ring.listRationalFunctionSpace {
|
||||
if (coefficients.isEmpty()) return zero
|
||||
var result: ListRationalFunction<C> = coefficients.last().asRationalFunction()
|
||||
for (j in coefficients.size - 2 downTo 0) {
|
||||
result = (arg * result) + coefficients[j]
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates value of [this] Double rational function in provided Double argument.
|
||||
*/
|
||||
public fun ListRationalFunction<Double>.substitute(arg: Double): Double =
|
||||
numerator.substitute(arg) / denominator.substitute(arg)
|
||||
|
||||
/**
|
||||
* Evaluates value of [this] polynomial for provided argument.
|
||||
*
|
||||
* It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method).
|
||||
*/
|
||||
public fun <C> ListRationalFunction<C>.substitute(ring: Field<C>, arg: C): C = ring {
|
||||
numerator.substitute(ring, arg) / denominator.substitute(ring, arg)
|
||||
}
|
||||
|
||||
/**
|
||||
* Substitutes provided polynomial [arg] into [this] rational function.
|
||||
*/ // TODO: To optimize boxing
|
||||
public fun <C> ListRationalFunction<C>.substitute(ring: Ring<C>, arg: ListPolynomial<C>) : ListRationalFunction<C> =
|
||||
ring.listRationalFunctionSpace {
|
||||
numerator.substitute(ring, arg) / denominator.substitute(ring, arg)
|
||||
}
|
||||
|
||||
/**
|
||||
* Substitutes provided rational function [arg] into [this] rational function.
|
||||
*/ // TODO: To optimize boxing
|
||||
public fun <C> ListRationalFunction<C>.substitute(ring: Ring<C>, arg: ListRationalFunction<C>) : ListRationalFunction<C> =
|
||||
ring.listRationalFunctionSpace {
|
||||
numerator.substitute(ring, arg) / denominator.substitute(ring, arg)
|
||||
}
|
||||
|
||||
/**
|
||||
* Represent [this] polynomial as a regular context-less function.
|
||||
*/
|
||||
public fun <C, A : Ring<C>> ListPolynomial<C>.asFunctionOver(ring: A): (C) -> C = { substitute(ring, it) }
|
||||
|
||||
/**
|
||||
* Represent [this] polynomial as a regular context-less function.
|
||||
*/
|
||||
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>.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.
|
||||
*/
|
||||
public fun <C, A : Field<C>> ListRationalFunction<C>.asFunctionOver(ring: A): (C) -> C = { substitute(ring, it) }
|
||||
|
||||
/**
|
||||
* Represent [this] rational function as a regular context-less function.
|
||||
*/
|
||||
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>.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.
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public fun <C, A> ListPolynomial<C>.derivative(
|
||||
ring: A,
|
||||
): ListPolynomial<C> where A : Ring<C>, A : NumericAlgebra<C> = ring {
|
||||
ListPolynomial(
|
||||
buildList(max(0, coefficients.size - 1)) {
|
||||
for (deg in 1 .. coefficients.lastIndex) add(number(deg) * coefficients[deg])
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns algebraic derivative of received polynomial of specified [order]. The [order] should be non-negative integer.
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public fun <C, A> ListPolynomial<C>.nthDerivative(
|
||||
ring: A,
|
||||
order: Int,
|
||||
): ListPolynomial<C> where A : Ring<C>, A : NumericAlgebra<C> = ring {
|
||||
require(order >= 0) { "Order of derivative must be non-negative" }
|
||||
ListPolynomial(
|
||||
buildList(max(0, coefficients.size - order)) {
|
||||
for (deg in order.. coefficients.lastIndex)
|
||||
add((deg - order + 1 .. deg).fold(coefficients[deg]) { acc, d -> acc * number(d) })
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns algebraic antiderivative of received polynomial.
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public fun <C, A> ListPolynomial<C>.antiderivative(
|
||||
ring: A,
|
||||
): ListPolynomial<C> where A : Field<C>, A : NumericAlgebra<C> = ring {
|
||||
ListPolynomial(
|
||||
buildList(coefficients.size + 1) {
|
||||
add(zero)
|
||||
coefficients.mapIndexedTo(this) { index, t -> t / number(index + 1) }
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns algebraic antiderivative of received polynomial of specified [order]. The [order] should be non-negative integer.
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public fun <C, A> ListPolynomial<C>.nthAntiderivative(
|
||||
ring: A,
|
||||
order: Int,
|
||||
): ListPolynomial<C> where A : Field<C>, A : NumericAlgebra<C> = ring {
|
||||
require(order >= 0) { "Order of antiderivative must be non-negative" }
|
||||
ListPolynomial(
|
||||
buildList(coefficients.size + order) {
|
||||
repeat(order) { add(zero) }
|
||||
coefficients.mapIndexedTo(this) { index, c -> (1..order).fold(c) { acc, i -> acc / number(index + i) } }
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes a definite integral of [this] polynomial in the specified [range].
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public fun <C : Comparable<C>> ListPolynomial<C>.integrate(
|
||||
ring: Field<C>,
|
||||
range: ClosedRange<C>,
|
||||
): C = ring {
|
||||
val antiderivative = antiderivative(ring)
|
||||
antiderivative.substitute(ring, range.endInclusive) - antiderivative.substitute(ring, range.start)
|
||||
}
|
@ -5,41 +5,91 @@
|
||||
|
||||
package space.kscience.kmath.functions
|
||||
|
||||
import space.kscience.kmath.operations.Field
|
||||
import space.kscience.kmath.operations.Ring
|
||||
import space.kscience.kmath.operations.invoke
|
||||
import kotlin.contracts.InvocationKind
|
||||
import kotlin.contracts.contract
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
|
||||
/**
|
||||
* Creates a [ListRationalFunctionSpace] over a received ring.
|
||||
*/
|
||||
public fun <C, A : Ring<C>> A.listRationalFunction(): ListRationalFunctionSpace<C, A> =
|
||||
ListRationalFunctionSpace(this)
|
||||
|
||||
/**
|
||||
* Creates a [ListRationalFunctionSpace]'s scope over a received ring.
|
||||
*/
|
||||
public inline fun <C, A : Ring<C>, R> A.listRationalFunction(block: ListRationalFunctionSpace<C, A>.() -> R): R {
|
||||
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
|
||||
return ListRationalFunctionSpace(this).block()
|
||||
// TODO: Optimized copies of substitution and invocation
|
||||
@UnstablePolynomialBoxingOptimization
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
internal inline fun <C> copyTo(
|
||||
origin: List<C>,
|
||||
originDegree: Int,
|
||||
target: MutableList<C>,
|
||||
) {
|
||||
for (deg in 0 .. originDegree) target[deg] = origin[deg]
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates the value of the given double polynomial for given double argument.
|
||||
*/
|
||||
public fun ListRationalFunction<Double>.substitute(arg: Double): Double =
|
||||
numerator.substitute(arg) / denominator.substitute(arg)
|
||||
@UnstablePolynomialBoxingOptimization
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
internal inline fun <C> multiplyAddingToUpdater(
|
||||
ring: Ring<C>,
|
||||
multiplicand: MutableList<C>,
|
||||
multiplicandDegree: Int,
|
||||
multiplier: List<C>,
|
||||
multiplierDegree: Int,
|
||||
updater: MutableList<C>,
|
||||
zero: C,
|
||||
) {
|
||||
multiplyAddingTo(
|
||||
ring = ring,
|
||||
multiplicand = multiplicand,
|
||||
multiplicandDegree = multiplicandDegree,
|
||||
multiplier = multiplier,
|
||||
multiplierDegree = multiplierDegree,
|
||||
target = updater
|
||||
)
|
||||
for (updateDeg in 0 .. multiplicandDegree + multiplierDegree) {
|
||||
multiplicand[updateDeg] = updater[updateDeg]
|
||||
updater[updateDeg] = zero
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates the value of the given polynomial for given argument.
|
||||
*
|
||||
* It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method).
|
||||
*/
|
||||
public fun <C> ListRationalFunction<C>.substitute(ring: Field<C>, arg: C): C = ring {
|
||||
numerator.substitute(ring, arg) / denominator.substitute(ring, arg)
|
||||
@UnstablePolynomialBoxingOptimization
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
internal inline fun <C> multiplyAddingTo(
|
||||
ring: Ring<C>,
|
||||
multiplicand: List<C>,
|
||||
multiplicandDegree: Int,
|
||||
multiplier: List<C>,
|
||||
multiplierDegree: Int,
|
||||
target: MutableList<C>
|
||||
) = ring {
|
||||
for (d in 0 .. multiplicandDegree + multiplierDegree)
|
||||
for (k in max(0, d - multiplierDegree)..min(multiplicandDegree, d))
|
||||
target[d] += multiplicand[k] * multiplier[d - k]
|
||||
}
|
||||
|
||||
@UnstablePolynomialBoxingOptimization
|
||||
public fun <C> ListPolynomial<C>.substitute2(ring: Ring<C>, arg: ListPolynomial<C>) : ListPolynomial<C> = ring {
|
||||
if (coefficients.isEmpty()) return ListPolynomial(emptyList())
|
||||
|
||||
val thisDegree = coefficients.lastIndex
|
||||
if (thisDegree == -1) return ListPolynomial(emptyList())
|
||||
val argDegree = arg.coefficients.lastIndex
|
||||
if (argDegree == -1) return coefficients[0].asListPolynomial()
|
||||
val constantZero = zero
|
||||
val resultCoefs: MutableList<C> = MutableList(thisDegree * argDegree + 1) { constantZero }
|
||||
resultCoefs[0] = coefficients[thisDegree]
|
||||
val resultCoefsUpdate: MutableList<C> = MutableList(thisDegree * argDegree + 1) { constantZero }
|
||||
var resultDegree = 0
|
||||
for (deg in thisDegree - 1 downTo 0) {
|
||||
resultCoefsUpdate[0] = coefficients[deg]
|
||||
multiplyAddingToUpdater(
|
||||
ring = ring,
|
||||
multiplicand = resultCoefs,
|
||||
multiplicandDegree = resultDegree,
|
||||
multiplier = arg.coefficients,
|
||||
multiplierDegree = argDegree,
|
||||
updater = resultCoefsUpdate,
|
||||
zero = constantZero
|
||||
)
|
||||
resultDegree += argDegree
|
||||
}
|
||||
|
||||
return ListPolynomial<C>(resultCoefs)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -52,6 +102,7 @@ public fun <C> ListRationalFunction<C>.substitute(ring: Field<C>, arg: C): C = r
|
||||
*
|
||||
* Used in [ListPolynomial.substitute] and [ListRationalFunction.substitute] for performance optimisation.
|
||||
*/ // TODO: Дописать
|
||||
@UnstablePolynomialBoxingOptimization
|
||||
internal fun <C> ListPolynomial<C>.substituteRationalFunctionTakeNumerator(ring: Ring<C>, arg: ListRationalFunction<C>): ListPolynomial<C> = ring {
|
||||
if (coefficients.isEmpty()) return ListPolynomial(emptyList())
|
||||
|
||||
@ -197,25 +248,3 @@ internal fun <C> ListPolynomial<C>.substituteRationalFunctionTakeNumerator(ring:
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
//operator fun <T: Field<T>> RationalFunction<T>.invoke(arg: T): T = numerator(arg) / denominator(arg)
|
||||
//
|
||||
//fun <T: Field<T>> RationalFunction<T>.reduced(): RationalFunction<T> =
|
||||
// polynomialGCD(numerator, denominator).let {
|
||||
// RationalFunction(
|
||||
// numerator / it,
|
||||
// denominator / it
|
||||
// )
|
||||
// }
|
||||
|
||||
///**
|
||||
// * Returns result of applying formal derivative to the polynomial.
|
||||
// *
|
||||
// * @param T Field where we are working now.
|
||||
// * @return Result of the operator.
|
||||
// */
|
||||
//fun <T: Ring<T>> RationalFunction<T>.derivative() =
|
||||
// RationalFunction(
|
||||
// numerator.derivative() * denominator - denominator.derivative() * numerator,
|
||||
// denominator * denominator
|
||||
// )
|
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
|
||||
/**
|
||||
* Marks operations that are going to be optimized reimplementations by reducing number of boxings but currently is
|
||||
* under development and is not stable (or even ready to use).
|
||||
*/
|
||||
@RequiresOptIn(
|
||||
message = "It's copy of operation with optimized boxing. It's currently unstable.",
|
||||
level = RequiresOptIn.Level.ERROR
|
||||
)
|
||||
internal annotation class UnstablePolynomialBoxingOptimization
|
||||
|
||||
/**
|
||||
* Marks declarations that give access to internal entities of polynomials delicate structure. Thus, it allows to
|
||||
* optimize performance a bit by skipping standard steps, but such skips may cause critical errors if something is
|
||||
* implemented badly. Make sure you fully read and understand documentation and don't break internal contracts.
|
||||
*/
|
||||
@RequiresOptIn(
|
||||
message = "This declaration gives access to delicate internal structure of polynomials. " +
|
||||
"It allows to optimize performance by skipping unnecessary arguments check. " +
|
||||
"But at the same time makes it easy to make a mistake " +
|
||||
"that will cause wrong computation result or even runtime error. " +
|
||||
"Make sure you fully read and understand documentation.",
|
||||
level = RequiresOptIn.Level.WARNING
|
||||
)
|
||||
internal annotation class DelicatePolynomialAPI
|
@ -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
|
||||
@ -14,182 +16,474 @@ import space.kscience.kmath.operations.Ring
|
||||
*/
|
||||
internal fun List<UInt>.cleanUp() = subList(0, indexOfLast { it != 0U } + 1)
|
||||
|
||||
// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available
|
||||
/**
|
||||
* Constructs [NumberedPolynomial] with provided coefficients map [coefs]. The map is used as is.
|
||||
*/
|
||||
@PublishedApi
|
||||
internal inline fun <C> NumberedPolynomialAsIs(coefs: Map<List<UInt>, C>) : NumberedPolynomial<C> = NumberedPolynomial<C>(coefs)
|
||||
|
||||
@Suppress("FunctionName", "NOTHING_TO_INLINE")
|
||||
internal inline fun <C, A: Ring<C>> NumberedPolynomialSpace<C, A>.NumberedPolynomial(coefs: Map<List<UInt>, C>, toCheckInput: Boolean = true) : NumberedPolynomial<C> = ring.NumberedPolynomial(coefs, toCheckInput)
|
||||
@Suppress("FunctionName", "NOTHING_TO_INLINE")
|
||||
internal inline fun <C, A: Ring<C>> NumberedRationalFunctionSpace<C, A>.NumberedPolynomial(coefs: Map<List<UInt>, C>, toCheckInput: Boolean = true) : NumberedPolynomial<C> = ring.NumberedPolynomial(coefs, toCheckInput)
|
||||
@Suppress("FunctionName")
|
||||
internal fun <C, A: Ring<C>> A.NumberedPolynomial(coefs: Map<List<UInt>, C>, toCheckInput: Boolean = true) : NumberedPolynomial<C> {
|
||||
if (!toCheckInput) return 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.
|
||||
*/
|
||||
@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.
|
||||
*/
|
||||
@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]. The map is used as is.
|
||||
*
|
||||
* **Be sure you read description of [NumberedPolynomial.coefficients]. Otherwise, you may make a mistake that will
|
||||
* cause wrong computation result or even runtime error.**
|
||||
*/
|
||||
@DelicatePolynomialAPI
|
||||
public inline fun <C> NumberedPolynomialWithoutCheck(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.
|
||||
*
|
||||
* **Be sure you read description of [NumberedPolynomial.coefficients]. Otherwise, you may make a mistake that will
|
||||
* cause wrong computation result or even runtime error.**
|
||||
*/
|
||||
@DelicatePolynomialAPI
|
||||
public inline fun <C> NumberedPolynomialWithoutCheck(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.
|
||||
*
|
||||
* **Be sure you read description of [NumberedPolynomial.coefficients]. Otherwise, you may make a mistake that will
|
||||
* cause wrong computation result or even runtime error.**
|
||||
*/
|
||||
@DelicatePolynomialAPI
|
||||
public inline fun <C> NumberedPolynomialWithoutCheck(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.
|
||||
*/
|
||||
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) fixedCoefs[key]!! + value else value
|
||||
fixedCoefs[key] = if (key in fixedCoefs) add(fixedCoefs[key]!!, value) else value
|
||||
}
|
||||
|
||||
return NumberedPolynomial<C>(fixedCoefs)
|
||||
}
|
||||
|
||||
@Suppress("FunctionName", "NOTHING_TO_INLINE")
|
||||
internal inline fun <C, A: Ring<C>> NumberedPolynomialSpace<C, A>.NumberedPolynomial(pairs: Collection<Pair<List<UInt>, C>>, toCheckInput: Boolean = true) : NumberedPolynomial<C> = ring.NumberedPolynomial(pairs, toCheckInput)
|
||||
@Suppress("FunctionName", "NOTHING_TO_INLINE")
|
||||
internal inline fun <C, A: Ring<C>> NumberedRationalFunctionSpace<C, A>.NumberedPolynomial(pairs: Collection<Pair<List<UInt>, C>>, toCheckInput: Boolean = true) : NumberedPolynomial<C> = ring.NumberedPolynomial(pairs, toCheckInput)
|
||||
@Suppress("FunctionName")
|
||||
internal fun <C, A: Ring<C>> A.NumberedPolynomial(pairs: Collection<Pair<List<UInt>, C>>, toCheckInput: Boolean = true) : NumberedPolynomial<C> {
|
||||
if (!toCheckInput) return NumberedPolynomial<C>(pairs.toMap())
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
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) fixedCoefs[key]!! + value else value
|
||||
fixedCoefs[key] = if (key in fixedCoefs) add(fixedCoefs[key]!!, value) else value
|
||||
}
|
||||
|
||||
return NumberedPolynomial<C>(fixedCoefs)
|
||||
}
|
||||
|
||||
@Suppress("FunctionName", "NOTHING_TO_INLINE")
|
||||
internal inline fun <C, A: Ring<C>> NumberedPolynomialSpace<C, A>.NumberedPolynomial(vararg pairs: Pair<List<UInt>, C>, toCheckInput: Boolean = true) : NumberedPolynomial<C> = ring.NumberedPolynomial(pairs = pairs, toCheckInput = toCheckInput)
|
||||
@Suppress("FunctionName", "NOTHING_TO_INLINE")
|
||||
internal inline fun <C, A: Ring<C>> NumberedRationalFunctionSpace<C, A>.NumberedPolynomial(vararg pairs: Pair<List<UInt>, C>, toCheckInput: Boolean = true) : NumberedPolynomial<C> = ring.NumberedPolynomial(pairs = pairs, toCheckInput = toCheckInput)
|
||||
@Suppress("FunctionName")
|
||||
internal fun <C, A: Ring<C>> A.NumberedPolynomial(vararg pairs: Pair<List<UInt>, C>, toCheckInput: Boolean = true) : NumberedPolynomial<C> {
|
||||
if (!toCheckInput) return NumberedPolynomial<C>(pairs.toMap())
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
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) fixedCoefs[key]!! + value else value
|
||||
fixedCoefs[key] = if (key in fixedCoefs) add(fixedCoefs[key]!!, value) else value
|
||||
}
|
||||
|
||||
return NumberedPolynomial<C>(fixedCoefs)
|
||||
}
|
||||
|
||||
@Suppress("FunctionName")
|
||||
public fun <C, A: Ring<C>> A.NumberedPolynomial(coefs: Map<List<UInt>, C>) : NumberedPolynomial<C> = NumberedPolynomial(coefs, toCheckInput = true)
|
||||
@Suppress("FunctionName")
|
||||
public fun <C, A: Ring<C>> NumberedPolynomialSpace<C, A>.NumberedPolynomial(coefs: Map<List<UInt>, C>) : NumberedPolynomial<C> = NumberedPolynomial(coefs, toCheckInput = true)
|
||||
@Suppress("FunctionName")
|
||||
public fun <C, A: Ring<C>> NumberedRationalFunctionSpace<C, A>.NumberedPolynomial(coefs: Map<List<UInt>, C>) : NumberedPolynomial<C> = NumberedPolynomial(coefs, toCheckInput = true)
|
||||
// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available
|
||||
|
||||
@Suppress("FunctionName")
|
||||
public fun <C, A: Ring<C>> A.NumberedPolynomial(pairs: Collection<Pair<List<UInt>, C>>) : NumberedPolynomial<C> = NumberedPolynomial(pairs, toCheckInput = true)
|
||||
@Suppress("FunctionName")
|
||||
public fun <C, A: Ring<C>> NumberedPolynomialSpace<C, A>.NumberedPolynomial(pairs: Collection<Pair<List<UInt>, C>>) : NumberedPolynomial<C> = NumberedPolynomial(pairs, toCheckInput = true)
|
||||
@Suppress("FunctionName")
|
||||
public fun <C, A: Ring<C>> NumberedRationalFunctionSpace<C, A>.NumberedPolynomial(pairs: Collection<Pair<List<UInt>, C>>) : NumberedPolynomial<C> = NumberedPolynomial(pairs, toCheckInput = true)
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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 }
|
||||
|
||||
@Suppress("FunctionName")
|
||||
public fun <C, A: Ring<C>> A.NumberedPolynomial(vararg pairs: Pair<List<UInt>, C>) : NumberedPolynomial<C> = NumberedPolynomial(*pairs, toCheckInput = true)
|
||||
@Suppress("FunctionName")
|
||||
public fun <C, A: Ring<C>> NumberedPolynomialSpace<C, A>.NumberedPolynomial(vararg pairs: Pair<List<UInt>, C>) : NumberedPolynomial<C> = NumberedPolynomial(*pairs, toCheckInput = true)
|
||||
@Suppress("FunctionName")
|
||||
public fun <C, A: Ring<C>> NumberedRationalFunctionSpace<C, A>.NumberedPolynomial(vararg pairs: Pair<List<UInt>, C>) : NumberedPolynomial<C> = NumberedPolynomial(*pairs, toCheckInput = true)
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
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 }
|
||||
|
||||
public fun <C> C.asNumberedPolynomial() : NumberedPolynomial<C> = NumberedPolynomial<C>(mapOf(emptyList<UInt>() to this))
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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].
|
||||
*/
|
||||
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()
|
||||
public fun build(): List<UInt> = signature
|
||||
|
||||
/**
|
||||
* Builds the resulting signature.
|
||||
*
|
||||
* In fact, it just returns [signature] as regular signature of type `List<UInt>`.
|
||||
*/
|
||||
@PublishedApi
|
||||
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 })
|
||||
val index = this - 1
|
||||
if (index > signature.lastIndex) {
|
||||
signature.addAll(List(index - signature.lastIndex - 1) { 0u })
|
||||
signature.add(deg)
|
||||
} else {
|
||||
signature[this] = deg
|
||||
signature[index] += deg
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 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
|
||||
public class NumberedPolynomialBuilder<C>(private val zero: C, private val add: (C, C) -> C, capacity: Int = 0) {
|
||||
private val coefficients: MutableMap<List<UInt>, C> = LinkedHashMap(capacity)
|
||||
public fun build(): NumberedPolynomial<C> = NumberedPolynomial<C>(coefficients)
|
||||
public operator fun C.invoke(block: NumberedPolynomialTermSignatureBuilder.() -> Unit) {
|
||||
val signature = NumberedPolynomialTermSignatureBuilder().apply(block).build()
|
||||
coefficients[signature] = add(coefficients.getOrElse(signature) { zero }, this@invoke)
|
||||
@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>) {
|
||||
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: NumberedPolynomialTermSignatureBuilder.() -> Unit): Unit = this.invoke(block)
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline infix fun (NumberedPolynomialTermSignatureBuilder.() -> Unit).with(coef: C): Unit = coef.invoke(this)
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public infix fun sig(block: NumberedPolynomialTermSignatureBuilder.() -> Unit): NumberedPolynomialTermSignatureBuilder.() -> Unit = block
|
||||
/**
|
||||
* 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: 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
|
||||
// * }
|
||||
// * }
|
||||
// * ```
|
||||
// */
|
||||
// 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.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
|
||||
@NumberedPolynomialConstructorDSL
|
||||
@Suppress("FunctionName")
|
||||
public inline fun <C, A: Ring<C>> A.NumberedPolynomial(block: NumberedPolynomialBuilder<C>.() -> Unit) : NumberedPolynomial<C> = NumberedPolynomialBuilder(zero, ::add).apply(block).build()
|
||||
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.
|
||||
*
|
||||
* 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
|
||||
@NumberedPolynomialConstructorDSL
|
||||
@Suppress("FunctionName")
|
||||
public inline fun <C, A: Ring<C>> A.NumberedPolynomial(capacity: Int, block: NumberedPolynomialBuilder<C>.() -> Unit) : NumberedPolynomial<C> = NumberedPolynomialBuilder(zero, ::add, capacity).apply(block).build()
|
||||
@UnstableKMathAPI
|
||||
@NumberedPolynomialConstructorDSL
|
||||
@Suppress("FunctionName")
|
||||
public inline fun <C, A: Ring<C>> NumberedPolynomialSpace<C, A>.NumberedPolynomial(block: NumberedPolynomialBuilder<C>.() -> Unit) : NumberedPolynomial<C> = NumberedPolynomialBuilder(constantZero, { left: C, right: C -> left + right}).apply(block).build()
|
||||
@UnstableKMathAPI
|
||||
@NumberedPolynomialConstructorDSL
|
||||
@Suppress("FunctionName")
|
||||
public inline fun <C, A: Ring<C>> NumberedPolynomialSpace<C, A>.NumberedPolynomial(capacity: Int, block: NumberedPolynomialBuilder<C>.() -> Unit) : NumberedPolynomial<C> = NumberedPolynomialBuilder(constantZero, { left: C, right: C -> left + right}, capacity).apply(block).build()
|
||||
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
|
||||
|
||||
@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, toCheckInput = true),
|
||||
NumberedPolynomial(denominatorCoefficients, toCheckInput = true)
|
||||
)
|
||||
@Suppress("FunctionName")
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public fun <C, A: Ring<C>> A.NumberedRationalFunction(numeratorCoefficients: Map<List<UInt>, C>, denominatorCoefficients: Map<List<UInt>, C>): NumberedRationalFunction<C> =
|
||||
NumberedRationalFunction<C>(
|
||||
NumberedPolynomial(numeratorCoefficients, toCheckInput = true),
|
||||
NumberedPolynomial(denominatorCoefficients, toCheckInput = true)
|
||||
NumberedPolynomial(numeratorCoefficients),
|
||||
NumberedPolynomial(denominatorCoefficients)
|
||||
)
|
||||
@Suppress("FunctionName")
|
||||
public fun <C, A: Ring<C>> NumberedRationalFunctionSpace<C, A>.NumberedRationalFunction(numerator: NumberedPolynomial<C>): NumberedRationalFunction<C> =
|
||||
NumberedRationalFunction<C>(numerator, polynomialOne)
|
||||
@Suppress("FunctionName")
|
||||
public fun <C, A: Ring<C>> A.NumberedRationalFunction(numerator: NumberedPolynomial<C>): NumberedRationalFunction<C> =
|
||||
NumberedRationalFunction<C>(numerator, NumberedPolynomial(mapOf(emptyList<UInt>() to one), toCheckInput = false))
|
||||
@Suppress("FunctionName")
|
||||
public fun <C, A: Ring<C>> NumberedRationalFunctionSpace<C, A>.NumberedRationalFunction(numeratorCoefficients: Map<List<UInt>, C>): NumberedRationalFunction<C> =
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
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, toCheckInput = true),
|
||||
polynomialOne
|
||||
)
|
||||
@Suppress("FunctionName")
|
||||
public fun <C, A: Ring<C>> A.NumberedRationalFunction(numeratorCoefficients: Map<List<UInt>, C>): NumberedRationalFunction<C> =
|
||||
NumberedRationalFunction<C>(
|
||||
NumberedPolynomial(numeratorCoefficients, toCheckInput = true),
|
||||
NumberedPolynomial(mapOf(emptyList<UInt>() to one), toCheckInput = false)
|
||||
NumberedPolynomial(numeratorCoefficients),
|
||||
NumberedPolynomial(denominatorCoefficients)
|
||||
)
|
||||
|
||||
/**
|
||||
* Constructs [NumberedRationalFunction] with provided [numerator] and unit denominator.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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] constant to [NumberedRationalFunction].
|
||||
// */
|
||||
//context(A)
|
||||
//public fun <C, A: Ring<C>> C.asNumberedRationalFunction() : NumberedRationalFunction<C> = NumberedRationalFunction(asLabeledPolynomial())
|
||||
//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] constant to [NumberedRationalFunction].
|
||||
// */
|
||||
//context(NumberedRationalFunctionSpace<C, A>)
|
||||
//public fun <C, A: Ring<C>> C.asNumberedRationalFunction() : NumberedRationalFunction<C> = NumberedRationalFunction(asLabeledPolynomial())
|
||||
//public fun <C, A: Ring<C>> C.asNumberedRationalFunction() : NumberedRationalFunction<C> =
|
||||
// NumberedRationalFunction(
|
||||
// NumberedPolynomialAsIs(mapOf(emptyList<UInt>() to this)),
|
||||
// NumberedPolynomialAsIs(mapOf(emptyList<UInt>() to constantOne))
|
||||
// )
|
@ -1,528 +0,0 @@
|
||||
package space.kscience.kmath.functions
|
||||
|
||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||
import space.kscience.kmath.operations.*
|
||||
import kotlin.contracts.*
|
||||
import kotlin.jvm.JvmName
|
||||
import kotlin.math.max
|
||||
|
||||
|
||||
// TODO: Docs
|
||||
|
||||
/**
|
||||
* Creates a [NumberedPolynomialSpace] over a received ring.
|
||||
*/
|
||||
public fun <C, A : Ring<C>> A.numberedPolynomial(): NumberedPolynomialSpace<C, A> =
|
||||
NumberedPolynomialSpace(this)
|
||||
|
||||
/**
|
||||
* Creates a [NumberedPolynomialSpace]'s scope over a received ring.
|
||||
*/
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
public inline fun <C, A : Ring<C>, R> A.numberedPolynomial(block: NumberedPolynomialSpace<C, A>.() -> R): R {
|
||||
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
|
||||
return NumberedPolynomialSpace(this).block()
|
||||
}
|
||||
|
||||
///**
|
||||
// * Represents the polynomial as a [String] where name of variable with index `i` is [withVariableName] + `"_${i+1}"`.
|
||||
// * Consider that monomials are sorted in lexicographic order.
|
||||
// */
|
||||
//context(NumberedPolynomialSpace<C, A>)
|
||||
//public fun <C, A: Ring<C>> NumberedPolynomial<C>.represent(withVariableName: String = NumberedPolynomial.defaultVariableName): String =
|
||||
// coefficients.entries
|
||||
// .sortedWith { o1, o2 -> NumberedPolynomial.monomialComparator.compare(o1.key, o2.key) }
|
||||
// .asSequence()
|
||||
// .map { (degs, t) ->
|
||||
// if (degs.isEmpty()) "$t"
|
||||
// else {
|
||||
// when {
|
||||
// t.isOne() -> ""
|
||||
// t.isMinusOne() -> "-"
|
||||
// else -> "$t "
|
||||
// } +
|
||||
// degs
|
||||
// .mapIndexed { index, deg ->
|
||||
// when (deg) {
|
||||
// 0U -> ""
|
||||
// 1U -> "${withVariableName}_${index+1}"
|
||||
// else -> "${withVariableName}_${index+1}^$deg"
|
||||
// }
|
||||
// }
|
||||
// .filter { it.isNotEmpty() }
|
||||
// .joinToString(separator = " ") { it }
|
||||
// }
|
||||
// }
|
||||
// .joinToString(separator = " + ") { it }
|
||||
// .ifEmpty { "0" }
|
||||
//
|
||||
///**
|
||||
// * Represents the polynomial as a [String] naming variables by [namer].
|
||||
// * Consider that monomials are sorted in lexicographic order.
|
||||
// */
|
||||
//context(NumberedPolynomialSpace<C, A>)
|
||||
//public fun <C, A: Ring<C>> NumberedPolynomial<C>.represent(namer: (Int) -> String): String =
|
||||
// coefficients.entries
|
||||
// .sortedWith { o1, o2 -> NumberedPolynomial.monomialComparator.compare(o1.key, o2.key) }
|
||||
// .asSequence()
|
||||
// .map { (degs, t) ->
|
||||
// if (degs.isEmpty()) "$t"
|
||||
// else {
|
||||
// when {
|
||||
// t.isOne() -> ""
|
||||
// t.isMinusOne() -> "-"
|
||||
// else -> "$t "
|
||||
// } +
|
||||
// degs
|
||||
// .mapIndexed { index, deg ->
|
||||
// when (deg) {
|
||||
// 0U -> ""
|
||||
// 1U -> namer(index)
|
||||
// else -> "${namer(index)}^$deg"
|
||||
// }
|
||||
// }
|
||||
// .filter { it.isNotEmpty() }
|
||||
// .joinToString(separator = " ") { it }
|
||||
// }
|
||||
// }
|
||||
// .joinToString(separator = " + ") { it }
|
||||
// .ifEmpty { "0" }
|
||||
//
|
||||
///**
|
||||
// * Represents the polynomial as a [String] where name of variable with index `i` is [withVariableName] + `"_${i+1}"`
|
||||
// * and with brackets around the string if needed (i.e. when there are at least two addends in the representation).
|
||||
// * Consider that monomials are sorted in lexicographic order.
|
||||
// */
|
||||
//context(NumberedPolynomialSpace<C, A>)
|
||||
//public fun <C, A: Ring<C>> NumberedPolynomial<C>.representWithBrackets(withVariableName: String = NumberedPolynomial.defaultVariableName): String =
|
||||
// with(represent(withVariableName)) { if (coefficients.count() == 1) this else "($this)" }
|
||||
//
|
||||
///**
|
||||
// * Represents the polynomial as a [String] naming variables by [namer] and with brackets around the string if needed
|
||||
// * (i.e. when there are at least two addends in the representation).
|
||||
// * Consider that monomials are sorted in lexicographic order.
|
||||
// */
|
||||
//context(NumberedPolynomialSpace<C, A>)
|
||||
//public fun <C, A: Ring<C>> NumberedPolynomial<C>.representWithBrackets(namer: (Int) -> String): String =
|
||||
// with(represent(namer)) { if (coefficients.count() == 1) this else "($this)" }
|
||||
//
|
||||
///**
|
||||
// * Represents the polynomial as a [String] where name of variable with index `i` is [withVariableName] + `"_${i+1}"`.
|
||||
// * Consider that monomials are sorted in **reversed** lexicographic order.
|
||||
// */
|
||||
//context(NumberedPolynomialSpace<C, A>)
|
||||
//public fun <C, A: Ring<C>> NumberedPolynomial<C>.representReversed(withVariableName: String = NumberedPolynomial.defaultVariableName): String =
|
||||
// coefficients.entries
|
||||
// .sortedWith { o1, o2 -> -NumberedPolynomial.monomialComparator.compare(o1.key, o2.key) }
|
||||
// .asSequence()
|
||||
// .map { (degs, t) ->
|
||||
// if (degs.isEmpty()) "$t"
|
||||
// else {
|
||||
// when {
|
||||
// t.isOne() -> ""
|
||||
// t.isMinusOne() -> "-"
|
||||
// else -> "$t "
|
||||
// } +
|
||||
// degs
|
||||
// .mapIndexed { index, deg ->
|
||||
// when (deg) {
|
||||
// 0U -> ""
|
||||
// 1U -> "${withVariableName}_${index+1}"
|
||||
// else -> "${withVariableName}_${index+1}^$deg"
|
||||
// }
|
||||
// }
|
||||
// .filter { it.isNotEmpty() }
|
||||
// .joinToString(separator = " ") { it }
|
||||
// }
|
||||
// }
|
||||
// .joinToString(separator = " + ") { it }
|
||||
// .ifEmpty { "0" }
|
||||
//
|
||||
///**
|
||||
// * Represents the polynomial as a [String] naming variables by [namer].
|
||||
// * Consider that monomials are sorted in **reversed** lexicographic order.
|
||||
// */
|
||||
//context(NumberedPolynomialSpace<C, A>)
|
||||
//public fun <C, A: Ring<C>> NumberedPolynomial<C>.representReversed(namer: (Int) -> String): String =
|
||||
// coefficients.entries
|
||||
// .sortedWith { o1, o2 -> -NumberedPolynomial.monomialComparator.compare(o1.key, o2.key) }
|
||||
// .asSequence()
|
||||
// .map { (degs, t) ->
|
||||
// if (degs.isEmpty()) "$t"
|
||||
// else {
|
||||
// when {
|
||||
// t.isOne() -> ""
|
||||
// t.isMinusOne() -> "-"
|
||||
// else -> "$t "
|
||||
// } +
|
||||
// degs
|
||||
// .mapIndexed { index, deg ->
|
||||
// when (deg) {
|
||||
// 0U -> ""
|
||||
// 1U -> namer(index)
|
||||
// else -> "${namer(index)}^$deg"
|
||||
// }
|
||||
// }
|
||||
// .filter { it.isNotEmpty() }
|
||||
// .joinToString(separator = " ") { it }
|
||||
// }
|
||||
// }
|
||||
// .joinToString(separator = " + ") { it }
|
||||
// .ifEmpty { "0" }
|
||||
//
|
||||
///**
|
||||
// * Represents the polynomial as a [String] where name of variable with index `i` is [withVariableName] + `"_${i+1}"`
|
||||
// * and with brackets around the string if needed (i.e. when there are at least two addends in the representation).
|
||||
// * Consider that monomials are sorted in **reversed** lexicographic order.
|
||||
// */
|
||||
//context(NumberedPolynomialSpace<C, A>)
|
||||
//public fun <C, A: Ring<C>> NumberedPolynomial<C>.representReversedWithBrackets(withVariableName: String = NumberedPolynomial.defaultVariableName): String =
|
||||
// with(representReversed(withVariableName)) { if (coefficients.count() == 1) this else "($this)" }
|
||||
//
|
||||
///**
|
||||
// * Represents the polynomial as a [String] naming variables by [namer] and with brackets around the string if needed
|
||||
// * (i.e. when there are at least two addends in the representation).
|
||||
// * Consider that monomials are sorted in **reversed** lexicographic order.
|
||||
// */
|
||||
//context(NumberedPolynomialSpace<C, A>)
|
||||
//public fun <C, A: Ring<C>> NumberedPolynomial<C>.representReversedWithBrackets(namer: (Int) -> String): String =
|
||||
// with(representReversed(namer)) { if (coefficients.count() == 1) this else "($this)" }
|
||||
|
||||
//public fun <C> NumberedPolynomial<C>.substitute(ring: Ring<C>, args: Map<Int, C>): NumberedPolynomial<C> = ring {
|
||||
// if (coefficients.isEmpty()) return this@substitute
|
||||
// NumberedPolynomial<C>(
|
||||
// buildMap {
|
||||
// coefficients.forEach { (degs, c) ->
|
||||
// val newDegs = degs.mapIndexed { index, deg -> if (index in args) 0U else deg }.cleanUp()
|
||||
// val newC = degs.foldIndexed(c) { index, acc, deg ->
|
||||
// if (index in args) multiplyWithPower(acc, args[index]!!, deg)
|
||||
// else acc
|
||||
// }
|
||||
// this[newDegs] = if (newDegs in this) this[newDegs]!! + newC else newC
|
||||
// }
|
||||
// }
|
||||
// )
|
||||
//}
|
||||
//
|
||||
//// TODO: Replace with optimisation: the [result] may be unboxed, and all operations may be performed as soon as
|
||||
//// possible on it
|
||||
//@JvmName("substitutePolynomial")
|
||||
//public fun <C> NumberedPolynomial<C>.substitute(ring: Ring<C>, arg: Map<Int, NumberedPolynomial<C>>) : NumberedPolynomial<C> =
|
||||
// ring.numberedPolynomialSpace {
|
||||
// if (coefficients.isEmpty()) return zero
|
||||
// coefficients
|
||||
// .asSequence()
|
||||
// .map { (degs, c) ->
|
||||
// degs.foldIndexed(
|
||||
// NumberedPolynomial(
|
||||
// degs.mapIndexed { index, deg -> if (index in arg) 0U else deg } to c
|
||||
// )
|
||||
// ) { index, acc, deg -> if (index in arg) multiplyWithPower(acc, arg[index]!!, deg) else acc }
|
||||
// }
|
||||
// .reduce { acc, polynomial -> acc + polynomial } // TODO: Rewrite. Might be slow.
|
||||
// }
|
||||
//
|
||||
//// TODO: Substitute rational function
|
||||
//
|
||||
//public fun <C, A : Ring<C>> NumberedPolynomial<C>.asFunctionOver(ring: A): (Map<Int, C>) -> NumberedPolynomial<C> =
|
||||
// { substitute(ring, it) }
|
||||
//
|
||||
//public fun <C, A : Ring<C>> NumberedPolynomial<C>.asPolynomialFunctionOver(ring: A): (Map<Int, NumberedPolynomial<C>>) -> NumberedPolynomial<C> =
|
||||
// { substitute(ring, it) }
|
||||
|
||||
//operator fun <T: Field<T>> Polynomial<T>.div(other: T): Polynomial<T> =
|
||||
// if (other.isZero()) throw ArithmeticException("/ by zero")
|
||||
// else
|
||||
// Polynomial(
|
||||
// coefficients
|
||||
// .mapValues { it.value / other },
|
||||
// toCheckInput = false
|
||||
// )
|
||||
|
||||
/**
|
||||
* Evaluates the value of the given double polynomial for given double argument.
|
||||
*/
|
||||
public fun NumberedPolynomial<Double>.substitute(args: Map<Int, Double>): NumberedPolynomial<Double> = Double.algebra {
|
||||
val acc = LinkedHashMap<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 acc) acc[newDegs] = newC
|
||||
else acc[newDegs] = acc[newDegs]!! + newC
|
||||
}
|
||||
return NumberedPolynomial<Double>(acc)
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates the value of the given polynomial for given argument.
|
||||
*
|
||||
* It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method).
|
||||
*/
|
||||
public fun <C> NumberedPolynomial<C>.substitute(ring: Ring<C>, args: Map<Int, C>): NumberedPolynomial<C> = ring {
|
||||
val acc = LinkedHashMap<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 acc) acc[newDegs] = newC
|
||||
else acc[newDegs] = acc[newDegs]!! + newC
|
||||
}
|
||||
return NumberedPolynomial<C>(acc)
|
||||
}
|
||||
|
||||
// TODO: (Waiting for hero) Replace with optimisation: the [result] may be unboxed, and all operations may be performed
|
||||
// as soon as possible on it
|
||||
@JvmName("substitutePolynomial")
|
||||
public fun <C> NumberedPolynomial<C>.substitute(ring: Ring<C>, args: Map<Int, NumberedPolynomial<C>>) : NumberedPolynomial<C> = TODO() /*ring.numberedPolynomial {
|
||||
val acc = LinkedHashMap<List<UInt>, NumberedPolynomial<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.asNumberedPolynomial()) { product, (variable, substitution) ->
|
||||
val deg = degs.getOrElse(variable) { 0u }
|
||||
if (deg == 0u) product else product * power(substitution, deg)
|
||||
}
|
||||
if (newDegs !in acc) acc[newDegs] = c.asNumberedPolynomial()
|
||||
else acc[newDegs] = acc[newDegs]!! + c
|
||||
}
|
||||
}*/
|
||||
|
||||
/**
|
||||
* Represent the polynomial as a regular context-less function.
|
||||
*/
|
||||
public fun <C, A : Ring<C>> NumberedPolynomial<C>.asFunction(ring: A): (Map<Int, C>) -> NumberedPolynomial<C> = { substitute(ring, it) }
|
||||
|
||||
/**
|
||||
* Represent the polynomial as a regular context-less function.
|
||||
*/
|
||||
public fun <C, A : Ring<C>> NumberedPolynomial<C>.asPolynomialFunctionOver(ring: A): (Map<Int, NumberedPolynomial<C>>) -> NumberedPolynomial<C> = { substitute(ring, it) }
|
||||
|
||||
/**
|
||||
* Returns algebraic derivative of received polynomial.
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public fun <C, A : Ring<C>> NumberedPolynomial<C>.derivativeWithRespectTo(
|
||||
algebra: A,
|
||||
variable: Int,
|
||||
): NumberedPolynomial<C> = algebra {
|
||||
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.
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public fun <C, A : Ring<C>> NumberedPolynomial<C>.derivativeWithRespectTo(
|
||||
algebra: A,
|
||||
variables: Collection<Int>,
|
||||
): NumberedPolynomial<C> = algebra {
|
||||
val cleanedVariables = variables.toSet()
|
||||
if (cleanedVariables.isEmpty()) return this@derivativeWithRespectTo
|
||||
val maxRespectedVariable = cleanedVariables.maxOrNull()!!
|
||||
NumberedPolynomial<C>(
|
||||
buildMap(coefficients.size) {
|
||||
coefficients
|
||||
.forEach { (degs, c) ->
|
||||
if (degs.size > maxRespectedVariable) return@forEach
|
||||
put(
|
||||
degs.mapIndexed { index, deg ->
|
||||
when {
|
||||
index !in cleanedVariables -> deg
|
||||
deg > 0u -> deg - 1u
|
||||
else -> return@forEach
|
||||
}
|
||||
}.cleanUp(),
|
||||
cleanedVariables.fold(c) { acc, variable -> multiplyByDoubling(acc, degs[variable]) }
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns algebraic derivative of received polynomial.
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public fun <C, A : Ring<C>> NumberedPolynomial<C>.nthDerivativeWithRespectTo(
|
||||
algebra: A,
|
||||
variable: Int,
|
||||
order: UInt
|
||||
): NumberedPolynomial<C> = algebra {
|
||||
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.
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public fun <C, A : Ring<C>> NumberedPolynomial<C>.nthDerivativeWithRespectTo(
|
||||
algebra: A,
|
||||
variablesAndOrders: Map<Int, UInt>,
|
||||
): NumberedPolynomial<C> = algebra {
|
||||
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.
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public fun <C, A : Field<C>> NumberedPolynomial<C>.antiderivativeWithRespectTo(
|
||||
algebra: A,
|
||||
variable: Int,
|
||||
): NumberedPolynomial<C> = algebra {
|
||||
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.
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public fun <C, A : Field<C>> NumberedPolynomial<C>.antiderivativeWithRespectTo(
|
||||
algebra: A,
|
||||
variables: Collection<Int>,
|
||||
): NumberedPolynomial<C> = algebra {
|
||||
val cleanedVariables = variables.toSet()
|
||||
if (cleanedVariables.isEmpty()) return this@antiderivativeWithRespectTo
|
||||
val maxRespectedVariable = cleanedVariables.maxOrNull()!!
|
||||
NumberedPolynomial<C>(
|
||||
buildMap(coefficients.size) {
|
||||
coefficients
|
||||
.forEach { (degs, c) ->
|
||||
put(
|
||||
List(max(maxRespectedVariable + 1, degs.size)) { if (it !in variables) degs[it] else degs[it] + 1u },
|
||||
cleanedVariables.fold(c) { acc, variable -> acc / multiplyByDoubling(one, degs[variable]) }
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns algebraic derivative of received polynomial.
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public fun <C, A : Field<C>> NumberedPolynomial<C>.nthAntiderivativeWithRespectTo(
|
||||
algebra: A,
|
||||
variable: Int,
|
||||
order: UInt
|
||||
): NumberedPolynomial<C> = algebra {
|
||||
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.
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public fun <C, A : Field<C>> NumberedPolynomial<C>.nthAntiderivativeWithRespectTo(
|
||||
algebra: A,
|
||||
variablesAndOrders: Map<Int, UInt>,
|
||||
): NumberedPolynomial<C> = algebra {
|
||||
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) }
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018-2021 KMath contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package space.kscience.kmath.functions
|
||||
|
||||
import space.kscience.kmath.operations.Ring
|
||||
import kotlin.contracts.InvocationKind
|
||||
import kotlin.contracts.contract
|
||||
|
||||
|
||||
/**
|
||||
* Creates a [NumberedRationalFunctionSpace] over a received ring.
|
||||
*/
|
||||
public fun <C, A : Ring<C>> A.numberedRationalFunction(): NumberedRationalFunctionSpace<C, A> =
|
||||
NumberedRationalFunctionSpace(this)
|
||||
|
||||
/**
|
||||
* Creates a [NumberedRationalFunctionSpace]'s scope over a received ring.
|
||||
*/
|
||||
public inline fun <C, A : Ring<C>, R> A.numberedRationalFunction(block: NumberedRationalFunctionSpace<C, A>.() -> R): R {
|
||||
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
|
||||
return NumberedRationalFunctionSpace(this).block()
|
||||
}
|
||||
|
||||
//fun <T: Field<T>> NumberedRationalFunction<T>.reduced(): NumberedRationalFunction<T> {
|
||||
// val greatestCommonDivider = polynomialGCD(numerator, denominator)
|
||||
// return NumberedRationalFunction(
|
||||
// numerator / greatestCommonDivider,
|
||||
// denominator / greatestCommonDivider
|
||||
// )
|
||||
//}
|
@ -0,0 +1,513 @@
|
||||
/*
|
||||
* 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(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())
|
||||
}
|
||||
this[newDegs] = if (newDegs !in this) newC else 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(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)
|
||||
}
|
||||
this[newDegs] = if (newDegs !in this) newC else 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 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 calculation
|
||||
@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 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 calculation
|
||||
@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) }
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
@ -3,6 +3,8 @@
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@file:Suppress("LocalVariableName")
|
||||
|
||||
package space.kscience.kmath.functions
|
||||
|
||||
import space.kscience.kmath.test.misc.*
|
||||
@ -12,7 +14,7 @@ import kotlin.test.*
|
||||
class ListPolynomialTest {
|
||||
@Test
|
||||
fun test_Polynomial_Int_plus() {
|
||||
RationalField.listPolynomial {
|
||||
RationalField.listPolynomialSpace {
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)),
|
||||
ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + -3,
|
||||
@ -28,31 +30,38 @@ class ListPolynomialTest {
|
||||
ListPolynomial(Rational(-2)) + 2,
|
||||
"test 3"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(),
|
||||
ListPolynomial<Rational>() + 0,
|
||||
val polynomial_4 = ListPolynomial<Rational>()
|
||||
assertSame(
|
||||
polynomial_4,
|
||||
polynomial_4 + 0,
|
||||
"test 4"
|
||||
)
|
||||
val polynomial_5 = ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7))
|
||||
assertSame(
|
||||
polynomial_5,
|
||||
polynomial_5 + 0,
|
||||
"test 5"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(-1), Rational(0), Rational(0), Rational(0)),
|
||||
ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + 1,
|
||||
"test 5"
|
||||
"test 6"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(-1)),
|
||||
ListPolynomial(Rational(-2)) + 1,
|
||||
"test 6"
|
||||
"test 7"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(2)),
|
||||
ListPolynomial<Rational>() + 2,
|
||||
"test 7"
|
||||
"test 8"
|
||||
)
|
||||
}
|
||||
}
|
||||
@Test
|
||||
fun test_Polynomial_Int_minus() {
|
||||
RationalField.listPolynomial {
|
||||
RationalField.listPolynomialSpace {
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)),
|
||||
ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - -3,
|
||||
@ -68,31 +77,38 @@ class ListPolynomialTest {
|
||||
ListPolynomial(Rational(2)) - 2,
|
||||
"test 3"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(),
|
||||
ListPolynomial<Rational>() - 0,
|
||||
val polynomial_4 = ListPolynomial<Rational>()
|
||||
assertSame(
|
||||
polynomial_4,
|
||||
polynomial_4 - 0,
|
||||
"test 4"
|
||||
)
|
||||
val polynomial_5 = ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7))
|
||||
assertEquals(
|
||||
polynomial_5,
|
||||
polynomial_5 - 0,
|
||||
"test 5"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(1), Rational(0), Rational(0), Rational(0)),
|
||||
ListPolynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - 1,
|
||||
"test 5"
|
||||
"test 6"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(1)),
|
||||
ListPolynomial(Rational(2)) - 1,
|
||||
"test 6"
|
||||
"test 7"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(-2)),
|
||||
ListPolynomial<Rational>() - 2,
|
||||
"test 7"
|
||||
"test 8"
|
||||
)
|
||||
}
|
||||
}
|
||||
@Test
|
||||
fun test_Polynomial_Int_times() {
|
||||
IntModuloRing(35).listPolynomial {
|
||||
IntModuloRing(35).listPolynomialSpace {
|
||||
assertEquals(
|
||||
ListPolynomial(34, 2, 1, 20, 2),
|
||||
ListPolynomial(22, 26, 13, 15, 26) * 27,
|
||||
@ -103,11 +119,22 @@ class ListPolynomialTest {
|
||||
ListPolynomial(7, 0, 49, 21, 14) * 15,
|
||||
"test 2"
|
||||
)
|
||||
val polynomial = ListPolynomial(22, 26, 13, 15, 26)
|
||||
assertSame(
|
||||
zero,
|
||||
polynomial * 0,
|
||||
"test 3"
|
||||
)
|
||||
assertSame(
|
||||
polynomial,
|
||||
polynomial * 1,
|
||||
"test 4"
|
||||
)
|
||||
}
|
||||
}
|
||||
@Test
|
||||
fun test_Int_Polynomial_plus() {
|
||||
RationalField.listPolynomial {
|
||||
RationalField.listPolynomialSpace {
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)),
|
||||
-3 + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)),
|
||||
@ -123,31 +150,38 @@ class ListPolynomialTest {
|
||||
2 + ListPolynomial(Rational(-2)),
|
||||
"test 3"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(),
|
||||
0 + ListPolynomial(),
|
||||
val polynomial_4 = ListPolynomial<Rational>()
|
||||
assertSame(
|
||||
polynomial_4,
|
||||
0 + polynomial_4,
|
||||
"test 4"
|
||||
)
|
||||
val polynomial_5 = ListPolynomial<Rational>(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7))
|
||||
assertSame(
|
||||
polynomial_5,
|
||||
0 + polynomial_5,
|
||||
"test 5"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(-1), Rational(0), Rational(0), Rational(0)),
|
||||
1 + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)),
|
||||
"test 5"
|
||||
"test 6"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(-1)),
|
||||
1 + ListPolynomial(Rational(-2)),
|
||||
"test 6"
|
||||
"test 7"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(2)),
|
||||
2 + ListPolynomial(),
|
||||
"test 7"
|
||||
"test 8"
|
||||
)
|
||||
}
|
||||
}
|
||||
@Test
|
||||
fun test_Int_Polynomial_minus() {
|
||||
RationalField.listPolynomial {
|
||||
RationalField.listPolynomialSpace {
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)),
|
||||
3 - ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)),
|
||||
@ -163,31 +197,36 @@ class ListPolynomialTest {
|
||||
-2 - ListPolynomial(Rational(-2)),
|
||||
"test 3"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(-32, 9), Rational(-8, -9), Rational(8, 7)),
|
||||
0 - ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)),
|
||||
"test 4"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(),
|
||||
0 - ListPolynomial(),
|
||||
"test 4"
|
||||
"test 5"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(1), Rational(0), Rational(0), Rational(0)),
|
||||
-1 - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)),
|
||||
"test 5"
|
||||
"test 6"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(1)),
|
||||
-1 - ListPolynomial(Rational(-2)),
|
||||
"test 6"
|
||||
"test 7"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(-2)),
|
||||
-2 - ListPolynomial(),
|
||||
"test 7"
|
||||
"test 8"
|
||||
)
|
||||
}
|
||||
}
|
||||
@Test
|
||||
fun test_Int_Polynomial_times() {
|
||||
IntModuloRing(35).listPolynomial {
|
||||
IntModuloRing(35).listPolynomialSpace {
|
||||
assertEquals(
|
||||
ListPolynomial(34, 2, 1, 20, 2),
|
||||
27 * ListPolynomial(22, 26, 13, 15, 26),
|
||||
@ -198,11 +237,22 @@ class ListPolynomialTest {
|
||||
15 * ListPolynomial(7, 0, 49, 21, 14),
|
||||
"test 2"
|
||||
)
|
||||
val polynomial = ListPolynomial(22, 26, 13, 15, 26)
|
||||
assertSame(
|
||||
zero,
|
||||
0 * polynomial,
|
||||
"test 3"
|
||||
)
|
||||
assertSame(
|
||||
polynomial,
|
||||
1 * polynomial,
|
||||
"test 4"
|
||||
)
|
||||
}
|
||||
}
|
||||
@Test
|
||||
fun test_Polynomial_Constant_plus() {
|
||||
RationalField.listPolynomial {
|
||||
RationalField.listPolynomialSpace {
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)),
|
||||
ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + Rational(-3),
|
||||
@ -242,7 +292,7 @@ class ListPolynomialTest {
|
||||
}
|
||||
@Test
|
||||
fun test_Polynomial_Constant_minus() {
|
||||
RationalField.listPolynomial {
|
||||
RationalField.listPolynomialSpace {
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)),
|
||||
ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - Rational(-3),
|
||||
@ -282,7 +332,7 @@ class ListPolynomialTest {
|
||||
}
|
||||
@Test
|
||||
fun test_Polynomial_Constant_times() {
|
||||
IntModuloRing(35).listPolynomial {
|
||||
IntModuloRing(35).listPolynomialSpace {
|
||||
assertEquals(
|
||||
ListPolynomial(34, 2, 1, 20, 2),
|
||||
ListPolynomial(22, 26, 13, 15, 26) * 27.asConstant(),
|
||||
@ -297,7 +347,7 @@ class ListPolynomialTest {
|
||||
}
|
||||
@Test
|
||||
fun test_Constant_Polynomial_plus() {
|
||||
RationalField.listPolynomial {
|
||||
RationalField.listPolynomialSpace {
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)),
|
||||
Rational(-3) + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)),
|
||||
@ -337,7 +387,7 @@ class ListPolynomialTest {
|
||||
}
|
||||
@Test
|
||||
fun test_Constant_Polynomial_minus() {
|
||||
RationalField.listPolynomial {
|
||||
RationalField.listPolynomialSpace {
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)),
|
||||
Rational(3) - ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)),
|
||||
@ -377,7 +427,7 @@ class ListPolynomialTest {
|
||||
}
|
||||
@Test
|
||||
fun test_Constant_Polynomial_times() {
|
||||
IntModuloRing(35).listPolynomial {
|
||||
IntModuloRing(35).listPolynomialSpace {
|
||||
assertEquals(
|
||||
ListPolynomial(34, 2, 1, 20, 2),
|
||||
27 * ListPolynomial(22, 26, 13, 15, 26),
|
||||
@ -392,7 +442,7 @@ class ListPolynomialTest {
|
||||
}
|
||||
@Test
|
||||
fun test_Polynomial_unaryMinus() {
|
||||
RationalField.listPolynomial {
|
||||
RationalField.listPolynomialSpace {
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)),
|
||||
-ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)),
|
||||
@ -407,7 +457,7 @@ class ListPolynomialTest {
|
||||
}
|
||||
@Test
|
||||
fun test_Polynomial_Polynomial_plus() {
|
||||
RationalField.listPolynomial {
|
||||
RationalField.listPolynomialSpace {
|
||||
// (5/9 - 8/9 x - 8/7 x^2) + (-5/7 + 5/1 x + 5/8 x^2) ?= -10/63 + 37/9 x - 29/56 x^2
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(-10, 63), Rational(37, 9), Rational(-29, 56)),
|
||||
@ -440,7 +490,7 @@ class ListPolynomialTest {
|
||||
}
|
||||
@Test
|
||||
fun test_Polynomial_Polynomial_minus() {
|
||||
RationalField.listPolynomial {
|
||||
RationalField.listPolynomialSpace {
|
||||
// (5/9 - 8/9 x - 8/7 x^2) - (-5/7 + 5/1 x + 5/8 x^2) ?= 80/63 - 53/9 x - 99/56 x^2
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(80, 63), Rational(-53, 9), Rational(-99, 56)),
|
||||
@ -473,7 +523,7 @@ class ListPolynomialTest {
|
||||
}
|
||||
@Test
|
||||
fun test_Polynomial_Polynomial_times() {
|
||||
IntModuloRing(35).listPolynomial {
|
||||
IntModuloRing(35).listPolynomialSpace {
|
||||
// (1 + x + x^2) * (1 - x + x^2) ?= 1 + x^2 + x^4
|
||||
assertEquals(
|
||||
ListPolynomial(1, 0, 1, 0, 1),
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
package space.kscience.kmath.functions
|
||||
|
||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||
import space.kscience.kmath.test.misc.Rational
|
||||
import space.kscience.kmath.test.misc.RationalField
|
||||
import kotlin.test.Test
|
||||
@ -12,6 +13,7 @@ import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFailsWith
|
||||
|
||||
|
||||
@OptIn(UnstableKMathAPI::class)
|
||||
class ListPolynomialUtilTest {
|
||||
@Test
|
||||
fun test_substitute_Double() {
|
||||
|
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright 2018-2021 KMath contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package space.kscience.kmath.functions
|
||||
|
||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||
import space.kscience.kmath.operations.algebra
|
||||
import space.kscience.kmath.operations.invoke
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
|
||||
class NumberedConstructorsTest {
|
||||
@Test
|
||||
@UnstableKMathAPI
|
||||
fun testBuilder() {
|
||||
assertEquals(
|
||||
NumberedPolynomialAsIs(
|
||||
listOf(2u, 0u, 3u) to 5,
|
||||
listOf(0u, 1u) to -6,
|
||||
),
|
||||
Int.algebra.numberedPolynomialSpace {
|
||||
NumberedPolynomial {
|
||||
5 { 1 inPowerOf 2u; 3 inPowerOf 3u }
|
||||
(-6) { 2 inPowerOf 1u }
|
||||
}
|
||||
},
|
||||
"test 1"
|
||||
)
|
||||
assertEquals(
|
||||
NumberedPolynomialAsIs(
|
||||
listOf<UInt>() to -1,
|
||||
),
|
||||
Int.algebra.numberedPolynomialSpace {
|
||||
NumberedPolynomial {
|
||||
5 { }
|
||||
(-6) { }
|
||||
}
|
||||
},
|
||||
"test 2"
|
||||
)
|
||||
assertEquals(
|
||||
NumberedPolynomialAsIs(
|
||||
listOf(2u) to -1,
|
||||
),
|
||||
Int.algebra.numberedPolynomialSpace {
|
||||
NumberedPolynomial {
|
||||
5 { 1 inPowerOf 1u; 1 inPowerOf 1u }
|
||||
(-6) { 1 inPowerOf 2u }
|
||||
}
|
||||
},
|
||||
"test 3"
|
||||
)
|
||||
}
|
||||
@Test
|
||||
@UnstableKMathAPI
|
||||
fun testFabric() {
|
||||
assertEquals(
|
||||
NumberedPolynomialAsIs(
|
||||
listOf(2u, 0u, 3u) to 5,
|
||||
listOf(0u, 1u) to -6,
|
||||
),
|
||||
Int.algebra {
|
||||
NumberedPolynomial(
|
||||
listOf(2u, 0u, 3u) to 5,
|
||||
listOf(0u, 1u) to -6,
|
||||
)
|
||||
},
|
||||
"test 1"
|
||||
)
|
||||
assertEquals(
|
||||
NumberedPolynomialAsIs(
|
||||
listOf(2u, 0u, 3u) to 5,
|
||||
listOf(0u, 1u) to -6,
|
||||
),
|
||||
Int.algebra {
|
||||
NumberedPolynomial(
|
||||
listOf(2u, 0u, 3u, 0u) to 5,
|
||||
listOf(0u, 1u, 0u, 0u) to -6,
|
||||
)
|
||||
},
|
||||
"test 2"
|
||||
)
|
||||
assertEquals(
|
||||
NumberedPolynomialAsIs(
|
||||
listOf<UInt>() to -1,
|
||||
),
|
||||
Int.algebra {
|
||||
NumberedPolynomial(
|
||||
listOf(0u) to 5,
|
||||
listOf(0u, 0u) to -6,
|
||||
)
|
||||
},
|
||||
"test 3"
|
||||
)
|
||||
assertEquals(
|
||||
NumberedPolynomialAsIs(
|
||||
listOf<UInt>() to 0,
|
||||
),
|
||||
Int.algebra {
|
||||
NumberedPolynomial(
|
||||
listOf(0u) to 5,
|
||||
listOf(0u, 0u) to -5,
|
||||
)
|
||||
},
|
||||
"test 4"
|
||||
)
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,293 @@
|
||||
/*
|
||||
* Copyright 2018-2021 KMath contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package space.kscience.kmath.functions
|
||||
|
||||
import space.kscience.kmath.test.misc.Rational
|
||||
import space.kscience.kmath.test.misc.RationalField
|
||||
import space.kscience.kmath.test.misc.assertContentEquals
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
|
||||
class NumberedPolynomialUtilTest {
|
||||
@Test
|
||||
fun test_substitute_Double_Map() {
|
||||
assertContentEquals(
|
||||
mapOf(emptyList<UInt>() to 0.0),
|
||||
NumberedPolynomialAsIs(
|
||||
listOf<UInt>() to 1.0,
|
||||
listOf(1u) to -2.0,
|
||||
listOf(2u) to 1.0,
|
||||
).substitute(mapOf(
|
||||
0 to 1.0
|
||||
)).coefficients,
|
||||
0.001,
|
||||
"test 1"
|
||||
)
|
||||
assertContentEquals(
|
||||
mapOf(
|
||||
listOf<UInt>() to 0.8597048543814783,
|
||||
listOf(1u) to 0.22997637465889875,
|
||||
listOf(2u) to 0.32675302591924016,
|
||||
listOf(0u, 1u) to 0.4561746111587508,
|
||||
listOf(1u, 1u) to 0.5304946210170756,
|
||||
listOf(2u, 1u) to 0.6244313712888998,
|
||||
listOf(0u, 2u) to 0.2700930201481795,
|
||||
listOf(1u, 2u) to -0.06962351375204712,
|
||||
listOf(2u, 2u) to -0.015206988092131501,
|
||||
),
|
||||
NumberedPolynomialAsIs(
|
||||
listOf<UInt>() to 0.8597048543814783,
|
||||
listOf(1u) to 0.22997637465889875,
|
||||
listOf(2u) to 0.32675302591924016,
|
||||
listOf(0u, 1u) to 0.4561746111587508,
|
||||
listOf(1u, 1u) to 0.5304946210170756,
|
||||
listOf(2u, 1u) to 0.6244313712888998,
|
||||
listOf(0u, 2u) to 0.2700930201481795,
|
||||
listOf(1u, 2u) to -0.06962351375204712,
|
||||
listOf(2u, 2u) to -0.015206988092131501,
|
||||
).substitute(mapOf()).coefficients,
|
||||
0.001,
|
||||
"test 2"
|
||||
)
|
||||
assertContentEquals(
|
||||
mapOf(
|
||||
listOf<UInt>() to 0.8597048543814783,
|
||||
listOf(0u, 1u) to 0.4561746111587508,
|
||||
listOf(0u, 2u) to 0.2700930201481795,
|
||||
),
|
||||
NumberedPolynomialAsIs(
|
||||
listOf<UInt>() to 0.8597048543814783,
|
||||
listOf(1u) to 0.22997637465889875,
|
||||
listOf(2u) to 0.32675302591924016,
|
||||
listOf(0u, 1u) to 0.4561746111587508,
|
||||
listOf(1u, 1u) to 0.5304946210170756,
|
||||
listOf(2u, 1u) to 0.6244313712888998,
|
||||
listOf(0u, 2u) to 0.2700930201481795,
|
||||
listOf(1u, 2u) to -0.06962351375204712,
|
||||
listOf(2u, 2u) to -0.015206988092131501,
|
||||
).substitute(mapOf(
|
||||
0 to 0.0
|
||||
)).coefficients,
|
||||
0.001,
|
||||
"test 3"
|
||||
)
|
||||
assertContentEquals(
|
||||
mapOf(
|
||||
listOf<UInt>() to 1.433510890645169,
|
||||
listOf(1u) to 0.6264844682514724,
|
||||
listOf(2u) to 0.8405727903771333,
|
||||
),
|
||||
NumberedPolynomialAsIs(
|
||||
listOf<UInt>() to 0.8597048543814783,
|
||||
listOf(1u) to 0.22997637465889875,
|
||||
listOf(2u) to 0.32675302591924016,
|
||||
listOf(0u, 1u) to 0.4561746111587508,
|
||||
listOf(1u, 1u) to 0.5304946210170756,
|
||||
listOf(2u, 1u) to 0.6244313712888998,
|
||||
listOf(0u, 2u) to 0.2700930201481795,
|
||||
listOf(1u, 2u) to -0.06962351375204712,
|
||||
listOf(2u, 2u) to -0.015206988092131501,
|
||||
).substitute(mapOf(
|
||||
1 to 0.8400458576651112
|
||||
)).coefficients,
|
||||
0.001,
|
||||
"test 4"
|
||||
)
|
||||
assertContentEquals(
|
||||
mapOf(
|
||||
listOf<UInt>() to 1.934530767358133,
|
||||
),
|
||||
NumberedPolynomialAsIs(
|
||||
listOf<UInt>() to 0.8597048543814783,
|
||||
listOf(1u) to 0.22997637465889875,
|
||||
listOf(2u) to 0.32675302591924016,
|
||||
listOf(0u, 1u) to 0.4561746111587508,
|
||||
listOf(1u, 1u) to 0.5304946210170756,
|
||||
listOf(2u, 1u) to 0.6244313712888998,
|
||||
listOf(0u, 2u) to 0.2700930201481795,
|
||||
listOf(1u, 2u) to -0.06962351375204712,
|
||||
listOf(2u, 2u) to -0.015206988092131501,
|
||||
).substitute(mapOf(
|
||||
0 to 0.4846192734143442,
|
||||
1 to 0.8400458576651112,
|
||||
)).coefficients,
|
||||
0.001,
|
||||
"test 5"
|
||||
)
|
||||
assertContentEquals(
|
||||
mapOf(
|
||||
listOf<UInt>() to 0.8597048543814783,
|
||||
listOf(1u) to 0.22997637465889875,
|
||||
listOf(2u) to 0.32675302591924016,
|
||||
listOf(0u, 1u) to 0.4561746111587508,
|
||||
listOf(1u, 1u) to 0.5304946210170756,
|
||||
listOf(2u, 1u) to 0.6244313712888998,
|
||||
listOf(0u, 2u) to 0.2700930201481795,
|
||||
listOf(1u, 2u) to -0.06962351375204712,
|
||||
listOf(2u, 2u) to -0.015206988092131501,
|
||||
),
|
||||
NumberedPolynomialAsIs(
|
||||
listOf<UInt>() to 0.8597048543814783,
|
||||
listOf(1u) to 0.22997637465889875,
|
||||
listOf(2u) to 0.32675302591924016,
|
||||
listOf(0u, 1u) to 0.4561746111587508,
|
||||
listOf(1u, 1u) to 0.5304946210170756,
|
||||
listOf(2u, 1u) to 0.6244313712888998,
|
||||
listOf(0u, 2u) to 0.2700930201481795,
|
||||
listOf(1u, 2u) to -0.06962351375204712,
|
||||
listOf(2u, 2u) to -0.015206988092131501,
|
||||
).substitute(mapOf(
|
||||
5 to 0.9211194782050933
|
||||
)).coefficients,
|
||||
0.001,
|
||||
"test 6"
|
||||
)
|
||||
}
|
||||
@Test
|
||||
fun test_substitute_Constant() {
|
||||
assertEquals(
|
||||
NumberedPolynomialAsIs(
|
||||
listOf<UInt>() to Rational(0)
|
||||
),
|
||||
NumberedPolynomialAsIs(
|
||||
listOf<UInt>() to Rational(1),
|
||||
listOf(1u) to Rational(-2),
|
||||
listOf(2u) to Rational(1)
|
||||
).substitute(RationalField, mapOf(
|
||||
0 to Rational(1)
|
||||
)),
|
||||
"test 1"
|
||||
)
|
||||
// https://www.wolframalpha.com/input?i=%28-3%2F2+%2B+8%2F6+x+%2B+14%2F6+x%5E2%29+%2B+%28-3%2F1+%2B+-19%2F2+x+%2B+9%2F4+x%5E2%29+y+%2B+%285%2F5+%2B+18%2F9+x+%2B+5%2F2+x%5E2%29+y%5E2+where+x+%3D+-2%2F5%2C+y+%3D+12%2F9
|
||||
assertEquals(
|
||||
NumberedPolynomialAsIs(
|
||||
listOf<UInt>() to Rational(143, 150)
|
||||
),
|
||||
NumberedPolynomialAsIs(
|
||||
listOf<UInt>() to Rational(-3, 2),
|
||||
listOf(1u) to Rational(8, 6),
|
||||
listOf(2u) to Rational(14, 6),
|
||||
listOf(0u, 1u) to Rational(-3, 1),
|
||||
listOf(1u, 1u) to Rational(-19, 2),
|
||||
listOf(2u, 1u) to Rational(9, 4),
|
||||
listOf(0u, 2u) to Rational(5, 5),
|
||||
listOf(1u, 2u) to Rational(18, 9),
|
||||
listOf(2u, 2u) to Rational(5, 2),
|
||||
).substitute(RationalField, mapOf(
|
||||
0 to Rational(-2, 5),
|
||||
1 to Rational(12, 9),
|
||||
)),
|
||||
"test 2"
|
||||
)
|
||||
// https://www.wolframalpha.com/input?i=%28%28-3%2F2+%2B+8%2F6+x+%2B+14%2F6+x%5E2%29+%2B+%28-3%2F1+%2B+-19%2F2+x+%2B+9%2F4+x%5E2%29+y+%2B+%285%2F5+%2B+18%2F9+x+%2B+5%2F2+x%5E2%29+y%5E2%29+p%5E8+where+x+%3D+q%2Fp%2C+y+%3D+x%5E3%2C+p+%3D+-2%2F5%2C+q+%3D+12%2F9
|
||||
assertEquals(
|
||||
NumberedPolynomialAsIs(
|
||||
listOf<UInt>() to Rational(47639065216, 2562890625)
|
||||
),
|
||||
NumberedPolynomialAsIs(
|
||||
listOf(8u) to Rational(-3, 2),
|
||||
listOf(7u, 1u) to Rational(8, 6),
|
||||
listOf(6u, 2u) to Rational(14, 6),
|
||||
listOf(5u, 3u) to Rational(-3, 1),
|
||||
listOf(4u, 4u) to Rational(-19, 2),
|
||||
listOf(3u, 5u) to Rational(9, 4),
|
||||
listOf(2u, 6u) to Rational(5, 5),
|
||||
listOf(1u, 7u) to Rational(18, 9),
|
||||
listOf(0u, 8u) to Rational(5, 2),
|
||||
).substitute(RationalField, mapOf(
|
||||
0 to Rational(-2, 5),
|
||||
1 to Rational(12, 9),
|
||||
)),
|
||||
"test 3"
|
||||
)
|
||||
// https://www.wolframalpha.com/input?i=%28%28-3%2F2+%2B+8%2F6+x+%2B+14%2F6+x%5E2%29+%2B+%28-3%2F1+%2B+-19%2F2+x+%2B+9%2F4+x%5E2%29+y+%2B+%285%2F5+%2B+18%2F9+x+%2B+5%2F2+x%5E2%29+y%5E2%29+p%5E8+where+x+%3D+q%2Fp%2C+y+%3D+x%5E3%2C+p+%3D+-2%2F5%2C+q+%3D+12%2F9
|
||||
assertEquals(
|
||||
NumberedPolynomialAsIs(
|
||||
listOf(8u) to Rational(-3, 2),
|
||||
listOf(7u, 1u) to Rational(8, 6),
|
||||
listOf(6u, 2u) to Rational(14, 6),
|
||||
listOf(5u, 3u) to Rational(-3, 1),
|
||||
listOf(4u, 4u) to Rational(-19, 2),
|
||||
listOf(3u, 5u) to Rational(9, 4),
|
||||
listOf(2u, 6u) to Rational(5, 5),
|
||||
listOf(1u, 7u) to Rational(18, 9),
|
||||
listOf(0u, 8u) to Rational(5, 2),
|
||||
),
|
||||
NumberedPolynomialAsIs(
|
||||
listOf(8u) to Rational(-3, 2),
|
||||
listOf(7u, 1u) to Rational(8, 6),
|
||||
listOf(6u, 2u) to Rational(14, 6),
|
||||
listOf(5u, 3u) to Rational(-3, 1),
|
||||
listOf(4u, 4u) to Rational(-19, 2),
|
||||
listOf(3u, 5u) to Rational(9, 4),
|
||||
listOf(2u, 6u) to Rational(5, 5),
|
||||
listOf(1u, 7u) to Rational(18, 9),
|
||||
listOf(0u, 8u) to Rational(5, 2),
|
||||
).substitute(RationalField, mapOf<Int, Rational>()),
|
||||
"test 4"
|
||||
)
|
||||
}
|
||||
@Test
|
||||
fun test_substitute_Polynomial() {
|
||||
assertEquals(
|
||||
NumberedPolynomialAsIs(
|
||||
listOf<UInt>() to Rational(0)
|
||||
),
|
||||
NumberedPolynomialAsIs(
|
||||
listOf<UInt>() to Rational(1),
|
||||
listOf(1u) to Rational(-2),
|
||||
listOf(2u) to Rational(1)
|
||||
).substitute(RationalField, mapOf(
|
||||
0 to NumberedPolynomialAsIs(
|
||||
listOf<UInt>() to Rational(1)
|
||||
)
|
||||
)),
|
||||
"test 1"
|
||||
)
|
||||
// https://www.wolframalpha.com/input?i=%28-3%2F2+%2B+8%2F6+x+%2B+14%2F6+x%5E2%29+%2B+%28-3%2F1+%2B+-19%2F2+x+%2B+9%2F4+x%5E2%29+y+%2B+%285%2F5+%2B+18%2F9+x+%2B+5%2F2+x%5E2%29+y%5E2+where+x+%3D+-2%2F5%2C+y+%3D+12%2F9
|
||||
assertEquals(
|
||||
NumberedPolynomialAsIs(
|
||||
listOf<UInt>() to Rational(-3, 2),
|
||||
listOf(0u, 1u) to Rational(-92, 21),
|
||||
listOf(0u, 2u) to Rational(-2627, 2352),
|
||||
listOf(0u, 3u) to Rational(4565, 3136),
|
||||
listOf(0u, 4u) to Rational(605, 1568),
|
||||
listOf(1u) to Rational(-20, 3),
|
||||
listOf(1u, 1u) to Rational(1445, 21),
|
||||
listOf(1u, 2u) to Rational(-13145, 392),
|
||||
listOf(1u, 3u) to Rational(-3025, 196),
|
||||
listOf(2u) to Rational(175, 3),
|
||||
listOf(2u, 1u) to Rational(2475, 28),
|
||||
listOf(2u, 2u) to Rational(15125, 98),
|
||||
listOf(3u) to Rational(0),
|
||||
listOf(3u, 1u) to Rational(0),
|
||||
listOf(4u) to Rational(0),
|
||||
),
|
||||
NumberedPolynomialAsIs(
|
||||
listOf<UInt>() to Rational(-3, 2),
|
||||
listOf(1u) to Rational(8, 6),
|
||||
listOf(2u) to Rational(14, 6),
|
||||
listOf(0u, 1u) to Rational(-3, 1),
|
||||
listOf(1u, 1u) to Rational(-19, 2),
|
||||
listOf(2u, 1u) to Rational(9, 4),
|
||||
listOf(0u, 2u) to Rational(5, 5),
|
||||
listOf(1u, 2u) to Rational(18, 9),
|
||||
listOf(2u, 2u) to Rational(5, 2),
|
||||
).substitute(RationalField, mapOf(
|
||||
0 to NumberedPolynomialAsIs(
|
||||
listOf(1u) to Rational(-5, 1),
|
||||
listOf(0u, 1u) to Rational(2, 8),
|
||||
),
|
||||
1 to NumberedPolynomialAsIs(
|
||||
listOf(1u) to Rational(0, 5),
|
||||
listOf(0u, 1u) to Rational(11, 7),
|
||||
),
|
||||
)),
|
||||
"test 2"
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright 2018-2021 KMath contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package space.kscience.kmath.test.misc
|
||||
|
||||
import space.kscience.kmath.functions.ListPolynomial
|
||||
import space.kscience.kmath.functions.ListPolynomialSpace
|
||||
import space.kscience.kmath.functions.PolynomialSpaceOverRing
|
||||
import space.kscience.kmath.operations.Ring
|
||||
|
||||
|
||||
class IntModulo {
|
||||
val residue: Int
|
||||
val modulus: Int
|
||||
|
||||
@PublishedApi
|
||||
internal constructor(residue: Int, modulus: Int, toCheckInput: Boolean = true) {
|
||||
if (toCheckInput) {
|
||||
require(modulus != 0) { "modulus can not be zero" }
|
||||
this.modulus = if (modulus < 0) -modulus else modulus
|
||||
this.residue = residue.mod(modulus)
|
||||
} else {
|
||||
this.residue = residue
|
||||
this.modulus = modulus
|
||||
}
|
||||
}
|
||||
|
||||
constructor(residue: Int, modulus: Int) : this(residue, modulus, true)
|
||||
|
||||
operator fun unaryPlus(): IntModulo = this
|
||||
operator fun unaryMinus(): IntModulo =
|
||||
IntModulo(
|
||||
if (residue == 0) 0 else modulus - residue,
|
||||
modulus,
|
||||
toCheckInput = false
|
||||
)
|
||||
operator fun plus(other: IntModulo): IntModulo {
|
||||
require(modulus == other.modulus) { "can not add two residue different modulo" }
|
||||
return IntModulo(
|
||||
(residue + other.residue) % modulus,
|
||||
modulus,
|
||||
toCheckInput = false
|
||||
)
|
||||
}
|
||||
operator fun plus(other: Int): IntModulo =
|
||||
IntModulo(
|
||||
(residue + other) % modulus,
|
||||
modulus,
|
||||
toCheckInput = false
|
||||
)
|
||||
operator fun minus(other: IntModulo): IntModulo {
|
||||
require(modulus == other.modulus) { "can not subtract two residue different modulo" }
|
||||
return IntModulo(
|
||||
(residue - other.residue) % modulus,
|
||||
modulus,
|
||||
toCheckInput = false
|
||||
)
|
||||
}
|
||||
operator fun minus(other: Int): IntModulo =
|
||||
IntModulo(
|
||||
(residue - other) % modulus,
|
||||
modulus,
|
||||
toCheckInput = false
|
||||
)
|
||||
operator fun times(other: IntModulo): IntModulo {
|
||||
require(modulus == other.modulus) { "can not multiply two residue different modulo" }
|
||||
return IntModulo(
|
||||
(residue * other.residue) % modulus,
|
||||
modulus,
|
||||
toCheckInput = false
|
||||
)
|
||||
}
|
||||
operator fun times(other: Int): IntModulo =
|
||||
IntModulo(
|
||||
(residue * other) % modulus,
|
||||
modulus,
|
||||
toCheckInput = false
|
||||
)
|
||||
operator fun div(other: IntModulo): IntModulo {
|
||||
require(modulus == other.modulus) { "can not divide two residue different modulo" }
|
||||
val (reciprocalCandidate, gcdOfOtherResidueAndModulus) = bezoutIdentityWithGCD(other.residue, modulus)
|
||||
require(gcdOfOtherResidueAndModulus == 1) { "can not divide to residue that has non-trivial GCD with modulo" }
|
||||
return IntModulo(
|
||||
(residue * reciprocalCandidate) % modulus,
|
||||
modulus,
|
||||
toCheckInput = false
|
||||
)
|
||||
}
|
||||
operator fun div(other: Int): IntModulo {
|
||||
val (reciprocalCandidate, gcdOfOtherResidueAndModulus) = bezoutIdentityWithGCD(other, modulus)
|
||||
require(gcdOfOtherResidueAndModulus == 1) { "can not divide to residue that has non-trivial GCD with modulo" }
|
||||
return IntModulo(
|
||||
(residue * reciprocalCandidate) % modulus,
|
||||
modulus,
|
||||
toCheckInput = false
|
||||
)
|
||||
}
|
||||
override fun equals(other: Any?): Boolean =
|
||||
when (other) {
|
||||
is IntModulo -> residue == other.residue && modulus == other.modulus
|
||||
else -> false
|
||||
}
|
||||
|
||||
override fun hashCode(): Int = residue.hashCode()
|
||||
|
||||
override fun toString(): String = "$residue mod $modulus"
|
||||
}
|
||||
|
||||
@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE")
|
||||
class IntModuloRing : Ring<IntModulo> {
|
||||
|
||||
val modulus: Int
|
||||
|
||||
constructor(modulus: Int) {
|
||||
require(modulus != 0) { "modulus can not be zero" }
|
||||
this.modulus = if (modulus < 0) -modulus else modulus
|
||||
}
|
||||
|
||||
override inline val zero: IntModulo get() = IntModulo(0, modulus, toCheckInput = false)
|
||||
override inline val one: IntModulo get() = IntModulo(1, modulus, toCheckInput = false)
|
||||
|
||||
fun number(arg: Int) = IntModulo(arg, modulus, toCheckInput = false)
|
||||
|
||||
override inline fun add(left: IntModulo, right: IntModulo): IntModulo = left + right
|
||||
override inline fun multiply(left: IntModulo, right: IntModulo): IntModulo = left * right
|
||||
|
||||
override inline fun IntModulo.unaryMinus(): IntModulo = -this
|
||||
override inline fun IntModulo.plus(arg: IntModulo): IntModulo = this + arg
|
||||
override inline fun IntModulo.minus(arg: IntModulo): IntModulo = this - arg
|
||||
override inline fun IntModulo.times(arg: IntModulo): IntModulo = this * arg
|
||||
inline fun IntModulo.div(arg: IntModulo): IntModulo = this / arg
|
||||
}
|
||||
|
||||
fun ListPolynomialSpace<IntModulo, IntModuloRing>.ListPolynomial(vararg coefs: Int): ListPolynomial<IntModulo> =
|
||||
ListPolynomial(coefs.map { IntModulo(it, ring.modulus) })
|
||||
fun IntModuloRing.ListPolynomial(vararg coefs: Int): ListPolynomial<IntModulo> =
|
||||
ListPolynomial(coefs.map { IntModulo(it, modulus) })
|
||||
|
||||
fun IntModuloRing.m(arg: Int) = IntModulo(arg, modulus)
|
||||
fun PolynomialSpaceOverRing<IntModulo, *, IntModuloRing>.m(arg: Int) = IntModulo(arg, ring.modulus)
|
@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright 2018-2021 KMath contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package space.kscience.kmath.test.misc
|
||||
|
||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||
import space.kscience.kmath.operations.Field
|
||||
import space.kscience.kmath.operations.NumbersAddOps
|
||||
|
||||
class Rational {
|
||||
companion object {
|
||||
val ZERO: Rational = Rational(0L)
|
||||
val ONE: Rational = Rational(1L)
|
||||
}
|
||||
|
||||
val numerator: Long
|
||||
val denominator: Long
|
||||
|
||||
internal constructor(numerator: Long, denominator: Long, toCheckInput: Boolean = true) {
|
||||
if (toCheckInput) {
|
||||
if (denominator == 0L) throw ArithmeticException("/ by zero")
|
||||
|
||||
val greatestCommonDivider = gcd(numerator, denominator).let { if (denominator < 0L) -it else it }
|
||||
|
||||
this.numerator = numerator / greatestCommonDivider
|
||||
this.denominator = denominator / greatestCommonDivider
|
||||
} else {
|
||||
this.numerator = numerator
|
||||
this.denominator = denominator
|
||||
}
|
||||
}
|
||||
|
||||
constructor(numerator: Int, denominator: Int) : this(numerator.toLong(), denominator.toLong(), true)
|
||||
constructor(numerator: Int, denominator: Long) : this(numerator.toLong(), denominator, true)
|
||||
constructor(numerator: Long, denominator: Int) : this(numerator, denominator.toLong(), true)
|
||||
constructor(numerator: Long, denominator: Long) : this(numerator, denominator, true)
|
||||
constructor(numerator: Int) : this(numerator.toLong(), 1L, false)
|
||||
constructor(numerator: Long) : this(numerator, 1L, false)
|
||||
|
||||
operator fun unaryPlus(): Rational = this
|
||||
operator fun unaryMinus(): Rational = Rational(-this.numerator, this.denominator)
|
||||
operator fun plus(other: Rational): Rational =
|
||||
Rational(
|
||||
numerator * other.denominator + denominator * other.numerator,
|
||||
denominator * other.denominator
|
||||
)
|
||||
operator fun plus(other: Int): Rational =
|
||||
Rational(
|
||||
numerator + denominator * other.toLong(),
|
||||
denominator
|
||||
)
|
||||
operator fun plus(other: Long): Rational =
|
||||
Rational(
|
||||
numerator + denominator * other,
|
||||
denominator
|
||||
)
|
||||
operator fun minus(other: Rational): Rational =
|
||||
Rational(
|
||||
numerator * other.denominator - denominator * other.numerator,
|
||||
denominator * other.denominator
|
||||
)
|
||||
operator fun minus(other: Int): Rational =
|
||||
Rational(
|
||||
numerator - denominator * other.toLong(),
|
||||
denominator
|
||||
)
|
||||
operator fun minus(other: Long): Rational =
|
||||
Rational(
|
||||
numerator - denominator * other,
|
||||
denominator
|
||||
)
|
||||
operator fun times(other: Rational): Rational =
|
||||
Rational(
|
||||
numerator * other.numerator,
|
||||
denominator * other.denominator
|
||||
)
|
||||
operator fun times(other: Int): Rational =
|
||||
Rational(
|
||||
numerator * other.toLong(),
|
||||
denominator
|
||||
)
|
||||
operator fun times(other: Long): Rational =
|
||||
Rational(
|
||||
numerator * other,
|
||||
denominator
|
||||
)
|
||||
operator fun div(other: Rational): Rational =
|
||||
Rational(
|
||||
numerator * other.denominator,
|
||||
denominator * other.numerator
|
||||
)
|
||||
operator fun div(other: Int): Rational =
|
||||
Rational(
|
||||
numerator,
|
||||
denominator * other.toLong()
|
||||
)
|
||||
operator fun div(other: Long): Rational =
|
||||
Rational(
|
||||
numerator,
|
||||
denominator * other
|
||||
)
|
||||
override fun equals(other: Any?): Boolean =
|
||||
when (other) {
|
||||
is Rational -> numerator == other.numerator && denominator == other.denominator
|
||||
is Int -> numerator == other && denominator == 1L
|
||||
is Long -> numerator == other && denominator == 1L
|
||||
else -> false
|
||||
}
|
||||
|
||||
override fun hashCode(): Int = 31 * numerator.hashCode() + denominator.hashCode()
|
||||
|
||||
override fun toString(): String = if (denominator == 1L) "$numerator" else "$numerator/$denominator"
|
||||
}
|
||||
|
||||
@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE")
|
||||
@OptIn(UnstableKMathAPI::class)
|
||||
object RationalField : Field<Rational>, NumbersAddOps<Rational> {
|
||||
override inline val zero: Rational get() = Rational.ZERO
|
||||
override inline val one: Rational get() = Rational.ONE
|
||||
|
||||
override inline fun number(value: Number): Rational = Rational(value.toLong())
|
||||
|
||||
override inline fun add(left: Rational, right: Rational): Rational = left + right
|
||||
override inline fun multiply(left: Rational, right: Rational): Rational = left * right
|
||||
override inline fun divide(left: Rational, right: Rational): Rational = left / right
|
||||
override inline fun scale(a: Rational, value: Double): Rational = a * number(value)
|
||||
|
||||
override inline fun Rational.unaryMinus(): Rational = -this
|
||||
override inline fun Rational.plus(arg: Rational): Rational = this + arg
|
||||
override inline fun Rational.minus(arg: Rational): Rational = this - arg
|
||||
override inline fun Rational.times(arg: Rational): Rational = this * arg
|
||||
override inline fun Rational.div(arg: Rational): Rational = this / arg
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
/*
|
||||
* Copyright 2018-2021 KMath contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package space.kscience.kmath.test.misc
|
||||
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
|
||||
fun <T> assertContentEquals(expected: Map<T, Double>, actual: Map<T, Double>, absoluteTolerance: Double, message: String? = null) {
|
||||
assertEquals(expected.keys, actual.keys, message)
|
||||
for ((key, expectedValue) in expected) assertEquals(expectedValue, actual[key]!!, absoluteTolerance, message)
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2018-2021 KMath contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package space.kscience.kmath.test.misc
|
||||
|
||||
import kotlin.math.abs
|
||||
|
||||
|
||||
data class BezoutIdentityWithGCD<T>(val first: T, val second: T, val gcd: T)
|
||||
|
||||
tailrec fun gcd(a: Long, b: Long): Long = if (a == 0L) abs(b) else gcd(b % a, a)
|
||||
|
||||
fun bezoutIdentityWithGCD(a: Int, b: Int): BezoutIdentityWithGCD<Int> =
|
||||
when {
|
||||
a < 0 && b < 0 -> with(bezoutIdentityWithGCDInternalLogic(-a, -b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(-first, -second, gcd) }
|
||||
a < 0 -> with(bezoutIdentityWithGCDInternalLogic(-a, b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(-first, second, gcd) }
|
||||
b < 0 -> with(bezoutIdentityWithGCDInternalLogic(a, -b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(first, -second, gcd) }
|
||||
else -> bezoutIdentityWithGCDInternalLogic(a, b, 1, 0, 0, 1)
|
||||
}
|
||||
|
||||
internal tailrec fun bezoutIdentityWithGCDInternalLogic(a: Int, b: Int, m1: Int, m2: Int, m3: Int, m4: Int): BezoutIdentityWithGCD<Int> =
|
||||
if (b == 0) BezoutIdentityWithGCD(m1, m3, a)
|
||||
else {
|
||||
val quotient = a / b
|
||||
val reminder = a % b
|
||||
bezoutIdentityWithGCDInternalLogic(b, reminder, m2, m1 - quotient * m2, m4, m3 - quotient * m4)
|
||||
}
|
Loading…
Reference in New Issue
Block a user