forked from kscience/kmath
Moved polynomials to https://github.com/SciProgCentre/kmath-polynomial
This commit is contained in:
parent
cff563c321
commit
b14e2fdd08
@ -20,6 +20,7 @@
|
||||
### Deprecated
|
||||
|
||||
### Removed
|
||||
- Polynomials moved to https://github.com/SciProgCentre/kmath-polynomial
|
||||
|
||||
### Fixed
|
||||
|
||||
|
@ -18,7 +18,6 @@ dependencies {
|
||||
implementation(project(":kmath-commons"))
|
||||
implementation(project(":kmath-complex"))
|
||||
implementation(project(":kmath-functions"))
|
||||
implementation(project(":kmath-polynomial"))
|
||||
implementation(project(":kmath-optimization"))
|
||||
implementation(project(":kmath-stat"))
|
||||
implementation(project(":kmath-viktor"))
|
||||
|
@ -1,399 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018-2022 KMath contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@file:Suppress("LocalVariableName")
|
||||
|
||||
package space.kscience.kmath.functions
|
||||
|
||||
import space.kscience.kmath.expressions.Symbol
|
||||
import space.kscience.kmath.expressions.symbol
|
||||
import space.kscience.kmath.operations.algebra
|
||||
import space.kscience.kmath.operations.invoke
|
||||
|
||||
|
||||
/**
|
||||
* Shows [ListPolynomial]s' and [ListRationalFunction]s' capabilities.
|
||||
*/
|
||||
fun listPolynomialsExample() {
|
||||
// [ListPolynomial] is a representation of a univariate polynomial as a list of coefficients from the least term to
|
||||
// the greatest term. For example,
|
||||
val polynomial1: ListPolynomial<Int> = ListPolynomial(listOf(2, -3, 1))
|
||||
// represents polynomial 2 + (-3) x + x^2
|
||||
|
||||
// There are also shortcut fabrics:
|
||||
val polynomial2: ListPolynomial<Int> = ListPolynomial(2, -3, 1)
|
||||
println(polynomial1 == polynomial2) // true
|
||||
// and even
|
||||
val polynomial3: ListPolynomial<Int> = 57.asListPolynomial()
|
||||
val polynomial4: ListPolynomial<Int> = ListPolynomial(listOf(57))
|
||||
println(polynomial3 == polynomial4) // true
|
||||
|
||||
val polynomial5: ListPolynomial<Int> = ListPolynomial(3, -1)
|
||||
// For every ring there can be provided a polynomial ring:
|
||||
Int.algebra.listPolynomialSpace {
|
||||
println(-polynomial5 == ListPolynomial(-3, 1)) // true
|
||||
println(polynomial1 + polynomial5 == ListPolynomial(5, -4, 1)) // true
|
||||
println(polynomial1 - polynomial5 == ListPolynomial(-1, -2, 1)) // true
|
||||
println(polynomial1 * polynomial5 == ListPolynomial(6, -11, 6, -1)) // true
|
||||
}
|
||||
// You can even write
|
||||
val x: ListPolynomial<Double> = ListPolynomial(0.0, 1.0)
|
||||
val polynomial6: ListPolynomial<Double> = ListPolynomial(2.0, -3.0, 1.0)
|
||||
Double.algebra.listPolynomialSpace {
|
||||
println(2 - 3 * x + x * x == polynomial6)
|
||||
println(2.0 - 3.0 * x + x * x == polynomial6)
|
||||
}
|
||||
|
||||
// Also there are some utilities for polynomials:
|
||||
println(polynomial1.substitute(Int.algebra, 1) == 0) // true, because 2 + (-3) * 1 + 1^2 = 0
|
||||
println(polynomial1.substitute(Int.algebra, polynomial5) == polynomial1) // true, because 2 + (-3) * (3-x) + (3-x)^2 = 2 - 3x + x^2
|
||||
println(polynomial1.derivative(Int.algebra) == ListPolynomial(-3, 2)) // true, (2 - 3x + x^2)' = -3 + 2x
|
||||
println(polynomial1.nthDerivative(Int.algebra, 2) == 2.asListPolynomial()) // true, (2 - 3x + x^2)'' = 2
|
||||
|
||||
// Lastly, there are rational functions and some other utilities:
|
||||
Double.algebra.listRationalFunctionSpace {
|
||||
val rationalFunction1: ListRationalFunction<Double> = ListRationalFunction(listOf(2.0, -3.0, 1.0), listOf(3.0, -1.0))
|
||||
// It's just (2 - 3x + x^2)/(3 - x)
|
||||
|
||||
val rationalFunction2 : ListRationalFunction<Double> = ListRationalFunction(listOf(5.0, -4.0, 1.0), listOf(3.0, -1.0))
|
||||
// It's just (5 - 4x + x^2)/(3 - x)
|
||||
|
||||
println(rationalFunction1 + 1 == rationalFunction2)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows [NumberedPolynomial]s' and [NumberedRationalFunction]s' capabilities.
|
||||
*/
|
||||
fun numberedPolynomialsExample() {
|
||||
// Consider polynomial
|
||||
// 3 + 5 x_2 - 7 x_1^2 x_3
|
||||
// Consider, for example, its term -7 x_1^2 x_3. -7 is a coefficient of the term, whereas (2, 0, 1, 0, 0, ...) is
|
||||
// description of degrees of variables x_1, x_2, ... in the term. Such description with removed leading zeros
|
||||
// [2, 0, 1] is called "signature" of the term -7 x_1^2 x_3.
|
||||
|
||||
val polynomial1: NumberedPolynomial<Int>
|
||||
with(Int.algebra) {
|
||||
// [NumberedPolynomial] is a representation of a multivariate polynomial, that stores terms in a map with terms'
|
||||
// signatures as the map's keys and terms' coefficients as corresponding values. For example,
|
||||
polynomial1 = NumberedPolynomial(
|
||||
mapOf(
|
||||
listOf<UInt>() to 3,
|
||||
listOf(0u, 1u) to 5,
|
||||
listOf(2u, 0u, 1u) to -7,
|
||||
)
|
||||
)
|
||||
// represents polynomial 3 + 5 x_2 - 7 x_1^2 x_3
|
||||
|
||||
// This `NumberedPolynomial` function needs context of either ring of constant (as `Int.algebra` in this example)
|
||||
// or space of NumberedPolynomials over it. To understand why it is like this see documentations of functions
|
||||
// NumberedPolynomial and NumberedPolynomialWithoutCheck
|
||||
|
||||
// There are also shortcut fabrics:
|
||||
val polynomial2: NumberedPolynomial<Int> = NumberedPolynomial(
|
||||
listOf<UInt>() to 3,
|
||||
listOf(0u, 1u) to 5,
|
||||
listOf(2u, 0u, 1u) to -7,
|
||||
)
|
||||
println(polynomial1 == polynomial2) // true
|
||||
// and even
|
||||
val polynomial3: NumberedPolynomial<Int> = 57.asNumberedPolynomial() // This one actually does not algebraic context!
|
||||
val polynomial4: NumberedPolynomial<Int> = NumberedPolynomial(listOf<UInt>() to 57)
|
||||
println(polynomial3 == polynomial4) // true
|
||||
|
||||
numberedPolynomialSpace {
|
||||
// Also there is DSL for constructing NumberedPolynomials:
|
||||
val polynomial5: NumberedPolynomial<Int> = NumberedPolynomialDSL1 {
|
||||
3 {}
|
||||
5 { 1 inPowerOf 1u }
|
||||
-7 with { 0 pow 2u; 2 pow 1u }
|
||||
// `pow` and `inPowerOf` are the same
|
||||
// `with` is omittable
|
||||
}
|
||||
println(polynomial1 == polynomial5) // true
|
||||
|
||||
// Unfortunately the DSL does not work good in bare context of constants' ring, so for now it's disabled and
|
||||
// works only in NumberedPolynomialSpace and NumberedRationalFunctionSpace
|
||||
}
|
||||
}
|
||||
|
||||
val polynomial6: NumberedPolynomial<Int> = Int.algebra {
|
||||
NumberedPolynomial(
|
||||
listOf<UInt>() to 7,
|
||||
listOf(0u, 1u) to -5,
|
||||
listOf(2u, 0u, 1u) to 0,
|
||||
listOf(0u, 0u, 0u, 4u) to 4,
|
||||
)
|
||||
}
|
||||
// For every ring there can be provided a polynomial ring:
|
||||
Int.algebra.numberedPolynomialSpace {
|
||||
println(
|
||||
-polynomial6 == NumberedPolynomial(
|
||||
listOf<UInt>() to -7,
|
||||
listOf(0u, 1u) to 5,
|
||||
listOf(2u, 0u, 1u) to 0,
|
||||
listOf(0u, 0u, 0u, 4u) to (-4),
|
||||
)
|
||||
) // true
|
||||
println(
|
||||
polynomial1 + polynomial6 == NumberedPolynomial(
|
||||
listOf<UInt>() to 10,
|
||||
listOf(0u, 1u) to 0,
|
||||
listOf(2u, 0u, 1u) to -7,
|
||||
listOf(0u, 0u, 0u, 4u) to 4,
|
||||
)
|
||||
) // true
|
||||
println(
|
||||
polynomial1 - polynomial6 == NumberedPolynomial(
|
||||
listOf<UInt>() to -4,
|
||||
listOf(0u, 1u) to 10,
|
||||
listOf(2u, 0u, 1u) to -7,
|
||||
listOf(0u, 0u, 0u, 4u) to -4,
|
||||
)
|
||||
) // true
|
||||
|
||||
polynomial1 * polynomial6 // Multiplication works too
|
||||
}
|
||||
|
||||
Double.algebra.numberedPolynomialSpace {
|
||||
// You can even write
|
||||
val x_1: NumberedPolynomial<Double> = NumberedPolynomial(listOf(1u) to 1.0)
|
||||
val x_2: NumberedPolynomial<Double> = NumberedPolynomial(listOf(0u, 1u) to 1.0)
|
||||
val x_3: NumberedPolynomial<Double> = NumberedPolynomial(listOf(0u, 0u, 1u) to 1.0)
|
||||
val polynomial7: NumberedPolynomial<Double> = NumberedPolynomial(
|
||||
listOf<UInt>() to 3.0,
|
||||
listOf(0u, 1u) to 5.0,
|
||||
listOf(2u, 0u, 1u) to -7.0,
|
||||
)
|
||||
Double.algebra.listPolynomialSpace {
|
||||
println(3 + 5 * x_2 - 7 * x_1 * x_1 * x_3 == polynomial7)
|
||||
println(3.0 + 5.0 * x_2 - 7.0 * x_1 * x_1 * x_3 == polynomial7)
|
||||
}
|
||||
}
|
||||
|
||||
Int.algebra.numberedPolynomialSpace {
|
||||
val x_4: NumberedPolynomial<Int> = NumberedPolynomial(listOf(0u, 0u, 0u, 4u) to 1)
|
||||
// Also there are some utilities for polynomials:
|
||||
println(polynomial1.substitute(mapOf(0 to 1, 1 to -2, 2 to -1)) == 0.asNumberedPolynomial()) // true,
|
||||
// because it's substitution x_1 -> 1, x_2 -> -2, x_3 -> -1,
|
||||
// so 3 + 5 x_2 - 7 x_1^2 x_3 = 3 + 5 * (-2) - 7 * 1^2 * (-1) = 3 - 10 + 7 = 0
|
||||
println(
|
||||
polynomial1.substitute(mapOf(1 to x_4)) == NumberedPolynomial(
|
||||
listOf<UInt>() to 3,
|
||||
listOf(0u, 1u) to 5,
|
||||
listOf(2u, 0u, 1u) to -7,
|
||||
)
|
||||
) // true, because it's substitution x_2 -> x_4, so result is 3 + 5 x_4 - 7 x_1^2 x_3
|
||||
println(
|
||||
polynomial1.derivativeWithRespectTo(Int.algebra, 1) ==
|
||||
NumberedPolynomial(listOf<UInt>() to 5)
|
||||
) // true, d/dx_2 (3 + 5 x_2 - 7 x_1^2 x_3) = 5
|
||||
}
|
||||
|
||||
// Lastly, there are rational functions and some other utilities:
|
||||
Double.algebra.numberedRationalFunctionSpace {
|
||||
val rationalFunction1: NumberedRationalFunction<Double> = NumberedRationalFunction(
|
||||
NumberedPolynomial(
|
||||
listOf<UInt>() to 2.0,
|
||||
listOf(1u) to -3.0,
|
||||
listOf(2u) to 1.0,
|
||||
),
|
||||
NumberedPolynomial(
|
||||
listOf<UInt>() to 3.0,
|
||||
listOf(1u) to -1.0,
|
||||
)
|
||||
)
|
||||
// It's just (2 - 3x + x^2)/(3 - x) where x = x_1
|
||||
|
||||
val rationalFunction2: NumberedRationalFunction<Double> = NumberedRationalFunction(
|
||||
NumberedPolynomial(
|
||||
listOf<UInt>() to 5.0,
|
||||
listOf(1u) to -4.0,
|
||||
listOf(2u) to 1.0,
|
||||
),
|
||||
NumberedPolynomial(
|
||||
listOf<UInt>() to 3.0,
|
||||
listOf(1u) to -1.0,
|
||||
)
|
||||
)
|
||||
// It's just (5 - 4x + x^2)/(3 - x) where x = x_1
|
||||
|
||||
println(rationalFunction1 + 1 == rationalFunction2)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows [LabeledPolynomial]s' and [LabeledRationalFunction]s' capabilities.
|
||||
*/
|
||||
fun labeledPolynomialsExample() {
|
||||
val x by symbol
|
||||
val y by symbol
|
||||
val z by symbol
|
||||
val t by symbol
|
||||
|
||||
// Consider polynomial
|
||||
// 3 + 5 y - 7 x^2 z
|
||||
// Consider, for example, its term -7 x^2 z. -7 is a coefficient of the term, whereas matching (x -> 2, z -> 3) is
|
||||
// description of degrees of variables x_1, x_2, ... in the term. Such description is called "signature" of the
|
||||
// term -7 x_1^2 x_3.
|
||||
|
||||
val polynomial1: LabeledPolynomial<Int>
|
||||
with(Int.algebra) {
|
||||
// [LabeledPolynomial] is a representation of a multivariate polynomial, that stores terms in a map with terms'
|
||||
// signatures as the map's keys and terms' coefficients as corresponding values. For example,
|
||||
polynomial1 = LabeledPolynomial(
|
||||
mapOf(
|
||||
mapOf<Symbol, UInt>() to 3,
|
||||
mapOf(y to 1u) to 5,
|
||||
mapOf(x to 2u, z to 1u) to -7,
|
||||
)
|
||||
)
|
||||
// represents polynomial 3 + 5 y - 7 x^2 z
|
||||
|
||||
// This `LabeledPolynomial` function needs context of either ring of constant (as `Int.algebra` in this example)
|
||||
// or space of LabeledPolynomials over it. To understand why it is like this see documentations of functions
|
||||
// LabeledPolynomial and LabeledPolynomialWithoutCheck
|
||||
|
||||
// There are also shortcut fabrics:
|
||||
val polynomial2: LabeledPolynomial<Int> = LabeledPolynomial(
|
||||
mapOf<Symbol, UInt>() to 3,
|
||||
mapOf(y to 1u) to 5,
|
||||
mapOf(x to 2u, z to 1u) to -7,
|
||||
)
|
||||
println(polynomial1 == polynomial2) // true
|
||||
// and even
|
||||
val polynomial3: LabeledPolynomial<Int> = 57.asLabeledPolynomial() // This one actually does not algebraic context!
|
||||
val polynomial4: LabeledPolynomial<Int> = LabeledPolynomial(mapOf<Symbol, UInt>() to 57)
|
||||
println(polynomial3 == polynomial4) // true
|
||||
|
||||
labeledPolynomialSpace {
|
||||
// Also there is DSL for constructing NumberedPolynomials:
|
||||
val polynomial5: LabeledPolynomial<Int> = LabeledPolynomialDSL1 {
|
||||
3 {}
|
||||
5 { y inPowerOf 1u }
|
||||
-7 with { x pow 2u; z pow 1u }
|
||||
// `pow` and `inPowerOf` are the same
|
||||
// `with` is omittable
|
||||
}
|
||||
println(polynomial1 == polynomial5) // true
|
||||
|
||||
// Unfortunately the DSL does not work good in bare context of constants' ring, so for now it's disabled and
|
||||
// works only in NumberedPolynomialSpace and NumberedRationalFunctionSpace
|
||||
}
|
||||
}
|
||||
|
||||
val polynomial6: LabeledPolynomial<Int> = Int.algebra {
|
||||
LabeledPolynomial(
|
||||
mapOf<Symbol, UInt>() to 7,
|
||||
mapOf(y to 1u) to -5,
|
||||
mapOf(x to 2u, z to 1u) to 0,
|
||||
mapOf(t to 4u) to 4,
|
||||
)
|
||||
}
|
||||
// For every ring there can be provided a polynomial ring:
|
||||
Int.algebra.labeledPolynomialSpace {
|
||||
println(
|
||||
-polynomial6 == LabeledPolynomial(
|
||||
mapOf<Symbol, UInt>() to -7,
|
||||
mapOf(y to 1u) to 5,
|
||||
mapOf(x to 2u, z to 1u) to 0,
|
||||
mapOf(t to 4u) to -4,
|
||||
)
|
||||
) // true
|
||||
println(
|
||||
polynomial1 + polynomial6 == LabeledPolynomial(
|
||||
mapOf<Symbol, UInt>() to 10,
|
||||
mapOf(y to 1u) to 0,
|
||||
mapOf(x to 2u, z to 1u) to -7,
|
||||
mapOf(t to 4u) to 4,
|
||||
)
|
||||
) // true
|
||||
println(
|
||||
polynomial1 - polynomial6 == LabeledPolynomial(
|
||||
mapOf<Symbol, UInt>() to -4,
|
||||
mapOf(y to 1u) to 10,
|
||||
mapOf(x to 2u, z to 1u) to -7,
|
||||
mapOf(t to 4u) to -4,
|
||||
)
|
||||
) // true
|
||||
|
||||
polynomial1 * polynomial6 // Multiplication works too
|
||||
}
|
||||
|
||||
Double.algebra.labeledPolynomialSpace {
|
||||
// You can even write
|
||||
val polynomial7: LabeledPolynomial<Double> = LabeledPolynomial(
|
||||
mapOf<Symbol, UInt>() to 3.0,
|
||||
mapOf(y to 1u) to 5.0,
|
||||
mapOf(x to 2u, z to 1u) to -7.0,
|
||||
)
|
||||
Double.algebra.listPolynomialSpace {
|
||||
println(3 + 5 * y - 7 * x * x * z == polynomial7)
|
||||
println(3.0 + 5.0 * y - 7.0 * x * x * z == polynomial7)
|
||||
}
|
||||
}
|
||||
|
||||
Int.algebra.labeledPolynomialSpace {
|
||||
// Also there are some utilities for polynomials:
|
||||
println(polynomial1.substitute(mapOf(x to 1, y to -2, z to -1)) == 0.asLabeledPolynomial()) // true,
|
||||
// because it's substitution x -> 1, y -> -2, z -> -1,
|
||||
// so 3 + 5 y - 7 x^2 z = 3 + 5 * (-2) - 7 * 1^2 * (-1) = 3 - 10 + 7 = 0
|
||||
println(
|
||||
polynomial1.substitute(mapOf(y to t.asPolynomial())) == LabeledPolynomial(
|
||||
mapOf<Symbol, UInt>() to 3,
|
||||
mapOf(t to 1u) to 5,
|
||||
mapOf(x to 2u, z to 1u) to -7,
|
||||
)
|
||||
) // true, because it's substitution y -> t, so result is 3 + 5 t - 7 x^2 z
|
||||
println(
|
||||
polynomial1.derivativeWithRespectTo(Int.algebra, y) == LabeledPolynomial(mapOf<Symbol, UInt>() to 5)
|
||||
) // true, d/dy (3 + 5 y - 7 x^2 z) = 5
|
||||
}
|
||||
|
||||
// Lastly, there are rational functions and some other utilities:
|
||||
Double.algebra.labeledRationalFunctionSpace {
|
||||
val rationalFunction1: LabeledRationalFunction<Double> = LabeledRationalFunction(
|
||||
LabeledPolynomial(
|
||||
mapOf<Symbol, UInt>() to 2.0,
|
||||
mapOf(x to 1u) to -3.0,
|
||||
mapOf(x to 2u) to 1.0,
|
||||
),
|
||||
LabeledPolynomial(
|
||||
mapOf<Symbol, UInt>() to 3.0,
|
||||
mapOf(x to 1u) to -1.0,
|
||||
)
|
||||
)
|
||||
// It's just (2 - 3x + x^2)/(3 - x)
|
||||
|
||||
val rationalFunction2: LabeledRationalFunction<Double> = LabeledRationalFunction(
|
||||
LabeledPolynomial(
|
||||
mapOf<Symbol, UInt>() to 5.0,
|
||||
mapOf(x to 1u) to -4.0,
|
||||
mapOf(x to 2u) to 1.0,
|
||||
),
|
||||
LabeledPolynomial(
|
||||
mapOf<Symbol, UInt>() to 3.0,
|
||||
mapOf(x to 1u) to -1.0,
|
||||
)
|
||||
)
|
||||
// It's just (5 - 4x + x^2)/(3 - x)
|
||||
|
||||
println(rationalFunction1 + 1 == rationalFunction2)
|
||||
}
|
||||
}
|
||||
|
||||
fun main() {
|
||||
println("ListPolynomials:")
|
||||
listPolynomialsExample()
|
||||
println()
|
||||
|
||||
println("NumberedPolynomials:")
|
||||
numberedPolynomialsExample()
|
||||
println()
|
||||
|
||||
println("ListPolynomials:")
|
||||
labeledPolynomialsExample()
|
||||
println()
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
# Module kmath-polynomial
|
||||
|
||||
Polynomials, rational functions, and utilities
|
||||
|
||||
## Features
|
||||
|
||||
- [polynomial abstraction](src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt) : Abstraction for polynomial spaces.
|
||||
- [rational function abstraction](src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt) : Abstraction for rational functions spaces.
|
||||
- ["list" polynomials](src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt) : List implementation of univariate polynomials.
|
||||
- ["list" rational functions](src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt) : List implementation of univariate rational functions.
|
||||
- ["list" polynomials and rational functions constructors](src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt) : Constructors for list polynomials and rational functions.
|
||||
- ["list" polynomials and rational functions utilities](src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt) : Utilities for list polynomials and rational functions.
|
||||
- ["numbered" polynomials](src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt) : Numbered implementation of multivariate polynomials.
|
||||
- ["numbered" rational functions](src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt) : Numbered implementation of multivariate rational functions.
|
||||
- ["numbered" polynomials and rational functions constructors](src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt) : Constructors for numbered polynomials and rational functions.
|
||||
- ["numbered" polynomials and rational functions utilities](src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt) : Utilities for numbered polynomials and rational functions.
|
||||
- ["labeled" polynomials](src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt) : Labeled implementation of multivariate polynomials.
|
||||
- ["labeled" rational functions](src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt) : Labeled implementation of multivariate rational functions.
|
||||
- ["labeled" polynomials and rational functions constructors](src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt) : Constructors for labeled polynomials and rational functions.
|
||||
- ["labeled" polynomials and rational functions utilities](src/commonMain/kotlin/space/kscience/kmath/functions/labeledUtil.kt) : Utilities for labeled polynomials and rational functions.
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
## Artifact:
|
||||
|
||||
The Maven coordinates of this project are `space.kscience:kmath-polynomial:0.3.1-dev-1`.
|
||||
|
||||
**Gradle Groovy:**
|
||||
```groovy
|
||||
repositories {
|
||||
maven { url 'https://repo.kotlin.link' }
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'space.kscience:kmath-polynomial:0.3.1-dev-1'
|
||||
}
|
||||
```
|
||||
**Gradle Kotlin DSL:**
|
||||
```kotlin
|
||||
repositories {
|
||||
maven("https://repo.kotlin.link")
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("space.kscience:kmath-polynomial:0.3.1-dev-1")
|
||||
}
|
||||
```
|
@ -1,69 +0,0 @@
|
||||
plugins {
|
||||
id("space.kscience.gradle.mpp")
|
||||
}
|
||||
|
||||
kscience{
|
||||
native()
|
||||
}
|
||||
|
||||
description = "Polynomials, rational functions, and utilities"
|
||||
|
||||
kotlin.sourceSets {
|
||||
commonMain {
|
||||
dependencies {
|
||||
api(projects.kmathCore)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
dokkaPlugin("org.jetbrains.dokka:mathjax-plugin:${npmlibs.versions.dokka.get()}")
|
||||
}
|
||||
|
||||
readme {
|
||||
maturity = space.kscience.gradle.Maturity.PROTOTYPE
|
||||
propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md"))
|
||||
|
||||
feature("polynomial abstraction", "src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt") {
|
||||
"Abstraction for polynomial spaces."
|
||||
}
|
||||
feature("rational function abstraction", "src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt") {
|
||||
"Abstraction for rational functions spaces."
|
||||
}
|
||||
feature("\"list\" polynomials", "src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt") {
|
||||
"List implementation of univariate polynomials."
|
||||
}
|
||||
feature("\"list\" rational functions", "src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt") {
|
||||
"List implementation of univariate rational functions."
|
||||
}
|
||||
feature("\"list\" polynomials and rational functions constructors", "src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt") {
|
||||
"Constructors for list polynomials and rational functions."
|
||||
}
|
||||
feature("\"list\" polynomials and rational functions utilities", "src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt") {
|
||||
"Utilities for list polynomials and rational functions."
|
||||
}
|
||||
feature("\"numbered\" polynomials", "src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt") {
|
||||
"Numbered implementation of multivariate polynomials."
|
||||
}
|
||||
feature("\"numbered\" rational functions", "src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt") {
|
||||
"Numbered implementation of multivariate rational functions."
|
||||
}
|
||||
feature("\"numbered\" polynomials and rational functions constructors", "src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt") {
|
||||
"Constructors for numbered polynomials and rational functions."
|
||||
}
|
||||
feature("\"numbered\" polynomials and rational functions utilities", "src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt") {
|
||||
"Utilities for numbered polynomials and rational functions."
|
||||
}
|
||||
feature("\"labeled\" polynomials", "src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt") {
|
||||
"Labeled implementation of multivariate polynomials."
|
||||
}
|
||||
feature("\"labeled\" rational functions", "src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt") {
|
||||
"Labeled implementation of multivariate rational functions."
|
||||
}
|
||||
feature("\"labeled\" polynomials and rational functions constructors", "src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt") {
|
||||
"Constructors for labeled polynomials and rational functions."
|
||||
}
|
||||
feature("\"labeled\" polynomials and rational functions utilities", "src/commonMain/kotlin/space/kscience/kmath/functions/labeledUtil.kt") {
|
||||
"Utilities for labeled polynomials and rational functions."
|
||||
}
|
||||
}
|
@ -1,529 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018-2022 KMath contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@file:Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress")
|
||||
|
||||
package space.kscience.kmath.functions
|
||||
|
||||
import space.kscience.kmath.expressions.Symbol
|
||||
import space.kscience.kmath.operations.Ring
|
||||
import kotlin.jvm.JvmName
|
||||
import kotlin.math.max
|
||||
|
||||
|
||||
/**
|
||||
* Represents multivariate polynomial that stores its coefficients in a [Map] and terms' signatures in a [Map] that
|
||||
* associates variables (of type [Symbol]) with their degree.
|
||||
*
|
||||
* @param C the type of constants.
|
||||
*/
|
||||
public data class LabeledPolynomial<out C>
|
||||
@PublishedApi
|
||||
internal constructor(
|
||||
/**
|
||||
* Map that contains coefficients of the polynomial.
|
||||
*
|
||||
* Every monomial \(a x_1^{d_1} ... x_n^{d_n}\) is stored as a pair "key-value" in the map, where the value is the
|
||||
* coefficient \(a\) and the key is a map that associates variables in the monomial with their degree in the monomial.
|
||||
* For example, coefficients of a polynomial \(5 a^2 c^3 - 6 b\) can be represented as
|
||||
* ```
|
||||
* mapOf(
|
||||
* mapOf(
|
||||
* a to 2,
|
||||
* c to 3
|
||||
* ) to 5,
|
||||
* mapOf(
|
||||
* b to 1
|
||||
* ) to (-6)
|
||||
* )
|
||||
* ```
|
||||
* and also as
|
||||
* ```
|
||||
* mapOf(
|
||||
* mapOf(
|
||||
* a to 2,
|
||||
* c to 3
|
||||
* ) to 5,
|
||||
* mapOf(
|
||||
* b to 1
|
||||
* ) to (-6),
|
||||
* mapOf(
|
||||
* b to 1,
|
||||
* c to 1
|
||||
* ) to 0
|
||||
* )
|
||||
* ```
|
||||
* where \(a\), \(b\) and \(c\) are corresponding [Symbol] objects.
|
||||
*
|
||||
* It is not prohibited to put extra zero monomials into the map (as for \(0 b c\) 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.
|
||||
* @usesMathJax
|
||||
*/
|
||||
public val coefficients: Map<Map<Symbol, UInt>, C>
|
||||
) {
|
||||
override fun toString(): String = "LabeledPolynomial$coefficients"
|
||||
}
|
||||
|
||||
/**
|
||||
* Arithmetic context for multivariate polynomials with coefficients stored as a [Map] and terms' signatures stored as a
|
||||
* [Map] constructed with the provided [ring] of constants.
|
||||
*
|
||||
* @param C the type of constants. Polynomials have them a coefficients in their terms.
|
||||
* @param A type of provided underlying ring of constants. It's [Ring] of [C].
|
||||
* @param ring underlying ring of constants of type [A].
|
||||
*/
|
||||
public class LabeledPolynomialSpace<C, out A : Ring<C>>(
|
||||
public override val ring: A,
|
||||
) : MultivariatePolynomialSpace<C, Symbol, LabeledPolynomial<C>>, PolynomialSpaceOverRing<C, LabeledPolynomial<C>, A> {
|
||||
/**
|
||||
* Returns sum of the variable represented as a monic monomial and the integer represented as a constant polynomial.
|
||||
*/
|
||||
public override operator fun Symbol.plus(other: Int): LabeledPolynomial<C> =
|
||||
if (other == 0) LabeledPolynomialAsIs(
|
||||
mapOf(this@plus to 1U) to constantOne,
|
||||
)
|
||||
else LabeledPolynomialAsIs(
|
||||
mapOf(this@plus to 1U) to constantOne,
|
||||
emptyMap<Symbol, UInt>() to other.asConstant(),
|
||||
)
|
||||
/**
|
||||
* Returns difference between the variable represented as a monic monomial and the integer represented as a constant polynomial.
|
||||
*/
|
||||
public override operator fun Symbol.minus(other: Int): LabeledPolynomial<C> =
|
||||
if (other == 0) LabeledPolynomialAsIs(
|
||||
mapOf(this@minus to 1U) to constantOne,
|
||||
)
|
||||
else LabeledPolynomialAsIs(
|
||||
mapOf(this@minus to 1U) to constantOne,
|
||||
emptyMap<Symbol, UInt>() to (-other).asConstant(),
|
||||
)
|
||||
/**
|
||||
* Returns product of the variable represented as a monic monomial and the integer represented as a constant polynomial.
|
||||
*/
|
||||
public override operator fun Symbol.times(other: Int): LabeledPolynomial<C> =
|
||||
if (other == 0) zero
|
||||
else LabeledPolynomialAsIs(
|
||||
mapOf(this to 1U) to other.asConstant(),
|
||||
)
|
||||
|
||||
/**
|
||||
* Returns sum of the integer represented as a constant polynomial and the variable represented as a monic monomial.
|
||||
*/
|
||||
public override operator fun Int.plus(other: Symbol): LabeledPolynomial<C> =
|
||||
if (this == 0) LabeledPolynomialAsIs(
|
||||
mapOf(other to 1U) to constantOne,
|
||||
)
|
||||
else LabeledPolynomialAsIs(
|
||||
mapOf(other to 1U) to constantOne,
|
||||
emptyMap<Symbol, UInt>() to this@plus.asConstant(),
|
||||
)
|
||||
/**
|
||||
* Returns difference between the integer represented as a constant polynomial and the variable represented as a monic monomial.
|
||||
*/
|
||||
public override operator fun Int.minus(other: Symbol): LabeledPolynomial<C> =
|
||||
if (this == 0) LabeledPolynomialAsIs(
|
||||
mapOf(other to 1U) to -constantOne,
|
||||
)
|
||||
else LabeledPolynomialAsIs(
|
||||
mapOf(other to 1U) to -constantOne,
|
||||
emptyMap<Symbol, UInt>() to constantOne * this@minus,
|
||||
)
|
||||
/**
|
||||
* Returns product of the integer represented as a constant polynomial and the variable represented as a monic monomial.
|
||||
*/
|
||||
public override operator fun Int.times(other: Symbol): LabeledPolynomial<C> =
|
||||
if (this == 0) zero
|
||||
else LabeledPolynomialAsIs(
|
||||
mapOf(other to 1U) to this@times.asConstant(),
|
||||
)
|
||||
|
||||
/**
|
||||
* 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> =
|
||||
when {
|
||||
other == 0 -> this
|
||||
coefficients.isEmpty() -> other.asPolynomial()
|
||||
else -> LabeledPolynomialAsIs(
|
||||
coefficients.withPutOrChanged(emptyMap(), other.asConstant()) { it -> it + other }
|
||||
)
|
||||
}
|
||||
/**
|
||||
* Returns difference between the polynomial and the integer represented as a polynomial.
|
||||
*
|
||||
* The operation is equivalent to subtraction [other] copies of unit polynomial from [this].
|
||||
*/
|
||||
public override operator fun LabeledPolynomial<C>.minus(other: Int): LabeledPolynomial<C> =
|
||||
when {
|
||||
other == 0 -> this
|
||||
coefficients.isEmpty() -> other.asPolynomial()
|
||||
else -> LabeledPolynomialAsIs(
|
||||
coefficients.withPutOrChanged(emptyMap(), (-other).asConstant()) { it -> it - other }
|
||||
)
|
||||
}
|
||||
/**
|
||||
* Returns product of the polynomial and the integer represented as a polynomial.
|
||||
*
|
||||
* The operation is equivalent to sum of [other] copies of [this].
|
||||
*/
|
||||
public override operator fun LabeledPolynomial<C>.times(other: Int): LabeledPolynomial<C> =
|
||||
when(other) {
|
||||
0 -> zero
|
||||
1 -> this
|
||||
else -> LabeledPolynomialAsIs(
|
||||
coefficients.mapValues { (_, value) -> value * other }
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns sum of the integer represented as a polynomial and the polynomial.
|
||||
*
|
||||
* The operation is equivalent to adding [this] copies of unit polynomial to [other].
|
||||
*/
|
||||
public override operator fun Int.plus(other: LabeledPolynomial<C>): LabeledPolynomial<C> =
|
||||
when {
|
||||
this == 0 -> other
|
||||
other.coefficients.isEmpty() -> this@plus.asPolynomial()
|
||||
else -> LabeledPolynomialAsIs(
|
||||
other.coefficients.withPutOrChanged(emptyMap(), this@plus.asConstant()) { it -> this@plus + it }
|
||||
)
|
||||
}
|
||||
/**
|
||||
* 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> =
|
||||
when {
|
||||
this == 0 -> -other
|
||||
other.coefficients.isEmpty() -> this@minus.asPolynomial()
|
||||
else -> LabeledPolynomialAsIs(
|
||||
buildMap(other.coefficients.size + 1) {
|
||||
put(emptyMap(), asConstant())
|
||||
other.coefficients.copyMapToBy(this, { _, c -> -c }, { currentC, newC -> currentC - newC })
|
||||
}
|
||||
)
|
||||
}
|
||||
/**
|
||||
* Returns product of the integer represented as a polynomial and the polynomial.
|
||||
*
|
||||
* The operation is equivalent to sum of [this] copies of [other].
|
||||
*/
|
||||
public override operator fun Int.times(other: LabeledPolynomial<C>): LabeledPolynomial<C> =
|
||||
when(this) {
|
||||
0 -> zero
|
||||
1 -> other
|
||||
else -> LabeledPolynomialAsIs(
|
||||
other.coefficients.mapValues { (_, value) -> this@times * value }
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns sum of the variable represented as a monic monomial and the constant represented as a constant polynomial.
|
||||
*/
|
||||
public override operator fun Symbol.plus(other: C): LabeledPolynomial<C> =
|
||||
LabeledPolynomialAsIs(
|
||||
mapOf(this@plus to 1U) to constantOne,
|
||||
emptyMap<Symbol, UInt>() to other,
|
||||
)
|
||||
/**
|
||||
* Returns difference between the variable represented as a monic monomial and the constant represented as a constant polynomial.
|
||||
*/
|
||||
public override operator fun Symbol.minus(other: C): LabeledPolynomial<C> =
|
||||
LabeledPolynomialAsIs(
|
||||
mapOf(this@minus to 1U) to constantOne,
|
||||
emptyMap<Symbol, UInt>() to -other,
|
||||
)
|
||||
/**
|
||||
* Returns product of the variable represented as a monic monomial and the constant represented as a constant polynomial.
|
||||
*/
|
||||
public override operator fun Symbol.times(other: C): LabeledPolynomial<C> =
|
||||
LabeledPolynomialAsIs(
|
||||
mapOf(this@times to 1U) to other,
|
||||
)
|
||||
|
||||
/**
|
||||
* Returns sum of the constant represented as a constant polynomial and the variable represented as a monic monomial.
|
||||
*/
|
||||
public override operator fun C.plus(other: Symbol): LabeledPolynomial<C> =
|
||||
LabeledPolynomialAsIs(
|
||||
mapOf(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(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(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> =
|
||||
if (other.coefficients.isEmpty()) this@plus.asLabeledPolynomial()
|
||||
else LabeledPolynomialAsIs(
|
||||
other.coefficients.withPutOrChanged(emptyMap(), this@plus) { it -> this@plus + it }
|
||||
)
|
||||
/**
|
||||
* Returns difference between the constant represented as a polynomial and the polynomial.
|
||||
*/
|
||||
override operator fun C.minus(other: LabeledPolynomial<C>): LabeledPolynomial<C> =
|
||||
if (other.coefficients.isEmpty()) this@minus.asPolynomial()
|
||||
else LabeledPolynomialAsIs(
|
||||
buildMap(other.coefficients.size + 1) {
|
||||
put(emptyMap(), this@minus)
|
||||
other.coefficients.copyMapToBy(this, { _, c -> -c }, { currentC, newC -> currentC - newC })
|
||||
}
|
||||
)
|
||||
/**
|
||||
* Returns product of the constant represented as a polynomial and the polynomial.
|
||||
*/
|
||||
override operator fun C.times(other: LabeledPolynomial<C>): LabeledPolynomial<C> =
|
||||
LabeledPolynomialAsIs(
|
||||
other.coefficients.mapValues { this@times * it.value }
|
||||
)
|
||||
|
||||
/**
|
||||
* Returns sum of the constant represented as a polynomial and the polynomial.
|
||||
*/
|
||||
override operator fun LabeledPolynomial<C>.plus(other: C): LabeledPolynomial<C> =
|
||||
if (coefficients.isEmpty()) other.asLabeledPolynomial()
|
||||
else LabeledPolynomialAsIs(
|
||||
coefficients.withPutOrChanged(emptyMap(), other) { it -> it + other }
|
||||
)
|
||||
/**
|
||||
* Returns difference between the constant represented as a polynomial and the polynomial.
|
||||
*/
|
||||
override operator fun LabeledPolynomial<C>.minus(other: C): LabeledPolynomial<C> =
|
||||
if (coefficients.isEmpty()) other.asLabeledPolynomial()
|
||||
else LabeledPolynomialAsIs(
|
||||
coefficients.withPutOrChanged(emptyMap(), -other) { it -> it - other }
|
||||
)
|
||||
/**
|
||||
* Returns product of the constant represented as a polynomial and the polynomial.
|
||||
*/
|
||||
override operator fun LabeledPolynomial<C>.times(other: C): LabeledPolynomial<C> =
|
||||
LabeledPolynomialAsIs(
|
||||
coefficients.mapValues { it.value * other }
|
||||
)
|
||||
|
||||
/**
|
||||
* Converts the constant [value] to polynomial.
|
||||
*/
|
||||
public override fun number(value: C): LabeledPolynomial<C> = value.asLabeledPolynomial()
|
||||
|
||||
/**
|
||||
* Represents the variable as a monic monomial.
|
||||
*/
|
||||
public override operator fun Symbol.unaryPlus(): LabeledPolynomial<C> =
|
||||
LabeledPolynomialAsIs(
|
||||
mapOf(this to 1U) to constantOne,
|
||||
)
|
||||
/**
|
||||
* Returns negation of representation of the variable as a monic monomial.
|
||||
*/
|
||||
public override operator fun Symbol.unaryMinus(): LabeledPolynomial<C> =
|
||||
LabeledPolynomialAsIs(
|
||||
mapOf(this to 1U) to -constantOne,
|
||||
)
|
||||
/**
|
||||
* Returns sum of the variables represented as monic monomials.
|
||||
*/
|
||||
public override operator fun Symbol.plus(other: Symbol): LabeledPolynomial<C> =
|
||||
if (this == other) LabeledPolynomialAsIs(
|
||||
mapOf(this to 1U) to constantOne * 2
|
||||
)
|
||||
else LabeledPolynomialAsIs(
|
||||
mapOf(this to 1U) to constantOne,
|
||||
mapOf(other to 1U) to constantOne,
|
||||
)
|
||||
/**
|
||||
* Returns difference between the variables represented as monic monomials.
|
||||
*/
|
||||
public override operator fun Symbol.minus(other: Symbol): LabeledPolynomial<C> =
|
||||
if (this == other) zero
|
||||
else LabeledPolynomialAsIs(
|
||||
mapOf(this to 1U) to constantOne,
|
||||
mapOf(other to 1U) to -constantOne,
|
||||
)
|
||||
/**
|
||||
* Returns product of the variables represented as monic monomials.
|
||||
*/
|
||||
public override operator fun Symbol.times(other: Symbol): LabeledPolynomial<C> =
|
||||
if (this == other) LabeledPolynomialAsIs(
|
||||
mapOf(this to 2U) to constantOne
|
||||
)
|
||||
else LabeledPolynomialAsIs(
|
||||
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> =
|
||||
if (other.coefficients.isEmpty()) this@plus.asPolynomial()
|
||||
else LabeledPolynomialAsIs(
|
||||
other.coefficients.withPutOrChanged(mapOf(this@plus to 1U), constantOne) { it -> constantOne + it }
|
||||
)
|
||||
/**
|
||||
* Returns difference between the variable represented as a monic monomial and the polynomial.
|
||||
*/
|
||||
public override operator fun Symbol.minus(other: LabeledPolynomial<C>): LabeledPolynomial<C> =
|
||||
if (other.coefficients.isEmpty()) this@minus.asPolynomial()
|
||||
else LabeledPolynomialAsIs(
|
||||
buildMap(other.coefficients.size + 1) {
|
||||
put(mapOf(this@minus to 1U), constantOne)
|
||||
other.coefficients.copyMapToBy(this, { _, c -> -c }) { currentC, newC -> currentC - newC }
|
||||
}
|
||||
)
|
||||
/**
|
||||
* Returns product of the variable represented as a monic monomial and the polynomial.
|
||||
*/
|
||||
public override operator fun Symbol.times(other: LabeledPolynomial<C>): LabeledPolynomial<C> =
|
||||
LabeledPolynomialAsIs(
|
||||
other.coefficients
|
||||
.mapKeys { (degs, _) -> degs.withPutOrChanged(this, 1u) { it -> it + 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> =
|
||||
if (coefficients.isEmpty()) other.asPolynomial()
|
||||
else LabeledPolynomialAsIs(
|
||||
coefficients.withPutOrChanged(mapOf(other to 1U), constantOne) { it -> it + constantOne }
|
||||
)
|
||||
/**
|
||||
* Returns difference between the polynomial and the variable represented as a monic monomial.
|
||||
*/
|
||||
public override operator fun LabeledPolynomial<C>.minus(other: Symbol): LabeledPolynomial<C> =
|
||||
if (coefficients.isEmpty()) other.asPolynomial()
|
||||
else LabeledPolynomialAsIs(
|
||||
coefficients.withPutOrChanged(mapOf(other to 1U), -constantOne) { it -> it - constantOne }
|
||||
)
|
||||
/**
|
||||
* Returns product of the polynomial and the variable represented as a monic monomial.
|
||||
*/
|
||||
public override operator fun LabeledPolynomial<C>.times(other: Symbol): LabeledPolynomial<C> =
|
||||
LabeledPolynomialAsIs(
|
||||
coefficients
|
||||
.mapKeys { (degs, _) -> degs.withPutOrChanged(other, 1u) { it -> it + 1u } }
|
||||
)
|
||||
|
||||
/**
|
||||
* Returns negation of the polynomial.
|
||||
*/
|
||||
override fun LabeledPolynomial<C>.unaryMinus(): LabeledPolynomial<C> =
|
||||
LabeledPolynomialAsIs(
|
||||
coefficients.mapValues { -it.value }
|
||||
)
|
||||
/**
|
||||
* Returns sum of the polynomials.
|
||||
*/
|
||||
override operator fun LabeledPolynomial<C>.plus(other: LabeledPolynomial<C>): LabeledPolynomial<C> =
|
||||
LabeledPolynomialAsIs(
|
||||
mergeBy(coefficients, other.coefficients) { c1, c2 -> c1 + c2 }
|
||||
)
|
||||
/**
|
||||
* Returns difference of the polynomials.
|
||||
*/
|
||||
override operator fun LabeledPolynomial<C>.minus(other: LabeledPolynomial<C>): LabeledPolynomial<C> =
|
||||
LabeledPolynomialAsIs(
|
||||
buildMap(coefficients.size + other.coefficients.size) {
|
||||
coefficients.copyTo(this)
|
||||
other.coefficients.copyMapToBy(this, { _, c -> -c }, { currentC, newC -> currentC - newC })
|
||||
}
|
||||
)
|
||||
/**
|
||||
* Returns product of the polynomials.
|
||||
*/
|
||||
override operator fun LabeledPolynomial<C>.times(other: LabeledPolynomial<C>): LabeledPolynomial<C> =
|
||||
LabeledPolynomialAsIs(
|
||||
buildMap(coefficients.size * other.coefficients.size) {
|
||||
for ((degs1, c1) in coefficients) for ((degs2, c2) in other.coefficients) {
|
||||
val degs = mergeBy(degs1, degs2) { deg1, deg2 -> deg1 + deg2 }
|
||||
val c = c1 * c2
|
||||
this.putOrChange(degs, c) { it -> it + c }
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
/**
|
||||
* Instance of zero polynomial (zero of the polynomial ring).
|
||||
*/
|
||||
override val zero: LabeledPolynomial<C> = LabeledPolynomialAsIs()
|
||||
/**
|
||||
* Instance of unit polynomial (unit of the polynomial ring).
|
||||
*/
|
||||
override val one: LabeledPolynomial<C> = constantOne.asLabeledPolynomial()
|
||||
|
||||
/**
|
||||
* Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is
|
||||
* zero, degree is -1.
|
||||
*/
|
||||
override val LabeledPolynomial<C>.degree: Int
|
||||
get() = coefficients.entries.maxOfOrNull { (degs, _) -> degs.values.sum().toInt() } ?: -1
|
||||
/**
|
||||
* Map that associates variables (that appear in the polynomial in positive exponents) with their most exponents
|
||||
* in which they are appeared in the polynomial.
|
||||
*
|
||||
* As consequence all values in the map are positive integers. Also, if the polynomial is constant, the map is empty.
|
||||
* And keys of the map is the same as in [variables].
|
||||
*/
|
||||
public override val LabeledPolynomial<C>.degrees: Map<Symbol, UInt>
|
||||
get() =
|
||||
buildMap {
|
||||
coefficients.keys.forEach { degs ->
|
||||
degs.copyToBy(this, ::max)
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Counts degree of the polynomial by the specified [variable].
|
||||
*/
|
||||
public override fun LabeledPolynomial<C>.degreeBy(variable: Symbol): UInt =
|
||||
coefficients.entries.maxOfOrNull { (degs, _) -> degs.getOrElse(variable) { 0u } } ?: 0u
|
||||
/**
|
||||
* Counts degree of the polynomial by the specified [variables].
|
||||
*/
|
||||
public override fun LabeledPolynomial<C>.degreeBy(variables: Collection<Symbol>): UInt =
|
||||
coefficients.entries.maxOfOrNull { (degs, _) -> degs.filterKeys { it in variables }.values.sum() } ?: 0u
|
||||
/**
|
||||
* Set of all variables that appear in the polynomial in positive exponents.
|
||||
*/
|
||||
public override val LabeledPolynomial<C>.variables: Set<Symbol>
|
||||
get() =
|
||||
buildSet {
|
||||
coefficients.entries.forEach { (degs, _) -> addAll(degs.keys) }
|
||||
}
|
||||
/**
|
||||
* Count of all variables that appear in the polynomial in positive exponents.
|
||||
*/
|
||||
public override val LabeledPolynomial<C>.countOfVariables: Int get() = variables.size
|
||||
|
||||
// TODO: When context receivers will be ready move all of this substitutions and invocations to utilities with
|
||||
// [ListPolynomialSpace] as a context receiver
|
||||
/**
|
||||
* Substitutes provided arguments [arguments] into [this] polynomial.
|
||||
*/
|
||||
public inline fun LabeledPolynomial<C>.substitute(arguments: Map<Symbol, C>): LabeledPolynomial<C> = substitute(ring, arguments)
|
||||
/**
|
||||
* Substitutes provided arguments [arguments] into [this] polynomial.
|
||||
*/
|
||||
@JvmName("substitutePolynomial")
|
||||
public inline fun LabeledPolynomial<C>.substitute(arguments: Map<Symbol, LabeledPolynomial<C>>) : LabeledPolynomial<C> = substitute(ring, arguments)
|
||||
}
|
@ -1,92 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018-2022 KMath contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@file:Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress")
|
||||
|
||||
package space.kscience.kmath.functions
|
||||
|
||||
import space.kscience.kmath.expressions.Symbol
|
||||
import space.kscience.kmath.operations.Ring
|
||||
import kotlin.jvm.JvmName
|
||||
|
||||
|
||||
/**
|
||||
* Represents multivariate rational function that stores its numerator and denominator as [LabeledPolynomial]s.
|
||||
*/
|
||||
public data class LabeledRationalFunction<C>(
|
||||
public override val numerator: LabeledPolynomial<C>,
|
||||
public override val denominator: LabeledPolynomial<C>
|
||||
) : RationalFunction<C, LabeledPolynomial<C>> {
|
||||
override fun toString(): String = "LabeledRationalFunction${numerator.coefficients}/${denominator.coefficients}"
|
||||
}
|
||||
|
||||
/**
|
||||
* Arithmetic context for univariate rational functions with numerator and denominator represented as [LabeledPolynomial]s.
|
||||
*
|
||||
* @param C the type of constants. Polynomials have them a coefficients in their terms.
|
||||
* @param A type of provided underlying ring of constants. It's [Ring] of [C].
|
||||
* @param ring underlying ring of constants of type [A].
|
||||
*/
|
||||
public class LabeledRationalFunctionSpace<C, A: Ring<C>>(
|
||||
public val ring: A,
|
||||
) :
|
||||
MultivariateRationalFunctionSpaceOverMultivariatePolynomialSpace<
|
||||
C,
|
||||
Symbol,
|
||||
LabeledPolynomial<C>,
|
||||
LabeledRationalFunction<C>,
|
||||
LabeledPolynomialSpace<C, A>,
|
||||
>,
|
||||
MultivariatePolynomialSpaceOfFractions<
|
||||
C,
|
||||
Symbol,
|
||||
LabeledPolynomial<C>,
|
||||
LabeledRationalFunction<C>,
|
||||
>() {
|
||||
|
||||
/**
|
||||
* Underlying polynomial ring. Its polynomial operations are inherited by local polynomial operations.
|
||||
*/
|
||||
override val polynomialRing : LabeledPolynomialSpace<C, A> = LabeledPolynomialSpace(ring)
|
||||
/**
|
||||
* Constructor of rational functions (of type [LabeledRationalFunction]) from numerator and denominator (of type [LabeledPolynomial]).
|
||||
*/
|
||||
override fun constructRationalFunction(
|
||||
numerator: LabeledPolynomial<C>,
|
||||
denominator: LabeledPolynomial<C>
|
||||
): LabeledRationalFunction<C> =
|
||||
LabeledRationalFunction<C>(numerator, denominator)
|
||||
|
||||
// TODO: When context receivers will be ready move all of this substitutions and invocations to utilities with
|
||||
// [ListPolynomialSpace] as a context receiver
|
||||
/**
|
||||
* Substitutes provided constant [argument] into [this] polynomial.
|
||||
*/
|
||||
public inline fun LabeledPolynomial<C>.substitute(argument: Map<Symbol, C>): LabeledPolynomial<C> = substitute(ring, argument)
|
||||
/**
|
||||
* Substitutes provided polynomial [argument] into [this] polynomial.
|
||||
*/
|
||||
@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.
|
||||
*/
|
||||
@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.
|
||||
*/
|
||||
public inline fun LabeledRationalFunction<C>.substitute(argument: Map<Symbol, C>): LabeledRationalFunction<C> = substitute(ring, argument)
|
||||
/**
|
||||
* Substitutes provided polynomial [argument] into [this] rational function.
|
||||
*/
|
||||
@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.
|
||||
*/
|
||||
@JvmName("substituteRationalFunction")
|
||||
public inline fun LabeledRationalFunction<C>.substitute(argument: Map<Symbol, LabeledRationalFunction<C>>): LabeledRationalFunction<C> = substitute(ring, argument)
|
||||
}
|
@ -1,374 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018-2022 KMath contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@file:Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress")
|
||||
|
||||
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.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
|
||||
/**
|
||||
* Represents univariate polynomial that stores its coefficients in a [List].
|
||||
*
|
||||
* @param C the type of constants.
|
||||
*/
|
||||
public data class ListPolynomial<out C>(
|
||||
/**
|
||||
* 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 +
|
||||
* 0, // 0 x +
|
||||
* 5, // 5 x^2
|
||||
* )
|
||||
* ```
|
||||
* and also as
|
||||
* ```
|
||||
* listOf(
|
||||
* -6, // -6 +
|
||||
* 0, // 0 x +
|
||||
* 5, // 5 x^2
|
||||
* 0, // 0 x^3
|
||||
* 0, // 0 x^4
|
||||
* )
|
||||
* ```
|
||||
* It is 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.
|
||||
* @usesMathJax
|
||||
*/
|
||||
public val coefficients: List<C>
|
||||
) {
|
||||
override fun toString(): String = "ListPolynomial$coefficients"
|
||||
}
|
||||
|
||||
/**
|
||||
* Arithmetic context for univariate polynomials with coefficients stored as a [List] constructed with the provided
|
||||
* [ring] of constants.
|
||||
*
|
||||
* @param C the type of constants. Polynomials have them a coefficients in their terms.
|
||||
* @param A type of provided underlying ring of constants. It's [Ring] of [C].
|
||||
* @param ring underlying ring of constants of type [A].
|
||||
*/
|
||||
public open class ListPolynomialSpace<C, out A : Ring<C>>(
|
||||
public override val ring: A,
|
||||
) : PolynomialSpaceOverRing<C, ListPolynomial<C>, A> {
|
||||
/**
|
||||
* Returns sum of the polynomial and the integer represented as a polynomial.
|
||||
*
|
||||
* The operation is equivalent to adding [other] copies of unit polynomial to [this].
|
||||
*/
|
||||
public override operator fun ListPolynomial<C>.plus(other: Int): ListPolynomial<C> =
|
||||
if (other == 0) this
|
||||
else
|
||||
ListPolynomial(
|
||||
coefficients
|
||||
.toMutableList()
|
||||
.apply {
|
||||
val result = getOrElse(0) { constantZero } + other
|
||||
|
||||
if(size == 0) add(result)
|
||||
else this[0] = result
|
||||
}
|
||||
)
|
||||
/**
|
||||
* Returns difference between the polynomial and the integer represented as a polynomial.
|
||||
*
|
||||
* The operation is equivalent to subtraction [other] copies of unit polynomial from [this].
|
||||
*/
|
||||
public override operator fun ListPolynomial<C>.minus(other: Int): ListPolynomial<C> =
|
||||
if (other == 0) this
|
||||
else
|
||||
ListPolynomial(
|
||||
coefficients
|
||||
.toMutableList()
|
||||
.apply {
|
||||
val result = getOrElse(0) { constantZero } - other
|
||||
|
||||
if(size == 0) add(result)
|
||||
else this[0] = result
|
||||
}
|
||||
)
|
||||
/**
|
||||
* Returns product of the polynomial and the integer represented as a polynomial.
|
||||
*
|
||||
* The operation is equivalent to sum of [other] copies of [this].
|
||||
*/
|
||||
public override operator fun ListPolynomial<C>.times(other: Int): ListPolynomial<C> =
|
||||
when (other) {
|
||||
0 -> zero
|
||||
1 -> this
|
||||
else -> ListPolynomial(
|
||||
coefficients.map { it * other }
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns sum of the integer represented as a polynomial and the polynomial.
|
||||
*
|
||||
* The operation is equivalent to adding [this] copies of unit polynomial to [other].
|
||||
*/
|
||||
public override operator fun Int.plus(other: ListPolynomial<C>): ListPolynomial<C> =
|
||||
if (this == 0) other
|
||||
else
|
||||
ListPolynomial(
|
||||
other.coefficients
|
||||
.toMutableList()
|
||||
.apply {
|
||||
val result = this@plus + getOrElse(0) { constantZero }
|
||||
|
||||
if(size == 0) add(result)
|
||||
else this[0] = result
|
||||
}
|
||||
)
|
||||
/**
|
||||
* Returns difference between the integer represented as 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> =
|
||||
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)
|
||||
else this[0] = result
|
||||
}
|
||||
}
|
||||
)
|
||||
/**
|
||||
* Returns product of the integer represented as a polynomial and the polynomial.
|
||||
*
|
||||
* The operation is equivalent to sum of [this] copies of [other].
|
||||
*/
|
||||
public override operator fun Int.times(other: ListPolynomial<C>): ListPolynomial<C> =
|
||||
when (this) {
|
||||
0 -> zero
|
||||
1 -> other
|
||||
else -> ListPolynomial(
|
||||
other.coefficients.map { this@times * it }
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
if (isEmpty()) ListPolynomial(listOf(this@plus))
|
||||
else ListPolynomial(
|
||||
toMutableList()
|
||||
.apply {
|
||||
val result = if (size == 0) this@plus else this@plus + get(0)
|
||||
|
||||
if(size == 0) add(result)
|
||||
else this[0] = result
|
||||
}
|
||||
)
|
||||
}
|
||||
/**
|
||||
* Returns difference between the constant represented as a polynomial and the polynomial.
|
||||
*/
|
||||
public override operator fun C.minus(other: ListPolynomial<C>): ListPolynomial<C> =
|
||||
with(other.coefficients) {
|
||||
if (isEmpty()) ListPolynomial(listOf(this@minus))
|
||||
else ListPolynomial(
|
||||
toMutableList()
|
||||
.apply {
|
||||
(1 .. lastIndex).forEach { this[it] = -this[it] }
|
||||
|
||||
val result = if (size == 0) this@minus else this@minus - get(0)
|
||||
|
||||
if(size == 0) add(result)
|
||||
else this[0] = result
|
||||
}
|
||||
)
|
||||
}
|
||||
/**
|
||||
* Returns product of the constant represented as a polynomial and the polynomial.
|
||||
*/
|
||||
public override operator fun C.times(other: ListPolynomial<C>): ListPolynomial<C> =
|
||||
ListPolynomial(
|
||||
other.coefficients.map { this@times * it }
|
||||
)
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
if (isEmpty()) ListPolynomial(listOf(other))
|
||||
else ListPolynomial(
|
||||
toMutableList()
|
||||
.apply {
|
||||
val result = if (size == 0) other else get(0) + other
|
||||
|
||||
if(size == 0) add(result)
|
||||
else this[0] = result
|
||||
}
|
||||
)
|
||||
}
|
||||
/**
|
||||
* Returns difference between the constant represented as a polynomial and the polynomial.
|
||||
*/
|
||||
public override operator fun ListPolynomial<C>.minus(other: C): ListPolynomial<C> =
|
||||
with(coefficients) {
|
||||
if (isEmpty()) ListPolynomial(listOf(-other))
|
||||
else ListPolynomial(
|
||||
toMutableList()
|
||||
.apply {
|
||||
val result = if (size == 0) other else get(0) - other
|
||||
|
||||
if(size == 0) add(result)
|
||||
else this[0] = result
|
||||
}
|
||||
)
|
||||
}
|
||||
/**
|
||||
* Returns product of the constant represented as a polynomial and the polynomial.
|
||||
*/
|
||||
public override operator fun ListPolynomial<C>.times(other: C): ListPolynomial<C> =
|
||||
ListPolynomial(
|
||||
coefficients.map { it * other }
|
||||
)
|
||||
|
||||
/**
|
||||
* Converts the constant [value] to polynomial.
|
||||
*/
|
||||
public override fun number(value: C): ListPolynomial<C> = ListPolynomial(listOf(value))
|
||||
|
||||
/**
|
||||
* Returns negation of the polynomial.
|
||||
*/
|
||||
public override operator fun ListPolynomial<C>.unaryMinus(): ListPolynomial<C> =
|
||||
ListPolynomial(coefficients.map { -it })
|
||||
/**
|
||||
* Returns sum of the polynomials.
|
||||
*/
|
||||
public override operator fun ListPolynomial<C>.plus(other: ListPolynomial<C>): ListPolynomial<C> {
|
||||
val thisDegree = degree
|
||||
val otherDegree = other.degree
|
||||
return ListPolynomial(
|
||||
List(max(thisDegree, otherDegree) + 1) {
|
||||
when {
|
||||
it > thisDegree -> other.coefficients[it]
|
||||
it > otherDegree -> coefficients[it]
|
||||
else -> coefficients[it] + other.coefficients[it]
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
/**
|
||||
* Returns difference of the polynomials.
|
||||
*/
|
||||
public override operator fun ListPolynomial<C>.minus(other: ListPolynomial<C>): ListPolynomial<C> {
|
||||
val thisDegree = degree
|
||||
val otherDegree = other.degree
|
||||
return ListPolynomial(
|
||||
List(max(thisDegree, otherDegree) + 1) {
|
||||
when {
|
||||
it > thisDegree -> -other.coefficients[it]
|
||||
it > otherDegree -> coefficients[it]
|
||||
else -> coefficients[it] - other.coefficients[it]
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
/**
|
||||
* Returns product of the polynomials.
|
||||
*/
|
||||
public override operator fun ListPolynomial<C>.times(other: ListPolynomial<C>): ListPolynomial<C> {
|
||||
val thisDegree = degree
|
||||
val otherDegree = other.degree
|
||||
return ListPolynomial(
|
||||
List(thisDegree + otherDegree + 1) { d ->
|
||||
(max(0, d - otherDegree)..min(thisDegree, d))
|
||||
.map { coefficients[it] * other.coefficients[d - it] }
|
||||
.reduce { acc, rational -> acc + rational }
|
||||
}
|
||||
)
|
||||
}
|
||||
/**
|
||||
* 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 polynomial (unit of the polynomial ring).
|
||||
*/
|
||||
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
|
||||
* zero, degree is -1.
|
||||
*/
|
||||
public override val ListPolynomial<C>.degree: Int get() = coefficients.lastIndex
|
||||
|
||||
// TODO: When context receivers will be ready move all of this substitutions and invocations to utilities with
|
||||
// [ListPolynomialSpace] as a context receiver
|
||||
/**
|
||||
* Evaluates value of [this] polynomial on provided [argument].
|
||||
*/
|
||||
public inline fun ListPolynomial<C>.substitute(argument: C): C = substitute(ring, argument)
|
||||
/**
|
||||
* Substitutes provided polynomial [argument] into [this] polynomial.
|
||||
*/
|
||||
public inline fun ListPolynomial<C>.substitute(argument: ListPolynomial<C>): ListPolynomial<C> = substitute(ring, argument)
|
||||
|
||||
/**
|
||||
* Represent [this] polynomial as a regular context-less function.
|
||||
*/
|
||||
public inline fun ListPolynomial<C>.asFunction(): (C) -> C = asFunctionOver(ring)
|
||||
/**
|
||||
* Represent [this] polynomial as a regular context-less function.
|
||||
*/
|
||||
public inline fun ListPolynomial<C>.asFunctionOfConstant(): (C) -> C = asFunctionOfConstantOver(ring)
|
||||
/**
|
||||
* Represent [this] polynomial as a regular context-less function.
|
||||
*/
|
||||
public inline fun ListPolynomial<C>.asFunctionOfPolynomial(): (ListPolynomial<C>) -> ListPolynomial<C> = asFunctionOfPolynomialOver(ring)
|
||||
|
||||
/**
|
||||
* Evaluates value of [this] polynomial on provided [argument].
|
||||
*/
|
||||
public inline operator fun ListPolynomial<C>.invoke(argument: C): C = substitute(ring, argument)
|
||||
/**
|
||||
* Evaluates value of [this] polynomial on provided [argument].
|
||||
*/
|
||||
public inline operator fun ListPolynomial<C>.invoke(argument: ListPolynomial<C>): ListPolynomial<C> = substitute(ring, argument)
|
||||
}
|
||||
|
||||
/**
|
||||
* Space of polynomials constructed over ring.
|
||||
*
|
||||
* @param C the type of constants. Polynomials have them as a coefficients in their terms.
|
||||
* @param A type of underlying ring of constants. It's [Ring] of [C].
|
||||
* @param ring underlying ring of constants of type [A].
|
||||
*/
|
||||
public class ScalableListPolynomialSpace<C, out A>(
|
||||
ring: A,
|
||||
) : ListPolynomialSpace<C, A>(ring), ScaleOperations<ListPolynomial<C>> where A : Ring<C>, A : ScaleOperations<C> {
|
||||
override fun scale(a: ListPolynomial<C>, value: Double): ListPolynomial<C> =
|
||||
ring { ListPolynomial(a.coefficients.map { scale(it, value) }) }
|
||||
}
|
@ -1,123 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018-2022 KMath contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@file:Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress")
|
||||
|
||||
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 = "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,
|
||||
) :
|
||||
RationalFunctionSpaceOverPolynomialSpace<
|
||||
C,
|
||||
ListPolynomial<C>,
|
||||
ListRationalFunction<C>,
|
||||
ListPolynomialSpace<C, A>,
|
||||
>,
|
||||
PolynomialSpaceOfFractions<
|
||||
C,
|
||||
ListPolynomial<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
|
||||
/**
|
||||
* Evaluates value of [this] polynomial on provided argument.
|
||||
*/
|
||||
public inline fun ListPolynomial<C>.substitute(argument: C): C = substitute(ring, argument)
|
||||
/**
|
||||
* Substitutes provided polynomial [argument] into [this] polynomial.
|
||||
*/
|
||||
public inline fun ListPolynomial<C>.substitute(argument: ListPolynomial<C>): ListPolynomial<C> = substitute(ring, argument)
|
||||
/**
|
||||
* Substitutes provided rational function [argument] into [this] polynomial.
|
||||
*/
|
||||
public inline fun ListPolynomial<C>.substitute(argument: ListRationalFunction<C>): ListRationalFunction<C> = substitute(ring, argument)
|
||||
/**
|
||||
* Substitutes provided polynomial [argument] into [this] rational function.
|
||||
*/
|
||||
public inline fun ListRationalFunction<C>.substitute(argument: ListPolynomial<C>): ListRationalFunction<C> = substitute(ring, argument)
|
||||
/**
|
||||
* Substitutes provided rational function [argument] into [this] rational function.
|
||||
*/
|
||||
public inline fun ListRationalFunction<C>.substitute(argument: ListRationalFunction<C>): ListRationalFunction<C> = substitute(ring, argument)
|
||||
|
||||
/**
|
||||
* Represent [this] polynomial as a regular context-less function.
|
||||
*/
|
||||
public inline fun ListPolynomial<C>.asFunction(): (C) -> C = { substitute(ring, it) }
|
||||
/**
|
||||
* Represent [this] polynomial as a regular context-less function.
|
||||
*/
|
||||
public inline fun ListPolynomial<C>.asFunctionOfConstant(): (C) -> C = { substitute(ring, it) }
|
||||
/**
|
||||
* Represent [this] polynomial as a regular context-less function.
|
||||
*/
|
||||
public inline fun ListPolynomial<C>.asFunctionOfPolynomial(): (ListPolynomial<C>) -> ListPolynomial<C> = { substitute(ring, it) }
|
||||
/**
|
||||
* Represent [this] polynomial as a regular context-less function.
|
||||
*/
|
||||
public inline fun ListPolynomial<C>.asFunctionOfRationalFunction(): (ListRationalFunction<C>) -> ListRationalFunction<C> = { substitute(ring, it) }
|
||||
/**
|
||||
* Represent [this] rational function as a regular context-less function.
|
||||
*/
|
||||
public inline fun ListRationalFunction<C>.asFunctionOfPolynomial(): (ListPolynomial<C>) -> ListRationalFunction<C> = { substitute(ring, it) }
|
||||
/**
|
||||
* Represent [this] rational function as a regular context-less function.
|
||||
*/
|
||||
public inline fun ListRationalFunction<C>.asFunctionOfRationalFunction(): (ListRationalFunction<C>) -> ListRationalFunction<C> = { substitute(ring, it) }
|
||||
|
||||
/**
|
||||
* Evaluates value of [this] polynomial on provided argument.
|
||||
*/
|
||||
public inline operator fun ListPolynomial<C>.invoke(argument: C): C = substitute(ring, argument)
|
||||
/**
|
||||
* Evaluates value of [this] polynomial on provided argument.
|
||||
*/
|
||||
public inline operator fun ListPolynomial<C>.invoke(argument: ListPolynomial<C>): ListPolynomial<C> = substitute(ring, argument)
|
||||
/**
|
||||
* Evaluates value of [this] polynomial on provided argument.
|
||||
*/
|
||||
public inline operator fun ListPolynomial<C>.invoke(argument: ListRationalFunction<C>): ListRationalFunction<C> = substitute(ring, argument)
|
||||
/**
|
||||
* Evaluates value of [this] rational function on provided argument.
|
||||
*/
|
||||
public inline operator fun ListRationalFunction<C>.invoke(argument: ListPolynomial<C>): ListRationalFunction<C> = substitute(ring, argument)
|
||||
/**
|
||||
* Evaluates value of [this] rational function on provided argument.
|
||||
*/
|
||||
public inline operator fun ListRationalFunction<C>.invoke(argument: ListRationalFunction<C>): ListRationalFunction<C> = substitute(ring, argument)
|
||||
}
|
@ -1,350 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018-2022 KMath contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@file:Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress")
|
||||
|
||||
package space.kscience.kmath.functions
|
||||
|
||||
import space.kscience.kmath.operations.Ring
|
||||
import space.kscience.kmath.structures.Buffer
|
||||
import kotlin.jvm.JvmName
|
||||
import kotlin.math.max
|
||||
|
||||
|
||||
/**
|
||||
* Represents 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<out C>
|
||||
@PublishedApi
|
||||
internal constructor(
|
||||
/**
|
||||
* Map that contains coefficients of the polynomial.
|
||||
*
|
||||
* Every monomial \(a x_1^{d_1} ... x_n^{d_n}\) is stored as a pair "key-value" in the map, where the value is the
|
||||
* coefficient \(a\) and the key is a list that associates index of every variable in the monomial with their degree
|
||||
* in the monomial. For example, coefficients of a polynomial \(5 x_1^2 x_3^3 - 6 x_2\) can be represented as
|
||||
* ```
|
||||
* mapOf(
|
||||
* listOf(2, 0, 3) to 5, // 5 x_1^2 x_3^3 +
|
||||
* listOf(0, 1) to (-6), // (-6) x_2^1
|
||||
* )
|
||||
* ```
|
||||
* and also as
|
||||
* ```
|
||||
* mapOf(
|
||||
* listOf(2, 0, 3) to 5, // 5 x_1^2 x_3^3 +
|
||||
* listOf(0, 1) to (-6), // (-6) x_2^1
|
||||
* listOf(0, 1, 1) to 0, // 0 x_2^1 x_3^1
|
||||
* )
|
||||
* ```
|
||||
* It is not prohibited to put extra zero monomials into the map (as for \(0 x_2 x_3\) in the example). But the
|
||||
* bigger the coefficients map the worse performance of arithmetical operations performed on it. Thus, it is
|
||||
* recommended not to put (or even to remove) extra (or useless) monomials in the coefficients map.
|
||||
* @usesMathJax
|
||||
*/
|
||||
public val coefficients: Map<List<UInt>, C>
|
||||
) {
|
||||
override fun toString(): String = "NumberedPolynomial$coefficients"
|
||||
}
|
||||
|
||||
/**
|
||||
* Arithmetic context for multivariate polynomials with coefficients stored as a [Map] and terms' signatures stored as a
|
||||
* [List] constructed with the provided [ring] of constants.
|
||||
*
|
||||
* @param C the type of constants. Polynomials have them a coefficients in their terms.
|
||||
* @param A type of provided underlying ring of constants. It's [Ring] of [C].
|
||||
* @param ring underlying ring of constants of type [A].
|
||||
*/
|
||||
public class NumberedPolynomialSpace<C, out A : Ring<C>>(
|
||||
public override val ring: A,
|
||||
) : PolynomialSpaceOverRing<C, NumberedPolynomial<C>, A> {
|
||||
/**
|
||||
* Returns sum of the polynomial and the integer represented as a polynomial.
|
||||
*
|
||||
* The operation is equivalent to adding [other] copies of unit polynomial to [this].
|
||||
*/
|
||||
public override operator fun NumberedPolynomial<C>.plus(other: Int): NumberedPolynomial<C> =
|
||||
if (other == 0) this
|
||||
else NumberedPolynomialAsIs(
|
||||
coefficients.withPutOrChanged(emptyList(), other.asConstant()) { it -> it + other }
|
||||
)
|
||||
/**
|
||||
* Returns difference between the polynomial and the integer represented as a polynomial.
|
||||
*
|
||||
* The operation is equivalent to subtraction [other] copies of unit polynomial from [this].
|
||||
*/
|
||||
public override operator fun NumberedPolynomial<C>.minus(other: Int): NumberedPolynomial<C> =
|
||||
if (other == 0) this
|
||||
else NumberedPolynomialAsIs(
|
||||
coefficients.withPutOrChanged(emptyList(), (-other).asConstant()) { it -> it - other }
|
||||
)
|
||||
/**
|
||||
* Returns product of the polynomial and the integer represented as a polynomial.
|
||||
*
|
||||
* The operation is equivalent to sum of [other] copies of [this].
|
||||
*/
|
||||
public override operator fun NumberedPolynomial<C>.times(other: Int): NumberedPolynomial<C> =
|
||||
when (other) {
|
||||
0 -> zero
|
||||
1 -> this
|
||||
else -> NumberedPolynomialAsIs(
|
||||
coefficients.mapValues { it.value * other }
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns sum of the integer represented as a polynomial and the polynomial.
|
||||
*
|
||||
* The operation is equivalent to adding [this] copies of unit polynomial to [other].
|
||||
*/
|
||||
public override operator fun Int.plus(other: NumberedPolynomial<C>): NumberedPolynomial<C> =
|
||||
if (this == 0) other
|
||||
else NumberedPolynomialAsIs(
|
||||
other.coefficients.withPutOrChanged(emptyList(), this@plus.asConstant()) { it -> this@plus + it }
|
||||
)
|
||||
/**
|
||||
* 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> =
|
||||
when {
|
||||
this == 0 -> -other
|
||||
other.coefficients.isEmpty() -> this.asPolynomial()
|
||||
else -> NumberedPolynomialAsIs(
|
||||
buildMap(other.coefficients.size + 1) {
|
||||
put(emptyList(), other.coefficients.computeOnOrElse(emptyList(), { this@minus.asConstant() }, { it -> this@minus - it}))
|
||||
other.coefficients.copyMapToBy(this, { _, c -> -c }) { currentC, _ -> currentC }
|
||||
}
|
||||
)
|
||||
}
|
||||
/**
|
||||
* 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> =
|
||||
when (this) {
|
||||
0 -> zero
|
||||
1 -> other
|
||||
else -> NumberedPolynomialAsIs(
|
||||
other.coefficients.mapValues { this@times * it.value }
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns sum of the constant represented as a polynomial and the polynomial.
|
||||
*/
|
||||
override operator fun C.plus(other: NumberedPolynomial<C>): NumberedPolynomial<C> =
|
||||
if (other.coefficients.isEmpty()) this@plus.asPolynomial()
|
||||
else NumberedPolynomialAsIs(
|
||||
other.coefficients.withPutOrChanged(emptyList(), this@plus) { it -> this@plus + it }
|
||||
)
|
||||
/**
|
||||
* Returns difference between the constant represented as a polynomial and the polynomial.
|
||||
*/
|
||||
override operator fun C.minus(other: NumberedPolynomial<C>): NumberedPolynomial<C> =
|
||||
if (other.coefficients.isEmpty()) this@minus.asPolynomial()
|
||||
else NumberedPolynomialAsIs(
|
||||
buildMap(other.coefficients.size) {
|
||||
put(emptyList(), other.coefficients.computeOnOrElse(emptyList(), this@minus) { it -> this@minus - it })
|
||||
other.coefficients.copyMapToBy(this, { _, c -> -c }, { currentC, _ -> currentC })
|
||||
}
|
||||
)
|
||||
/**
|
||||
* Returns product of the constant represented as a polynomial and the polynomial.
|
||||
*/
|
||||
override operator fun C.times(other: NumberedPolynomial<C>): NumberedPolynomial<C> =
|
||||
NumberedPolynomialAsIs(
|
||||
other.coefficients.mapValues { this@times * it.value }
|
||||
)
|
||||
|
||||
/**
|
||||
* Returns sum of the constant represented as a polynomial and the polynomial.
|
||||
*/
|
||||
override operator fun NumberedPolynomial<C>.plus(other: C): NumberedPolynomial<C> =
|
||||
if (coefficients.isEmpty()) other.asPolynomial()
|
||||
else NumberedPolynomialAsIs(
|
||||
coefficients.withPutOrChanged(emptyList(), other) { it -> it + other }
|
||||
)
|
||||
/**
|
||||
* Returns difference between the constant represented as a polynomial and the polynomial.
|
||||
*/
|
||||
override operator fun NumberedPolynomial<C>.minus(other: C): NumberedPolynomial<C> =
|
||||
if (coefficients.isEmpty()) other.asPolynomial()
|
||||
else NumberedPolynomialAsIs(
|
||||
coefficients.withPutOrChanged(emptyList(), -other) { it -> it - other }
|
||||
)
|
||||
/**
|
||||
* Returns product of the constant represented as a polynomial and the polynomial.
|
||||
*/
|
||||
override operator fun NumberedPolynomial<C>.times(other: C): NumberedPolynomial<C> =
|
||||
NumberedPolynomialAsIs(
|
||||
coefficients.mapValues { it.value * other }
|
||||
)
|
||||
|
||||
/**
|
||||
* Converts the constant [value] to polynomial.
|
||||
*/
|
||||
public override fun number(value: C): NumberedPolynomial<C> =
|
||||
NumberedPolynomialAsIs(mapOf(emptyList<UInt>() to value))
|
||||
|
||||
/**
|
||||
* Returns negation of the polynomial.
|
||||
*/
|
||||
override fun NumberedPolynomial<C>.unaryMinus(): NumberedPolynomial<C> =
|
||||
NumberedPolynomialAsIs(
|
||||
coefficients.mapValues { -it.value }
|
||||
)
|
||||
/**
|
||||
* Returns sum of the polynomials.
|
||||
*/
|
||||
override operator fun NumberedPolynomial<C>.plus(other: NumberedPolynomial<C>): NumberedPolynomial<C> =
|
||||
NumberedPolynomialAsIs(
|
||||
mergeBy(coefficients, other.coefficients) { c1, c2 -> c1 + c2 }
|
||||
)
|
||||
/**
|
||||
* Returns difference of the polynomials.
|
||||
*/
|
||||
override operator fun NumberedPolynomial<C>.minus(other: NumberedPolynomial<C>): NumberedPolynomial<C> =
|
||||
NumberedPolynomialAsIs(
|
||||
buildMap(coefficients.size + other.coefficients.size) {
|
||||
coefficients.copyTo(this)
|
||||
other.coefficients.copyMapToBy(this, { _, c -> -c }, { currentC, newC -> currentC - newC })
|
||||
}
|
||||
)
|
||||
/**
|
||||
* Returns product of the polynomials.
|
||||
*/
|
||||
override operator fun NumberedPolynomial<C>.times(other: NumberedPolynomial<C>): NumberedPolynomial<C> =
|
||||
NumberedPolynomialAsIs(
|
||||
buildMap(coefficients.size * other.coefficients.size) {
|
||||
for ((degs1, c1) in coefficients) for ((degs2, c2) in other.coefficients) {
|
||||
val degs =
|
||||
(0..max(degs1.lastIndex, degs2.lastIndex))
|
||||
.map { degs1.getOrElse(it) { 0U } + degs2.getOrElse(it) { 0U } }
|
||||
val c = c1 * c2
|
||||
putOrChange(degs, c) { it -> it + c }
|
||||
}
|
||||
}
|
||||
)
|
||||
/**
|
||||
* Raises [arg] to the integer power [exponent].
|
||||
*/ // TODO: To optimize boxing
|
||||
override fun power(arg: NumberedPolynomial<C>, exponent: UInt): NumberedPolynomial<C> = super.power(arg, exponent)
|
||||
|
||||
/**
|
||||
* Instance of zero polynomial (zero of the polynomial ring).
|
||||
*/
|
||||
override val zero: NumberedPolynomial<C> = NumberedPolynomialAsIs(emptyMap())
|
||||
/**
|
||||
* Instance of unit polynomial (unit of the polynomial ring).
|
||||
*/
|
||||
override val one: NumberedPolynomial<C> by lazy { NumberedPolynomialAsIs(mapOf(emptyList<UInt>() to constantOne)) }
|
||||
|
||||
/**
|
||||
* Maximal index (ID) of variable occurring in the polynomial with positive power. If there is no such variable,
|
||||
* the result is -1.
|
||||
*/
|
||||
public val NumberedPolynomial<C>.lastVariable: Int
|
||||
get() = coefficients.keys.maxOfOrNull { degs -> degs.lastIndex } ?: -1
|
||||
/**
|
||||
* Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is
|
||||
* zero, degree is -1.
|
||||
*/
|
||||
override val NumberedPolynomial<C>.degree: Int
|
||||
get() = coefficients.keys.maxOfOrNull { degs -> degs.sum().toInt() } ?: -1
|
||||
/**
|
||||
* List that associates indices of variables (that appear in the polynomial in positive exponents) with their most
|
||||
* exponents in which the variables are appeared in the polynomial.
|
||||
*
|
||||
* As consequence all values in the list are non-negative integers. Also, if the polynomial is constant, the list is empty.
|
||||
* And last index of the list is [lastVariable].
|
||||
*/
|
||||
public val NumberedPolynomial<C>.degrees: List<UInt>
|
||||
get() =
|
||||
MutableList(lastVariable + 1) { 0u }.apply {
|
||||
coefficients.keys.forEach { degs ->
|
||||
degs.forEachIndexed { index, deg ->
|
||||
this[index] = max(this[index], deg)
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Counts degree of the polynomial by the specified [variable].
|
||||
*/
|
||||
public fun NumberedPolynomial<C>.degreeBy(variable: Int): UInt =
|
||||
coefficients.keys.maxOfOrNull { degs -> degs.getOrElse(variable) { 0u } } ?: 0u
|
||||
/**
|
||||
* Counts degree of the polynomial by the specified [variables].
|
||||
*/
|
||||
public fun NumberedPolynomial<C>.degreeBy(variables: Collection<Int>): UInt =
|
||||
coefficients.keys.maxOfOrNull { degs ->
|
||||
degs.withIndex().fold(0u) { acc, (index, value) -> if (index in variables) acc + value else acc }
|
||||
} ?: 0u
|
||||
/**
|
||||
* Count of variables occurring in the polynomial with positive power. If there is no such variable,
|
||||
* the result is 0.
|
||||
*/
|
||||
public val NumberedPolynomial<C>.countOfVariables: Int
|
||||
get() =
|
||||
MutableList(lastVariable + 1) { false }.apply {
|
||||
coefficients.entries.forEach { (degs, _) ->
|
||||
degs.forEachIndexed { index, deg ->
|
||||
if (deg != 0u) this[index] = true
|
||||
}
|
||||
}
|
||||
}.count { it }
|
||||
|
||||
// TODO: When context receivers will be ready move all of this substitutions and invocations to utilities with
|
||||
// [ListPolynomialSpace] as a context receiver
|
||||
/**
|
||||
* Substitutes provided arguments [arguments] into [this] polynomial.
|
||||
*/
|
||||
public inline fun NumberedPolynomial<C>.substitute(arguments: Map<Int, C>): NumberedPolynomial<C> = substitute(ring, arguments)
|
||||
/**
|
||||
* Substitutes provided arguments [arguments] into [this] polynomial.
|
||||
*/
|
||||
@JvmName("substitutePolynomial")
|
||||
public inline fun NumberedPolynomial<C>.substitute(arguments: Map<Int, NumberedPolynomial<C>>) : NumberedPolynomial<C> = substitute(ring, arguments)
|
||||
/**
|
||||
* Substitutes provided arguments [arguments] into [this] polynomial.
|
||||
*/
|
||||
public inline fun NumberedPolynomial<C>.substitute(arguments: Buffer<C>): NumberedPolynomial<C> = substitute(ring, arguments)
|
||||
/**
|
||||
* Substitutes provided arguments [arguments] into [this] polynomial.
|
||||
*/
|
||||
@JvmName("substitutePolynomial")
|
||||
public inline fun NumberedPolynomial<C>.substitute(arguments: Buffer<NumberedPolynomial<C>>) : NumberedPolynomial<C> = substitute(ring, arguments)
|
||||
/**
|
||||
* Substitutes provided arguments [arguments] into [this] polynomial.
|
||||
*/
|
||||
public inline fun NumberedPolynomial<C>.substituteFully(arguments: Buffer<C>): C = this.substituteFully(ring, arguments)
|
||||
|
||||
/**
|
||||
* Represent [this] polynomial as a regular context-less function.
|
||||
*/
|
||||
public inline fun NumberedPolynomial<C>.asFunction(): (Buffer<C>) -> C = asFunctionOver(ring)
|
||||
/**
|
||||
* Represent [this] polynomial as a regular context-less function.
|
||||
*/
|
||||
public inline fun NumberedPolynomial<C>.asFunctionOfConstant(): (Buffer<C>) -> C = asFunctionOfConstantOver(ring)
|
||||
/**
|
||||
* Represent [this] polynomial as a regular context-less function.
|
||||
*/
|
||||
public inline fun NumberedPolynomial<C>.asFunctionOfPolynomial(): (Buffer<NumberedPolynomial<C>>) -> NumberedPolynomial<C> = asFunctionOfPolynomialOver(ring)
|
||||
|
||||
/**
|
||||
* Evaluates value of [this] polynomial on provided [arguments].
|
||||
*/
|
||||
public inline operator fun NumberedPolynomial<C>.invoke(arguments: Buffer<C>): C = substituteFully(ring, arguments)
|
||||
/**
|
||||
* Substitutes provided [arguments] into [this] polynomial.
|
||||
*/
|
||||
@JvmName("invokePolynomial")
|
||||
public inline operator fun NumberedPolynomial<C>.invoke(arguments: Buffer<NumberedPolynomial<C>>): NumberedPolynomial<C> = substitute(ring, arguments)
|
||||
}
|
@ -1,225 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018-2022 KMath contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@file:Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress")
|
||||
|
||||
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 data class NumberedRationalFunction<C>(
|
||||
public override val numerator: NumberedPolynomial<C>,
|
||||
public override val denominator: NumberedPolynomial<C>
|
||||
) : RationalFunction<C, NumberedPolynomial<C>> {
|
||||
override fun toString(): String = "NumberedRationalFunction${numerator.coefficients}/${denominator.coefficients}"
|
||||
}
|
||||
|
||||
/**
|
||||
* Arithmetic context for univariate rational functions with numerator and denominator represented as [NumberedPolynomial]s.
|
||||
*
|
||||
* @param C the type of constants. Polynomials have them a coefficients in their terms.
|
||||
* @param A type of provided underlying ring of constants. It's [Ring] of [C].
|
||||
* @param ring underlying ring of constants of type [A].
|
||||
*/
|
||||
public class NumberedRationalFunctionSpace<C, A: Ring<C>> (
|
||||
public val ring: A,
|
||||
) :
|
||||
RationalFunctionSpaceOverPolynomialSpace<
|
||||
C,
|
||||
NumberedPolynomial<C>,
|
||||
NumberedRationalFunction<C>,
|
||||
NumberedPolynomialSpace<C, A>,
|
||||
>,
|
||||
PolynomialSpaceOfFractions<
|
||||
C,
|
||||
NumberedPolynomial<C>,
|
||||
NumberedRationalFunction<C>,
|
||||
>() {
|
||||
|
||||
/**
|
||||
* Underlying polynomial ring. Its polynomial operations are inherited by local polynomial operations.
|
||||
*/
|
||||
public override val polynomialRing : NumberedPolynomialSpace<C, A> = NumberedPolynomialSpace(ring)
|
||||
/**
|
||||
* Constructor of rational functions (of type [NumberedRationalFunction]) from numerator and denominator (of type [NumberedPolynomial]).
|
||||
*/
|
||||
protected override fun constructRationalFunction(
|
||||
numerator: NumberedPolynomial<C>,
|
||||
denominator: NumberedPolynomial<C>
|
||||
): NumberedRationalFunction<C> =
|
||||
NumberedRationalFunction(numerator, denominator)
|
||||
|
||||
/**
|
||||
* Maximal index (ID) of variable occurring in the polynomial with positive power. If there is no such variable,
|
||||
* the result is `-1`.
|
||||
*/
|
||||
public val NumberedPolynomial<C>.lastVariable: Int get() = polynomialRing { lastVariable }
|
||||
/**
|
||||
* List that associates indices of variables (that appear in the polynomial in positive exponents) with their most
|
||||
* exponents in which the variables are appeared in the polynomial.
|
||||
*
|
||||
* As consequence all values in the list are non-negative integers. Also, if the polynomial is constant, the list is empty.
|
||||
* And last index of the list is [lastVariable].
|
||||
*/
|
||||
public val NumberedPolynomial<C>.degrees: List<UInt> get() = polynomialRing { degrees }
|
||||
/**
|
||||
* Counts degree of the polynomial by the specified [variable].
|
||||
*/
|
||||
public fun NumberedPolynomial<C>.degreeBy(variable: Int): UInt = polynomialRing { degreeBy(variable) }
|
||||
/**
|
||||
* Counts degree of the polynomial by the specified [variables].
|
||||
*/
|
||||
public fun NumberedPolynomial<C>.degreeBy(variables: Collection<Int>): UInt = polynomialRing { degreeBy(variables) }
|
||||
/**
|
||||
* Count of variables occurring in the polynomial with positive power. If there is no such variable,
|
||||
* the result is `0`.
|
||||
*/
|
||||
public val NumberedPolynomial<C>.countOfVariables: Int get() = polynomialRing { countOfVariables }
|
||||
|
||||
/**
|
||||
* Count of all variables that appear in the polynomial in positive exponents.
|
||||
*/
|
||||
public val NumberedRationalFunction<C>.lastVariable: Int
|
||||
get() = polynomialRing { max(numerator.lastVariable, denominator.lastVariable) }
|
||||
/**
|
||||
* Count of variables occurring in the rational function with positive power. If there is no such variable,
|
||||
* the result is `0`.
|
||||
*/
|
||||
public val NumberedRationalFunction<C>.countOfVariables: Int
|
||||
get() =
|
||||
MutableList(lastVariable + 1) { false }.apply {
|
||||
numerator.coefficients.entries.forEach { (degs, _) ->
|
||||
degs.forEachIndexed { index, deg ->
|
||||
if (deg != 0u) this[index] = true
|
||||
}
|
||||
}
|
||||
denominator.coefficients.entries.forEach { (degs, _) ->
|
||||
degs.forEachIndexed { index, deg ->
|
||||
if (deg != 0u) this[index] = true
|
||||
}
|
||||
}
|
||||
}.count { it }
|
||||
|
||||
// TODO: When context receivers will be ready move all of this substitutions and invocations to utilities with
|
||||
// [ListPolynomialSpace] as a context receiver
|
||||
/**
|
||||
* Substitutes provided constant [argument] into [this] polynomial.
|
||||
*/
|
||||
public inline fun NumberedPolynomial<C>.substitute(argument: Map<Int, C>): NumberedPolynomial<C> = substitute(ring, argument)
|
||||
/**
|
||||
* Substitutes provided polynomial [argument] into [this] polynomial.
|
||||
*/
|
||||
@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.
|
||||
*/
|
||||
@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.
|
||||
*/
|
||||
public inline fun NumberedRationalFunction<C>.substitute(argument: Map<Int, C>): NumberedRationalFunction<C> = substitute(ring, argument)
|
||||
/**
|
||||
* Substitutes provided polynomial [argument] into [this] rational function.
|
||||
*/
|
||||
@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.
|
||||
*/
|
||||
@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.
|
||||
*/
|
||||
public inline fun NumberedPolynomial<C>.substitute(argument: Buffer<C>): NumberedPolynomial<C> = substitute(ring, argument)
|
||||
/**
|
||||
* Substitutes provided polynomial [argument] into [this] polynomial.
|
||||
*/
|
||||
@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.
|
||||
*/
|
||||
@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.
|
||||
*/
|
||||
public inline fun NumberedRationalFunction<C>.substitute(argument: Buffer<C>): NumberedRationalFunction<C> = substitute(ring, argument)
|
||||
/**
|
||||
* Substitutes provided polynomial [arguments] into [this] rational function.
|
||||
*/
|
||||
@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.
|
||||
*/
|
||||
@JvmName("substituteRationalFunction")
|
||||
public inline fun NumberedRationalFunction<C>.substitute(arguments: Buffer<NumberedRationalFunction<C>>): NumberedRationalFunction<C> = substitute(ring, arguments)
|
||||
/**
|
||||
* Substitutes provided constant [arguments] into [this] polynomial.
|
||||
*/
|
||||
public inline fun NumberedPolynomial<C>.substituteFully(arguments: Buffer<C>): C = substituteFully(ring, arguments)
|
||||
|
||||
/**
|
||||
* Represent [this] polynomial as a regular context-less function.
|
||||
*/
|
||||
public inline fun NumberedPolynomial<C>.asFunction(): (Buffer<C>) -> C = asFunctionOver(ring)
|
||||
/**
|
||||
* Represent [this] polynomial as a regular context-less function.
|
||||
*/
|
||||
public inline fun NumberedPolynomial<C>.asFunctionOfConstant(): (Buffer<C>) -> C = asFunctionOfConstantOver(ring)
|
||||
/**
|
||||
* Represent [this] polynomial as a regular context-less function.
|
||||
*/
|
||||
public inline fun NumberedPolynomial<C>.asFunctionOfPolynomial(): (Buffer<NumberedPolynomial<C>>) -> NumberedPolynomial<C> = asFunctionOfPolynomialOver(ring)
|
||||
/**
|
||||
* Represent [this] polynomial as a regular context-less function.
|
||||
*/
|
||||
public inline fun NumberedPolynomial<C>.asFunctionOfRationalFunction(): (Buffer<NumberedRationalFunction<C>>) -> NumberedRationalFunction<C> = asFunctionOfRationalFunctionOver(ring)
|
||||
/**
|
||||
* Represent [this] polynomial as a regular context-less function.
|
||||
*/
|
||||
public inline fun NumberedRationalFunction<C>.asFunctionOfPolynomial(): (Buffer<NumberedPolynomial<C>>) -> NumberedRationalFunction<C> = asFunctionOfPolynomialOver(ring)
|
||||
/**
|
||||
* Represent [this] polynomial as a regular context-less function.
|
||||
*/
|
||||
public inline fun NumberedRationalFunction<C>.asFunctionOfRationalFunction(): (Buffer<NumberedRationalFunction<C>>) -> NumberedRationalFunction<C> = asFunctionOfRationalFunctionOver(ring)
|
||||
|
||||
/**
|
||||
* Evaluates value of [this] polynomial on provided [arguments].
|
||||
*/
|
||||
public inline operator fun NumberedPolynomial<C>.invoke(arguments: Buffer<C>): C = substituteFully(ring, arguments)
|
||||
/**
|
||||
* Substitutes provided [arguments] into [this] polynomial.
|
||||
*/
|
||||
@JvmName("invokePolynomial")
|
||||
public inline operator fun NumberedPolynomial<C>.invoke(arguments: Buffer<NumberedPolynomial<C>>): NumberedPolynomial<C> = substitute(ring, arguments)
|
||||
/**
|
||||
* Substitutes provided [arguments] into [this] polynomial.
|
||||
*/
|
||||
@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.
|
||||
*/
|
||||
@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.
|
||||
*/
|
||||
@JvmName("invokeRationalFunction")
|
||||
public inline operator fun NumberedRationalFunction<C>.invoke(arguments: Buffer<NumberedRationalFunction<C>>): NumberedRationalFunction<C> = substitute(ring, arguments)
|
||||
}
|
@ -1,527 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018-2022 KMath contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package space.kscience.kmath.functions
|
||||
|
||||
import space.kscience.kmath.operations.Ring
|
||||
import space.kscience.kmath.operations.invoke
|
||||
import kotlin.js.JsName
|
||||
import kotlin.jvm.JvmName
|
||||
|
||||
|
||||
/**
|
||||
* Abstraction of ring of polynomials of type [P] over ring of constants of type [C].
|
||||
*
|
||||
* @param C the type of constants. Polynomials have them as coefficients in their terms.
|
||||
* @param P the type of polynomials.
|
||||
*/
|
||||
@Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") // FIXME: Waiting for KT-31420
|
||||
public interface PolynomialSpace<C, P> : Ring<P> {
|
||||
/**
|
||||
* 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].
|
||||
*/
|
||||
@JvmName("plusConstantInt")
|
||||
public operator fun C.plus(other: Int): C
|
||||
/**
|
||||
* 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].
|
||||
*/
|
||||
@JvmName("minusConstantInt")
|
||||
public operator fun C.minus(other: Int): C
|
||||
/**
|
||||
* 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].
|
||||
*/
|
||||
@JvmName("timesConstantInt")
|
||||
public operator fun C.times(other: Int): C
|
||||
|
||||
/**
|
||||
* 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].
|
||||
*/
|
||||
@JvmName("plusIntConstant")
|
||||
public operator fun Int.plus(other: C): C
|
||||
/**
|
||||
* 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].
|
||||
*/
|
||||
@JvmName("minusIntConstant")
|
||||
public operator fun Int.minus(other: C): C
|
||||
/**
|
||||
* 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].
|
||||
*/
|
||||
@JvmName("timesIntConstant")
|
||||
public operator fun Int.times(other: C): C
|
||||
|
||||
/**
|
||||
* Converts the integer [value] to constant.
|
||||
*/
|
||||
public fun constantNumber(value: Int): C = constantOne * value
|
||||
/**
|
||||
* Converts the integer to constant.
|
||||
*/
|
||||
public fun Int.asConstant(): C = constantNumber(this)
|
||||
|
||||
/**
|
||||
* 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 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 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 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 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 a polynomial and the polynomial.
|
||||
*
|
||||
* The operation is equivalent to sum of [this] copies of [other].
|
||||
*/
|
||||
public operator fun Int.times(other: P): P = multiplyByDoubling(other, this)
|
||||
|
||||
/**
|
||||
* Converts the integer [value] to polynomial.
|
||||
*/
|
||||
public fun number(value: Int): P = number(constantNumber(value))
|
||||
/**
|
||||
* Converts the integer to polynomial.
|
||||
*/
|
||||
public fun Int.asPolynomial(): P = number(this)
|
||||
|
||||
/**
|
||||
* Returns the same constant.
|
||||
*/
|
||||
@JvmName("unaryPlusConstant")
|
||||
@JsName("unaryPlusConstant")
|
||||
public operator fun C.unaryPlus(): C = this
|
||||
/**
|
||||
* Returns negation of the constant.
|
||||
*/
|
||||
@JvmName("unaryMinusConstant")
|
||||
@JsName("unaryMinusConstant")
|
||||
public operator fun C.unaryMinus(): C
|
||||
/**
|
||||
* Returns sum of the constants.
|
||||
*/
|
||||
@JvmName("plusConstantConstant")
|
||||
@JsName("plusConstantConstant")
|
||||
public operator fun C.plus(other: C): C
|
||||
/**
|
||||
* Returns difference of the constants.
|
||||
*/
|
||||
@JvmName("minusConstantConstant")
|
||||
@JsName("minusConstantConstant")
|
||||
public operator fun C.minus(other: C): C
|
||||
/**
|
||||
* Returns product of the constants.
|
||||
*/
|
||||
@JvmName("timesConstantConstant")
|
||||
@JsName("timesConstantConstant")
|
||||
public operator fun C.times(other: C): C
|
||||
/**
|
||||
* Raises [arg] to the integer power [exponent].
|
||||
*/
|
||||
@JvmName("powerConstant")
|
||||
@JsName("powerConstant")
|
||||
public fun power(arg: C, exponent: UInt) : C
|
||||
|
||||
/**
|
||||
* Instance of zero constant (zero of the underlying ring).
|
||||
*/
|
||||
public val constantZero: C
|
||||
/**
|
||||
* Instance of unit constant (unit of the underlying ring).
|
||||
*/
|
||||
public val constantOne: C
|
||||
|
||||
/**
|
||||
* Returns sum of the constant represented as a polynomial and the polynomial.
|
||||
*/
|
||||
@JvmName("plusConstantPolynomial")
|
||||
public operator fun C.plus(other: P): P
|
||||
/**
|
||||
* Returns difference between the constant represented as a polynomial and the polynomial.
|
||||
*/
|
||||
@JvmName("minusConstantPolynomial")
|
||||
public operator fun C.minus(other: P): P
|
||||
/**
|
||||
* Returns product of the constant represented as a polynomial and the polynomial.
|
||||
*/
|
||||
@JvmName("timesConstantPolynomial")
|
||||
public operator fun C.times(other: P): P
|
||||
|
||||
/**
|
||||
* Returns sum of the constant represented as a polynomial and the polynomial.
|
||||
*/
|
||||
@JvmName("plusPolynomialConstant")
|
||||
public operator fun P.plus(other: C): P
|
||||
/**
|
||||
* Returns difference between the constant represented as a polynomial and the polynomial.
|
||||
*/
|
||||
@JvmName("minusPolynomialConstant")
|
||||
public operator fun P.minus(other: C): P
|
||||
/**
|
||||
* Returns product of the constant represented as a polynomial and the polynomial.
|
||||
*/
|
||||
@JvmName("timesPolynomialConstant")
|
||||
public operator fun P.times(other: C): P
|
||||
|
||||
/**
|
||||
* Converts the constant [value] to polynomial.
|
||||
*/
|
||||
public fun number(value: C): P = one * value
|
||||
/**
|
||||
* Converts the constant to polynomial.
|
||||
*/
|
||||
public fun C.asPolynomial(): P = number(this)
|
||||
|
||||
/**
|
||||
* Returns the same polynomial.
|
||||
*/
|
||||
public override operator fun P.unaryPlus(): P = this
|
||||
/**
|
||||
* Returns negation of the polynomial.
|
||||
*/
|
||||
public override operator fun P.unaryMinus(): P
|
||||
/**
|
||||
* Returns sum of the polynomials.
|
||||
*/
|
||||
public override operator fun P.plus(other: P): P
|
||||
/**
|
||||
* Returns difference of the polynomials.
|
||||
*/
|
||||
public override operator fun P.minus(other: P): P
|
||||
/**
|
||||
* Returns product of the polynomials.
|
||||
*/
|
||||
public override operator fun P.times(other: P): P
|
||||
/**
|
||||
* Raises [arg] to the integer power [exponent].
|
||||
*/
|
||||
public override fun power(arg: P, exponent: UInt) : P = exponentiateBySquaring(arg, exponent)
|
||||
|
||||
/**
|
||||
* Instance of zero polynomial (zero of the polynomial ring).
|
||||
*/
|
||||
public override val zero: P
|
||||
/**
|
||||
* Instance of unit polynomial (unit of the polynomial ring).
|
||||
*/
|
||||
public override val one: P
|
||||
|
||||
/**
|
||||
* Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is
|
||||
* zero, degree is -1.
|
||||
*/
|
||||
public val P.degree: Int
|
||||
|
||||
override fun add(left: P, right: P): P = left + right
|
||||
override fun multiply(left: P, right: P): P = left * right
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstraction of ring of polynomials of type [P] over ring of constants of type [C]. It also assumes that there is
|
||||
* provided [ring] (of type [A]), that provides constant-wise operations.
|
||||
*
|
||||
* @param C the type of constants. Polynomials have them as coefficients in their terms.
|
||||
* @param P the type of polynomials.
|
||||
* @param A the type of algebraic structure (precisely, of ring) provided for constants.
|
||||
*/
|
||||
@Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420
|
||||
public interface PolynomialSpaceOverRing<C, P, out 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 a constant (member of underlying ring).
|
||||
*
|
||||
* The operation is equivalent to adding [other] copies of unit of underlying ring to [this].
|
||||
*/
|
||||
@JvmName("plusConstantInt")
|
||||
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 a constant (member of underlying ring).
|
||||
*
|
||||
* The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this].
|
||||
*/
|
||||
@JvmName("minusConstantInt")
|
||||
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 a constant (member of underlying ring).
|
||||
*
|
||||
* The operation is equivalent to sum of [other] copies of [this].
|
||||
*/
|
||||
@JvmName("timesConstantInt")
|
||||
public override operator fun C.times(other: Int): C = ring { multiplyByDoubling(this@times, other) }
|
||||
|
||||
/**
|
||||
* 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].
|
||||
*/
|
||||
@JvmName("plusIntConstant")
|
||||
public override operator fun Int.plus(other: C): C = ring { addMultipliedByDoubling(other, one, this@plus) }
|
||||
/**
|
||||
* 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].
|
||||
*/
|
||||
@JvmName("minusIntConstant")
|
||||
public override operator fun Int.minus(other: C): C = ring { addMultipliedByDoubling(-other, one, this@minus) }
|
||||
/**
|
||||
* 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].
|
||||
*/
|
||||
@JvmName("timesIntConstant")
|
||||
public override operator fun Int.times(other: C): C = ring { multiplyByDoubling(other, this@times) }
|
||||
|
||||
/**
|
||||
* Returns negation of the constant.
|
||||
*/
|
||||
@JvmName("unaryMinusConstant")
|
||||
public override operator fun C.unaryMinus(): C = ring { -this@unaryMinus }
|
||||
/**
|
||||
* Returns sum of the constants.
|
||||
*/
|
||||
@JvmName("plusConstantConstant")
|
||||
public override operator fun C.plus(other: C): C = ring { this@plus + other }
|
||||
/**
|
||||
* Returns difference of the constants.
|
||||
*/
|
||||
@JvmName("minusConstantConstant")
|
||||
public override operator fun C.minus(other: C): C = ring { this@minus - other }
|
||||
/**
|
||||
* Returns product of the constants.
|
||||
*/
|
||||
@JvmName("timesConstantConstant")
|
||||
public override operator fun C.times(other: C): C = ring { this@times * other }
|
||||
/**
|
||||
* Raises [arg] to the integer power [exponent].
|
||||
*/
|
||||
@JvmName("powerConstant")
|
||||
override fun power(arg: C, exponent: UInt): C = ring { power(arg, exponent) }
|
||||
|
||||
/**
|
||||
* Instance of zero constant (zero of the underlying ring).
|
||||
*/
|
||||
public override val constantZero: C get() = ring.zero
|
||||
/**
|
||||
* Instance of unit constant (unit of the underlying ring).
|
||||
*/
|
||||
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>: PolynomialSpace<C, P> {
|
||||
/**
|
||||
* Returns sum of the variable represented as a monic monomial and the integer represented as a constant polynomial.
|
||||
*/
|
||||
@JvmName("plusVariableInt")
|
||||
@JsName("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")
|
||||
@JsName("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")
|
||||
@JsName("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")
|
||||
@JsName("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")
|
||||
@JsName("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")
|
||||
@JsName("timesIntVariable")
|
||||
public operator fun Int.times(other: V): P
|
||||
|
||||
/**
|
||||
* Returns sum of the variable represented as a monic monomial and the constant represented as a constant polynomial.
|
||||
*/
|
||||
@JvmName("plusVariableConstant")
|
||||
@JsName("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")
|
||||
@JsName("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")
|
||||
@JsName("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")
|
||||
@JsName("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")
|
||||
@JsName("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")
|
||||
@JsName("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
|
||||
|
||||
/**
|
||||
* Map that associates variables (that appear in the polynomial in positive exponents) with their most exponents
|
||||
* in which they are appeared in the polynomial.
|
||||
*
|
||||
* As consequence all values in the map are positive integers. Also, if the polynomial is constant, the map is empty.
|
||||
* And keys of the map is the same as in [variables].
|
||||
*/
|
||||
public val P.degrees: Map<V, UInt>
|
||||
/**
|
||||
* Counts degree of the polynomial by the specified [variable].
|
||||
*/
|
||||
public fun P.degreeBy(variable: V): UInt = degrees.getOrElse(variable) { 0u }
|
||||
/**
|
||||
* Counts degree of the polynomial by the specified [variables].
|
||||
*/
|
||||
public fun P.degreeBy(variables: Collection<V>): UInt
|
||||
/**
|
||||
* Set of all variables that appear in the polynomial in positive exponents.
|
||||
*/
|
||||
public val P.variables: Set<V> get() = degrees.keys
|
||||
/**
|
||||
* Count of all variables that appear in the polynomial in positive exponents.
|
||||
*/
|
||||
public val P.countOfVariables: Int get() = variables.size
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,146 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018-2022 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.*
|
||||
|
||||
|
||||
// TODO: All of this should be moved to algebraic structures' place for utilities
|
||||
// FIXME: Move receiver to context receiver
|
||||
/**
|
||||
* Returns product of [arg] and integer [multiplier].
|
||||
*
|
||||
* @param arg the multiplicand.
|
||||
* @param multiplier the integer multiplier.
|
||||
* @return product of the multiplicand [arg] and the multiplier [multiplier].
|
||||
* @author Gleb Minaev
|
||||
*/
|
||||
internal fun <C> Group<C>.multiplyByDoubling(arg: C, multiplier: Int): C =
|
||||
if (multiplier >= 0) multiplyByDoubling(arg, multiplier.toUInt())
|
||||
else multiplyByDoubling(-arg, (-multiplier).toUInt())
|
||||
|
||||
// FIXME: Move receiver to context receiver
|
||||
/**
|
||||
* Adds product of [arg] and [multiplier] to [base].
|
||||
*
|
||||
* @param base the augend.
|
||||
* @param arg the multiplicand.
|
||||
* @param multiplier the integer multiplier.
|
||||
* @return sum of the augend [base] and product of the multiplicand [arg] and the multiplier [multiplier].
|
||||
* @author Gleb Minaev
|
||||
*/
|
||||
internal fun <C> GroupOps<C>.addMultipliedByDoubling(base: C, arg: C, multiplier: Int): C =
|
||||
if (multiplier >= 0) addMultipliedByDoubling(base, arg, multiplier.toUInt())
|
||||
else addMultipliedByDoubling(base, -arg, (-multiplier).toUInt())
|
||||
|
||||
// FIXME: Move receiver to context receiver
|
||||
/**
|
||||
* Returns product of [arg] and integer [multiplier].
|
||||
*
|
||||
* This is implementation of variation of [exponentiation by squaring](https://en.wikipedia.org/wiki/Exponentiation_by_squaring)
|
||||
*
|
||||
* @param arg the multiplicand.
|
||||
* @param multiplier the integer multiplier.
|
||||
* @return product of the multiplicand [arg] and the multiplier [multiplier].
|
||||
* @author Gleb Minaev
|
||||
*/
|
||||
internal tailrec fun <C> Group<C>.multiplyByDoubling(arg: C, multiplier: UInt): C =
|
||||
when {
|
||||
multiplier == 0u -> zero
|
||||
multiplier == 1u -> arg
|
||||
multiplier and 1u == 0u -> multiplyByDoubling(arg + arg, multiplier shr 1)
|
||||
multiplier and 1u == 1u -> addMultipliedByDoubling(arg, arg + arg, multiplier shr 1)
|
||||
else -> error("Error in multiplication group instant by unsigned integer: got reminder by division by 2 different from 0 and 1")
|
||||
}
|
||||
|
||||
// FIXME: Move receiver to context receiver
|
||||
/**
|
||||
* Adds product of [arg] and [multiplier] to [base].
|
||||
*
|
||||
* This is implementation of variation of [exponentiation by squaring](https://en.wikipedia.org/wiki/Exponentiation_by_squaring)
|
||||
*
|
||||
* @param base the augend.
|
||||
* @param arg the multiplicand.
|
||||
* @param multiplier the integer multiplier.
|
||||
* @return sum of the augend [base] and product of the multiplicand [arg] and the multiplier [multiplier].
|
||||
* @author Gleb Minaev
|
||||
*/
|
||||
internal tailrec fun <C> GroupOps<C>.addMultipliedByDoubling(base: C, arg: C, multiplier: UInt): C =
|
||||
when {
|
||||
multiplier == 0u -> base
|
||||
multiplier == 1u -> base + arg
|
||||
multiplier and 1u == 0u -> addMultipliedByDoubling(base, arg + arg, multiplier shr 1)
|
||||
multiplier and 1u == 1u -> addMultipliedByDoubling(base + arg, arg + arg, multiplier shr 1)
|
||||
else -> error("Error in multiplication group instant by unsigned integer: got reminder by division by 2 different from 0 and 1")
|
||||
}
|
||||
|
||||
// FIXME: Move receiver to context receiver
|
||||
/**
|
||||
* Raises [arg] to the integer power [exponent].
|
||||
*
|
||||
* @param arg the base of the power.
|
||||
* @param exponent the exponent of the power.
|
||||
* @return [arg] raised to the power [exponent].
|
||||
* @author Gleb Minaev
|
||||
*/
|
||||
internal fun <C> Field<C>.exponentiateBySquaring(arg: C, exponent: Int): C =
|
||||
if (exponent >= 0) exponentiateBySquaring(arg, exponent.toUInt())
|
||||
else exponentiateBySquaring(one / arg, (-exponent).toUInt())
|
||||
|
||||
// FIXME: Move receiver to context receiver
|
||||
/**
|
||||
* Multiplies [base] and [arg] raised to the integer power [exponent].
|
||||
*
|
||||
* @param base the multiplicand.
|
||||
* @param arg the base of the power.
|
||||
* @param exponent the exponent of the power.
|
||||
* @return product of [base] and [arg] raised to the power [exponent].
|
||||
* @author Gleb Minaev
|
||||
*/
|
||||
internal fun <C> Field<C>.multiplyExponentiatedBySquaring(base: C, arg: C, exponent: Int): C =
|
||||
if (exponent >= 0) multiplyExponentiatedBySquaring(base, arg, exponent.toUInt())
|
||||
else multiplyExponentiatedBySquaring(base, one / arg, (-exponent).toUInt())
|
||||
|
||||
// FIXME: Move receiver to context receiver
|
||||
/**
|
||||
* Raises [arg] to the integer power [exponent].
|
||||
*
|
||||
* This is implementation of variation of [exponentiation by squaring](https://en.wikipedia.org/wiki/Exponentiation_by_squaring)
|
||||
*
|
||||
* @param arg the base of the power.
|
||||
* @param exponent the exponent of the power.
|
||||
* @return [arg] raised to the power [exponent].
|
||||
* @author Gleb Minaev
|
||||
*/
|
||||
internal tailrec fun <C> Ring<C>.exponentiateBySquaring(arg: C, exponent: UInt): C =
|
||||
when {
|
||||
exponent == 0u -> zero
|
||||
exponent == 1u -> arg
|
||||
exponent and 1u == 0u -> exponentiateBySquaring(arg * arg, exponent shr 1)
|
||||
exponent and 1u == 1u -> multiplyExponentiatedBySquaring(arg, arg * arg, exponent shr 1)
|
||||
else -> error("Error in multiplication group instant by unsigned integer: got reminder by division by 2 different from 0 and 1")
|
||||
}
|
||||
|
||||
// FIXME: Move receiver to context receiver
|
||||
/**
|
||||
* Multiplies [base] and [arg] raised to the integer power [exponent].
|
||||
*
|
||||
* This is implementation of variation of [exponentiation by squaring](https://en.wikipedia.org/wiki/Exponentiation_by_squaring)
|
||||
*
|
||||
* @param base the multiplicand.
|
||||
* @param arg the base of the power.
|
||||
* @param exponent the exponent of the power.
|
||||
* @return product of [base] and [arg] raised to the power [exponent].
|
||||
* @author Gleb Minaev
|
||||
*/
|
||||
internal tailrec fun <C> RingOps<C>.multiplyExponentiatedBySquaring(base: C, arg: C, exponent: UInt): C =
|
||||
when {
|
||||
exponent == 0u -> base
|
||||
exponent == 1u -> base * arg
|
||||
exponent and 1u == 0u -> multiplyExponentiatedBySquaring(base, arg * arg, exponent shr 1)
|
||||
exponent and 1u == 1u -> multiplyExponentiatedBySquaring(base * arg, arg * arg, exponent shr 1)
|
||||
else -> error("Error in multiplication group instant by unsigned integer: got reminder by division by 2 different from 0 and 1")
|
||||
}
|
@ -1,906 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018-2022 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 kotlin.contracts.InvocationKind.*
|
||||
import kotlin.contracts.contract
|
||||
|
||||
|
||||
/**
|
||||
* Computes the given lambda [compute] on value corresponding to the provided [key] or `null` if the key is not present.
|
||||
*
|
||||
* @param key key which corresponding value will be used if it's present.
|
||||
* @param compute lambda that is computed on the received value.
|
||||
* @return result of the computation of the lambda.
|
||||
*/
|
||||
internal inline fun <K, V, R> Map<in K, V>.computeOn(key: K, compute: (V?) -> R): R {
|
||||
contract {
|
||||
callsInPlace(compute, EXACTLY_ONCE)
|
||||
}
|
||||
return compute(get(key))
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the given lambda [compute] on value corresponding to the provided [key] or computes the given lambda
|
||||
* [defaultResult] if the key is not present.
|
||||
*
|
||||
* @param key key which corresponding value will be used if it's present.
|
||||
* @param compute lambda that is computed on the value corresponding to the [key].
|
||||
* @param defaultResult lambda that is computed if the [key] is not present.
|
||||
* @return result of [compute] lambda if the [key] is present or result of [defaultResult] otherwise.
|
||||
*/
|
||||
internal inline fun <K, V, R> Map<K, V>.computeOnOrElse(key: K, defaultResult: () -> R, compute: (value: V) -> R): R {
|
||||
contract {
|
||||
callsInPlace(defaultResult, AT_MOST_ONCE)
|
||||
callsInPlace(compute, AT_MOST_ONCE)
|
||||
}
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return (if (key !in this) defaultResult() else compute(get(key) as V))
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the given lambda [compute] on value corresponding to the provided [key] or computes the given lambda
|
||||
* [defaultResult] if the key is not present.
|
||||
*
|
||||
* @param key key which corresponding value will be used if it's present.
|
||||
* @param compute lambda that is computed on the value corresponding to the [key].
|
||||
* @param defaultResult default result that is returned in case of the [key]'s absence.
|
||||
* @return result of [compute] lambda if the [key] is present or [defaultResult] otherwise.
|
||||
*/
|
||||
internal inline fun <K, V, R> Map<K, V>.computeOnOrElse(key: K, defaultResult: R, compute: (value: V) -> R): R {
|
||||
contract {
|
||||
callsInPlace(compute, AT_MOST_ONCE)
|
||||
}
|
||||
return computeOnOrElse(key, { defaultResult }, compute)
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the given lambda [compute] on value corresponding to the provided [key] or computes the given lambda
|
||||
* [defaultResult] if the key is not present.
|
||||
*
|
||||
* @param key key which corresponding value will be used if it's present.
|
||||
* @param compute lambda that is computed on the value corresponding to the [key].
|
||||
* @param defaultResult default result that is returned in case of the [key]'s absence.
|
||||
* @return result of [compute] lambda if the [key] is present or [defaultResult] otherwise.
|
||||
*/
|
||||
internal inline fun <K, V, R> Map<K, V>.computeOnOrElse(key: K, defaultResult: R, compute: (key: K, value: V) -> R): R {
|
||||
contract {
|
||||
callsInPlace(compute, AT_MOST_ONCE)
|
||||
}
|
||||
return computeOnOrElse(key, { defaultResult }, { it -> compute(key, it) })
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the [transformation][transform] to the value corresponding to the given [key] or null instead if it's not
|
||||
* present.
|
||||
*
|
||||
* @param key key to check.
|
||||
* @param transform transformation to apply.
|
||||
* @return result of the transformation
|
||||
*/
|
||||
internal inline fun <K, V> MutableMap<in K, V>.applyToKey(key: K, transform: (currentValue: V?) -> V): V {
|
||||
contract {
|
||||
callsInPlace(transform, EXACTLY_ONCE)
|
||||
}
|
||||
return computeOn(key, transform).also { this[key] = it }
|
||||
}
|
||||
|
||||
/**
|
||||
* Depending on presence of value corresponding to the given [key] either puts new value calculated by [valueOnPut] or
|
||||
* changes the present value with [transformOnChange].
|
||||
*
|
||||
* @param key key to check.
|
||||
* @param valueOnPut lazily calculated value to put in case of absence of the [key].
|
||||
* @param transformOnChange transform to apply to current value corresponding to the [key] in case of its presence. Uses
|
||||
* current value as a parameter.
|
||||
* @return result value corresponding to the [key].
|
||||
*/
|
||||
internal inline fun <K, V> MutableMap<K, V>.putOrChange(key: K, valueOnPut: () -> V, transformOnChange: (currentValue: V) -> V): V {
|
||||
contract {
|
||||
callsInPlace(valueOnPut, AT_MOST_ONCE)
|
||||
callsInPlace(transformOnChange, AT_MOST_ONCE)
|
||||
}
|
||||
return computeOnOrElse(key, valueOnPut, transformOnChange).also { this[key] = it }
|
||||
}
|
||||
|
||||
/**
|
||||
* Depending on presence of value corresponding to the given [key] either puts new value [valueOnPut] or
|
||||
* changes the present value with [transformOnChange].
|
||||
*
|
||||
* @param key key to check.
|
||||
* @param valueOnPut value to put in case of absence of the [key].
|
||||
* @param transformOnChange transform to apply to current value corresponding to the [key] in case of its presence. Uses
|
||||
* current value as a parameter.
|
||||
* @return result value corresponding to the [key].
|
||||
*/
|
||||
internal inline fun <K, V> MutableMap<K, V>.putOrChange(key: K, valueOnPut: V, transformOnChange: (currentValue: V) -> V): V {
|
||||
contract {
|
||||
callsInPlace(transformOnChange, AT_MOST_ONCE)
|
||||
}
|
||||
return putOrChange<K, V>(key, { valueOnPut }, transformOnChange)
|
||||
}
|
||||
|
||||
/**
|
||||
* Depending on presence of value corresponding to the given [key] either puts new value [valueOnPut] or
|
||||
* changes the present value with [transformOnChange].
|
||||
*
|
||||
* @param key key to check.
|
||||
* @param valueOnPut value to put in case of absence of the [key].
|
||||
* @param transformOnChange transform to apply to current value corresponding to the [key] in case of its presence. Uses
|
||||
* current value and new value as parameters.
|
||||
* @return result value corresponding to the [key].
|
||||
*/
|
||||
internal inline fun <K, V> MutableMap<K, V>.putOrChange(key: K, valueOnPut: V, transformOnChange: (currentValue: V, newValue: V) -> V): V {
|
||||
contract {
|
||||
callsInPlace(transformOnChange, AT_MOST_ONCE)
|
||||
}
|
||||
return putOrChange<K, V>(key, { valueOnPut }, { transformOnChange(it, valueOnPut) })
|
||||
}
|
||||
|
||||
/**
|
||||
* Depending on presence of value corresponding to the given [key] either puts new value [valueOnPut] or
|
||||
* changes the present value with [transformOnChange].
|
||||
*
|
||||
* @param key key to check.
|
||||
* @param valueOnPut value to put in case of absence of the [key].
|
||||
* @param transformOnChange transform to apply to current value corresponding to the [key] in case of its presence. Uses
|
||||
* the [key], current value, and new value as parameters.
|
||||
* @return result value corresponding to the [key].
|
||||
*/
|
||||
internal inline fun <K, V> MutableMap<K, V>.putOrChange(key: K, valueOnPut: V, transformOnChange: (key: K, currentValue: V, newValue: V) -> V): V {
|
||||
contract {
|
||||
callsInPlace(transformOnChange, AT_MOST_ONCE)
|
||||
}
|
||||
return putOrChange<K, V>(key, { valueOnPut }, { transformOnChange(key, it, valueOnPut) })
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates copy of [the map][this] and applies the [transformation][transform] to the value corresponding to the given
|
||||
* [key] in the copy or null instead if it's not present.
|
||||
*
|
||||
* @param key key to check.
|
||||
* @param transform transformation to apply.
|
||||
* @return the copy of [the map][this].
|
||||
*/
|
||||
internal inline fun <K, V> Map<in K, V>.withAppliedToKey(key: K, transform: (currentValue: V?) -> V): Map<K, V> {
|
||||
contract {
|
||||
callsInPlace(transform, EXACTLY_ONCE)
|
||||
}
|
||||
return buildMap(size) {
|
||||
putAll(this)
|
||||
applyToKey(key, transform)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates copy of [the map][this] and depending on presence of value corresponding to the given [key] either puts new
|
||||
* value calculated by [valueOnPut] or changes the present value with [transformOnChange].
|
||||
*
|
||||
* @param key key to check.
|
||||
* @param valueOnPut lazily calculated value to put in case of absence of the [key].
|
||||
* @param transformOnChange transform to apply to current value corresponding to the [key] in case of its presence. Uses
|
||||
* current value as a parameter.
|
||||
* @return the copy of [the map][this].
|
||||
*/
|
||||
internal inline fun <K, V> Map<K, V>.withPutOrChanged(key: K, valueOnPut: () -> V, transformOnChange: (currentValue: V) -> V): Map<K, V> {
|
||||
contract {
|
||||
callsInPlace(valueOnPut, AT_MOST_ONCE)
|
||||
callsInPlace(transformOnChange, AT_MOST_ONCE)
|
||||
}
|
||||
return buildMap(size + 1) {
|
||||
putAll(this@withPutOrChanged)
|
||||
putOrChange(key, valueOnPut, transformOnChange)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates copy of [the map][this] and depending on presence of value corresponding to the given [key] either puts new
|
||||
* value [valueOnPut] or changes the present value with [transformOnChange].
|
||||
*
|
||||
* @param key key to check.
|
||||
* @param valueOnPut value to put in case of absence of the [key].
|
||||
* @param transformOnChange transform to apply to current value corresponding to the [key] in case of its presence. Uses
|
||||
* current value as a parameter.
|
||||
* @return the copy of [the map][this].
|
||||
*/
|
||||
internal inline fun <K, V> Map<K, V>.withPutOrChanged(key: K, valueOnPut: V, transformOnChange: (currentValue: V) -> V): Map<K, V> {
|
||||
contract {
|
||||
callsInPlace(transformOnChange, AT_MOST_ONCE)
|
||||
}
|
||||
return withPutOrChanged<K, V>(key, { valueOnPut }, transformOnChange)
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates copy of [the map][this] and depending on presence of value corresponding to the given [key] either puts new
|
||||
* value [valueOnPut] or changes the present value with [transformOnChange].
|
||||
*
|
||||
* @param key key to check.
|
||||
* @param valueOnPut value to put in case of absence of the [key].
|
||||
* @param transformOnChange transform to apply to current value corresponding to the [key] in case of its presence. Uses
|
||||
* current value and new value as parameters.
|
||||
* @return the copy of [the map][this].
|
||||
*/
|
||||
internal inline fun <K, V> Map<K, V>.withPutOrChanged(key: K, valueOnPut: V, transformOnChange: (currentValue: V, newValue: V) -> V): Map<K, V> {
|
||||
contract {
|
||||
callsInPlace(transformOnChange, AT_MOST_ONCE)
|
||||
}
|
||||
return withPutOrChanged<K, V>(key, { valueOnPut }, { transformOnChange(it, valueOnPut) })
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates copy of [the map][this] and depending on presence of value corresponding to the given [key] either puts new
|
||||
* value [valueOnPut] or changes the present value with [transformOnChange].
|
||||
*
|
||||
* @param key key to check.
|
||||
* @param valueOnPut value to put in case of absence of the [key].
|
||||
* @param transformOnChange transform to apply to current value corresponding to the [key] in case of its presence. Uses
|
||||
* the [key], current value, and new value as parameters.
|
||||
* @return the copy of [the map][this].
|
||||
*/
|
||||
internal inline fun <K, V> Map<K, V>.withPutOrChanged(key: K, valueOnPut: V, transformOnChange: (key: K, currentValue: V, newValue: V) -> V): Map<K, V> {
|
||||
contract {
|
||||
callsInPlace(transformOnChange, AT_MOST_ONCE)
|
||||
}
|
||||
return withPutOrChanged<K, V>(key, { valueOnPut }, { transformOnChange(key, it, valueOnPut) })
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies entries of [this map][this] to the [destination] map overriding present ones if needed.
|
||||
*
|
||||
* @receiver map to be copied.
|
||||
* @param destination map to receive copies.
|
||||
* @return the [destination].
|
||||
*/
|
||||
internal fun <K, V, D: MutableMap<K, V>> Map<K, V>.copyTo(destination: D): D {
|
||||
for ((key, value) in this) {
|
||||
destination[key] = value
|
||||
}
|
||||
return destination
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies entries of [this map][this] to the [destination] map merging present entries with new ones using [resolve]
|
||||
* lambda.
|
||||
*
|
||||
* @receiver map to be copied.
|
||||
* @param destination map to receive copies.
|
||||
* @param resolve lambda function that resolves overriding. It takes a key, current value corresponding to the key, and
|
||||
* a new one and returns value to associate to the key.
|
||||
* @return the [destination].
|
||||
*/
|
||||
internal inline fun <K, V: W, W, D: MutableMap<K, W>> Map<out K, V>.copyToBy(destination: D, resolve: (key: K, currentValue: W, newValue: V) -> W): D {
|
||||
for ((key, value) in this) {
|
||||
destination.putOrChange(key, value) { it -> resolve(key, it, value) }
|
||||
}
|
||||
return destination
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies entries of [this map][this] to the [destination] map merging present entries with new ones using [resolve]
|
||||
* lambda.
|
||||
*
|
||||
* @receiver map to be copied.
|
||||
* @param destination map to receive copies.
|
||||
* @param resolve lambda function that resolves overriding. It takes current value corresponding to some key, and
|
||||
* a new one and returns value to associate to the key.
|
||||
* @return the [destination].
|
||||
*/
|
||||
internal inline fun <K, V: W, W, D: MutableMap<K, W>> Map<out K, V>.copyToBy(destination: D, resolve: (currentValue: W, newValue: V) -> W): D =
|
||||
copyToBy(destination) { _, currentValue, newValue -> resolve(currentValue, newValue) }
|
||||
|
||||
/**
|
||||
* Transforms values of entries of [this map][this] with [the given transformation][transform] and copies resulting
|
||||
* entries to the [destination] map overriding present ones if needed. Is equivalent to
|
||||
* ```kotlin
|
||||
* this.mapValues(transform).copyTo(destination)
|
||||
* ```
|
||||
*
|
||||
* @receiver map to be transformed and copied.
|
||||
* @param destination map to receive copies.
|
||||
* @param transform generates value of transformed entry using initial entry as an argument. Key of transformed entry is
|
||||
* the same as initial entry.
|
||||
* @return the [destination].
|
||||
*/
|
||||
internal inline fun <K, V, W, D: MutableMap<K, W>> Map<out K, V>.copyMapTo(destination: D, transform: (Map.Entry<K, V>) -> W): D {
|
||||
for (entry in this) {
|
||||
destination[entry.key] = transform(entry)
|
||||
}
|
||||
return destination
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms values of entries of [this map][this] with [the given transformation][transform] and copies resulting
|
||||
* entries to the [destination] map overriding present ones if needed. Is equivalent to
|
||||
* ```kotlin
|
||||
* this.mapValues(transform).copyTo(destination)
|
||||
* ```
|
||||
*
|
||||
* @receiver map to be transformed and copied.
|
||||
* @param destination map to receive copies.
|
||||
* @param transform generates value of transformed entry using initial entry as an argument. Key of transformed entry is
|
||||
* the same as initial entry.
|
||||
* @return the [destination].
|
||||
*/
|
||||
internal inline fun <K, V, W, D: MutableMap<K, W>> Map<out K, V>.copyMapTo(destination: D, transform: (key: K, value: V) -> W): D =
|
||||
copyMapTo(destination) { (key, value) -> transform(key, value) }
|
||||
|
||||
/**
|
||||
* Transforms values of entries of [this map][this] with [the given transformation][transform] and copies resulting
|
||||
* entries to the [destination] map merging present entries with new ones using [resolve] lambda. Is equivalent to
|
||||
* ```kotlin
|
||||
* this.mapValues(transform).copyToBy(destination, resolve)
|
||||
* ```
|
||||
*
|
||||
* @receiver map to be transformed and copied.
|
||||
* @param destination map to receive copies.
|
||||
* @param transform generates value of transformed entry using initial entry as an argument. Key of transformed entry is
|
||||
* the same as initial entry.
|
||||
* @param resolve lambda function that resolves overriding. It takes a key, current value corresponding to the key, and
|
||||
* a new one and returns value to associate to the key.
|
||||
* @return the [destination].
|
||||
*/
|
||||
internal inline fun <K, V, W, D: MutableMap<K, W>> Map<out K, V>.copyMapToBy(destination: D, transform: (Map.Entry<K, V>) -> W, resolve: (key: K, currentValue: W, newValue: V) -> W): D {
|
||||
for (entry in this) {
|
||||
val (key, value) = entry
|
||||
destination.putOrChange(key, transform(entry)) { it -> resolve(key, it, value) }
|
||||
}
|
||||
return destination
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms values of entries of [this map][this] with [the given transformation][transform] and copies resulting
|
||||
* entries to the [destination] map merging present entries with new ones using [resolve] lambda. Is equivalent to
|
||||
* ```kotlin
|
||||
* this.mapValues(transform).copyToBy(destination, resolve)
|
||||
* ```
|
||||
*
|
||||
* @receiver map to be transformed and copied.
|
||||
* @param destination map to receive copies.
|
||||
* @param transform generates value of transformed entry using initial entry as an argument. Key of transformed entry is
|
||||
* the same as initial entry.
|
||||
* @param resolve lambda function that resolves overriding. It takes a key, current value corresponding to the key, and
|
||||
* a new one and returns value to associate to the key.
|
||||
* @return the [destination].
|
||||
*/
|
||||
internal inline fun <K, V, W, D: MutableMap<K, W>> Map<out K, V>.copyMapToBy(destination: D, transform: (key: K, value: V) -> W, resolve: (key: K, currentValue: W, newValue: V) -> W): D =
|
||||
copyMapToBy(destination, { (key, value) -> transform(key, value) }, resolve)
|
||||
|
||||
/**
|
||||
* Transforms values of entries of [this map][this] with [the given transformation][transform] and copies resulting
|
||||
* entries to the [destination] map merging present entries with new ones using [resolve] lambda. Is equivalent to
|
||||
* ```kotlin
|
||||
* this.mapValues(transform).copyToBy(destination, resolve)
|
||||
* ```
|
||||
*
|
||||
* @receiver map to be transformed and copied.
|
||||
* @param destination map to receive copies.
|
||||
* @param transform generates value of transformed entry using initial entry as an argument. Key of transformed entry is
|
||||
* the same as initial entry.
|
||||
* @param resolve lambda function that resolves overriding. It takes current value corresponding to some key, and
|
||||
* a new one and returns value to associate to the key.
|
||||
* @return the [destination].
|
||||
*/
|
||||
internal inline fun <K, V, W, D: MutableMap<K, W>> Map<out K, V>.copyMapToBy(destination: D, transform: (Map.Entry<K, V>) -> W, resolve: (currentValue: W, newValue: V) -> W): D =
|
||||
copyMapToBy(destination, transform, { _, currentValue, newValue -> resolve(currentValue, newValue) })
|
||||
|
||||
/**
|
||||
* Transforms values of entries of [this map][this] with [the given transformation][transform] and copies resulting
|
||||
* entries to the [destination] map merging present entries with new ones using [resolve] lambda. Is equivalent to
|
||||
* ```kotlin
|
||||
* this.mapValues(transform).copyToBy(destination, resolve)
|
||||
* ```
|
||||
*
|
||||
* @receiver map to be transformed and copied.
|
||||
* @param destination map to receive copies.
|
||||
* @param transform generates value of transformed entry using initial entry as an argument. Key of transformed entry is
|
||||
* the same as initial entry.
|
||||
* @param resolve lambda function that resolves overriding. It takes current value corresponding to some key, and
|
||||
* a new one and returns value to associate to the key.
|
||||
* @return the [destination].
|
||||
*/
|
||||
internal inline fun <K, V, W, D: MutableMap<K, W>> Map<out K, V>.copyMapToBy(destination: D, transform: (key: K, value: V) -> W, resolve: (currentValue: W, newValue: V) -> W): D =
|
||||
copyMapToBy(destination, { (key, value) -> transform(key, value) }, { _, currentValue, newValue -> resolve(currentValue, newValue) })
|
||||
|
||||
/**
|
||||
* Merges [the first map][map1] and [the second map][map2] prioritising the second one, puts result to the [destination]
|
||||
* and returns the [destination].
|
||||
*
|
||||
* Precisely, corresponding keys and values of the received maps are put into the destination overriding existing values
|
||||
* in the [destination] if needed. For every key appearing in both maps corresponding value from the second map is
|
||||
* chosen.
|
||||
*
|
||||
* @param map1 the first (less prioritised) map to merge.
|
||||
* @param map2 the second (more prioritised) map to merge.
|
||||
* @param destination the map where result of the merge is put.
|
||||
* @return the destination.
|
||||
*/
|
||||
internal fun <K, V, D: MutableMap<in K, in V>> mergeTo(map1: Map<out K, V>, map2: Map<out K, V>, destination: D): D {
|
||||
for ((key, value) in map1) {
|
||||
destination.put(key, value)
|
||||
}
|
||||
for ((key, value) in map2) {
|
||||
destination.put(key, value)
|
||||
}
|
||||
return destination
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges [the first map][map1] and [the second map][map2] resolving conflicts with [resolve] lambda, puts result to the
|
||||
* [destination] and returns the [destination].
|
||||
*
|
||||
* Precisely, corresponding keys and values of the received maps are put into the destination overriding existing values
|
||||
* in the [destination] if needed. For every key appearing in both maps corresponding value is a result of the [resolve]
|
||||
* lambda calculated on the key and its corresponding values from the merged maps.
|
||||
*
|
||||
* @param map1 the first (less prioritised) map to merge.
|
||||
* @param map2 the second (more prioritised) map to merge.
|
||||
* @param resolve lambda function that resolves merge conflicts.
|
||||
* @param destination the map where result of the merge is put.
|
||||
* @return the destination.
|
||||
*/
|
||||
internal inline fun <K, V1: W, V2: W, W, D: MutableMap<K, W>> mergeToBy(map1: Map<out K, V1>, map2: Map<out K, V2>, destination: D, resolve: (key: K, value1: V1, value2: V2) -> W): D {
|
||||
for (key in map2.keys) {
|
||||
destination.remove(key)
|
||||
}
|
||||
for ((key, value) in map1) {
|
||||
destination.put(key, value)
|
||||
}
|
||||
for ((key, value) in map2) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
destination.putOrChange(key, value) { it -> resolve(key, it as V1, value) }
|
||||
}
|
||||
return destination
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges [the first map][map1] and [the second map][map2] resolving conflicts with [resolve] lambda, puts result to the
|
||||
* [destination] and returns the [destination].
|
||||
*
|
||||
* Precisely, corresponding keys and values of the received maps are put into the destination overriding existing values
|
||||
* in the [destination] if needed. For every key appearing in both maps corresponding value is a result of the [resolve]
|
||||
* lambda calculated on the key's corresponding values from the merged maps.
|
||||
*
|
||||
* @param map1 the first (less prioritised) map to merge.
|
||||
* @param map2 the second (more prioritised) map to merge.
|
||||
* @param resolve lambda function that resolves merge conflicts.
|
||||
* @param destination the map where result of the merge is put.
|
||||
* @return the destination.
|
||||
*/
|
||||
internal inline fun <K, V1: W, V2: W, W, D: MutableMap<K, W>> mergeToBy(map1: Map<K, V1>, map2: Map<K, V2>, destination: D, resolve: (value1: V1, value2: V2) -> W): D =
|
||||
mergeToBy(map1, map2, destination) { _, value1, value2 -> resolve(value1, value2) }
|
||||
|
||||
/**
|
||||
* Merges [the first map][map1] and [the second map][map2] prioritising the second one.
|
||||
*
|
||||
* Precisely, corresponding keys and values of the received maps are put into a new empty map which is returned after
|
||||
* afterwards. For every key appearing in both maps corresponding value from the second map is chosen.
|
||||
*
|
||||
* @param map1 the first (less prioritised) map to merge.
|
||||
* @param map2 the second (more prioritised) map to merge.
|
||||
* @return the result of the merge.
|
||||
*/
|
||||
internal fun <K, V1: W, V2: W, W> merge(map1: Map<K, V1>, map2: Map<K, V2>): Map<K, W> {
|
||||
val result = LinkedHashMap<K, W>(map1.size + map2.size)
|
||||
return mergeTo(map1, map2, result)
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges [the first map][map1] and [the second map][map2] resolving conflicts with [resolve] lambda.
|
||||
*
|
||||
* Precisely, corresponding keys and values of the received maps are put into a new empty map which is returned after
|
||||
* afterwards. For every key appearing in both maps corresponding value is a result of the [resolve] lambda calculated
|
||||
* on the key and its corresponding values from the merged maps.
|
||||
*
|
||||
* @param map1 the first (less prioritised) map to merge.
|
||||
* @param map2 the second (more prioritised) map to merge.
|
||||
* @param resolve lambda function that resolves merge conflicts.
|
||||
* @return the result of the merge.
|
||||
*/
|
||||
internal inline fun <K, V1: W, V2: W, W> mergeBy(map1: Map<K, V1>, map2: Map<K, V2>, resolve: (key: K, value1: V1, value2: V2) -> W): Map<K, W> {
|
||||
val result = LinkedHashMap<K, W>(map1.size + map2.size)
|
||||
return mergeToBy(map1, map2, result, resolve)
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges [the first map][map1] and [the second map][map2] resolving conflicts with [resolve] lambda.
|
||||
*
|
||||
* Precisely, corresponding keys and values of the received maps are put into a new empty map which is returned after
|
||||
* afterwards. For every key appearing in both maps corresponding value is a result of the [resolve] lambda calculated
|
||||
* on the key's corresponding values from the merged maps.
|
||||
*
|
||||
* @param map1 the first (less prioritised) map to merge.
|
||||
* @param map2 the second (more prioritised) map to merge.
|
||||
* @param resolve lambda function that resolves merge conflicts.
|
||||
* @return the result of the merge.
|
||||
*/
|
||||
internal inline fun <K, V1: W, V2: W, W> mergeBy(map1: Map<K, V1>, map2: Map<K, V2>, resolve: (value1: V1, value2: V2) -> W): Map<K, W> =
|
||||
mergeBy(map1, map2) { _, value1, value2 -> resolve(value1, value2) }
|
||||
|
||||
/**
|
||||
* Populates the [destination] map with key-value pairs provided by [transform] function applied to each element of the
|
||||
* given collection resolving conflicts with [resolve] function and returns the [destination].
|
||||
*
|
||||
* All pairs are added and resolved in order of iteration.
|
||||
*
|
||||
* @param destination the destination of the generated key-value pairs.
|
||||
* @param transform function which transforms each element to key-value.
|
||||
* @param resolve lambda function that resolves merge conflicts which receives some key, its current, and new
|
||||
* corresponding values.
|
||||
* @return the [destination].
|
||||
*/
|
||||
internal inline fun <T, K, V, D : MutableMap<K, V>> Iterable<T>.associateTo(destination: D, transform: (T) -> Pair<K, V>, resolve: (key: K, currentValue: V, newValue: V) -> V): D {
|
||||
for (element in this) {
|
||||
val (key, value) = transform(element)
|
||||
destination.putOrChange(key, value, resolve)
|
||||
}
|
||||
return destination
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates the [destination] map with key-value pairs, where key is provided by [keySelector] function and value is
|
||||
* provided by [valueTransform] applied to each element of the given collection, resolving conflicts with [resolve]
|
||||
* function and returns the [destination].
|
||||
*
|
||||
* All pairs are added and resolved in order of iteration.
|
||||
*
|
||||
* @param destination the destination of the generated key-value pairs.
|
||||
* @param keySelector lambda functions that generates keys for the key-value pairs.
|
||||
* @param valueTransform lambda functions that generates value for the key-value pairs.
|
||||
* @param resolve lambda function that resolves merge conflicts which receives some key, its current, and new
|
||||
* corresponding values.
|
||||
* @return the [destination].
|
||||
*/
|
||||
internal inline fun <T, K, V, D : MutableMap<K, V>> Iterable<T>.associateByTo(destination: D, keySelector: (T) -> K, valueTransform: (T) -> V, resolve: (key: K, currentValue: V, newValue: V) -> V): D {
|
||||
for (element in this) {
|
||||
val key = keySelector(element)
|
||||
val value = valueTransform(element)
|
||||
destination.putOrChange(key, value, resolve)
|
||||
}
|
||||
return destination
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates the [destination] map with key-value pairs, where key is provided by [keySelector] function applied to each
|
||||
* element of the given collection and value is the element itself, resolving conflicts with [resolve] function and
|
||||
* returns the [destination].
|
||||
*
|
||||
* All pairs are added and resolved in order of iteration.
|
||||
*
|
||||
* @param destination the destination of the generated key-value pairs.
|
||||
* @param keySelector lambda functions that generates keys for the key-value pairs.
|
||||
* @param resolve lambda function that resolves merge conflicts which receives some key, its current, and new
|
||||
* corresponding values.
|
||||
* @return the [destination].
|
||||
*/
|
||||
internal inline fun <T, K, D : MutableMap<K, T>> Iterable<T>.associateByTo(destination: D, keySelector: (T) -> K, resolve: (key: K, currentValue: T, newValue: T) -> T): D {
|
||||
for (element in this) {
|
||||
val key = keySelector(element)
|
||||
destination.putOrChange(key, element, resolve)
|
||||
}
|
||||
return destination
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates the [destination] map with key-value pairs provided by [transform] function applied to each element of the
|
||||
* given collection resolving conflicts with [resolve] function and returns the [destination].
|
||||
*
|
||||
* All pairs are added and resolved in order of iteration.
|
||||
*
|
||||
* @param destination the destination of the generated key-value pairs.
|
||||
* @param transform function which transforms each element to key-value pair.
|
||||
* @param resolve lambda function that resolves merge conflicts which receives some key, its current, and new
|
||||
* corresponding values.
|
||||
* @return the [destination].
|
||||
*/
|
||||
internal inline fun <T, K, V, D : MutableMap<K, V>> Iterable<T>.associateTo(destination: D, transform: (T) -> Pair<K, V>, resolve: (currentValue: V, newValue: V) -> V): D =
|
||||
associateTo(destination, transform) { _, currentValue, newValue -> resolve(currentValue, newValue) }
|
||||
|
||||
/**
|
||||
* Populates the [destination] map with key-value pairs, where key is provided by [keySelector] function and value is
|
||||
* provided by [valueTransform] applied to each element of the given collection, resolving conflicts with [resolve]
|
||||
* function and returns the [destination].
|
||||
*
|
||||
* All pairs are added and resolved in order of iteration.
|
||||
*
|
||||
* @param destination the destination of the generated key-value pairs.
|
||||
* @param keySelector lambda functions that generates keys for the key-value pairs.
|
||||
* @param valueTransform lambda functions that generates value for the key-value pairs.
|
||||
* @param resolve lambda function that resolves merge conflicts which receives some key, its current, and new
|
||||
* corresponding values.
|
||||
* @return the [destination].
|
||||
*/
|
||||
internal inline fun <T, K, V, D : MutableMap<K, V>> Iterable<T>.associateByTo(destination: D, keySelector: (T) -> K, valueTransform: (T) -> V, resolve: (currentValue: V, newValue: V) -> V): D =
|
||||
associateByTo(destination, keySelector, valueTransform) { _, currentValue, newValue -> resolve(currentValue, newValue) }
|
||||
|
||||
/**
|
||||
* Populates the [destination] map with key-value pairs, where key is provided by [keySelector] function applied to each
|
||||
* element of the given collection and value is the element itself, resolving conflicts with [resolve] function and
|
||||
* returns the [destination].
|
||||
*
|
||||
* All pairs are added and resolved in order of iteration.
|
||||
*
|
||||
* @param destination the destination of the generated key-value pairs.
|
||||
* @param keySelector lambda functions that generates keys for the key-value pairs.
|
||||
* @param resolve lambda function that resolves merge conflicts which receives some key, its current, and new
|
||||
* corresponding values.
|
||||
* @return the [destination].
|
||||
*/
|
||||
internal inline fun <T, K, D : MutableMap<K, T>> Iterable<T>.associateByTo(destination: D, keySelector: (T) -> K, resolve: (currentValue: T, newValue: T) -> T): D =
|
||||
associateByTo(destination, keySelector) { _, currentValue, newValue -> resolve(currentValue, newValue) }
|
||||
|
||||
/**
|
||||
* Returns a map containing key-value pairs provided by [transform] function applied to elements of the given collection.
|
||||
*
|
||||
* All pairs are added in order of iteration. If some key is already added to the map, adding new key-value pair with the
|
||||
* key is resolved with [resolve] function which takes the key, current value corresponding to the key, and new value
|
||||
* from the pair.
|
||||
*
|
||||
* @param transform function which transforms each element to key-value pair.
|
||||
* @param resolve lambda function that resolves merge conflicts which receives some key, its current, and new
|
||||
* corresponding values.
|
||||
* @return the result map.
|
||||
*/
|
||||
internal inline fun <T, K, V> Iterable<T>.associate(transform: (T) -> Pair<K, V>, resolve: (key: K, currentValue: V, newValue: V) -> V): Map<K, V> =
|
||||
associateTo(LinkedHashMap(), transform, resolve)
|
||||
|
||||
/**
|
||||
* Returns a map containing the values provided by [valueTransform] and indexed by [keySelector] functions applied to
|
||||
* elements of the given collection.
|
||||
*
|
||||
* All pairs are added in order of iteration. If some key is already added to the map, adding new key-value pair with
|
||||
* the key is resolved with [resolve] function which takes the key, current value corresponding to the key, and new
|
||||
* value from the pair.
|
||||
*
|
||||
* @param keySelector lambda functions that generates keys for the key-value pairs.
|
||||
* @param valueTransform lambda functions that generates value for the key-value pairs.
|
||||
* @param resolve lambda function that resolves merge conflicts which receives some key, its current, and new
|
||||
* corresponding values.
|
||||
* @return the result map.
|
||||
*/
|
||||
internal inline fun <T, K, V> Iterable<T>.associateBy(keySelector: (T) -> K, valueTransform: (T) -> V, resolve: (key: K, currentValue: V, newValue: V) -> V): Map<K, V> =
|
||||
associateByTo(LinkedHashMap(), keySelector, valueTransform, resolve)
|
||||
|
||||
/**
|
||||
* Returns a map containing the elements from the given collection indexed by the key returned from [keySelector]
|
||||
* function applied to each element.
|
||||
*
|
||||
* All pairs are added in order of iteration. If some key is already added to the map, adding new key-value pair with
|
||||
* the key is resolved with [resolve] function which takes the key, current value corresponding to the key, and new
|
||||
* value from the pair.
|
||||
*
|
||||
* @param keySelector lambda functions that generates keys for the key-value pairs.
|
||||
* @param resolve lambda function that resolves merge conflicts which receives some key, its current, and new
|
||||
* corresponding values.
|
||||
* @return the result map.
|
||||
*/
|
||||
internal inline fun <T, K> Iterable<T>.associateBy(keySelector: (T) -> K, resolve: (key: K, currentValue: T, newValue: T) -> T): Map<K, T> =
|
||||
associateByTo(LinkedHashMap(), keySelector, resolve)
|
||||
|
||||
/**
|
||||
* Returns a map containing key-value pairs provided by [transform] function applied to elements of the given collection.
|
||||
*
|
||||
* All pairs are added in order of iteration. If some key is already added to the map, adding new key-value pair with
|
||||
* the key is resolved with [resolve] function which takes current value corresponding to the key and new value from the
|
||||
* pair.
|
||||
*
|
||||
* @param transform function which transforms each element to key-value pair.
|
||||
* @param resolve lambda function that resolves merge conflicts which receives some key, its current, and new
|
||||
* corresponding values.
|
||||
* @return the result map.
|
||||
*/
|
||||
internal inline fun <T, K, V> Iterable<T>.associate(transform: (T) -> Pair<K, V>, resolve: (currentValue: V, newValue: V) -> V): Map<K, V> =
|
||||
associateTo(LinkedHashMap(), transform, resolve)
|
||||
|
||||
/**
|
||||
* Returns a map containing the values provided by [valueTransform] and indexed by [keySelector] functions applied to
|
||||
* elements of the given collection.
|
||||
*
|
||||
* All pairs are added in order of iteration. If some key is already added to the map, adding new key-value pair with
|
||||
* the key is resolved with [resolve] function which takes current value corresponding to the key and new value from the
|
||||
* pair.
|
||||
*
|
||||
* @param keySelector lambda functions that generates keys for the key-value pairs.
|
||||
* @param valueTransform lambda functions that generates value for the key-value pairs.
|
||||
* @param resolve lambda function that resolves merge conflicts which receives some key, its current, and new
|
||||
* corresponding values.
|
||||
* @return the result map.
|
||||
*/
|
||||
internal inline fun <T, K, V> Iterable<T>.associateBy(keySelector: (T) -> K, valueTransform: (T) -> V, resolve: (currentValue: V, newValue: V) -> V): Map<K, V> =
|
||||
associateByTo(LinkedHashMap(), keySelector, valueTransform, resolve)
|
||||
|
||||
/**
|
||||
* Returns a map containing the elements from the given collection indexed by the key returned from [keySelector]
|
||||
* function applied to each element.
|
||||
*
|
||||
* All pairs are added in order of iteration. If some key is already added to the map, adding new key-value pair with
|
||||
* the key is resolved with [resolve] function which takes current value corresponding to the key and new value from the
|
||||
* pair.
|
||||
*
|
||||
* @param keySelector lambda functions that generates keys for the key-value pairs.
|
||||
* @param resolve lambda function that resolves merge conflicts which receives some key, its current, and new
|
||||
* corresponding values.
|
||||
* @return the result map.
|
||||
*/
|
||||
internal inline fun <T, K> Iterable<T>.associateBy(keySelector: (T) -> K, resolve: (currentValue: T, newValue: T) -> T): Map<K, T> =
|
||||
associateByTo(LinkedHashMap(), keySelector, resolve)
|
||||
|
||||
/**
|
||||
* Populates the given [destination] map with entries having the keys of this map and the values obtained
|
||||
* by applying the [transform] function to each entry in this map resolving conflicts with [resolve] function and
|
||||
* returns the [destination].
|
||||
*
|
||||
* All pairs are added and resolved in order of iteration.
|
||||
*
|
||||
* @param destination the destination of the generated key-value pairs.
|
||||
* @param transform function which transforms each key-value pair to new value.
|
||||
* @param resolve lambda function that resolves merge conflicts which receives some key, its current, and new
|
||||
* corresponding values.
|
||||
* @return the [destination].
|
||||
*/
|
||||
internal inline fun <K, V, W, D : MutableMap<K, W>> Map<out K, V>.mapValuesTo(destination: D, transform: (Map.Entry<K, V>) -> W, resolve: (key: K, currentValue: W, newValue: W) -> W): D =
|
||||
entries.associateByTo(destination, { it.key }, transform, resolve)
|
||||
|
||||
/**
|
||||
* Populates the given [destination] map with entries having the keys of this map and the values obtained
|
||||
* by applying the [transform] function to each entry in this map resolving conflicts with [resolve] function and
|
||||
* returns the [destination].
|
||||
*
|
||||
* All pairs are added and resolved in order of iteration.
|
||||
*
|
||||
* @param destination the destination of the generated key-value pairs.
|
||||
* @param transform function which transforms each key-value pair to new value.
|
||||
* @param resolve lambda function that resolves merge conflicts which receives some key, its current, and new
|
||||
* corresponding values.
|
||||
* @return the [destination].
|
||||
*/
|
||||
internal inline fun <K, V, W, D : MutableMap<K, W>> Map<out K, V>.mapValuesTo(destination: D, transform: (key: K, value: V) -> W, resolve: (key: K, currentValue: W, newValue: W) -> W): D =
|
||||
entries.associateByTo(destination, { it.key }, { (key, value) -> transform(key, value) }, resolve)
|
||||
|
||||
/**
|
||||
* Populates the given [destination] map with entries having the keys of this map and the values obtained
|
||||
* by applying the [transform] function to each entry in this map resolving conflicts with [resolve] function and
|
||||
* returns the [destination].
|
||||
*
|
||||
* All pairs are added and resolved in order of iteration.
|
||||
*
|
||||
* @param destination the destination of the generated key-value pairs.
|
||||
* @param transform function which transforms each key-value pair to new value.
|
||||
* @param resolve lambda function that resolves merge conflicts which current and new values corresponding to some key.
|
||||
* @return the [destination].
|
||||
*/
|
||||
internal inline fun <K, V, W, D : MutableMap<K, W>> Map<out K, V>.mapValuesTo(destination: D, transform: (Map.Entry<K, V>) -> W, resolve: (currentValue: W, newValue: W) -> W): D =
|
||||
entries.associateByTo(destination, { it.key }, transform, resolve)
|
||||
|
||||
/**
|
||||
* Populates the given [destination] map with entries having the keys of this map and the values obtained
|
||||
* by applying the [transform] function to each entry in this map resolving conflicts with [resolve] function and
|
||||
* returns the [destination].
|
||||
*
|
||||
* All pairs are added and resolved in order of iteration.
|
||||
*
|
||||
* @param destination the destination of the generated key-value pairs.
|
||||
* @param transform function which transforms each key-value pair to new value.
|
||||
* @param resolve lambda function that resolves merge conflicts which current and new values corresponding to some key.
|
||||
* @return the [destination].
|
||||
*/
|
||||
internal inline fun <K, V, W, D : MutableMap<K, W>> Map<out K, V>.mapValuesTo(destination: D, transform: (key: K, value: V) -> W, resolve: (currentValue: W, newValue: W) -> W): D =
|
||||
entries.associateByTo(destination, { it.key }, { (key, value) -> transform(key, value) }, resolve)
|
||||
|
||||
/**
|
||||
* Populates the given [destination] map with entries having the keys obtained by applying the [transform] function to
|
||||
* each entry in this map and the values of this map, resolving conflicts with [resolve] function and returns the
|
||||
* [destination].
|
||||
*
|
||||
* All pairs are added and resolved in order of iteration.
|
||||
*
|
||||
* @param destination the destination of the generated key-value pairs.
|
||||
* @param transform function which transforms each key-value pair to new key.
|
||||
* @param resolve lambda function that resolves merge conflicts which receives some key, its current, and new
|
||||
* corresponding values.
|
||||
* @return the [destination].
|
||||
*/
|
||||
internal inline fun <K, V, L, D : MutableMap<L, V>> Map<out K, V>.mapKeysTo(destination: D, transform: (Map.Entry<K, V>) -> L, resolve: (key: L, currentValue: V, newValue: V) -> V): D =
|
||||
entries.associateByTo(destination, transform, { it.value }, resolve)
|
||||
|
||||
/**
|
||||
* Populates the given [destination] map with entries having the keys obtained by applying the [transform] function to
|
||||
* each entry in this map and the values of this map, resolving conflicts with [resolve] function and returns the
|
||||
* [destination].
|
||||
*
|
||||
* All pairs are added and resolved in order of iteration.
|
||||
*
|
||||
* @param destination the destination of the generated key-value pairs.
|
||||
* @param transform function which transforms each key-value pair to new key.
|
||||
* @param resolve lambda function that resolves merge conflicts which receives some key, its current, and new
|
||||
* corresponding values.
|
||||
* @return the [destination].
|
||||
*/
|
||||
internal inline fun <K, V, L, D : MutableMap<L, V>> Map<out K, V>.mapKeysTo(destination: D, transform: (key: K, value: V) -> L, resolve: (key: L, currentValue: V, newValue: V) -> V): D =
|
||||
entries.associateByTo(destination, { (key, value) -> transform(key, value) }, { it.value }, resolve)
|
||||
|
||||
/**
|
||||
* Populates the given [destination] map with entries having the keys obtained by applying the [transform] function to
|
||||
* each entry in this map and the values of this map, resolving conflicts with [resolve] function and returns the
|
||||
* [destination].
|
||||
*
|
||||
* All pairs are added and resolved in order of iteration.
|
||||
*
|
||||
* @param destination the destination of the generated key-value pairs.
|
||||
* @param transform function which transforms each key-value pair to new key.
|
||||
* @param resolve lambda function that resolves merge conflicts which current and new values corresponding to some key.
|
||||
* @return the [destination].
|
||||
*/
|
||||
internal inline fun <K, V, L, D : MutableMap<L, V>> Map<out K, V>.mapKeysTo(destination: D, transform: (Map.Entry<K, V>) -> L, resolve: (currentValue: V, newValue: V) -> V): D =
|
||||
entries.associateByTo(destination, transform, { it.value }, resolve)
|
||||
|
||||
/**
|
||||
* Populates the given [destination] map with entries having the keys obtained by applying the [transform] function to
|
||||
* each entry in this map and the values of this map, resolving conflicts with [resolve] function and returns the
|
||||
* [destination].
|
||||
*
|
||||
* All pairs are added and resolved in order of iteration.
|
||||
*
|
||||
* @param destination the destination of the generated key-value pairs.
|
||||
* @param transform function which transforms each key-value pair to new key.
|
||||
* @param resolve lambda function that resolves merge conflicts which current and new values corresponding to some key.
|
||||
* @return the [destination].
|
||||
*/
|
||||
internal inline fun <K, V, L, D : MutableMap<L, V>> Map<out K, V>.mapKeysTo(destination: D, transform: (key: K, value: V) -> L, resolve: (currentValue: V, newValue: V) -> V): D =
|
||||
entries.associateByTo(destination, { (key, value) -> transform(key, value) }, { it.value }, resolve)
|
||||
|
||||
/**
|
||||
* Returns a new map with entries having the keys obtained by applying the [transform] function to each entry in this
|
||||
* map and the values of this map and resolving conflicts with [resolve] function.
|
||||
*
|
||||
* All pairs are added and resolved in order of iteration.
|
||||
*
|
||||
* @param transform function which transforms each key-value pair to new key.
|
||||
* @param resolve lambda function that resolves merge conflicts which receives some key, its current, and new
|
||||
* corresponding values.
|
||||
* @return the result map.
|
||||
*/
|
||||
internal inline fun <K, V, L> Map<out K, V>.mapKeys(transform: (Map.Entry<K, V>) -> L, resolve: (key: L, currentValue: V, newValue: V) -> V): Map<L, V> =
|
||||
mapKeysTo(LinkedHashMap(size), transform, resolve)
|
||||
|
||||
/**
|
||||
* Returns a new map with entries having the keys obtained by applying the [transform] function to each entry in this
|
||||
* map and the values of this map and resolving conflicts with [resolve] function.
|
||||
*
|
||||
* All pairs are added and resolved in order of iteration.
|
||||
*
|
||||
* @param transform function which transforms each key-value pair to new key.
|
||||
* @param resolve lambda function that resolves merge conflicts which receives some key, its current, and new
|
||||
* corresponding values.
|
||||
* @return the result map.
|
||||
*/
|
||||
internal inline fun <K, V, L> Map<out K, V>.mapKeys(transform: (key: K, value: V) -> L, resolve: (key: L, currentValue: V, newValue: V) -> V): Map<L, V> =
|
||||
mapKeysTo(LinkedHashMap(size), transform, resolve)
|
||||
|
||||
/**
|
||||
* Returns a new map with entries having the keys obtained by applying the [transform] function to each entry in this
|
||||
* map and the values of this map and resolving conflicts with [resolve] function.
|
||||
*
|
||||
* All pairs are added and resolved in order of iteration.
|
||||
*
|
||||
* @param transform function which transforms each key-value pair to new key.
|
||||
* @param resolve lambda function that resolves merge conflicts which current and new values corresponding to some key.
|
||||
* @return the result map.
|
||||
*/
|
||||
internal inline fun <K, V, L> Map<out K, V>.mapKeys(transform: (Map.Entry<K, V>) -> L, resolve: (currentValue: V, newValue: V) -> V): Map<L, V> =
|
||||
mapKeysTo(LinkedHashMap(size), transform, resolve)
|
||||
|
||||
/**
|
||||
* Returns a new map with entries having the keys obtained by applying the [transform] function to each entry in this
|
||||
* map and the values of this map and resolving conflicts with [resolve] function.
|
||||
*
|
||||
* All pairs are added and resolved in order of iteration.
|
||||
*
|
||||
* @param transform function which transforms each key-value pair to new key.
|
||||
* @param resolve lambda function that resolves merge conflicts which current and new values corresponding to some key.
|
||||
* @return the result map.
|
||||
*/
|
||||
internal inline fun <K, V, L> Map<out K, V>.mapKeys(transform: (key: K, value: V) -> L, resolve: (currentValue: V, newValue: V) -> V): Map<L, V> =
|
||||
mapKeysTo(LinkedHashMap(size), transform, resolve)
|
@ -1,779 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018-2022 KMath contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@file:Suppress("FunctionName", "NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress")
|
||||
|
||||
package space.kscience.kmath.functions
|
||||
|
||||
import space.kscience.kmath.expressions.Symbol
|
||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||
import space.kscience.kmath.operations.Ring
|
||||
import space.kscience.kmath.operations.invoke
|
||||
|
||||
|
||||
/**
|
||||
* Returns the same degrees' description of the monomial, but without zero degrees.
|
||||
*/
|
||||
internal fun Map<Symbol, UInt>.cleanUp() = filterValues { it > 0U }
|
||||
|
||||
/**
|
||||
* Constructs [LabeledPolynomial] with provided coefficients map [coefs]. The map is used as is.
|
||||
*/
|
||||
@PublishedApi
|
||||
internal inline fun <C> LabeledPolynomialAsIs(coefs: Map<Map<Symbol, UInt>, C>) : LabeledPolynomial<C> = LabeledPolynomial<C>(coefs)
|
||||
|
||||
/**
|
||||
* Constructs [LabeledPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient".
|
||||
* The collections will be transformed to map with [toMap] and then will be used as is.
|
||||
*/
|
||||
@PublishedApi
|
||||
internal inline fun <C> LabeledPolynomialAsIs(pairs: Collection<Pair<Map<Symbol, UInt>, C>>) : LabeledPolynomial<C> = LabeledPolynomial<C>(pairs.toMap())
|
||||
|
||||
/**
|
||||
* Constructs [LabeledPolynomial] with provided array of [pairs] of pairs "term's signature — term's coefficient".
|
||||
* The array will be transformed to map with [toMap] and then will be used as is.
|
||||
*/
|
||||
@PublishedApi
|
||||
internal inline fun <C> LabeledPolynomialAsIs(vararg pairs: Pair<Map<Symbol, UInt>, C>) : LabeledPolynomial<C> = LabeledPolynomial<C>(pairs.toMap())
|
||||
|
||||
/**
|
||||
* Constructs [LabeledPolynomial] with provided coefficients map [coefs]. The map is used as is.
|
||||
*
|
||||
* **Be sure you read description of [LabeledPolynomial.coefficients]. Otherwise, you may make a mistake that will
|
||||
* cause wrong computation result or even runtime error.**
|
||||
*/
|
||||
@DelicatePolynomialAPI
|
||||
public inline fun <C> LabeledPolynomialWithoutCheck(coefs: Map<Map<Symbol, UInt>, C>) : LabeledPolynomial<C> = LabeledPolynomial<C>(coefs)
|
||||
|
||||
/**
|
||||
* Constructs [LabeledPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient".
|
||||
* The collections will be transformed to map with [toMap] and then will be used as is.
|
||||
*
|
||||
* **Be sure you read description of [LabeledPolynomial.coefficients]. Otherwise, you may make a mistake that will
|
||||
* cause wrong computation result or even runtime error.**
|
||||
*/
|
||||
@DelicatePolynomialAPI
|
||||
public inline fun <C> LabeledPolynomialWithoutCheck(pairs: Collection<Pair<Map<Symbol, UInt>, C>>) : LabeledPolynomial<C> = LabeledPolynomial<C>(pairs.toMap())
|
||||
|
||||
/**
|
||||
* Constructs [LabeledPolynomial] with provided array of [pairs] of pairs "term's signature — term's coefficient".
|
||||
* The array will be transformed to map with [toMap] and then will be used as is.
|
||||
*
|
||||
* **Be sure you read description of [LabeledPolynomial.coefficients]. Otherwise, you may make a mistake that will
|
||||
* cause wrong computation result or even runtime error.**
|
||||
*/
|
||||
@DelicatePolynomialAPI
|
||||
public inline fun <C> LabeledPolynomialWithoutCheck(vararg pairs: Pair<Map<Symbol, UInt>, C>) : LabeledPolynomial<C> = LabeledPolynomial<C>(pairs.toMap())
|
||||
|
||||
/**
|
||||
* Constructs [LabeledPolynomial] with provided coefficients map [coefs].
|
||||
*
|
||||
* [coefs] will be "cleaned up":
|
||||
* 1. Zeros at the ends of terms' signatures (e.g. [coefs] keys) will be removed. (See [cleanUp].)
|
||||
* 1. Terms that happen to have the same signature will be summed up.
|
||||
* 1. New map will be formed of resulting terms.
|
||||
*
|
||||
* @see LabeledPolynomialWithoutCheck
|
||||
*/
|
||||
public fun <C> LabeledPolynomial(coefs: Map<Map<Symbol, UInt>, C>, add: (C, C) -> C) : LabeledPolynomial<C> =
|
||||
LabeledPolynomialAsIs(
|
||||
coefs.mapKeys({ key, _ -> key.cleanUp() }, 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.
|
||||
*
|
||||
* @see LabeledPolynomialWithoutCheck
|
||||
*/
|
||||
public fun <C> LabeledPolynomial(pairs: Collection<Pair<Map<Symbol, UInt>, C>>, add: (C, C) -> C) : LabeledPolynomial<C> =
|
||||
LabeledPolynomialAsIs(
|
||||
pairs.associateBy({ it.first.cleanUp() }, { it.second }, add)
|
||||
)
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @see LabeledPolynomialWithoutCheck
|
||||
*/
|
||||
public fun <C> LabeledPolynomial(vararg pairs: Pair<Map<Symbol, UInt>, C>, add: (C, C) -> C) : LabeledPolynomial<C> =
|
||||
LabeledPolynomialAsIs(
|
||||
pairs.asIterable().associateBy({ it.first.cleanUp() }, { it.second }, add)
|
||||
)
|
||||
|
||||
// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available
|
||||
|
||||
/**
|
||||
* Constructs [LabeledPolynomial] with provided coefficients map [coefs].
|
||||
*
|
||||
* [coefs] will be "cleaned up":
|
||||
* 1. Zeros at the ends of terms' signatures (e.g. [coefs] keys) will be removed. (See [cleanUp].)
|
||||
* 1. Terms that happen to have the same signature will be summed up.
|
||||
* 1. New map will be formed of resulting terms.
|
||||
*
|
||||
* @see LabeledPolynomialWithoutCheck
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @see LabeledPolynomialWithoutCheck
|
||||
*/
|
||||
public inline fun <C, A: Ring<C>> LabeledPolynomialSpace<C, A>.LabeledPolynomial(coefs: Map<Map<Symbol, UInt>, C>) : LabeledPolynomial<C> = LabeledPolynomial(coefs) { left: C, right: C -> left + right }
|
||||
|
||||
/**
|
||||
* Constructs [LabeledPolynomial] with provided coefficients map [coefs].
|
||||
*
|
||||
* [coefs] will be "cleaned up":
|
||||
* 1. Zeros at the ends of terms' signatures (e.g. [coefs] keys) will be removed. (See [cleanUp].)
|
||||
* 1. Terms that happen to have the same signature will be summed up.
|
||||
* 1. New map will be formed of resulting terms.
|
||||
*
|
||||
* @see LabeledPolynomialWithoutCheck
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @see LabeledPolynomialWithoutCheck
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @see LabeledPolynomialWithoutCheck
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @see LabeledPolynomialWithoutCheck
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @see LabeledPolynomialWithoutCheck
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @see LabeledPolynomialWithoutCheck
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @see LabeledPolynomialWithoutCheck
|
||||
*/
|
||||
public inline fun <C, A: Ring<C>> LabeledRationalFunctionSpace<C, A>.LabeledPolynomial(vararg pairs: Pair<Map<Symbol, UInt>, C>) : LabeledPolynomial<C> = LabeledPolynomial(*pairs) { left: C, right: C -> left + right }
|
||||
|
||||
/**
|
||||
* Converts [this] constant to [LabeledPolynomial].
|
||||
*/
|
||||
public inline fun <C> C.asLabeledPolynomial() : LabeledPolynomial<C> = LabeledPolynomialAsIs(mapOf(emptyMap<Symbol, UInt>() to this))
|
||||
|
||||
///**
|
||||
//// * Converts [this] variable to [LabeledPolynomial].
|
||||
//// */
|
||||
//context(A)
|
||||
//public inline fun <C, A: Ring<C>> Symbol.asLabeledPolynomial() : LabeledPolynomial<C> = LabeledPolynomial<C>(mapOf(mapOf(this to 1u) to one))
|
||||
///**
|
||||
// * Converts [this] variable to [LabeledPolynomial].
|
||||
// */
|
||||
//context(LabeledPolynomialSpace<C, A>)
|
||||
//public inline fun <C, A: Ring<C>> Symbol.asLabeledPolynomial() : LabeledPolynomial<C> = LabeledPolynomial<C>(mapOf(mapOf(this to 1u) to constantOne))
|
||||
///**
|
||||
// * Converts [this] variable to [LabeledPolynomial].
|
||||
// */
|
||||
//context(LabeledRationalFunctionSpace<C, A>)
|
||||
//public inline fun <C, A: Ring<C>> Symbol.asLabeledPolynomial() : LabeledPolynomial<C> = LabeledPolynomial<C>(mapOf(mapOf(this to 1u) to constantOne))
|
||||
|
||||
/**
|
||||
* Marks DSL that allows to more simply create [LabeledPolynomial]s with good performance.
|
||||
*
|
||||
* For example, polynomial \(5 a^2 c^3 - 6 b\) can be described as
|
||||
* ```
|
||||
* Int.algebra {
|
||||
* val labeledPolynomial : LabeledPolynomial<Int> = LabeledPolynomialDSL1 {
|
||||
* 5 { a inPowerOf 2u; c inPowerOf 3u } // 5 a^2 c^3 +
|
||||
* (-6) { b inPowerOf 1u } // (-6) b^1
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
* @usesMathJax
|
||||
*/
|
||||
@DslMarker
|
||||
@UnstableKMathAPI
|
||||
internal annotation class LabeledPolynomialConstructorDSL1
|
||||
|
||||
/**
|
||||
* Builder of [LabeledPolynomial] signature. It should be used as an implicit context for lambdas that describe term signature.
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
@LabeledPolynomialConstructorDSL1
|
||||
public class DSL1LabeledPolynomialTermSignatureBuilder {
|
||||
/**
|
||||
* Signature storage. Any declaration of any variable's power updates the storage by increasing corresponding value.
|
||||
* Afterward the storage will be used as a resulting signature.
|
||||
*/
|
||||
private val signature: MutableMap<Symbol, UInt> = LinkedHashMap()
|
||||
|
||||
/**
|
||||
* Builds the resulting signature.
|
||||
*
|
||||
* In fact, it just returns [signature] as regular signature of type `List<UInt>`.
|
||||
*/
|
||||
@PublishedApi
|
||||
internal fun build(): Map<Symbol, UInt> = signature
|
||||
|
||||
/**
|
||||
* Declares power of [this] variable of degree [deg].
|
||||
*
|
||||
* Declaring another power of the same variable will increase its degree by received degree.
|
||||
*/
|
||||
public infix fun Symbol.inPowerOf(deg: UInt) {
|
||||
if (deg == 0u) return
|
||||
signature.putOrChange(this, deg) { it -> it + deg }
|
||||
}
|
||||
/**
|
||||
* Declares power of [this] variable of degree [deg].
|
||||
*
|
||||
* Declaring another power of the same variable will increase its degree by received degree.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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
|
||||
@LabeledPolynomialConstructorDSL1
|
||||
public class DSL1LabeledPolynomialBuilder<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? = null
|
||||
) {
|
||||
/**
|
||||
* 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> = if (initialCapacity != null) LinkedHashMap(initialCapacity) else LinkedHashMap()
|
||||
|
||||
/**
|
||||
* Builds the resulting coefficients map.
|
||||
*
|
||||
* In fact, it just returns [coefficients] as regular coefficients map of type `Map<Map<Symbol, 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.putOrChange(signature, this@with, add)
|
||||
}
|
||||
/**
|
||||
* 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 infix fun C.with(noinline block: DSL1LabeledPolynomialTermSignatureBuilder.() -> Unit): Unit = this.invoke(block)
|
||||
/**
|
||||
* Declares monomial with [this] coefficient and signature constructed by [block].
|
||||
*
|
||||
* Declaring another monomial with the same signature will add [this] coefficient to existing one. If the sum of such
|
||||
* coefficients is zero at any moment the monomial won't be removed but will be left as it is.
|
||||
*/
|
||||
public inline operator fun C.invoke(block: DSL1LabeledPolynomialTermSignatureBuilder.() -> Unit): Unit =
|
||||
this with DSL1LabeledPolynomialTermSignatureBuilder().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 a^2 c^3 - 6 b\) can be described as
|
||||
// * ```
|
||||
// * Int.algebra {
|
||||
// * val labeledPolynomial : LabeledPolynomial<Int> = LabeledPolynomialDSL1 {
|
||||
// * 5 { a inPowerOf 2u; c inPowerOf 3u } // 5 a^2 c^3 +
|
||||
// * (-6) { b inPowerOf 1u } // (-6) b^1
|
||||
// * }
|
||||
// * }
|
||||
// * ```
|
||||
// * @usesMathJax
|
||||
// */
|
||||
// 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.LabeledPolynomialDSL1(initialCapacity: Int? = null, 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 a^2 c^3 - 6 b\) can be described as
|
||||
* ```
|
||||
* Int.algebra {
|
||||
* val labeledPolynomial : LabeledPolynomial<Int> = LabeledPolynomialDSL1 {
|
||||
* 5 { a inPowerOf 2u; c inPowerOf 3u } // 5 a^2 c^3 +
|
||||
* (-6) { b inPowerOf 1u } // (-6) b^1
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
* @usesMathJax
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public inline fun <C, A: Ring<C>> LabeledPolynomialSpace<C, A>.LabeledPolynomialDSL1(initialCapacity: Int? = null, block: DSL1LabeledPolynomialBuilder<C>.() -> Unit) : LabeledPolynomial<C> = DSL1LabeledPolynomialBuilder({ 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 a^2 c^3 - 6 b\) can be described as
|
||||
* ```
|
||||
* Int.algebra {
|
||||
* val labeledPolynomial : LabeledPolynomial<Int> = LabeledPolynomialDSL1 {
|
||||
* 5 { a inPowerOf 2u; c inPowerOf 3u } // 5 a^2 c^3 +
|
||||
* (-6) { b inPowerOf 1u } // (-6) b^1
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
* @usesMathJax
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public inline fun <C, A: Ring<C>> LabeledRationalFunctionSpace<C, A>.LabeledPolynomialDSL1(initialCapacity: Int? = null, block: DSL1LabeledPolynomialBuilder<C>.() -> Unit) : LabeledPolynomial<C> = DSL1LabeledPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build()
|
||||
|
||||
/**
|
||||
* 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
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
* @usesMathJax
|
||||
*/
|
||||
@DslMarker
|
||||
@UnstableKMathAPI
|
||||
internal annotation class LabeledPolynomialBuilderDSL2
|
||||
|
||||
/**
|
||||
* Builder of [LabeledPolynomial]. It should be used as an implicit context for lambdas that describe [LabeledPolynomial].
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
@LabeledPolynomialBuilderDSL2
|
||||
public class DSL2LabeledPolynomialBuilder<C>(
|
||||
private val ring: Ring<C>,
|
||||
/**
|
||||
* Initial capacity of coefficients map.
|
||||
*/
|
||||
initialCapacity: Int? = null
|
||||
) {
|
||||
/**
|
||||
* 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> = if (initialCapacity != null) LinkedHashMap(initialCapacity) else LinkedHashMap()
|
||||
|
||||
/**
|
||||
* Builds the resulting coefficients map.
|
||||
*
|
||||
* In fact, it just returns [coefficients] as regular coefficients map of type `Map<Map<Symbol, UInt>, C>`.
|
||||
*/
|
||||
@PublishedApi
|
||||
internal fun build(): LabeledPolynomial<C> = LabeledPolynomial<C>(coefficients)
|
||||
|
||||
public inner class Term internal constructor(
|
||||
internal val signature: Map<Symbol, UInt> = HashMap(),
|
||||
internal val coefficient: C
|
||||
)
|
||||
|
||||
private inline fun submit(signature: Map<Symbol, UInt>, onPut: Ring<C>.() -> C, onChange: Ring<C>.(C) -> C) {
|
||||
coefficients.putOrChange<_, C>(signature, { ring.onPut() }, { ring.onChange(it) })
|
||||
}
|
||||
|
||||
private inline fun submit(signature: Map<Symbol, UInt>, lazyCoefficient: Ring<C>.() -> C) {
|
||||
submit(signature, lazyCoefficient) { it + lazyCoefficient() }
|
||||
}
|
||||
|
||||
private fun submit(signature: Map<Symbol, UInt>, coefficient: C) {
|
||||
submit(signature) { coefficient }
|
||||
}
|
||||
|
||||
// TODO: `@submit` will be resolved differently. Change it to `@C`.
|
||||
private fun C.submitSelf() = submit(emptyMap()) { this@submitSelf }
|
||||
|
||||
private fun Symbol.submit() = submit(mapOf(this to 1u)) { one }
|
||||
|
||||
private fun Term.submit(): Submit {
|
||||
submit(signature, coefficient)
|
||||
return Submit
|
||||
}
|
||||
|
||||
public object Submit
|
||||
|
||||
public operator fun C.unaryPlus(): Submit {
|
||||
submitSelf()
|
||||
return Submit
|
||||
}
|
||||
|
||||
public operator fun C.unaryMinus(): Submit {
|
||||
submit(emptyMap(), { -this@unaryMinus }, { it - this@unaryMinus })
|
||||
return Submit
|
||||
}
|
||||
|
||||
public operator fun C.plus(other: C): Submit {
|
||||
submit(emptyMap()) { this@plus + other }
|
||||
return Submit
|
||||
}
|
||||
|
||||
public operator fun C.minus(other: C): Submit {
|
||||
submit(emptyMap()) { this@minus - other }
|
||||
return Submit
|
||||
}
|
||||
|
||||
public operator fun C.times(other: C): C = ring { this@times * other }
|
||||
|
||||
public operator fun C.plus(other: Symbol): Submit {
|
||||
submit(emptyMap(), this)
|
||||
submit(mapOf(other to 1u), ring.one)
|
||||
return Submit
|
||||
}
|
||||
|
||||
public operator fun C.minus(other: Symbol): Submit {
|
||||
submit(emptyMap(), this)
|
||||
submit(mapOf(other to 1u), { -one }, { it - one })
|
||||
return Submit
|
||||
}
|
||||
|
||||
public operator fun C.times(other: Symbol): Term = Term(mapOf(other to 1u), this)
|
||||
|
||||
public operator fun C.plus(other: Term): Submit {
|
||||
submit(emptyMap(), this)
|
||||
other.submit()
|
||||
return Submit
|
||||
}
|
||||
|
||||
public operator fun C.minus(other: Term): Submit {
|
||||
submit(emptyMap(), this)
|
||||
submit(other.signature, { -other.coefficient }, { it - other.coefficient })
|
||||
return Submit
|
||||
}
|
||||
|
||||
public operator fun C.times(other: Term): Term = Term(other.signature, ring { this@times * other.coefficient })
|
||||
|
||||
public operator fun Symbol.plus(other: C): Submit {
|
||||
this.submit()
|
||||
other.submitSelf()
|
||||
return Submit
|
||||
}
|
||||
|
||||
public operator fun Symbol.minus(other: C): Submit {
|
||||
this.submit()
|
||||
submit(emptyMap(), { -other }, { it - other })
|
||||
return Submit
|
||||
}
|
||||
|
||||
public operator fun Symbol.times(other: C): Term = Term(mapOf(this to 1u), other)
|
||||
|
||||
public operator fun Symbol.unaryPlus(): Submit {
|
||||
this.submit()
|
||||
return Submit
|
||||
}
|
||||
|
||||
public operator fun Symbol.unaryMinus(): Submit {
|
||||
submit(mapOf(this to 1u), { -one }, { it - one })
|
||||
return Submit
|
||||
}
|
||||
|
||||
public operator fun Symbol.plus(other: Symbol): Submit {
|
||||
this.submit()
|
||||
other.submit()
|
||||
return Submit
|
||||
}
|
||||
|
||||
public operator fun Symbol.minus(other: Symbol): Submit {
|
||||
this.submit()
|
||||
submit(mapOf(other to 1u), { -one }, { it - one })
|
||||
return Submit
|
||||
}
|
||||
|
||||
public operator fun Symbol.times(other: Symbol): Term =
|
||||
if (this == other) Term(mapOf(this to 2u), ring.one)
|
||||
else Term(mapOf(this to 1u, other to 1u), ring.one)
|
||||
|
||||
public operator fun Symbol.plus(other: Term): Submit {
|
||||
this.submit()
|
||||
other.submit()
|
||||
return Submit
|
||||
}
|
||||
|
||||
public operator fun Symbol.minus(other: Term): Submit {
|
||||
this.submit()
|
||||
submit(other.signature, { -other.coefficient }, { it - other.coefficient })
|
||||
return Submit
|
||||
}
|
||||
|
||||
public operator fun Symbol.times(other: Term): Term =
|
||||
Term(
|
||||
other.signature.withPutOrChanged(this, 1u) { it -> it + 1u },
|
||||
other.coefficient
|
||||
)
|
||||
|
||||
public operator fun Term.plus(other: C): Submit {
|
||||
this.submit()
|
||||
other.submitSelf()
|
||||
return Submit
|
||||
}
|
||||
|
||||
public operator fun Term.minus(other: C): Submit {
|
||||
this.submit()
|
||||
submit(emptyMap(), { -other }, { it - other })
|
||||
return Submit
|
||||
}
|
||||
|
||||
public operator fun Term.times(other: C): Term =
|
||||
Term(
|
||||
signature,
|
||||
ring { coefficient * other }
|
||||
)
|
||||
|
||||
public operator fun Term.plus(other: Symbol): Submit {
|
||||
this.submit()
|
||||
other.submit()
|
||||
return Submit
|
||||
}
|
||||
|
||||
public operator fun Term.minus(other: Symbol): Submit {
|
||||
this.submit()
|
||||
submit(mapOf(other to 1u), { -one }, { it - one })
|
||||
return Submit
|
||||
}
|
||||
|
||||
public operator fun Term.times(other: Symbol): Term =
|
||||
Term(
|
||||
signature.withPutOrChanged(other, 1u) { it -> it + 1u },
|
||||
coefficient
|
||||
)
|
||||
|
||||
public operator fun Term.unaryPlus(): Submit {
|
||||
this.submit()
|
||||
return Submit
|
||||
}
|
||||
|
||||
public operator fun Term.unaryMinus(): Submit {
|
||||
submit(signature, { -coefficient }, { it - coefficient })
|
||||
return Submit
|
||||
}
|
||||
|
||||
public operator fun Term.plus(other: Term): Submit {
|
||||
this.submit()
|
||||
other.submit()
|
||||
return Submit
|
||||
}
|
||||
|
||||
public operator fun Term.minus(other: Term): Submit {
|
||||
this.submit()
|
||||
submit(other.signature, { -other.coefficient }, { it - other.coefficient })
|
||||
return Submit
|
||||
}
|
||||
|
||||
public operator fun Term.times(other: Term): Term =
|
||||
Term(
|
||||
mergeBy(signature, other.signature) { deg1, deg2 -> deg1 + deg2 },
|
||||
ring { coefficient * other.coefficient }
|
||||
)
|
||||
}
|
||||
|
||||
//@UnstableKMathAPI
|
||||
//public fun <C> Ring<C>.LabeledPolynomialDSL2(initialCapacity: Int? = null, block: DSL2LabeledPolynomialBuilder<C>.() -> Unit): LabeledPolynomial<C> = DSL2LabeledPolynomialBuilder(this, initialCapacity).apply(block).build()
|
||||
|
||||
@UnstableKMathAPI
|
||||
public fun <C, A: Ring<C>> LabeledPolynomialSpace<C, A>.LabeledPolynomialDSL2(initialCapacity: Int? = null, block: DSL2LabeledPolynomialBuilder<C>.() -> Unit): LabeledPolynomial<C> = DSL2LabeledPolynomialBuilder(ring, initialCapacity).apply(block).build()
|
||||
|
||||
@UnstableKMathAPI
|
||||
public fun <C, A: Ring<C>> LabeledRationalFunctionSpace<C, A>.LabeledPolynomialDSL2(initialCapacity: Int? = null, block: DSL2LabeledPolynomialBuilder<C>.() -> Unit): LabeledPolynomial<C> = DSL2LabeledPolynomialBuilder(ring, initialCapacity).apply(block).build()
|
||||
|
||||
// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available
|
||||
|
||||
/**
|
||||
* Constructs [LabeledRationalFunction] with provided coefficients maps [numeratorCoefficients] and [denominatorCoefficients].
|
||||
*
|
||||
* The maps will be "cleaned up":
|
||||
* 1. Zeros at the ends of terms' signatures (e.g. the maps' keys) will be removed. (See [cleanUp].)
|
||||
* 1. Terms that happen to have the same signature will be summed up.
|
||||
* 1. New map will be formed of resulting terms.
|
||||
*/
|
||||
public fun <C, A: Ring<C>> A.LabeledRationalFunction(numeratorCoefficients: Map<Map<Symbol, UInt>, C>, denominatorCoefficients: Map<Map<Symbol, UInt>, C>): LabeledRationalFunction<C> =
|
||||
LabeledRationalFunction<C>(
|
||||
LabeledPolynomial(numeratorCoefficients),
|
||||
LabeledPolynomial(denominatorCoefficients)
|
||||
)
|
||||
/**
|
||||
* Constructs [LabeledRationalFunction] with provided coefficients maps [numeratorCoefficients] and [denominatorCoefficients].
|
||||
*
|
||||
* The maps will be "cleaned up":
|
||||
* 1. Zeros at the ends of terms' signatures (e.g. the maps' keys) will be removed. (See [cleanUp].)
|
||||
* 1. Terms that happen to have the same signature will be summed up.
|
||||
* 1. New map will be formed of resulting terms.
|
||||
*/
|
||||
public fun <C, A: Ring<C>> LabeledRationalFunctionSpace<C, A>.LabeledRationalFunction(numeratorCoefficients: Map<Map<Symbol, UInt>, C>, denominatorCoefficients: Map<Map<Symbol, UInt>, C>): LabeledRationalFunction<C> =
|
||||
LabeledRationalFunction<C>(
|
||||
LabeledPolynomial(numeratorCoefficients),
|
||||
LabeledPolynomial(denominatorCoefficients)
|
||||
)
|
||||
|
||||
/**
|
||||
* Constructs [LabeledRationalFunction] with provided [numerator] and unit denominator.
|
||||
*/
|
||||
public fun <C, A: Ring<C>> A.LabeledRationalFunction(numerator: LabeledPolynomial<C>): LabeledRationalFunction<C> =
|
||||
LabeledRationalFunction<C>(numerator, LabeledPolynomial(mapOf(emptyMap<Symbol, UInt>() to one)))
|
||||
/**
|
||||
* Constructs [LabeledRationalFunction] with provided [numerator] and unit denominator.
|
||||
*/
|
||||
public fun <C, A: Ring<C>> LabeledRationalFunctionSpace<C, A>.LabeledRationalFunction(numerator: LabeledPolynomial<C>): LabeledRationalFunction<C> =
|
||||
LabeledRationalFunction<C>(numerator, polynomialOne)
|
||||
|
||||
/**
|
||||
* Constructs [LabeledRationalFunction] with provided coefficients map [numeratorCoefficients] for numerator and unit
|
||||
* denominator.
|
||||
*
|
||||
* [numeratorCoefficients] will be "cleaned up":
|
||||
* 1. Zeros at the ends of terms' signatures (e.g. [numeratorCoefficients]'s keys) will be removed. (See [cleanUp].)
|
||||
* 1. Terms that happen to have the same signature will be summed up.
|
||||
* 1. New map will be formed of resulting terms.
|
||||
*/
|
||||
public fun <C, A: Ring<C>> LabeledRationalFunctionSpace<C, A>.LabeledRationalFunction(numeratorCoefficients: Map<Map<Symbol, UInt>, C>): LabeledRationalFunction<C> =
|
||||
LabeledRationalFunction<C>(
|
||||
LabeledPolynomial(numeratorCoefficients),
|
||||
polynomialOne
|
||||
)
|
||||
/**
|
||||
* Constructs [LabeledRationalFunction] with provided coefficients map [numeratorCoefficients] for numerator and unit
|
||||
* denominator.
|
||||
*
|
||||
* [numeratorCoefficients] will be "cleaned up":
|
||||
* 1. Zeros at the ends of terms' signatures (e.g. [numeratorCoefficients]'s keys) will be removed. (See [cleanUp].)
|
||||
* 1. Terms that happen to have the same signature will be summed up.
|
||||
* 1. New map will be formed of resulting terms.
|
||||
*/
|
||||
public fun <C, A: Ring<C>> A.LabeledRationalFunction(numeratorCoefficients: Map<Map<Symbol, UInt>, C>): LabeledRationalFunction<C> =
|
||||
LabeledRationalFunction<C>(
|
||||
LabeledPolynomial(numeratorCoefficients),
|
||||
LabeledPolynomialAsIs(mapOf(emptyMap<Symbol, UInt>() to one))
|
||||
)
|
||||
|
||||
///**
|
||||
// * Converts [this] constant to [LabeledRationalFunction].
|
||||
// */
|
||||
//context(A)
|
||||
//public fun <C, A: Ring<C>> C.asLabeledRationalFunction() : LabeledRationalFunction<C> =
|
||||
// LabeledRationalFunction(
|
||||
// LabeledPolynomialAsIs(mapOf(emptyMap<Symbol, UInt>() to this)),
|
||||
// LabeledPolynomialAsIs(mapOf(emptyMap<Symbol, UInt>() to one))
|
||||
// )
|
||||
///**
|
||||
// * Converts [this] constant to [LabeledRationalFunction].
|
||||
// */
|
||||
//context(LabeledRationalFunctionSpace<C, A>)
|
||||
//public fun <C, A: Ring<C>> C.asLabeledRationalFunction() : LabeledRationalFunction<C> =
|
||||
// LabeledRationalFunction(
|
||||
// LabeledPolynomialAsIs(mapOf(emptyMap<Symbol, UInt>() to this)),
|
||||
// LabeledPolynomialAsIs(mapOf(emptyMap<Symbol, UInt>() to constantOne))
|
||||
// )
|
||||
|
||||
///**
|
||||
// * Converts [this] variable to [LabeledRationalFunction].
|
||||
// */
|
||||
//context(A)
|
||||
//public fun <C, A: Ring<C>> Symbol.asLabeledRationalFunction() : LabeledRationalFunction<C> =
|
||||
// LabeledRationalFunction(
|
||||
// LabeledPolynomialAsIs(mapOf(mapOf(this to 1u) to one)),
|
||||
// LabeledPolynomialAsIs(mapOf(emptyMap<Symbol, UInt>() to one))
|
||||
// )
|
||||
///**
|
||||
// * Converts [this] variable to [LabeledRationalFunction].
|
||||
// */
|
||||
//context(LabeledRationalFunctionSpace<C, A>)
|
||||
//public fun <C, A: Ring<C>> Symbol.asLabeledRationalFunction() : LabeledRationalFunction<C> =
|
||||
// LabeledRationalFunction(
|
||||
// LabeledPolynomialAsIs(mapOf(mapOf(this to 1u) to constantOne)),
|
||||
// LabeledPolynomialAsIs(mapOf(emptyMap<Symbol, UInt>() to constantOne))
|
||||
// )
|
@ -1,321 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018-2022 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.*
|
||||
import kotlin.contracts.InvocationKind
|
||||
import kotlin.contracts.contract
|
||||
import kotlin.jvm.JvmName
|
||||
|
||||
|
||||
/**
|
||||
* Creates a [LabeledPolynomialSpace] over a received ring.
|
||||
*/
|
||||
public inline val <C, A : Ring<C>> A.labeledPolynomialSpace: LabeledPolynomialSpace<C, A>
|
||||
get() = 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 inline val <C, A : Ring<C>> A.labeledRationalFunctionSpace: LabeledRationalFunctionSpace<C, A>
|
||||
get() = 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)
|
||||
}
|
||||
putOrChange(newDegs, newC, ::add)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
}
|
||||
putOrChange(newDegs, newC, ::add)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.count { it.key.getOrElse(variable) { 0u } >= 1u }) {
|
||||
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.count { it.key.getOrElse(variable) { 0u } >= order }) {
|
||||
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.count {
|
||||
variablesAndOrders.all { (variable, order) ->
|
||||
it.key.getOrElse(variable) { 0u } >= order
|
||||
}
|
||||
}
|
||||
) {
|
||||
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 = degs.withPutOrChanged(variable, 1u) { it -> it + 1u }
|
||||
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 = degs.withPutOrChanged(variable, order) { it -> it + order }
|
||||
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 = mergeBy(degs, filteredVariablesAndOrders) { deg, order -> deg + order }
|
||||
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,92 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018-2022 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
|
||||
|
||||
|
||||
/**
|
||||
* 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 })
|
||||
|
||||
/**
|
||||
* 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 } )
|
||||
)
|
||||
/**
|
||||
* 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(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,255 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018-2022 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 inline val <C, A : Ring<C>> A.listPolynomialSpace: ListPolynomialSpace<C, A>
|
||||
get() = 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 inline val <C, A> A.scalableListPolynomialSpace: ScalableListPolynomialSpace<C, A> where A : Ring<C>, A : ScaleOperations<C>
|
||||
get() = 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 inline val <C, A : Ring<C>> A.listRationalFunctionSpace: ListRationalFunctionSpace<C, A>
|
||||
get() = 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)
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018-2022 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 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.ERROR
|
||||
)
|
||||
public annotation class DelicatePolynomialAPI
|
@ -1,491 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018-2022 KMath contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@file:Suppress("FunctionName", "NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress")
|
||||
|
||||
package space.kscience.kmath.functions
|
||||
|
||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||
import space.kscience.kmath.operations.Ring
|
||||
|
||||
|
||||
/**
|
||||
* Returns the same degrees' description of the monomial, but without extra zero degrees on the end.
|
||||
*/
|
||||
internal fun List<UInt>.cleanUp() = subList(0, indexOfLast { it != 0U } + 1)
|
||||
|
||||
/**
|
||||
* Constructs [NumberedPolynomial] with provided coefficients map [coefs]. The map is used as is.
|
||||
*/
|
||||
@PublishedApi
|
||||
internal inline fun <C> NumberedPolynomialAsIs(coefs: Map<List<UInt>, C>) : NumberedPolynomial<C> = NumberedPolynomial<C>(coefs)
|
||||
|
||||
/**
|
||||
* Constructs [NumberedPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient".
|
||||
* The collections will be transformed to map with [toMap] and then will be used as is.
|
||||
*/
|
||||
@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.
|
||||
*
|
||||
* @see NumberedPolynomialWithoutCheck
|
||||
*/
|
||||
public fun <C> NumberedPolynomial(coefs: Map<List<UInt>, C>, add: (C, C) -> C) : NumberedPolynomial<C> =
|
||||
NumberedPolynomialAsIs(
|
||||
coefs.mapKeys({ key, _ -> key.cleanUp() }, 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.
|
||||
*
|
||||
* @see NumberedPolynomialWithoutCheck
|
||||
*/
|
||||
public fun <C> NumberedPolynomial(pairs: Collection<Pair<List<UInt>, C>>, add: (C, C) -> C) : NumberedPolynomial<C> =
|
||||
NumberedPolynomialAsIs(
|
||||
pairs.associateBy({ it.first.cleanUp() }, { it.second }, add)
|
||||
)
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @see NumberedPolynomialWithoutCheck
|
||||
*/
|
||||
public fun <C> NumberedPolynomial(vararg pairs: Pair<List<UInt>, C>, add: (C, C) -> C) : NumberedPolynomial<C> =
|
||||
NumberedPolynomialAsIs(
|
||||
pairs.asIterable().associateBy({ it.first.cleanUp() }, { it.second }, add)
|
||||
)
|
||||
|
||||
// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available
|
||||
|
||||
/**
|
||||
* Constructs [NumberedPolynomial] with provided coefficients map [coefs].
|
||||
*
|
||||
* [coefs] will be "cleaned up":
|
||||
* 1. Zeros at the ends of terms' signatures (e.g. [coefs] keys) will be removed. (See [cleanUp].)
|
||||
* 1. Terms that happen to have the same signature will be summed up.
|
||||
* 1. New map will be formed of resulting terms.
|
||||
*
|
||||
* @see NumberedPolynomialWithoutCheck
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @see NumberedPolynomialWithoutCheck
|
||||
*/
|
||||
public inline fun <C, A: Ring<C>> NumberedPolynomialSpace<C, A>.NumberedPolynomial(coefs: Map<List<UInt>, C>) : NumberedPolynomial<C> = NumberedPolynomial(coefs) { left: C, right: C -> left + right }
|
||||
|
||||
/**
|
||||
* Constructs [NumberedPolynomial] with provided coefficients map [coefs].
|
||||
*
|
||||
* [coefs] will be "cleaned up":
|
||||
* 1. Zeros at the ends of terms' signatures (e.g. [coefs] keys) will be removed. (See [cleanUp].)
|
||||
* 1. Terms that happen to have the same signature will be summed up.
|
||||
* 1. New map will be formed of resulting terms.
|
||||
*
|
||||
* @see NumberedPolynomialWithoutCheck
|
||||
*/
|
||||
public inline fun <C, A: Ring<C>> NumberedRationalFunctionSpace<C, A>.NumberedPolynomial(coefs: Map<List<UInt>, C>) : NumberedPolynomial<C> = NumberedPolynomial(coefs) { left: C, right: C -> left + right }
|
||||
|
||||
/**
|
||||
* Constructs [NumberedPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient".
|
||||
*
|
||||
* [pairs] will be "cleaned up":
|
||||
* 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].)
|
||||
* 1. Terms that happen to have the same signature will be summed up.
|
||||
* 1. New map will be formed of resulting terms.
|
||||
*
|
||||
* @see NumberedPolynomialWithoutCheck
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @see NumberedPolynomialWithoutCheck
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @see NumberedPolynomialWithoutCheck
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @see NumberedPolynomialWithoutCheck
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @see NumberedPolynomialWithoutCheck
|
||||
*/
|
||||
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_0^2 x_2^3 - 6 x_1\) can be described as
|
||||
* ```
|
||||
* Int.algebra {
|
||||
* val numberedPolynomial : NumberedPolynomial<Int> = NumberedPolynomial {
|
||||
* 5 { 0 inPowerOf 2u; 2 inPowerOf 3u } // 5 x_0^2 x_2^3 +
|
||||
* (-6) { 1 inPowerOf 1u } // (-6) x_1^1
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
* @usesMathJax
|
||||
*/
|
||||
@DslMarker
|
||||
@UnstableKMathAPI
|
||||
internal annotation class NumberedPolynomialConstructorDSL1
|
||||
|
||||
/**
|
||||
* Builder of [NumberedPolynomial] signature. It should be used as an implicit context for lambdas that describe term signature.
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
@NumberedPolynomialConstructorDSL1
|
||||
public class DSL1NumberedPolynomialTermSignatureBuilder {
|
||||
/**
|
||||
* Signature storage. Any declaration of any variable's power updates the storage by increasing corresponding value.
|
||||
* Afterward the storage will be used as a resulting signature.
|
||||
*/
|
||||
private val signature: MutableList<UInt> = ArrayList()
|
||||
|
||||
/**
|
||||
* Builds the resulting signature.
|
||||
*
|
||||
* In fact, it just returns [signature] as regular signature of type `List<UInt>`.
|
||||
*/
|
||||
@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 (deg == 0u) return
|
||||
val index = this
|
||||
if (index > signature.lastIndex) {
|
||||
signature.addAll(List(index - signature.lastIndex - 1) { 0u })
|
||||
signature.add(deg)
|
||||
} else {
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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
|
||||
@NumberedPolynomialConstructorDSL1
|
||||
public class DSL1NumberedPolynomialBuilder<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? = null
|
||||
) {
|
||||
/**
|
||||
* 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> = if (initialCapacity != null) LinkedHashMap(initialCapacity) else LinkedHashMap()
|
||||
|
||||
/**
|
||||
* 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.putOrChange(signature, this@with, add)
|
||||
}
|
||||
/**
|
||||
* 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 infix fun C.with(noinline block: DSL1NumberedPolynomialTermSignatureBuilder.() -> Unit): Unit = this.invoke(block)
|
||||
/**
|
||||
* Declares monomial with [this] coefficient and signature constructed by [block].
|
||||
*
|
||||
* Declaring another monomial with the same signature will add [this] coefficient to existing one. If the sum of such
|
||||
* coefficients is zero at any moment the monomial won't be removed but will be left as it is.
|
||||
*/
|
||||
public inline operator fun C.invoke(block: DSL1NumberedPolynomialTermSignatureBuilder.() -> Unit): Unit =
|
||||
this with DSL1NumberedPolynomialTermSignatureBuilder().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_0^2 x_2^3 - 6 x_1\) can be described as
|
||||
// * ```
|
||||
// * Int.algebra {
|
||||
// * val numberedPolynomial : NumberedPolynomial<Int> = NumberedPolynomial {
|
||||
// * 5 { 0 inPowerOf 2u; 2 inPowerOf 3u } // 5 x_0^2 x_2^3 +
|
||||
// * (-6) { 1 inPowerOf 1u } // (-6) x_1^1
|
||||
// * }
|
||||
// * }
|
||||
// * ```
|
||||
// * @usesMathJax
|
||||
// */
|
||||
// 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.NumberedPolynomialDSL1(initialCapacity: Int? = null, 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_0^2 x_2^3 - 6 x_1\) can be described as
|
||||
* ```
|
||||
* Int.algebra {
|
||||
* val numberedPolynomial : NumberedPolynomial<Int> = NumberedPolynomial {
|
||||
* 5 { 0 inPowerOf 2u; 2 inPowerOf 3u } // 5 x_0^2 x_2^3 +
|
||||
* (-6) { 1 inPowerOf 1u } // (-6) x_1^1
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
* @usesMathJax
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public inline fun <C, A: Ring<C>> NumberedPolynomialSpace<C, A>.NumberedPolynomialDSL1(initialCapacity: Int? = null, block: DSL1NumberedPolynomialBuilder<C>.() -> Unit) : NumberedPolynomial<C> = DSL1NumberedPolynomialBuilder({ 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_0^2 x_2^3 - 6 x_1\) can be described as
|
||||
* ```
|
||||
* Int.algebra {
|
||||
* val numberedPolynomial : NumberedPolynomial<Int> = NumberedPolynomial {
|
||||
* 5 { 0 inPowerOf 2u; 2 inPowerOf 3u } // 5 x_0^2 x_2^3 +
|
||||
* (-6) { 1 inPowerOf 1u } // (-6) x_1^1
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
* @usesMathJax
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public inline fun <C, A: Ring<C>> NumberedRationalFunctionSpace<C, A>.NumberedPolynomialDSL1(initialCapacity: Int? = null, block: DSL1NumberedPolynomialBuilder<C>.() -> Unit) : NumberedPolynomial<C> = DSL1NumberedPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build()
|
||||
|
||||
// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available
|
||||
|
||||
/**
|
||||
* Constructs [NumberedRationalFunction] with provided coefficients maps [numeratorCoefficients] and [denominatorCoefficients].
|
||||
*
|
||||
* The maps will be "cleaned up":
|
||||
* 1. Zeros at the ends of terms' signatures (e.g. the maps' keys) will be removed. (See [cleanUp].)
|
||||
* 1. Terms that happen to have the same signature will be summed up.
|
||||
* 1. New map will be formed of resulting terms.
|
||||
*/
|
||||
public fun <C, A: Ring<C>> A.NumberedRationalFunction(numeratorCoefficients: Map<List<UInt>, C>, denominatorCoefficients: Map<List<UInt>, C>): NumberedRationalFunction<C> =
|
||||
NumberedRationalFunction<C>(
|
||||
NumberedPolynomial(numeratorCoefficients),
|
||||
NumberedPolynomial(denominatorCoefficients)
|
||||
)
|
||||
/**
|
||||
* Constructs [NumberedRationalFunction] with provided coefficients maps [numeratorCoefficients] and [denominatorCoefficients].
|
||||
*
|
||||
* The maps will be "cleaned up":
|
||||
* 1. Zeros at the ends of terms' signatures (e.g. the maps' keys) will be removed. (See [cleanUp].)
|
||||
* 1. Terms that happen to have the same signature will be summed up.
|
||||
* 1. New map will be formed of resulting terms.
|
||||
*/
|
||||
public fun <C, A: Ring<C>> NumberedRationalFunctionSpace<C, A>.NumberedRationalFunction(numeratorCoefficients: Map<List<UInt>, C>, denominatorCoefficients: Map<List<UInt>, C>): NumberedRationalFunction<C> =
|
||||
NumberedRationalFunction<C>(
|
||||
NumberedPolynomial(numeratorCoefficients),
|
||||
NumberedPolynomial(denominatorCoefficients)
|
||||
)
|
||||
|
||||
/**
|
||||
* Constructs [NumberedRationalFunction] with provided [numerator] and unit denominator.
|
||||
*/
|
||||
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(
|
||||
// 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(
|
||||
// NumberedPolynomialAsIs(mapOf(emptyList<UInt>() to this)),
|
||||
// NumberedPolynomialAsIs(mapOf(emptyList<UInt>() to constantOne))
|
||||
// )
|
@ -1,513 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018-2022 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 inline val <C, A : Ring<C>> A.numberedPolynomialSpace: NumberedPolynomialSpace<C, A>
|
||||
get() = 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 inline val <C, A : Ring<C>> A.numberedRationalFunctionSpace: NumberedRationalFunctionSpace<C, A>
|
||||
get() = 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())
|
||||
}
|
||||
putOrChange(newDegs, newC) { it -> it + 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)
|
||||
}
|
||||
putOrChange(newDegs, newC) { it -> it + 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())
|
||||
}
|
||||
putOrChange(newDegs, newC) { it -> it + 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)
|
||||
}
|
||||
putOrChange(newDegs, newC) { it -> it + 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)
|
||||
}
|
||||
|
||||
internal const val fullSubstitutionExceptionMessage: String = "Fully substituting buffer should cover all variables of the polynomial."
|
||||
|
||||
/**
|
||||
* 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 }) { fullSubstitutionExceptionMessage }
|
||||
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 }) { fullSubstitutionExceptionMessage }
|
||||
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.count { it.key.getOrElse(variable) { 0u } >= 1u }) {
|
||||
coefficients
|
||||
.forEach { (degs, c) ->
|
||||
if (degs.lastIndex < 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.count { it.key.getOrElse(variable) { 0u } >= order }) {
|
||||
coefficients
|
||||
.forEach { (degs, c) ->
|
||||
if (degs.lastIndex < 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.lastIndex < 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)) { degs.getOrElse(it) { 0u } + if (it != variable) 0u else 1u },
|
||||
c / multiplyByDoubling(one, degs.getOrElse(variable) { 0u } + 1u)
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)) { degs.getOrElse(it) { 0u } + if (it != variable) 0u else order },
|
||||
degs.getOrElse(variable) { 0u }.let { deg ->
|
||||
(deg + 1u .. deg + order)
|
||||
.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.getOrElse(it) { 0u } + filteredVariablesAndOrders.getOrElse(it) { 0u } },
|
||||
filteredVariablesAndOrders.entries.fold(c) { acc1, (variable, order) ->
|
||||
degs.getOrElse(variable) { 0u }.let { deg ->
|
||||
(deg + 1u .. deg + order)
|
||||
.fold(acc1) { acc, ord -> acc / multiplyByDoubling(one, ord) }
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
@ -1,589 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018-2022 KMath contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package space.kscience.kmath.functions
|
||||
|
||||
|
||||
import space.kscience.kmath.operations.invoke
|
||||
import space.kscience.kmath.operations.Field
|
||||
import kotlin.jvm.JvmInline
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
@JvmInline
|
||||
value class Expr(val expr: String)
|
||||
|
||||
object ExprRing : Field<Expr> {
|
||||
override fun Expr.unaryMinus(): Expr = Expr("-${expr}")
|
||||
override fun add(left: Expr, right: Expr): Expr = Expr("(${left.expr} + ${right.expr})")
|
||||
override fun multiply(left: Expr, right: Expr): Expr = Expr("(${left.expr} * ${right.expr})")
|
||||
override val zero: Expr = Expr("0")
|
||||
override val one: Expr = Expr("1")
|
||||
override fun divide(left: Expr, right: Expr): Expr = Expr("(${left.expr} / ${right.expr})")
|
||||
override fun scale(a: Expr, value: Double): Expr = Expr("(${a.expr} / $value)")
|
||||
}
|
||||
|
||||
class AlgebraicStubTest {
|
||||
@Test
|
||||
fun test_addMultipliedBySquaring_for_UInt() {
|
||||
ExprRing {
|
||||
assertEquals(
|
||||
"57",
|
||||
addMultipliedByDoubling(Expr("57"), Expr("179"), 0u).expr,
|
||||
"tried addMultipliedBySquaring(57, 179, 0u)"
|
||||
)
|
||||
assertEquals(
|
||||
"(57 + 179)",
|
||||
addMultipliedByDoubling(Expr("57"), Expr("179"), 1u).expr,
|
||||
"tried addMultipliedBySquaring(57, 179, 1u)"
|
||||
)
|
||||
assertEquals(
|
||||
"(57 + (179 + 179))",
|
||||
addMultipliedByDoubling(Expr("57"), Expr("179"), 2u).expr,
|
||||
"tried addMultipliedBySquaring(57, 179, 2u)"
|
||||
)
|
||||
assertEquals(
|
||||
"((57 + 179) + (179 + 179))",
|
||||
addMultipliedByDoubling(Expr("57"), Expr("179"), 3u).expr,
|
||||
"tried addMultipliedBySquaring(57, 179, 3u)"
|
||||
)
|
||||
assertEquals(
|
||||
"(57 + ((179 + 179) + (179 + 179)))",
|
||||
addMultipliedByDoubling(Expr("57"), Expr("179"), 4u).expr,
|
||||
"tried addMultipliedBySquaring(57, 179, 4u)"
|
||||
)
|
||||
assertEquals(
|
||||
"((57 + 179) + ((179 + 179) + (179 + 179)))",
|
||||
addMultipliedByDoubling(Expr("57"), Expr("179"), 5u).expr,
|
||||
"tried addMultipliedBySquaring(57, 179, 5u)"
|
||||
)
|
||||
assertEquals(
|
||||
"((57 + (179 + 179)) + ((179 + 179) + (179 + 179)))",
|
||||
addMultipliedByDoubling(Expr("57"), Expr("179"), 6u).expr,
|
||||
"tried addMultipliedBySquaring(57, 179, 6u)"
|
||||
)
|
||||
assertEquals(
|
||||
"(((57 + 179) + (179 + 179)) + ((179 + 179) + (179 + 179)))",
|
||||
addMultipliedByDoubling(Expr("57"), Expr("179"), 7u).expr,
|
||||
"tried addMultipliedBySquaring(57, 179, 7u)"
|
||||
)
|
||||
assertEquals(
|
||||
"(57 + (((179 + 179) + (179 + 179)) + ((179 + 179) + (179 + 179))))",
|
||||
addMultipliedByDoubling(Expr("57"), Expr("179"), 8u).expr,
|
||||
"tried addMultipliedBySquaring(57, 179, 8u)"
|
||||
)
|
||||
}
|
||||
}
|
||||
@Test
|
||||
fun test_multiplyBySquaring_for_UInt() {
|
||||
ExprRing {
|
||||
assertEquals(
|
||||
"0",
|
||||
multiplyByDoubling(Expr("57"), 0u).expr,
|
||||
"tried multiplyBySquaring(57, 0u)"
|
||||
)
|
||||
assertEquals(
|
||||
"57",
|
||||
multiplyByDoubling(Expr("57"), 1u).expr,
|
||||
"tried multiplyBySquaring(57, 1u)"
|
||||
)
|
||||
assertEquals(
|
||||
"(57 + 57)",
|
||||
multiplyByDoubling(Expr("57"), 2u).expr,
|
||||
"tried multiplyBySquaring(57, 2u)"
|
||||
)
|
||||
assertEquals(
|
||||
"(57 + (57 + 57))",
|
||||
multiplyByDoubling(Expr("57"), 3u).expr,
|
||||
"tried multiplyBySquaring(57, 3u)"
|
||||
)
|
||||
assertEquals(
|
||||
"((57 + 57) + (57 + 57))",
|
||||
multiplyByDoubling(Expr("57"), 4u).expr,
|
||||
"tried multiplyBySquaring(57, 4u)"
|
||||
)
|
||||
assertEquals(
|
||||
"(57 + ((57 + 57) + (57 + 57)))",
|
||||
multiplyByDoubling(Expr("57"), 5u).expr,
|
||||
"tried multiplyBySquaring(57, 5u)"
|
||||
)
|
||||
assertEquals(
|
||||
"((57 + 57) + ((57 + 57) + (57 + 57)))",
|
||||
multiplyByDoubling(Expr("57"), 6u).expr,
|
||||
"tried multiplyBySquaring(57, 6u)"
|
||||
)
|
||||
assertEquals(
|
||||
"((57 + (57 + 57)) + ((57 + 57) + (57 + 57)))",
|
||||
multiplyByDoubling(Expr("57"), 7u).expr,
|
||||
"tried multiplyBySquaring(57, 7u)"
|
||||
)
|
||||
assertEquals(
|
||||
"(((57 + 57) + (57 + 57)) + ((57 + 57) + (57 + 57)))",
|
||||
multiplyByDoubling(Expr("57"), 8u).expr,
|
||||
"tried multiplyBySquaring(57, 8u)"
|
||||
)
|
||||
}
|
||||
}
|
||||
@Test
|
||||
fun test_addMultipliedBySquaring_for_Int() {
|
||||
ExprRing {
|
||||
assertEquals(
|
||||
"57",
|
||||
addMultipliedByDoubling(Expr("57"), Expr("179"), 0).expr,
|
||||
"tried addMultipliedBySquaring(57, 179, 0)"
|
||||
)
|
||||
assertEquals(
|
||||
"(57 + 179)",
|
||||
addMultipliedByDoubling(Expr("57"), Expr("179"), 1).expr,
|
||||
"tried addMultipliedBySquaring(57, 179, 1)"
|
||||
)
|
||||
assertEquals(
|
||||
"(57 + -179)",
|
||||
addMultipliedByDoubling(Expr("57"), Expr("179"), -1).expr,
|
||||
"tried addMultipliedBySquaring(57, 179, -1)"
|
||||
)
|
||||
assertEquals(
|
||||
"(57 + (179 + 179))",
|
||||
addMultipliedByDoubling(Expr("57"), Expr("179"), 2).expr,
|
||||
"tried addMultipliedBySquaring(57, 179, 2)"
|
||||
)
|
||||
assertEquals(
|
||||
"(57 + (-179 + -179))",
|
||||
addMultipliedByDoubling(Expr("57"), Expr("179"), -2).expr,
|
||||
"tried addMultipliedBySquaring(57, 179, -2)"
|
||||
)
|
||||
assertEquals(
|
||||
"((57 + 179) + (179 + 179))",
|
||||
addMultipliedByDoubling(Expr("57"), Expr("179"), 3).expr,
|
||||
"tried addMultipliedBySquaring(57, 179, 3)"
|
||||
)
|
||||
assertEquals(
|
||||
"((57 + -179) + (-179 + -179))",
|
||||
addMultipliedByDoubling(Expr("57"), Expr("179"), -3).expr,
|
||||
"tried addMultipliedBySquaring(57, 179, -3)"
|
||||
)
|
||||
assertEquals(
|
||||
"(57 + ((179 + 179) + (179 + 179)))",
|
||||
addMultipliedByDoubling(Expr("57"), Expr("179"), 4).expr,
|
||||
"tried addMultipliedBySquaring(57, 179, 4)"
|
||||
)
|
||||
assertEquals(
|
||||
"(57 + ((-179 + -179) + (-179 + -179)))",
|
||||
addMultipliedByDoubling(Expr("57"), Expr("179"), -4).expr,
|
||||
"tried addMultipliedBySquaring(57, 179, -4)"
|
||||
)
|
||||
assertEquals(
|
||||
"((57 + 179) + ((179 + 179) + (179 + 179)))",
|
||||
addMultipliedByDoubling(Expr("57"), Expr("179"), 5).expr,
|
||||
"tried addMultipliedBySquaring(57, 179, 5)"
|
||||
)
|
||||
assertEquals(
|
||||
"((57 + -179) + ((-179 + -179) + (-179 + -179)))",
|
||||
addMultipliedByDoubling(Expr("57"), Expr("179"), -5).expr,
|
||||
"tried addMultipliedBySquaring(57, 179, -5)"
|
||||
)
|
||||
assertEquals(
|
||||
"((57 + (179 + 179)) + ((179 + 179) + (179 + 179)))",
|
||||
addMultipliedByDoubling(Expr("57"), Expr("179"), 6).expr,
|
||||
"tried addMultipliedBySquaring(57, 179, 6)"
|
||||
)
|
||||
assertEquals(
|
||||
"((57 + (-179 + -179)) + ((-179 + -179) + (-179 + -179)))",
|
||||
addMultipliedByDoubling(Expr("57"), Expr("179"), -6).expr,
|
||||
"tried addMultipliedBySquaring(57, 179, -6)"
|
||||
)
|
||||
assertEquals(
|
||||
"(((57 + 179) + (179 + 179)) + ((179 + 179) + (179 + 179)))",
|
||||
addMultipliedByDoubling(Expr("57"), Expr("179"), 7).expr,
|
||||
"tried addMultipliedBySquaring(57, 179, 7)"
|
||||
)
|
||||
assertEquals(
|
||||
"(((57 + -179) + (-179 + -179)) + ((-179 + -179) + (-179 + -179)))",
|
||||
addMultipliedByDoubling(Expr("57"), Expr("179"), -7).expr,
|
||||
"tried addMultipliedBySquaring(57, 179, -7)"
|
||||
)
|
||||
assertEquals(
|
||||
"(57 + (((179 + 179) + (179 + 179)) + ((179 + 179) + (179 + 179))))",
|
||||
addMultipliedByDoubling(Expr("57"), Expr("179"), 8).expr,
|
||||
"tried addMultipliedBySquaring(57, 179, 8)"
|
||||
)
|
||||
assertEquals(
|
||||
"(57 + (((-179 + -179) + (-179 + -179)) + ((-179 + -179) + (-179 + -179))))",
|
||||
addMultipliedByDoubling(Expr("57"), Expr("179"), -8).expr,
|
||||
"tried addMultipliedBySquaring(57, 179, -8)"
|
||||
)
|
||||
}
|
||||
}
|
||||
@Test
|
||||
fun test_multiplyBySquaring_for_Int() {
|
||||
ExprRing {
|
||||
assertEquals(
|
||||
"0",
|
||||
multiplyByDoubling(Expr("57"), 0).expr,
|
||||
"tried multiplyBySquaring(57, 0)"
|
||||
)
|
||||
assertEquals(
|
||||
"57",
|
||||
multiplyByDoubling(Expr("57"), 1).expr,
|
||||
"tried multiplyBySquaring(57, 1)"
|
||||
)
|
||||
assertEquals(
|
||||
"-57",
|
||||
multiplyByDoubling(Expr("57"), -1).expr,
|
||||
"tried multiplyBySquaring(57, -1)"
|
||||
)
|
||||
assertEquals(
|
||||
"(57 + 57)",
|
||||
multiplyByDoubling(Expr("57"), 2).expr,
|
||||
"tried multiplyBySquaring(57, 2)"
|
||||
)
|
||||
assertEquals(
|
||||
"(-57 + -57)",
|
||||
multiplyByDoubling(Expr("57"), -2).expr,
|
||||
"tried multiplyBySquaring(57, -2)"
|
||||
)
|
||||
assertEquals(
|
||||
"(57 + (57 + 57))",
|
||||
multiplyByDoubling(Expr("57"), 3).expr,
|
||||
"tried multiplyBySquaring(57, 3)"
|
||||
)
|
||||
assertEquals(
|
||||
"(-57 + (-57 + -57))",
|
||||
multiplyByDoubling(Expr("57"), -3).expr,
|
||||
"tried multiplyBySquaring(57, -3)"
|
||||
)
|
||||
assertEquals(
|
||||
"((57 + 57) + (57 + 57))",
|
||||
multiplyByDoubling(Expr("57"), 4).expr,
|
||||
"tried multiplyBySquaring(57, 4)"
|
||||
)
|
||||
assertEquals(
|
||||
"((-57 + -57) + (-57 + -57))",
|
||||
multiplyByDoubling(Expr("57"), -4).expr,
|
||||
"tried multiplyBySquaring(57, -4)"
|
||||
)
|
||||
assertEquals(
|
||||
"(57 + ((57 + 57) + (57 + 57)))",
|
||||
multiplyByDoubling(Expr("57"), 5).expr,
|
||||
"tried multiplyBySquaring(57, 5)"
|
||||
)
|
||||
assertEquals(
|
||||
"(-57 + ((-57 + -57) + (-57 + -57)))",
|
||||
multiplyByDoubling(Expr("57"), -5).expr,
|
||||
"tried multiplyBySquaring(57, -5)"
|
||||
)
|
||||
assertEquals(
|
||||
"((57 + 57) + ((57 + 57) + (57 + 57)))",
|
||||
multiplyByDoubling(Expr("57"), 6).expr,
|
||||
"tried multiplyBySquaring(57, 6)"
|
||||
)
|
||||
assertEquals(
|
||||
"((-57 + -57) + ((-57 + -57) + (-57 + -57)))",
|
||||
multiplyByDoubling(Expr("57"), -6).expr,
|
||||
"tried multiplyBySquaring(57, -6)"
|
||||
)
|
||||
assertEquals(
|
||||
"((57 + (57 + 57)) + ((57 + 57) + (57 + 57)))",
|
||||
multiplyByDoubling(Expr("57"), 7).expr,
|
||||
"tried multiplyBySquaring(57, 7)"
|
||||
)
|
||||
assertEquals(
|
||||
"((-57 + (-57 + -57)) + ((-57 + -57) + (-57 + -57)))",
|
||||
multiplyByDoubling(Expr("57"), -7).expr,
|
||||
"tried multiplyBySquaring(57, -7)"
|
||||
)
|
||||
assertEquals(
|
||||
"(((57 + 57) + (57 + 57)) + ((57 + 57) + (57 + 57)))",
|
||||
multiplyByDoubling(Expr("57"), 8).expr,
|
||||
"tried multiplyBySquaring(57, 8)"
|
||||
)
|
||||
assertEquals(
|
||||
"(((-57 + -57) + (-57 + -57)) + ((-57 + -57) + (-57 + -57)))",
|
||||
multiplyByDoubling(Expr("57"), -8).expr,
|
||||
"tried multiplyBySquaring(57, -8)"
|
||||
)
|
||||
}
|
||||
}
|
||||
@Test
|
||||
fun test_multiplyExponentiationBySquaring_for_UInt() {
|
||||
ExprRing {
|
||||
assertEquals(
|
||||
"57",
|
||||
multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 0u).expr,
|
||||
"tried multiplyExponentiationBySquaring(57, 179, 0u)"
|
||||
)
|
||||
assertEquals(
|
||||
"(57 * 179)",
|
||||
multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 1u).expr,
|
||||
"tried multiplyExponentiationBySquaring(57, 179, 1u)"
|
||||
)
|
||||
assertEquals(
|
||||
"(57 * (179 * 179))",
|
||||
multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 2u).expr,
|
||||
"tried multiplyExponentiationBySquaring(57, 179, 2u)"
|
||||
)
|
||||
assertEquals(
|
||||
"((57 * 179) * (179 * 179))",
|
||||
multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 3u).expr,
|
||||
"tried multiplyExponentiationBySquaring(57, 179, 3u)"
|
||||
)
|
||||
assertEquals(
|
||||
"(57 * ((179 * 179) * (179 * 179)))",
|
||||
multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 4u).expr,
|
||||
"tried multiplyExponentiationBySquaring(57, 179, 4u)"
|
||||
)
|
||||
assertEquals(
|
||||
"((57 * 179) * ((179 * 179) * (179 * 179)))",
|
||||
multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 5u).expr,
|
||||
"tried multiplyExponentiationBySquaring(57, 179, 5u)"
|
||||
)
|
||||
assertEquals(
|
||||
"((57 * (179 * 179)) * ((179 * 179) * (179 * 179)))",
|
||||
multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 6u).expr,
|
||||
"tried multiplyExponentiationBySquaring(57, 179, 6u)"
|
||||
)
|
||||
assertEquals(
|
||||
"(((57 * 179) * (179 * 179)) * ((179 * 179) * (179 * 179)))",
|
||||
multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 7u).expr,
|
||||
"tried multiplyExponentiationBySquaring(57, 179, 7u)"
|
||||
)
|
||||
assertEquals(
|
||||
"(57 * (((179 * 179) * (179 * 179)) * ((179 * 179) * (179 * 179))))",
|
||||
multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 8u).expr,
|
||||
"tried multiplyExponentiationBySquaring(57, 179, 8u)"
|
||||
)
|
||||
}
|
||||
}
|
||||
@Test
|
||||
fun test_exponentiationBySquaring_for_UInt() {
|
||||
ExprRing {
|
||||
assertEquals(
|
||||
"0",
|
||||
exponentiateBySquaring(Expr("57"), 0u).expr,
|
||||
"tried exponentiationBySquaring(57, 0u)"
|
||||
)
|
||||
assertEquals(
|
||||
"57",
|
||||
exponentiateBySquaring(Expr("57"), 1u).expr,
|
||||
"tried exponentiationBySquaring(57, 1u)"
|
||||
)
|
||||
assertEquals(
|
||||
"(57 * 57)",
|
||||
exponentiateBySquaring(Expr("57"), 2u).expr,
|
||||
"tried exponentiationBySquaring(57, 2u)"
|
||||
)
|
||||
assertEquals(
|
||||
"(57 * (57 * 57))",
|
||||
exponentiateBySquaring(Expr("57"), 3u).expr,
|
||||
"tried exponentiationBySquaring(57, 3u)"
|
||||
)
|
||||
assertEquals(
|
||||
"((57 * 57) * (57 * 57))",
|
||||
exponentiateBySquaring(Expr("57"), 4u).expr,
|
||||
"tried exponentiationBySquaring(57, 4u)"
|
||||
)
|
||||
assertEquals(
|
||||
"(57 * ((57 * 57) * (57 * 57)))",
|
||||
exponentiateBySquaring(Expr("57"), 5u).expr,
|
||||
"tried exponentiationBySquaring(57, 5u)"
|
||||
)
|
||||
assertEquals(
|
||||
"((57 * 57) * ((57 * 57) * (57 * 57)))",
|
||||
exponentiateBySquaring(Expr("57"), 6u).expr,
|
||||
"tried exponentiationBySquaring(57, 6u)"
|
||||
)
|
||||
assertEquals(
|
||||
"((57 * (57 * 57)) * ((57 * 57) * (57 * 57)))",
|
||||
exponentiateBySquaring(Expr("57"), 7u).expr,
|
||||
"tried exponentiationBySquaring(57, 7u)"
|
||||
)
|
||||
assertEquals(
|
||||
"(((57 * 57) * (57 * 57)) * ((57 * 57) * (57 * 57)))",
|
||||
exponentiateBySquaring(Expr("57"), 8u).expr,
|
||||
"tried exponentiationBySquaring(57, 8u)"
|
||||
)
|
||||
}
|
||||
}
|
||||
@Test
|
||||
fun test_multiplyExponentiationBySquaring_for_Int() {
|
||||
ExprRing {
|
||||
assertEquals(
|
||||
"57",
|
||||
multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 0).expr,
|
||||
"tried multiplyExponentiationBySquaring(57, 179, 0)"
|
||||
)
|
||||
assertEquals(
|
||||
"(57 * 179)",
|
||||
multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 1).expr,
|
||||
"tried multiplyExponentiationBySquaring(57, 179, 1)"
|
||||
)
|
||||
assertEquals(
|
||||
"(57 * (1 / 179))",
|
||||
multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -1).expr,
|
||||
"tried multiplyExponentiationBySquaring(57, 179, -1)"
|
||||
)
|
||||
assertEquals(
|
||||
"(57 * (179 * 179))",
|
||||
multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 2).expr,
|
||||
"tried multiplyExponentiationBySquaring(57, 179, 2)"
|
||||
)
|
||||
assertEquals(
|
||||
"(57 * ((1 / 179) * (1 / 179)))",
|
||||
multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -2).expr,
|
||||
"tried multiplyExponentiationBySquaring(57, 179, -2)"
|
||||
)
|
||||
assertEquals(
|
||||
"((57 * 179) * (179 * 179))",
|
||||
multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 3).expr,
|
||||
"tried multiplyExponentiationBySquaring(57, 179, 3)"
|
||||
)
|
||||
assertEquals(
|
||||
"((57 * (1 / 179)) * ((1 / 179) * (1 / 179)))",
|
||||
multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -3).expr,
|
||||
"tried multiplyExponentiationBySquaring(57, 179, -3)"
|
||||
)
|
||||
assertEquals(
|
||||
"(57 * ((179 * 179) * (179 * 179)))",
|
||||
multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 4).expr,
|
||||
"tried multiplyExponentiationBySquaring(57, 179, 4)"
|
||||
)
|
||||
assertEquals(
|
||||
"(57 * (((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179))))",
|
||||
multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -4).expr,
|
||||
"tried multiplyExponentiationBySquaring(57, 179, -4)"
|
||||
)
|
||||
assertEquals(
|
||||
"((57 * 179) * ((179 * 179) * (179 * 179)))",
|
||||
multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 5).expr,
|
||||
"tried multiplyExponentiationBySquaring(57, 179, 5)"
|
||||
)
|
||||
assertEquals(
|
||||
"((57 * (1 / 179)) * (((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179))))",
|
||||
multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -5).expr,
|
||||
"tried multiplyExponentiationBySquaring(57, 179, -5)"
|
||||
)
|
||||
assertEquals(
|
||||
"((57 * (179 * 179)) * ((179 * 179) * (179 * 179)))",
|
||||
multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 6).expr,
|
||||
"tried multiplyExponentiationBySquaring(57, 179, 6)"
|
||||
)
|
||||
assertEquals(
|
||||
"((57 * ((1 / 179) * (1 / 179))) * (((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179))))",
|
||||
multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -6).expr,
|
||||
"tried multiplyExponentiationBySquaring(57, 179, -6)"
|
||||
)
|
||||
assertEquals(
|
||||
"(((57 * 179) * (179 * 179)) * ((179 * 179) * (179 * 179)))",
|
||||
multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 7).expr,
|
||||
"tried multiplyExponentiationBySquaring(57, 179, 7)"
|
||||
)
|
||||
assertEquals(
|
||||
"(((57 * (1 / 179)) * ((1 / 179) * (1 / 179))) * (((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179))))",
|
||||
multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -7).expr,
|
||||
"tried multiplyExponentiationBySquaring(57, 179, -7)"
|
||||
)
|
||||
assertEquals(
|
||||
"(57 * (((179 * 179) * (179 * 179)) * ((179 * 179) * (179 * 179))))",
|
||||
multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 8).expr,
|
||||
"tried multiplyExponentiationBySquaring(57, 179, 8)"
|
||||
)
|
||||
assertEquals(
|
||||
"(57 * ((((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179))) * (((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179)))))",
|
||||
multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -8).expr,
|
||||
"tried multiplyExponentiationBySquaring(57, 179, -8)"
|
||||
)
|
||||
}
|
||||
}
|
||||
@Test
|
||||
fun test_exponentiationBySquaring_for_Int() {
|
||||
ExprRing {
|
||||
assertEquals(
|
||||
"0",
|
||||
exponentiateBySquaring(Expr("57"), 0).expr,
|
||||
"tried exponentiationBySquaring(57, 0)"
|
||||
)
|
||||
assertEquals(
|
||||
"57",
|
||||
exponentiateBySquaring(Expr("57"), 1).expr,
|
||||
"tried exponentiationBySquaring(57, 1)"
|
||||
)
|
||||
assertEquals(
|
||||
"(1 / 57)",
|
||||
exponentiateBySquaring(Expr("57"), -1).expr,
|
||||
"tried exponentiationBySquaring(57, -1)"
|
||||
)
|
||||
assertEquals(
|
||||
"(57 * 57)",
|
||||
exponentiateBySquaring(Expr("57"), 2).expr,
|
||||
"tried exponentiationBySquaring(57, 2)"
|
||||
)
|
||||
assertEquals(
|
||||
"((1 / 57) * (1 / 57))",
|
||||
exponentiateBySquaring(Expr("57"), -2).expr,
|
||||
"tried exponentiationBySquaring(57, -2)"
|
||||
)
|
||||
assertEquals(
|
||||
"(57 * (57 * 57))",
|
||||
exponentiateBySquaring(Expr("57"), 3).expr,
|
||||
"tried exponentiationBySquaring(57, 3)"
|
||||
)
|
||||
assertEquals(
|
||||
"((1 / 57) * ((1 / 57) * (1 / 57)))",
|
||||
exponentiateBySquaring(Expr("57"), -3).expr,
|
||||
"tried exponentiationBySquaring(57, -3)"
|
||||
)
|
||||
assertEquals(
|
||||
"((57 * 57) * (57 * 57))",
|
||||
exponentiateBySquaring(Expr("57"), 4).expr,
|
||||
"tried exponentiationBySquaring(57, 4)"
|
||||
)
|
||||
assertEquals(
|
||||
"(((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57)))",
|
||||
exponentiateBySquaring(Expr("57"), -4).expr,
|
||||
"tried exponentiationBySquaring(57, -4)"
|
||||
)
|
||||
assertEquals(
|
||||
"(57 * ((57 * 57) * (57 * 57)))",
|
||||
exponentiateBySquaring(Expr("57"), 5).expr,
|
||||
"tried exponentiationBySquaring(57, 5)"
|
||||
)
|
||||
assertEquals(
|
||||
"((1 / 57) * (((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57))))",
|
||||
exponentiateBySquaring(Expr("57"), -5).expr,
|
||||
"tried exponentiationBySquaring(57, -5)"
|
||||
)
|
||||
assertEquals(
|
||||
"((57 * 57) * ((57 * 57) * (57 * 57)))",
|
||||
exponentiateBySquaring(Expr("57"), 6).expr,
|
||||
"tried exponentiationBySquaring(57, 6)"
|
||||
)
|
||||
assertEquals(
|
||||
"(((1 / 57) * (1 / 57)) * (((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57))))",
|
||||
exponentiateBySquaring(Expr("57"), -6).expr,
|
||||
"tried exponentiationBySquaring(57, -6)"
|
||||
)
|
||||
assertEquals(
|
||||
"((57 * (57 * 57)) * ((57 * 57) * (57 * 57)))",
|
||||
exponentiateBySquaring(Expr("57"), 7).expr,
|
||||
"tried exponentiationBySquaring(57, 7)"
|
||||
)
|
||||
assertEquals(
|
||||
"(((1 / 57) * ((1 / 57) * (1 / 57))) * (((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57))))",
|
||||
exponentiateBySquaring(Expr("57"), -7).expr,
|
||||
"tried exponentiationBySquaring(57, -7)"
|
||||
)
|
||||
assertEquals(
|
||||
"(((57 * 57) * (57 * 57)) * ((57 * 57) * (57 * 57)))",
|
||||
exponentiateBySquaring(Expr("57"), 8).expr,
|
||||
"tried exponentiationBySquaring(57, 8)"
|
||||
)
|
||||
assertEquals(
|
||||
"((((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57))) * (((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57))))",
|
||||
exponentiateBySquaring(Expr("57"), -8).expr,
|
||||
"tried exponentiationBySquaring(57, -8)"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,127 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018-2022 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.functions.testUtils.t
|
||||
import space.kscience.kmath.functions.testUtils.x
|
||||
import space.kscience.kmath.functions.testUtils.y
|
||||
import space.kscience.kmath.functions.testUtils.z
|
||||
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 LabeledConstructorsTest {
|
||||
@Test
|
||||
@UnstableKMathAPI
|
||||
fun testDSL1() {
|
||||
assertEquals(
|
||||
LabeledPolynomialAsIs(
|
||||
mapOf(x to 2u, z to 3u) to 5,
|
||||
mapOf(y to 1u) to -6,
|
||||
),
|
||||
Int.algebra.labeledPolynomialSpace {
|
||||
LabeledPolynomialDSL1 {
|
||||
5 { x pow 2u; z pow 3u }
|
||||
(-6) { y pow 1u }
|
||||
}
|
||||
},
|
||||
"test 1"
|
||||
)
|
||||
assertEquals(
|
||||
LabeledPolynomialAsIs(
|
||||
mapOf<Symbol, UInt>() to -1,
|
||||
),
|
||||
Int.algebra.labeledPolynomialSpace {
|
||||
LabeledPolynomialDSL1 {
|
||||
5 { }
|
||||
(-6) { }
|
||||
}
|
||||
},
|
||||
"test 2"
|
||||
)
|
||||
assertEquals(
|
||||
LabeledPolynomialAsIs(
|
||||
mapOf(x to 2u) to -1,
|
||||
),
|
||||
Int.algebra.labeledPolynomialSpace {
|
||||
LabeledPolynomialDSL1 {
|
||||
5 { x pow 1u; x pow 1u }
|
||||
(-6) { x pow 2u }
|
||||
}
|
||||
},
|
||||
"test 3"
|
||||
)
|
||||
assertEquals(
|
||||
LabeledPolynomialAsIs(
|
||||
mapOf(x to 2u) to -1,
|
||||
),
|
||||
Int.algebra.labeledPolynomialSpace {
|
||||
LabeledPolynomialDSL1 {
|
||||
5 { x pow 1u; x pow 1u }
|
||||
(-6) { x pow 2u; z pow 0u }
|
||||
}
|
||||
},
|
||||
"test 3"
|
||||
)
|
||||
}
|
||||
@Test
|
||||
@UnstableKMathAPI
|
||||
fun testFabric() {
|
||||
assertEquals(
|
||||
LabeledPolynomialAsIs(
|
||||
mapOf(x to 2u, z to 3u) to 5,
|
||||
mapOf(y to 1u) to -6,
|
||||
),
|
||||
Int.algebra {
|
||||
LabeledPolynomial(
|
||||
mapOf(x to 2u, z to 3u) to 5,
|
||||
mapOf(y to 1u) to -6,
|
||||
)
|
||||
},
|
||||
"test 1"
|
||||
)
|
||||
assertEquals(
|
||||
LabeledPolynomialAsIs(
|
||||
mapOf(x to 2u, z to 3u) to 5,
|
||||
mapOf(y to 1u) to -6,
|
||||
),
|
||||
Int.algebra {
|
||||
LabeledPolynomial(
|
||||
mapOf(x to 2u, y to 0u, z to 3u, t to 0u) to 5,
|
||||
mapOf(x to 0u, y to 1u, z to 0u, t to 0u) to -6,
|
||||
)
|
||||
},
|
||||
"test 2"
|
||||
)
|
||||
assertEquals(
|
||||
LabeledPolynomialAsIs(
|
||||
mapOf<Symbol, UInt>() to -1,
|
||||
),
|
||||
Int.algebra {
|
||||
LabeledPolynomial(
|
||||
mapOf(x to 0u) to 5,
|
||||
mapOf(y to 0u, z to 0u) to -6,
|
||||
)
|
||||
},
|
||||
"test 3"
|
||||
)
|
||||
assertEquals(
|
||||
LabeledPolynomialAsIs(
|
||||
mapOf<Symbol, UInt>() to 0,
|
||||
),
|
||||
Int.algebra {
|
||||
LabeledPolynomial(
|
||||
mapOf(x to 0u) to 5,
|
||||
mapOf(z to 0u, t to 0u) to -5,
|
||||
)
|
||||
},
|
||||
"test 4"
|
||||
)
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,544 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018-2022 KMath contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@file:Suppress("LocalVariableName")
|
||||
|
||||
package space.kscience.kmath.functions
|
||||
|
||||
import space.kscience.kmath.functions.testUtils.IntModuloRing
|
||||
import space.kscience.kmath.functions.testUtils.ListPolynomial
|
||||
import space.kscience.kmath.functions.testUtils.Rational
|
||||
import space.kscience.kmath.functions.testUtils.RationalField
|
||||
import kotlin.test.*
|
||||
|
||||
|
||||
class ListPolynomialTest {
|
||||
@Test
|
||||
fun test_Polynomial_Int_plus() {
|
||||
RationalField.listPolynomialSpace {
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)),
|
||||
ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + -3,
|
||||
"test 1"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)),
|
||||
ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + 2,
|
||||
"test 2"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(0)),
|
||||
ListPolynomial(Rational(-2)) + 2,
|
||||
"test 3"
|
||||
)
|
||||
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 6"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(-1)),
|
||||
ListPolynomial(Rational(-2)) + 1,
|
||||
"test 7"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(2)),
|
||||
ListPolynomial<Rational>() + 2,
|
||||
"test 8"
|
||||
)
|
||||
}
|
||||
}
|
||||
@Test
|
||||
fun test_Polynomial_Int_minus() {
|
||||
RationalField.listPolynomialSpace {
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)),
|
||||
ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - -3,
|
||||
"test 1"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)),
|
||||
ListPolynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - 2,
|
||||
"test 2"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(0)),
|
||||
ListPolynomial(Rational(2)) - 2,
|
||||
"test 3"
|
||||
)
|
||||
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 6"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(1)),
|
||||
ListPolynomial(Rational(2)) - 1,
|
||||
"test 7"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(-2)),
|
||||
ListPolynomial<Rational>() - 2,
|
||||
"test 8"
|
||||
)
|
||||
}
|
||||
}
|
||||
@Test
|
||||
fun test_Polynomial_Int_times() {
|
||||
IntModuloRing(35).listPolynomialSpace {
|
||||
assertEquals(
|
||||
ListPolynomial(34, 2, 1, 20, 2),
|
||||
ListPolynomial(22, 26, 13, 15, 26) * 27,
|
||||
"test 1"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(0, 0, 0, 0, 0),
|
||||
ListPolynomial(7, 0, 49, 21, 14) * 15,
|
||||
"test 2"
|
||||
)
|
||||
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.listPolynomialSpace {
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)),
|
||||
-3 + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)),
|
||||
"test 1"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)),
|
||||
2 + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)),
|
||||
"test 2"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(0)),
|
||||
2 + ListPolynomial(Rational(-2)),
|
||||
"test 3"
|
||||
)
|
||||
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 6"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(-1)),
|
||||
1 + ListPolynomial(Rational(-2)),
|
||||
"test 7"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(2)),
|
||||
2 + ListPolynomial(),
|
||||
"test 8"
|
||||
)
|
||||
}
|
||||
}
|
||||
@Test
|
||||
fun test_Int_Polynomial_minus() {
|
||||
RationalField.listPolynomialSpace {
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)),
|
||||
3 - ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)),
|
||||
"test 1"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)),
|
||||
-2 - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)),
|
||||
"test 2"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(0)),
|
||||
-2 - ListPolynomial(Rational(-2)),
|
||||
"test 3"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(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 5"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(1), Rational(0), Rational(0), Rational(0)),
|
||||
-1 - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)),
|
||||
"test 6"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(1)),
|
||||
-1 - ListPolynomial(Rational(-2)),
|
||||
"test 7"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(-2)),
|
||||
-2 - ListPolynomial(),
|
||||
"test 8"
|
||||
)
|
||||
}
|
||||
}
|
||||
@Test
|
||||
fun test_Int_Polynomial_times() {
|
||||
IntModuloRing(35).listPolynomialSpace {
|
||||
assertEquals(
|
||||
ListPolynomial(34, 2, 1, 20, 2),
|
||||
27 * ListPolynomial(22, 26, 13, 15, 26),
|
||||
"test 1"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(0, 0, 0, 0, 0),
|
||||
15 * ListPolynomial(7, 0, 49, 21, 14),
|
||||
"test 2"
|
||||
)
|
||||
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.listPolynomialSpace {
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)),
|
||||
ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + Rational(-3),
|
||||
"test 1"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)),
|
||||
ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + Rational(2),
|
||||
"test 2"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(0)),
|
||||
ListPolynomial(Rational(-2)) + Rational(2),
|
||||
"test 3"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(0)),
|
||||
ListPolynomial<Rational>() + Rational(0),
|
||||
"test 4"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(-1), Rational(0), Rational(0), Rational(0)),
|
||||
ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + Rational(1),
|
||||
"test 5"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(-1)),
|
||||
ListPolynomial(Rational(-2)) + Rational(1),
|
||||
"test 6"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(2)),
|
||||
ListPolynomial<Rational>() + Rational(2),
|
||||
"test 7"
|
||||
)
|
||||
}
|
||||
}
|
||||
@Test
|
||||
fun test_Polynomial_Constant_minus() {
|
||||
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),
|
||||
"test 1"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)),
|
||||
ListPolynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - Rational(2),
|
||||
"test 2"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(0)),
|
||||
ListPolynomial(Rational(2)) - Rational(2),
|
||||
"test 3"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(0)),
|
||||
ListPolynomial<Rational>() - Rational(0),
|
||||
"test 4"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(1), Rational(0), Rational(0), Rational(0)),
|
||||
ListPolynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - Rational(1),
|
||||
"test 5"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(1)),
|
||||
ListPolynomial(Rational(2)) - Rational(1),
|
||||
"test 6"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(-2)),
|
||||
ListPolynomial<Rational>() - Rational(2),
|
||||
"test 7"
|
||||
)
|
||||
}
|
||||
}
|
||||
@Test
|
||||
fun test_Polynomial_Constant_times() {
|
||||
IntModuloRing(35).listPolynomialSpace {
|
||||
assertEquals(
|
||||
ListPolynomial(34, 2, 1, 20, 2),
|
||||
ListPolynomial(22, 26, 13, 15, 26) * 27.asConstant(),
|
||||
"test 1"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(0, 0, 0, 0, 0),
|
||||
ListPolynomial(7, 0, 49, 21, 14) * 15.asConstant(),
|
||||
"test 2"
|
||||
)
|
||||
}
|
||||
}
|
||||
@Test
|
||||
fun test_Constant_Polynomial_plus() {
|
||||
RationalField.listPolynomialSpace {
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)),
|
||||
Rational(-3) + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)),
|
||||
"test 1"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)),
|
||||
Rational(2) + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)),
|
||||
"test 2"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(0)),
|
||||
Rational(2) + ListPolynomial(Rational(-2)),
|
||||
"test 3"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(0)),
|
||||
Rational(0) + ListPolynomial(),
|
||||
"test 4"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(-1), Rational(0), Rational(0), Rational(0)),
|
||||
Rational(1) + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)),
|
||||
"test 5"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(-1)),
|
||||
Rational(1) + ListPolynomial(Rational(-2)),
|
||||
"test 6"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(2)),
|
||||
Rational(2) + ListPolynomial(),
|
||||
"test 7"
|
||||
)
|
||||
}
|
||||
}
|
||||
@Test
|
||||
fun test_Constant_Polynomial_minus() {
|
||||
RationalField.listPolynomialSpace {
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)),
|
||||
Rational(3) - ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)),
|
||||
"test 1"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)),
|
||||
Rational(-2) - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)),
|
||||
"test 2"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(0)),
|
||||
Rational(-2) - ListPolynomial(Rational(-2)),
|
||||
"test 3"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(0)),
|
||||
Rational(0) - ListPolynomial(),
|
||||
"test 4"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(1), Rational(0), Rational(0), Rational(0)),
|
||||
Rational(-1) - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)),
|
||||
"test 5"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(1)),
|
||||
Rational(-1) - ListPolynomial(Rational(-2)),
|
||||
"test 6"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(-2)),
|
||||
Rational(-2) - ListPolynomial(),
|
||||
"test 7"
|
||||
)
|
||||
}
|
||||
}
|
||||
@Test
|
||||
fun test_Constant_Polynomial_times() {
|
||||
IntModuloRing(35).listPolynomialSpace {
|
||||
assertEquals(
|
||||
ListPolynomial(34, 2, 1, 20, 2),
|
||||
27 * ListPolynomial(22, 26, 13, 15, 26),
|
||||
"test 1"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(0, 0, 0, 0, 0),
|
||||
15 * ListPolynomial(7, 0, 49, 21, 14),
|
||||
"test 2"
|
||||
)
|
||||
}
|
||||
}
|
||||
@Test
|
||||
fun test_Polynomial_unaryMinus() {
|
||||
RationalField.listPolynomialSpace {
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)),
|
||||
-ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)),
|
||||
"test 1"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7), Rational(0), Rational(0)),
|
||||
-ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7), Rational(0), Rational(0)),
|
||||
"test 2"
|
||||
)
|
||||
}
|
||||
}
|
||||
@Test
|
||||
fun test_Polynomial_Polynomial_plus() {
|
||||
RationalField.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)),
|
||||
ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) +
|
||||
ListPolynomial(Rational(-5, 7), Rational(5, 1), Rational(5, 8)),
|
||||
"test 1"
|
||||
)
|
||||
// (-2/9 - 8/3 x) + (0 + 9/4 x + 2/4 x^2) ?= -2/9 - 5/12 x + 2/4 x^2
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(-2, 9), Rational(-5, 12), Rational(2, 4)),
|
||||
ListPolynomial(Rational(-2, 9), Rational(-8, 3)) +
|
||||
ListPolynomial(Rational(0), Rational(9, 4), Rational(2, 4)),
|
||||
"test 2"
|
||||
)
|
||||
// (-4/7 - 2/6 x + 0 x^2 + 0 x^3) + (-6/3 - 7/2 x + 2/3 x^2) ?= -18/7 - 23/6 x + 2/3 x^2
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(-18, 7), Rational(-23, 6), Rational(2, 3), Rational(0)),
|
||||
ListPolynomial(Rational(-4, 7), Rational(-2, 6), Rational(0), Rational(0)) +
|
||||
ListPolynomial(Rational(-6, 3), Rational(-7, 2), Rational(2, 3)),
|
||||
"test 3"
|
||||
)
|
||||
// (-2/4 - 6/9 x - 4/9 x^2) + (2/4 + 6/9 x + 4/9 x^2) ?= 0
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(0), Rational(0), Rational(0)),
|
||||
ListPolynomial(Rational(-2, 4), Rational(-6, 9), Rational(-4, 9)) +
|
||||
ListPolynomial(Rational(2, 4), Rational(6, 9), Rational(4, 9)),
|
||||
"test 4"
|
||||
)
|
||||
}
|
||||
}
|
||||
@Test
|
||||
fun test_Polynomial_Polynomial_minus() {
|
||||
RationalField.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)),
|
||||
ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) -
|
||||
ListPolynomial(Rational(-5, 7), Rational(5, 1), Rational(5, 8)),
|
||||
"test 1"
|
||||
)
|
||||
// (-2/9 - 8/3 x) - (0 + 9/4 x + 2/4 x^2) ?= -2/9 - 59/12 x - 2/4 x^2
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(-2, 9), Rational(-59, 12), Rational(-2, 4)),
|
||||
ListPolynomial(Rational(-2, 9), Rational(-8, 3)) -
|
||||
ListPolynomial(Rational(0), Rational(9, 4), Rational(2, 4)),
|
||||
"test 2"
|
||||
)
|
||||
// (-4/7 - 2/6 x + 0 x^2 + 0 x^3) - (-6/3 - 7/2 x + 2/3 x^2) ?= 10/7 + 19/6 x - 2/3 x^2
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(10, 7), Rational(19, 6), Rational(-2, 3), Rational(0)),
|
||||
ListPolynomial(Rational(-4, 7), Rational(-2, 6), Rational(0), Rational(0)) -
|
||||
ListPolynomial(Rational(-6, 3), Rational(-7, 2), Rational(2, 3)),
|
||||
"test 3"
|
||||
)
|
||||
// (-2/4 - 6/9 x - 4/9 x^2) - (-2/4 - 6/9 x - 4/9 x^2) ?= 0
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(0), Rational(0), Rational(0)),
|
||||
ListPolynomial(Rational(-2, 4), Rational(-6, 9), Rational(-4, 9)) -
|
||||
ListPolynomial(Rational(-2, 4), Rational(-6, 9), Rational(-4, 9)),
|
||||
"test 4"
|
||||
)
|
||||
}
|
||||
}
|
||||
@Test
|
||||
fun test_Polynomial_Polynomial_times() {
|
||||
IntModuloRing(35).listPolynomialSpace {
|
||||
// (1 + x + x^2) * (1 - x + x^2) ?= 1 + x^2 + x^4
|
||||
assertEquals(
|
||||
ListPolynomial(1, 0, 1, 0, 1),
|
||||
ListPolynomial(1, -1, 1) * ListPolynomial(1, 1, 1),
|
||||
"test 1"
|
||||
)
|
||||
// Spoiler: 5 * 7 = 0
|
||||
assertEquals(
|
||||
ListPolynomial(0, 0, 0, 0, 0),
|
||||
ListPolynomial(5, -25, 10) * ListPolynomial(21, 14, -7),
|
||||
"test 2"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,982 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018-2022 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.functions.testUtils.Rational
|
||||
import space.kscience.kmath.functions.testUtils.RationalField
|
||||
import space.kscience.kmath.functions.testUtils.assertFailsWithTypeAndMessage
|
||||
import kotlin.test.Ignore
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
|
||||
@OptIn(UnstableKMathAPI::class)
|
||||
class ListPolynomialUtilTest {
|
||||
@Test
|
||||
fun test_Polynomial_substitute_Double() {
|
||||
assertEquals(
|
||||
0.0,
|
||||
ListPolynomial(1.0, -2.0, 1.0).substitute(1.0),
|
||||
0.001,
|
||||
"test 1"
|
||||
)
|
||||
assertEquals(
|
||||
0.0,
|
||||
ListPolynomial(1.0, -2.0, 1.0).substitute(1.0),
|
||||
0.001,
|
||||
"test 1"
|
||||
)
|
||||
assertEquals(
|
||||
1.1931904761904761,
|
||||
ListPolynomial(0.625, 2.6666666666666665, 0.5714285714285714, 1.5).substitute(0.2),
|
||||
0.001,
|
||||
"test 2"
|
||||
)
|
||||
assertEquals(
|
||||
0.5681904761904762,
|
||||
ListPolynomial(0.0, 2.6666666666666665, 0.5714285714285714, 1.5).substitute(0.2),
|
||||
0.001,
|
||||
"test 3"
|
||||
)
|
||||
assertEquals(
|
||||
1.1811904761904761,
|
||||
ListPolynomial(0.625, 2.6666666666666665, 0.5714285714285714, 0.0).substitute(0.2),
|
||||
0.001,
|
||||
"test 4"
|
||||
)
|
||||
assertEquals(
|
||||
1.1703333333333332,
|
||||
ListPolynomial(0.625, 2.6666666666666665, 0.0, 1.5).substitute(0.2),
|
||||
0.001,
|
||||
"test 5"
|
||||
)
|
||||
}
|
||||
@Test
|
||||
fun test_Polynomial_substitute_Constant() {
|
||||
assertEquals(
|
||||
Rational(0),
|
||||
ListPolynomial(Rational(1), Rational(-2), Rational(1)).substitute(RationalField, Rational(1)),
|
||||
"test 1"
|
||||
)
|
||||
assertEquals(
|
||||
Rational(25057, 21000),
|
||||
ListPolynomial(Rational(5, 8), Rational(8, 3), Rational(4, 7), Rational(3, 2))
|
||||
.substitute(RationalField, Rational(1, 5)),
|
||||
"test 2"
|
||||
)
|
||||
assertEquals(
|
||||
Rational(2983, 5250),
|
||||
ListPolynomial(Rational(0), Rational(8, 3), Rational(4, 7), Rational(3, 2))
|
||||
.substitute(RationalField, Rational(1, 5)),
|
||||
"test 3"
|
||||
)
|
||||
assertEquals(
|
||||
Rational(4961, 4200),
|
||||
ListPolynomial(Rational(5, 8), Rational(8, 3), Rational(4, 7), Rational(0))
|
||||
.substitute(RationalField, Rational(1, 5)),
|
||||
"test 4"
|
||||
)
|
||||
assertEquals(
|
||||
Rational(3511, 3000),
|
||||
ListPolynomial(Rational(5, 8), Rational(8, 3), Rational(0), Rational(3, 2))
|
||||
.substitute(RationalField, Rational(1, 5)),
|
||||
"test 5"
|
||||
)
|
||||
}
|
||||
@Test
|
||||
fun test_Polynomial_substitute_Polynomial() {
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(0)),
|
||||
ListPolynomial(Rational(1), Rational(-2), Rational(1)).substitute(RationalField, ListPolynomial(Rational(1))),
|
||||
"test 1"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(709, 378), Rational(155, 252), Rational(19, 525), Rational(2, 875)),
|
||||
ListPolynomial(Rational(1, 7), Rational(9, 4), Rational(1, 3), Rational(2, 7))
|
||||
.substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(1, 5))),
|
||||
"test 2"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(655, 378), Rational(155, 252), Rational(19, 525), Rational(2, 875)),
|
||||
ListPolynomial(Rational(0), Rational(9, 4), Rational(1, 3), Rational(2, 7))
|
||||
.substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(1, 5))),
|
||||
"test 3"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(677, 378), Rational(97, 180), Rational(1, 75), Rational(0)),
|
||||
ListPolynomial(Rational(1, 7), Rational(9, 4), Rational(1, 3), Rational(0))
|
||||
.substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(1, 5))),
|
||||
"test 4"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(653, 378), Rational(221, 420), Rational(4, 175), Rational(2, 875)),
|
||||
ListPolynomial(Rational(1, 7), Rational(9, 4), Rational(0), Rational(2, 7))
|
||||
.substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(1, 5))),
|
||||
"test 5"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(89, 54), Rational(0), Rational(0), Rational(0)),
|
||||
ListPolynomial(Rational(0), Rational(9, 4), Rational(1, 3), Rational(0))
|
||||
.substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(0))),
|
||||
"test 6"
|
||||
)
|
||||
}
|
||||
@Test
|
||||
@Ignore // FIXME: This tests work only for sane realisations of the substitutions. Currently, it is not.
|
||||
// Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should return denominator r^deg(p),
|
||||
// not r^(deg(p)(deg(p)+1)/2) as it is now.
|
||||
fun test_Polynomial_substitute_RationalFunction() {
|
||||
assertEquals(
|
||||
ListRationalFunction(ListPolynomial(Rational(0)), ListPolynomial(Rational(1))),
|
||||
ListPolynomial(Rational(1), Rational(-2), Rational(1))
|
||||
.substitute(RationalField, ListRationalFunction(ListPolynomial(Rational(1)), ListPolynomial(Rational(1)))),
|
||||
"test 1"
|
||||
)
|
||||
assertEquals(
|
||||
ListRationalFunction(
|
||||
ListPolynomial(
|
||||
Rational(66349, 243),
|
||||
Rational(-17873, 405),
|
||||
Rational(173533, 3780),
|
||||
Rational(-91141, 567),
|
||||
Rational(5773909, 105840),
|
||||
Rational(-23243, 630),
|
||||
Rational(1573, 27)
|
||||
),
|
||||
ListPolynomial(
|
||||
Rational(169, 81),
|
||||
Rational(-130, 27),
|
||||
Rational(115, 18),
|
||||
Rational(-797, 54),
|
||||
Rational(1985, 144),
|
||||
Rational(-55, 6),
|
||||
Rational(121, 9)
|
||||
)
|
||||
),
|
||||
ListPolynomial(
|
||||
Rational(13, 3),
|
||||
Rational(-9, 5),
|
||||
Rational(5, 5)
|
||||
).substitute(RationalField,
|
||||
ListRationalFunction(
|
||||
ListPolynomial(
|
||||
Rational(15, 1),
|
||||
Rational(6, 9),
|
||||
Rational(-3, 7)
|
||||
),
|
||||
ListPolynomial(
|
||||
Rational(-13, 9),
|
||||
Rational(10, 6),
|
||||
Rational(-10, 8),
|
||||
Rational(11, 3)
|
||||
)
|
||||
)
|
||||
),
|
||||
"test 2"
|
||||
)
|
||||
assertEquals(
|
||||
ListRationalFunction(
|
||||
ListPolynomial(
|
||||
Rational(0, 1),
|
||||
Rational(0, 1),
|
||||
Rational(-14, 9),
|
||||
Rational(31, 14),
|
||||
Rational(-5077, 980),
|
||||
Rational(99, 35)
|
||||
),
|
||||
ListPolynomial(
|
||||
Rational(0, 1),
|
||||
Rational(0, 1),
|
||||
Rational(25, 9),
|
||||
Rational(-25, 6),
|
||||
Rational(1985, 144),
|
||||
Rational(-55, 6),
|
||||
Rational(121, 9)
|
||||
)
|
||||
),
|
||||
ListPolynomial(
|
||||
Rational(0),
|
||||
Rational(-9, 5),
|
||||
Rational(5, 5)
|
||||
).substitute(RationalField,
|
||||
ListRationalFunction(
|
||||
ListPolynomial(
|
||||
Rational(0),
|
||||
Rational(6, 9),
|
||||
Rational(-3, 7)
|
||||
),
|
||||
ListPolynomial(
|
||||
Rational(0),
|
||||
Rational(10, 6),
|
||||
Rational(-10, 8),
|
||||
Rational(11, 3)
|
||||
)
|
||||
)
|
||||
),
|
||||
"test 3"
|
||||
)
|
||||
assertEquals(
|
||||
ListRationalFunction(
|
||||
ListPolynomial(
|
||||
Rational(-898, 27),
|
||||
Rational(271, 45),
|
||||
Rational(-65, 12) ,
|
||||
Rational(0),
|
||||
Rational(0),
|
||||
Rational(0),
|
||||
Rational(0)
|
||||
),
|
||||
ListPolynomial(
|
||||
Rational(-13, 9),
|
||||
Rational(5, 3),
|
||||
Rational(-5, 4),
|
||||
Rational(0),
|
||||
Rational(0),
|
||||
Rational(0),
|
||||
Rational(0)
|
||||
)
|
||||
),
|
||||
ListPolynomial(
|
||||
Rational(13, 3),
|
||||
Rational(-9, 5),
|
||||
Rational(0)
|
||||
).substitute(RationalField,
|
||||
ListRationalFunction(
|
||||
ListPolynomial(
|
||||
Rational(15, 1),
|
||||
Rational(6, 9),
|
||||
Rational(0)
|
||||
),
|
||||
ListPolynomial(
|
||||
Rational(-13, 9),
|
||||
Rational(10, 6),
|
||||
Rational(-10, 8),
|
||||
Rational(0)
|
||||
)
|
||||
)
|
||||
),
|
||||
"test 4"
|
||||
)
|
||||
assertEquals(
|
||||
ListRationalFunction(
|
||||
ListPolynomial(
|
||||
Rational(56872, 243),
|
||||
Rational(0, 1),
|
||||
Rational(-90, 7),
|
||||
Rational(-3718, 81),
|
||||
Rational(9, 49),
|
||||
Rational(0, 1),
|
||||
Rational(1573, 27)
|
||||
),
|
||||
ListPolynomial(
|
||||
Rational(169, 81),
|
||||
Rational(0, 1),
|
||||
Rational(0, 1),
|
||||
Rational(-286, 27),
|
||||
Rational(0, 1),
|
||||
Rational(0, 1),
|
||||
Rational(121, 9)
|
||||
)
|
||||
),
|
||||
ListPolynomial(
|
||||
Rational(13, 3),
|
||||
Rational(0),
|
||||
Rational(5, 5)
|
||||
).substitute(RationalField,
|
||||
ListRationalFunction(
|
||||
ListPolynomial(
|
||||
Rational(15, 1),
|
||||
Rational(0),
|
||||
Rational(-3, 7)
|
||||
),
|
||||
ListPolynomial(
|
||||
Rational(-13, 9),
|
||||
Rational(0),
|
||||
Rational(0),
|
||||
Rational(11, 3)
|
||||
)
|
||||
)
|
||||
),
|
||||
"test 5"
|
||||
)
|
||||
}
|
||||
@Test
|
||||
fun test_RationalFunction_substitute_Double() {
|
||||
assertEquals(
|
||||
0.0,
|
||||
ListRationalFunction(
|
||||
ListPolynomial(1.0, -2.0, 1.0),
|
||||
ListPolynomial(-6.302012278484357, 5.831971885376948, -9.271604788393432, 5.494387848015814, -3.7187384450880785)
|
||||
).substitute(1.0),
|
||||
0.001,
|
||||
"test 1"
|
||||
)
|
||||
assertEquals(
|
||||
2.693702616649797,
|
||||
ListRationalFunction(
|
||||
ListPolynomial(-5.848840571263625, -1.660411278951134, -3.793740946372443, -9.624569269490076),
|
||||
ListPolynomial(-2.9680680215311073, -1.862973627119981, 4.776550592888336, -2.7320154512368466)
|
||||
).substitute(-7.53452770353279),
|
||||
0.001,
|
||||
"test 2"
|
||||
)
|
||||
assertEquals(
|
||||
2.692226268901378,
|
||||
ListRationalFunction(
|
||||
ListPolynomial(0.0, -1.660411278951134, -3.793740946372443, -9.624569269490076),
|
||||
ListPolynomial(0.0, -1.862973627119981, 4.776550592888336, -2.7320154512368466)
|
||||
).substitute(-7.53452770353279),
|
||||
0.001,
|
||||
"test 3"
|
||||
)
|
||||
assertEquals(
|
||||
-0.7394904842099175,
|
||||
ListRationalFunction(
|
||||
ListPolynomial(-5.848840571263625, -1.660411278951134, -3.793740946372443, 0.0),
|
||||
ListPolynomial(-2.9680680215311073, -1.862973627119981, 4.776550592888336, 0.0)
|
||||
).substitute(-7.53452770353279),
|
||||
0.001,
|
||||
"test 4"
|
||||
)
|
||||
assertEquals(
|
||||
3.526835209398159,
|
||||
ListRationalFunction(
|
||||
ListPolynomial(-5.848840571263625, 0.0, 0.0, -9.624569269490076),
|
||||
ListPolynomial(-2.9680680215311073, 0.0, 0.0, -2.7320154512368466)
|
||||
).substitute(-7.53452770353279),
|
||||
0.001,
|
||||
"test 5"
|
||||
)
|
||||
}
|
||||
@Test
|
||||
fun test_RationalFunction_substitute_Constant() {
|
||||
assertEquals(
|
||||
Rational(0),
|
||||
ListRationalFunction(
|
||||
ListPolynomial(Rational(1), Rational(-2), Rational(1)),
|
||||
ListPolynomial(Rational(1)),
|
||||
).substitute(RationalField, Rational(1)),
|
||||
"test 1"
|
||||
)
|
||||
assertEquals(
|
||||
Rational(1149615, 61306),
|
||||
ListRationalFunction(
|
||||
ListPolynomial(Rational(17, 7), Rational(18, 3), Rational(18, 8), Rational(9, 1)),
|
||||
ListPolynomial(Rational(11, 9), Rational(-6, 5), Rational(-12, 7), Rational(2, 1)),
|
||||
).substitute(RationalField, Rational(-7, 8)),
|
||||
"test 2"
|
||||
)
|
||||
assertEquals(
|
||||
Rational(3495, 586),
|
||||
ListRationalFunction(
|
||||
ListPolynomial(Rational(0), Rational(18, 3), Rational(18, 8), Rational(9, 1)),
|
||||
ListPolynomial(Rational(0), Rational(-6, 5), Rational(-12, 7), Rational(2, 1)),
|
||||
).substitute(RationalField, Rational(-7, 8)),
|
||||
"test 3"
|
||||
)
|
||||
assertEquals(
|
||||
Rational(-88605, 77392),
|
||||
ListRationalFunction(
|
||||
ListPolynomial(Rational(17, 7), Rational(18, 3), Rational(18, 8), Rational(0)),
|
||||
ListPolynomial(Rational(11, 9), Rational(-6, 5), Rational(-12, 7), Rational(0)),
|
||||
).substitute(RationalField, Rational(-7, 8)),
|
||||
"test 4"
|
||||
)
|
||||
assertEquals(
|
||||
Rational(116145, 3794),
|
||||
ListRationalFunction(
|
||||
ListPolynomial(Rational(17, 7), Rational(0), Rational(0), Rational(9, 1)),
|
||||
ListPolynomial(Rational(11, 9), Rational(0), Rational(0), Rational(2, 1)),
|
||||
).substitute(RationalField, Rational(-7, 8)),
|
||||
"test 5"
|
||||
)
|
||||
}
|
||||
@Test
|
||||
fun test_RationalFunction_substitute_Polynomial() {
|
||||
assertEquals(
|
||||
ListRationalFunction(
|
||||
ListPolynomial(Rational(0)),
|
||||
ListPolynomial(Rational(1))
|
||||
),
|
||||
ListRationalFunction(
|
||||
ListPolynomial(Rational(1), Rational(-2), Rational(1)),
|
||||
ListPolynomial(Rational(1)),
|
||||
).substitute(RationalField, ListPolynomial(Rational(1))),
|
||||
"test 1"
|
||||
)
|
||||
assertEquals(
|
||||
ListRationalFunction(
|
||||
ListPolynomial(
|
||||
Rational(-283303, 36),
|
||||
Rational(-23593, 24),
|
||||
Rational(368713, 192),
|
||||
Rational(1455, 8),
|
||||
Rational(-272171, 1536),
|
||||
Rational(-2149, 192),
|
||||
Rational(469, 64),
|
||||
Rational(11, 48),
|
||||
Rational(-11, 96)
|
||||
),
|
||||
ListPolynomial(
|
||||
Rational(5797, 12),
|
||||
Rational(595, 16),
|
||||
Rational(-5285, 72),
|
||||
Rational(-745, 192),
|
||||
Rational(1105, 288),
|
||||
Rational(5, 48),
|
||||
Rational(-5, 72)
|
||||
)
|
||||
),
|
||||
ListRationalFunction(
|
||||
ListPolynomial(
|
||||
Rational(2, 9),
|
||||
Rational(11, 3),
|
||||
Rational(-9, 4),
|
||||
Rational(-6, 1),
|
||||
Rational(-11, 6)
|
||||
),
|
||||
ListPolynomial(
|
||||
Rational(-2, 3),
|
||||
Rational(-15, 4),
|
||||
Rational(5, 9),
|
||||
Rational(-5, 9)
|
||||
)
|
||||
).substitute(RationalField,
|
||||
ListPolynomial(
|
||||
Rational(-9, 1),
|
||||
Rational(-1, 4),
|
||||
Rational(2, 4)
|
||||
)
|
||||
),
|
||||
"test 2"
|
||||
)
|
||||
assertEquals(
|
||||
ListRationalFunction(
|
||||
ListPolynomial(
|
||||
Rational(0, 1),
|
||||
Rational(-11, 12),
|
||||
Rational(325, 192),
|
||||
Rational(21, 32),
|
||||
Rational(-1739, 1536),
|
||||
Rational(227, 192),
|
||||
Rational(-59, 64),
|
||||
Rational(11, 48),
|
||||
Rational(-11, 96)
|
||||
),
|
||||
ListPolynomial(
|
||||
Rational(0, 1),
|
||||
Rational(15, 16),
|
||||
Rational(-265, 144),
|
||||
Rational(-25, 192),
|
||||
Rational(25, 288),
|
||||
Rational(5, 48),
|
||||
Rational(-5, 72)
|
||||
)
|
||||
),
|
||||
ListRationalFunction(
|
||||
ListPolynomial(
|
||||
Rational(0, 9),
|
||||
Rational(11, 3),
|
||||
Rational(-9, 4),
|
||||
Rational(-6, 1),
|
||||
Rational(-11, 6)
|
||||
),
|
||||
ListPolynomial(
|
||||
Rational(0, 3),
|
||||
Rational(-15, 4),
|
||||
Rational(5, 9),
|
||||
Rational(-5, 9)
|
||||
)
|
||||
).substitute(RationalField,
|
||||
ListPolynomial(
|
||||
Rational(0, 1),
|
||||
Rational(-1, 4),
|
||||
Rational(2, 4)
|
||||
)
|
||||
),
|
||||
"test 3"
|
||||
)
|
||||
assertEquals(
|
||||
ListRationalFunction(
|
||||
ListPolynomial(
|
||||
Rational(149723, 36),
|
||||
Rational(8483, 24),
|
||||
Rational(639, 64),
|
||||
Rational(3, 32),
|
||||
Rational(0),
|
||||
Rational(0),
|
||||
Rational(0),
|
||||
Rational(0),
|
||||
Rational(0)
|
||||
),
|
||||
ListPolynomial(
|
||||
Rational(937, 12),
|
||||
Rational(55, 16),
|
||||
Rational(5, 144),
|
||||
Rational(0),
|
||||
Rational(0),
|
||||
Rational(0),
|
||||
Rational(0)
|
||||
)
|
||||
),
|
||||
ListRationalFunction(
|
||||
ListPolynomial(
|
||||
Rational(2, 9),
|
||||
Rational(11, 3),
|
||||
Rational(-9, 4),
|
||||
Rational(-6, 1),
|
||||
Rational(0)
|
||||
),
|
||||
ListPolynomial(
|
||||
Rational(-2, 3),
|
||||
Rational(-15, 4),
|
||||
Rational(5, 9),
|
||||
Rational(0)
|
||||
)
|
||||
).substitute(RationalField,
|
||||
ListPolynomial(
|
||||
Rational(-9, 1),
|
||||
Rational(-1, 4),
|
||||
Rational(0)
|
||||
)
|
||||
),
|
||||
"test 4"
|
||||
)
|
||||
assertEquals(
|
||||
ListRationalFunction(
|
||||
ListPolynomial(
|
||||
Rational(-216509, 18),
|
||||
Rational(0, 1),
|
||||
Rational(2673, 1),
|
||||
Rational(0, 1),
|
||||
Rational(-891, 4),
|
||||
Rational(0, 1),
|
||||
Rational(33, 4),
|
||||
Rational(0, 1),
|
||||
Rational(-11, 96)
|
||||
),
|
||||
ListPolynomial(
|
||||
Rational(1213, 3),
|
||||
Rational(0, 1),
|
||||
Rational(-135, 2),
|
||||
Rational(0, 1),
|
||||
Rational(15, 4),
|
||||
Rational(0, 1),
|
||||
Rational(-5, 72)
|
||||
)
|
||||
),
|
||||
ListRationalFunction(
|
||||
ListPolynomial(
|
||||
Rational(2, 9),
|
||||
Rational(0),
|
||||
Rational(0),
|
||||
Rational(0),
|
||||
Rational(-11, 6)
|
||||
),
|
||||
ListPolynomial(
|
||||
Rational(-2, 3),
|
||||
Rational(0),
|
||||
Rational(0),
|
||||
Rational(-5, 9)
|
||||
)
|
||||
).substitute(RationalField,
|
||||
ListPolynomial(
|
||||
Rational(-9, 1),
|
||||
Rational(0),
|
||||
Rational(2, 4)
|
||||
)
|
||||
),
|
||||
"test 5"
|
||||
)
|
||||
}
|
||||
@Test
|
||||
@Ignore // FIXME: This tests work only for sane realisations of the substitutions. Currently, it is not.
|
||||
// Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should return denominator r^deg(p),
|
||||
// not r^(deg(p)(deg(p)+1)/2) as it is now.
|
||||
fun test_RationalFunction_substitute_RationalFunction() {
|
||||
assertEquals(
|
||||
ListRationalFunction(
|
||||
ListPolynomial(Rational(0)),
|
||||
ListPolynomial(Rational(1))
|
||||
),
|
||||
ListRationalFunction(
|
||||
ListPolynomial(Rational(1), Rational(-2), Rational(1)),
|
||||
ListPolynomial(Rational(1))
|
||||
).substitute(RationalField,
|
||||
ListRationalFunction(
|
||||
ListPolynomial(Rational(1)),
|
||||
ListPolynomial(Rational(1))
|
||||
)
|
||||
),
|
||||
"test 1"
|
||||
)
|
||||
assertEquals(
|
||||
ListRationalFunction(
|
||||
ListPolynomial(
|
||||
Rational(130087, 3888),
|
||||
Rational(-2866333, 65610),
|
||||
Rational(-5076229, 97200),
|
||||
Rational(222136997, 3280500),
|
||||
Rational(754719329, 20995200),
|
||||
Rational(-12010283, 324000),
|
||||
Rational(-2011967, 172800),
|
||||
Rational(18607, 2880),
|
||||
Rational(4705, 4096)
|
||||
),
|
||||
ListPolynomial(
|
||||
Rational(-143820355, 3779136),
|
||||
Rational(73886869, 1574640),
|
||||
Rational(1440175193, 15746400),
|
||||
Rational(-5308968857, 52488000),
|
||||
Rational(-186910083731, 2099520000),
|
||||
Rational(125043463, 1555200),
|
||||
Rational(5299123, 388800),
|
||||
Rational(-213757, 15360),
|
||||
Rational(1380785, 147456)
|
||||
)
|
||||
),
|
||||
ListRationalFunction(
|
||||
ListPolynomial(
|
||||
Rational(1, 1),
|
||||
Rational(-10, 5),
|
||||
Rational(18, 8),
|
||||
Rational(-8, 8)
|
||||
),
|
||||
ListPolynomial(
|
||||
Rational(-14, 8),
|
||||
Rational(-14, 8),
|
||||
Rational(-19, 6),
|
||||
Rational(14, 3),
|
||||
Rational(8, 9)
|
||||
)
|
||||
).substitute(RationalField,
|
||||
ListRationalFunction(
|
||||
ListPolynomial(
|
||||
Rational(14, 9),
|
||||
Rational(-2, 5),
|
||||
Rational(-14, 7)
|
||||
),
|
||||
ListPolynomial(
|
||||
Rational(-6, 4),
|
||||
Rational(5, 9),
|
||||
Rational(1, 8)
|
||||
)
|
||||
)
|
||||
),
|
||||
"test 2"
|
||||
)
|
||||
assertEquals(
|
||||
ListRationalFunction(
|
||||
ListPolynomial(
|
||||
Rational(0, 1),
|
||||
Rational(0, 1),
|
||||
Rational(0, 1),
|
||||
Rational(0, 1),
|
||||
Rational(5173, 18225),
|
||||
Rational(904291, 364500),
|
||||
Rational(283127, 43200),
|
||||
Rational(37189, 5760),
|
||||
Rational(147, 128)
|
||||
),
|
||||
ListPolynomial(
|
||||
Rational(0, 1),
|
||||
Rational(0, 1),
|
||||
Rational(0, 1),
|
||||
Rational(0, 1),
|
||||
Rational(-163589, 911250),
|
||||
Rational(-881831, 291600),
|
||||
Rational(-10722229, 777600),
|
||||
Rational(-640921, 46080),
|
||||
Rational(86303, 9216)
|
||||
)
|
||||
),
|
||||
ListRationalFunction(
|
||||
ListPolynomial(
|
||||
Rational(0),
|
||||
Rational(-10, 5),
|
||||
Rational(18, 8),
|
||||
Rational(-8, 8)
|
||||
),
|
||||
ListPolynomial(
|
||||
Rational(0),
|
||||
Rational(-14, 8),
|
||||
Rational(-19, 6),
|
||||
Rational(14, 3),
|
||||
Rational(8, 9)
|
||||
)
|
||||
).substitute(RationalField,
|
||||
ListRationalFunction(
|
||||
ListPolynomial(
|
||||
Rational(0),
|
||||
Rational(-2, 5),
|
||||
Rational(-14, 7)
|
||||
),
|
||||
ListPolynomial(
|
||||
Rational(0),
|
||||
Rational(5, 9),
|
||||
Rational(1, 8)
|
||||
)
|
||||
)
|
||||
),
|
||||
"test 3"
|
||||
)
|
||||
assertEquals(
|
||||
ListRationalFunction(
|
||||
ListPolynomial(
|
||||
Rational(445, 16),
|
||||
Rational(-2011, 54),
|
||||
Rational(1359199, 72900),
|
||||
Rational(-135733, 32805),
|
||||
Rational(2254, 6561),
|
||||
Rational(0, 1),
|
||||
Rational(0, 1),
|
||||
Rational(0, 1),
|
||||
Rational(0, 1)
|
||||
),
|
||||
ListPolynomial(
|
||||
Rational(-2018387, 46656),
|
||||
Rational(82316437, 1574640),
|
||||
Rational(-9335047, 393660),
|
||||
Rational(15765889, 3280500),
|
||||
Rational(-242089, 656100),
|
||||
Rational(0, 1),
|
||||
Rational(0, 1),
|
||||
Rational(0, 1),
|
||||
Rational(0, 1)
|
||||
)
|
||||
),
|
||||
ListRationalFunction(
|
||||
ListPolynomial(
|
||||
Rational(1, 1),
|
||||
Rational(-10, 5),
|
||||
Rational(18, 8),
|
||||
Rational(0)
|
||||
),
|
||||
ListPolynomial(
|
||||
Rational(-14, 8),
|
||||
Rational(-14, 8),
|
||||
Rational(-19, 6),
|
||||
Rational(14, 3),
|
||||
Rational(0)
|
||||
)
|
||||
).substitute(RationalField,
|
||||
ListRationalFunction(
|
||||
ListPolynomial(
|
||||
Rational(14, 9),
|
||||
Rational(-2, 5),
|
||||
Rational(0)
|
||||
),
|
||||
ListPolynomial(
|
||||
Rational(-6, 4),
|
||||
Rational(5, 9),
|
||||
Rational(0)
|
||||
)
|
||||
)
|
||||
),
|
||||
"test 4"
|
||||
)
|
||||
assertEquals(
|
||||
ListRationalFunction(
|
||||
ListPolynomial(
|
||||
Rational(41635, 3888),
|
||||
Rational(0, 1),
|
||||
Rational(-279187, 11664),
|
||||
Rational(0, 1),
|
||||
Rational(103769, 3456),
|
||||
Rational(0, 1),
|
||||
Rational(-11017, 768),
|
||||
Rational(0, 1),
|
||||
Rational(4097, 4096)
|
||||
),
|
||||
ListPolynomial(
|
||||
Rational(-13811791, 3779136),
|
||||
Rational(0, 1),
|
||||
Rational(-9999395, 419904),
|
||||
Rational(0, 1),
|
||||
Rational(6376601, 124416),
|
||||
Rational(0, 1),
|
||||
Rational(-3668315, 82944),
|
||||
Rational(0, 1),
|
||||
Rational(2097089, 147456)
|
||||
)
|
||||
),
|
||||
ListRationalFunction(
|
||||
ListPolynomial(
|
||||
Rational(1, 1),
|
||||
Rational(0),
|
||||
Rational(0),
|
||||
Rational(-8, 8)
|
||||
),
|
||||
ListPolynomial(
|
||||
Rational(-14, 8),
|
||||
Rational(0),
|
||||
Rational(0),
|
||||
Rational(0),
|
||||
Rational(8, 9)
|
||||
)
|
||||
).substitute(RationalField,
|
||||
ListRationalFunction(
|
||||
ListPolynomial(
|
||||
Rational(14, 9),
|
||||
Rational(0),
|
||||
Rational(-14, 7)
|
||||
),
|
||||
ListPolynomial(
|
||||
Rational(-6, 4),
|
||||
Rational(0),
|
||||
Rational(1, 8)
|
||||
)
|
||||
)
|
||||
),
|
||||
"test 5"
|
||||
)
|
||||
}
|
||||
@Test
|
||||
fun test_Polynomial_derivative() {
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(-2), Rational(2)),
|
||||
ListPolynomial(Rational(1), Rational(-2), Rational(1)).derivative(RationalField),
|
||||
"test 1"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(-8, 3), Rational(8, 9), Rational(15, 7), Rational(-20, 9)),
|
||||
ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).derivative(RationalField),
|
||||
"test 2"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(0), Rational(8, 9), Rational(15, 7), Rational(-20, 9)),
|
||||
ListPolynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).derivative(RationalField),
|
||||
"test 3"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(-8, 3), Rational(8, 9), Rational(15, 7), Rational(0)),
|
||||
ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).derivative(RationalField),
|
||||
"test 4"
|
||||
)
|
||||
}
|
||||
@Test
|
||||
fun test_Polynomial_nthDerivative() {
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(-2), Rational(2)),
|
||||
ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 1),
|
||||
"test 1"
|
||||
)
|
||||
assertFailsWithTypeAndMessage<IllegalArgumentException>(
|
||||
"Order of derivative must be non-negative",
|
||||
"test2"
|
||||
) {
|
||||
ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, -1)
|
||||
}
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(1), Rational(-2), Rational(1)),
|
||||
ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 0),
|
||||
"test 3"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(2)),
|
||||
ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 2),
|
||||
"test 4"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(),
|
||||
ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 3),
|
||||
"test 5"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(),
|
||||
ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 4),
|
||||
"test 6"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(8, 9), Rational(30, 7), Rational(-20, 3)),
|
||||
ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthDerivative(RationalField, 2),
|
||||
"test 7"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(8, 9), Rational(30, 7), Rational(-20, 3)),
|
||||
ListPolynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthDerivative(RationalField, 2),
|
||||
"test 8"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(8, 9), Rational(30, 7), Rational(0)),
|
||||
ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).nthDerivative(RationalField, 2),
|
||||
"test 9"
|
||||
)
|
||||
}
|
||||
@Test
|
||||
fun test_Polynomial_antiderivative() {
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(0), Rational(1), Rational(-1), Rational(1, 3)),
|
||||
ListPolynomial(Rational(1), Rational(-2), Rational(1)).antiderivative(RationalField),
|
||||
"test 1"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(0), Rational(1, 5), Rational(-4, 3), Rational(4, 27), Rational(5, 28), Rational(-1, 9)),
|
||||
ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).antiderivative(RationalField),
|
||||
"test 2"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(4, 27), Rational(5, 28), Rational(-1, 9)),
|
||||
ListPolynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).antiderivative(RationalField),
|
||||
"test 3"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(0), Rational(1, 5), Rational(-4, 3), Rational(4, 27), Rational(5, 28), Rational(0)),
|
||||
ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).antiderivative(RationalField),
|
||||
"test 4"
|
||||
)
|
||||
}
|
||||
@Test
|
||||
fun test_Polynomial_nthAntiderivative() {
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(0), Rational(1), Rational(-1), Rational(1, 3)),
|
||||
ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 1),
|
||||
"test 1"
|
||||
)
|
||||
assertFailsWithTypeAndMessage<IllegalArgumentException>(
|
||||
"Order of antiderivative must be non-negative",
|
||||
"test2"
|
||||
) {
|
||||
ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, -1)
|
||||
}
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(1), Rational(-2), Rational(1)),
|
||||
ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 0),
|
||||
"test 3"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(0), Rational(0), Rational(1, 2), Rational(-1, 3), Rational(1, 12)),
|
||||
ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 2),
|
||||
"test 4"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(1, 6), Rational(-1, 12), Rational(1, 60)),
|
||||
ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 3),
|
||||
"test 5"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0), Rational(1, 24), Rational(-1, 60), Rational(1, 360)),
|
||||
ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 4),
|
||||
"test 6"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(0), Rational(0), Rational(1, 10), Rational(-4, 9), Rational(1, 27), Rational(1, 28), Rational(-1, 54)),
|
||||
ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthAntiderivative(RationalField, 2),
|
||||
"test 7"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0), Rational(1, 27), Rational(1, 28), Rational(-1, 54)),
|
||||
ListPolynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthAntiderivative(RationalField, 2),
|
||||
"test 8"
|
||||
)
|
||||
assertEquals(
|
||||
ListPolynomial(Rational(0), Rational(0), Rational(1, 10), Rational(-4, 9), Rational(1, 27), Rational(1, 28), Rational(0)),
|
||||
ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).nthAntiderivative(RationalField, 2),
|
||||
"test 9"
|
||||
)
|
||||
}
|
||||
}
|
@ -1,123 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018-2022 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 testDSL1() {
|
||||
assertEquals(
|
||||
NumberedPolynomialAsIs(
|
||||
listOf(2u, 0u, 3u) to 5,
|
||||
listOf(0u, 1u) to -6,
|
||||
),
|
||||
Int.algebra.numberedPolynomialSpace {
|
||||
NumberedPolynomialDSL1 {
|
||||
5 { 0 pow 2u; 2 pow 3u }
|
||||
(-6) { 1 pow 1u }
|
||||
}
|
||||
},
|
||||
"test 1"
|
||||
)
|
||||
assertEquals(
|
||||
NumberedPolynomialAsIs(
|
||||
listOf<UInt>() to -1,
|
||||
),
|
||||
Int.algebra.numberedPolynomialSpace {
|
||||
NumberedPolynomialDSL1 {
|
||||
5 { }
|
||||
(-6) { }
|
||||
}
|
||||
},
|
||||
"test 2"
|
||||
)
|
||||
assertEquals(
|
||||
NumberedPolynomialAsIs(
|
||||
listOf(2u) to -1,
|
||||
),
|
||||
Int.algebra.numberedPolynomialSpace {
|
||||
NumberedPolynomialDSL1 {
|
||||
5 { 0 pow 1u; 0 pow 1u }
|
||||
(-6) { 0 pow 2u }
|
||||
}
|
||||
},
|
||||
"test 3"
|
||||
)
|
||||
assertEquals(
|
||||
NumberedPolynomialAsIs(
|
||||
listOf(2u) to -1,
|
||||
),
|
||||
Int.algebra.numberedPolynomialSpace {
|
||||
NumberedPolynomialDSL1 {
|
||||
5 { 0 pow 1u; 0 pow 1u }
|
||||
(-6) { 0 pow 2u; 2 pow 0u }
|
||||
}
|
||||
},
|
||||
"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
File diff suppressed because it is too large
Load Diff
@ -1,12 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018-2022 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.testUtils
|
||||
|
||||
import space.kscience.kmath.structures.Buffer
|
||||
import space.kscience.kmath.structures.asBuffer
|
||||
|
||||
|
||||
fun <T> bufferOf(vararg elements: T): Buffer<T> = elements.asBuffer()
|
@ -1,133 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018-2022 KMath contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@file:Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress")
|
||||
|
||||
package space.kscience.kmath.functions.testUtils
|
||||
|
||||
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(this.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")
|
||||
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 = 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
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018-2022 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.testUtils
|
||||
|
||||
import space.kscience.kmath.functions.ListPolynomial
|
||||
import space.kscience.kmath.functions.ListPolynomialSpace
|
||||
import space.kscience.kmath.functions.PolynomialSpaceOverRing
|
||||
|
||||
|
||||
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 = IntModulo(arg, modulus)
|
||||
fun PolynomialSpaceOverRing<IntModulo, *, IntModuloRing>.m(arg: Int): IntModulo = IntModulo(arg, ring.modulus)
|
@ -1,29 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018-2022 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.testUtils
|
||||
|
||||
import kotlin.math.abs
|
||||
|
||||
|
||||
internal data class BezoutIdentityWithGCD<T>(val first: T, val second: T, val gcd: T)
|
||||
|
||||
internal tailrec fun gcd(a: Long, b: Long): Long = if (a == 0L) abs(b) else gcd(b % a, a)
|
||||
|
||||
internal 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)
|
||||
}
|
@ -1,177 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018-2022 KMath contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@file:Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress")
|
||||
|
||||
package space.kscience.kmath.functions.testUtils
|
||||
|
||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||
import space.kscience.kmath.operations.Field
|
||||
import space.kscience.kmath.operations.NumbersAddOps
|
||||
|
||||
@Suppress("NAME_SHADOWING")
|
||||
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 {
|
||||
val denominatorsGcd = gcd(denominator, other.denominator)
|
||||
val dividedThisDenominator = denominator / denominatorsGcd
|
||||
val dividedOtherDenominator = other.denominator / denominatorsGcd
|
||||
val numeratorCandidate = numerator * dividedOtherDenominator + dividedThisDenominator * other.numerator
|
||||
val secondGcd = gcd(numeratorCandidate, denominatorsGcd)
|
||||
return Rational(
|
||||
numeratorCandidate / secondGcd,
|
||||
dividedThisDenominator * (other.denominator / secondGcd),
|
||||
toCheckInput = false
|
||||
)
|
||||
}
|
||||
operator fun plus(other: Int): Rational =
|
||||
Rational(
|
||||
numerator + denominator * other.toLong(),
|
||||
denominator,
|
||||
toCheckInput = false
|
||||
)
|
||||
operator fun plus(other: Long): Rational =
|
||||
Rational(
|
||||
numerator + denominator * other,
|
||||
denominator,
|
||||
toCheckInput = false
|
||||
)
|
||||
operator fun minus(other: Rational): Rational {
|
||||
val denominatorsGcd = gcd(denominator, other.denominator)
|
||||
val dividedThisDenominator = denominator / denominatorsGcd
|
||||
val dividedOtherDenominator = other.denominator / denominatorsGcd
|
||||
val numeratorCandidate = numerator * dividedOtherDenominator - dividedThisDenominator * other.numerator
|
||||
val secondGcd = gcd(numeratorCandidate, denominatorsGcd)
|
||||
return Rational(
|
||||
numeratorCandidate / secondGcd,
|
||||
dividedThisDenominator * (other.denominator / secondGcd),
|
||||
toCheckInput = false
|
||||
)
|
||||
}
|
||||
operator fun minus(other: Int): Rational =
|
||||
Rational(
|
||||
numerator - denominator * other.toLong(),
|
||||
denominator,
|
||||
toCheckInput = false
|
||||
)
|
||||
operator fun minus(other: Long): Rational =
|
||||
Rational(
|
||||
numerator - denominator * other,
|
||||
denominator,
|
||||
toCheckInput = false
|
||||
)
|
||||
operator fun times(other: Rational): Rational {
|
||||
val thisDenominatorAndOtherNumeratorGcd = gcd(denominator, other.numerator)
|
||||
val otherDenominatorAndThisNumeratorGcd = gcd(other.denominator, numerator)
|
||||
return Rational(
|
||||
(numerator / otherDenominatorAndThisNumeratorGcd) * (other.numerator / thisDenominatorAndOtherNumeratorGcd),
|
||||
(denominator / thisDenominatorAndOtherNumeratorGcd) * (other.denominator / otherDenominatorAndThisNumeratorGcd),
|
||||
toCheckInput = false
|
||||
)
|
||||
}
|
||||
operator fun times(other: Int): Rational {
|
||||
val other = other.toLong()
|
||||
val denominatorAndOtherGcd = gcd(denominator, other)
|
||||
return Rational(
|
||||
numerator * (other / denominatorAndOtherGcd),
|
||||
denominator / denominatorAndOtherGcd,
|
||||
toCheckInput = false
|
||||
)
|
||||
}
|
||||
operator fun times(other: Long): Rational {
|
||||
val denominatorAndOtherGcd = gcd(denominator, other)
|
||||
return Rational(
|
||||
numerator * (other / denominatorAndOtherGcd),
|
||||
denominator / denominatorAndOtherGcd,
|
||||
toCheckInput = false
|
||||
)
|
||||
}
|
||||
operator fun div(other: Rational): Rational {
|
||||
val denominatorsGcd = gcd(denominator, other.denominator)
|
||||
val numeratorsGcd = gcd(numerator, other.numerator)
|
||||
return Rational(
|
||||
(numerator / numeratorsGcd) * (other.denominator / denominatorsGcd),
|
||||
(denominator / denominatorsGcd) * (other.numerator / numeratorsGcd)
|
||||
)
|
||||
}
|
||||
operator fun div(other: Int): Rational {
|
||||
val other = other.toLong()
|
||||
val numeratorAndOtherGcd = gcd(numerator, other)
|
||||
return Rational(
|
||||
numerator / numeratorAndOtherGcd,
|
||||
denominator * (other / numeratorAndOtherGcd),
|
||||
toCheckInput = false
|
||||
)
|
||||
}
|
||||
operator fun div(other: Long): Rational {
|
||||
val numeratorAndOtherGcd = gcd(numerator, other)
|
||||
return Rational(
|
||||
numerator / numeratorAndOtherGcd,
|
||||
denominator * (other / numeratorAndOtherGcd),
|
||||
toCheckInput = false
|
||||
)
|
||||
}
|
||||
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")
|
||||
@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
|
||||
}
|
@ -1,104 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018-2022 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.testUtils
|
||||
|
||||
import space.kscience.kmath.functions.LabeledPolynomial
|
||||
import space.kscience.kmath.functions.LabeledRationalFunction
|
||||
import space.kscience.kmath.functions.NumberedPolynomial
|
||||
import space.kscience.kmath.functions.NumberedRationalFunction
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFailsWith
|
||||
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
fun assertEquals(
|
||||
expected: NumberedPolynomial<Double>,
|
||||
actual: NumberedPolynomial<Double>,
|
||||
absoluteTolerance: Double,
|
||||
message: String? = null
|
||||
) {
|
||||
assertContentEquals(
|
||||
expected.coefficients,
|
||||
actual.coefficients,
|
||||
absoluteTolerance,
|
||||
message
|
||||
)
|
||||
}
|
||||
|
||||
fun assertEquals(
|
||||
expected: LabeledPolynomial<Double>,
|
||||
actual: LabeledPolynomial<Double>,
|
||||
absoluteTolerance: Double,
|
||||
message: String? = null
|
||||
) {
|
||||
assertContentEquals(
|
||||
expected.coefficients,
|
||||
actual.coefficients,
|
||||
absoluteTolerance,
|
||||
message
|
||||
)
|
||||
}
|
||||
|
||||
fun assertEquals(
|
||||
expected: NumberedRationalFunction<Double>,
|
||||
actual: NumberedRationalFunction<Double>,
|
||||
absoluteTolerance: Double,
|
||||
message: String? = null
|
||||
) {
|
||||
assertEquals(
|
||||
expected.numerator,
|
||||
actual.numerator,
|
||||
absoluteTolerance,
|
||||
message
|
||||
)
|
||||
assertEquals(
|
||||
expected.denominator,
|
||||
actual.denominator,
|
||||
absoluteTolerance,
|
||||
message
|
||||
)
|
||||
}
|
||||
|
||||
fun assertEquals(
|
||||
expected: LabeledRationalFunction<Double>,
|
||||
actual: LabeledRationalFunction<Double>,
|
||||
absoluteTolerance: Double,
|
||||
message: String? = null
|
||||
) {
|
||||
assertEquals(
|
||||
expected.numerator,
|
||||
actual.numerator,
|
||||
absoluteTolerance,
|
||||
message
|
||||
)
|
||||
assertEquals(
|
||||
expected.denominator,
|
||||
actual.denominator,
|
||||
absoluteTolerance,
|
||||
message
|
||||
)
|
||||
}
|
||||
|
||||
inline fun <reified T : Throwable> assertFailsWithTypeAndMessage(
|
||||
expectedMessage: String? = null,
|
||||
assertionMessage: String? = null,
|
||||
block: () -> Unit
|
||||
) {
|
||||
assertEquals(
|
||||
expectedMessage,
|
||||
assertFailsWith(T::class, assertionMessage, block).message,
|
||||
assertionMessage
|
||||
)
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018-2022 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.testUtils
|
||||
|
||||
import space.kscience.kmath.expressions.Symbol
|
||||
import space.kscience.kmath.expressions.symbol
|
||||
|
||||
|
||||
val o: Rational = Rational(0)
|
||||
|
||||
val x: Symbol by symbol
|
||||
val y: Symbol by symbol
|
||||
val z: Symbol by symbol
|
||||
val t: Symbol by symbol
|
||||
val s: Symbol by symbol
|
||||
val iota: Symbol by symbol
|
@ -26,7 +26,6 @@ include(
|
||||
":kmath-core",
|
||||
":kmath-coroutines",
|
||||
":kmath-functions",
|
||||
":kmath-polynomial",
|
||||
":kmath-histograms",
|
||||
":kmath-commons",
|
||||
":kmath-viktor",
|
||||
|
Loading…
Reference in New Issue
Block a user