0.3.1-dev-11 #510

Merged
altavir merged 80 commits from dev into master 2023-04-05 18:46:36 +03:00
39 changed files with 1 additions and 35350 deletions
Showing only changes of commit b14e2fdd08 - Show all commits

View File

@ -20,6 +20,7 @@
### Deprecated ### Deprecated
### Removed ### Removed
- Polynomials moved to https://github.com/SciProgCentre/kmath-polynomial
### Fixed ### Fixed

View File

@ -18,7 +18,6 @@ dependencies {
implementation(project(":kmath-commons")) implementation(project(":kmath-commons"))
implementation(project(":kmath-complex")) implementation(project(":kmath-complex"))
implementation(project(":kmath-functions")) implementation(project(":kmath-functions"))
implementation(project(":kmath-polynomial"))
implementation(project(":kmath-optimization")) implementation(project(":kmath-optimization"))
implementation(project(":kmath-stat")) implementation(project(":kmath-stat"))
implementation(project(":kmath-viktor")) implementation(project(":kmath-viktor"))

View File

@ -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()
}

View File

@ -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")
}
```

View File

@ -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."
}
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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) }) }
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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
}

View File

@ -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")
}

View File

@ -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)

View File

@ -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 &mdash; 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 &mdash; 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 &mdash; 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 &mdash; 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 &mdash; 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 &mdash; 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 &mdash; 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 &mdash; 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 &mdash; 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 &mdash; 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 &mdash; 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 &mdash; 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))
// )

View File

@ -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) }
}
}
)
}
}
)
}

View File

@ -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())

View File

@ -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)
}

View File

@ -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

View File

@ -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 &mdash; 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 &mdash; 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 &mdash; 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 &mdash; 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 &mdash; 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 &mdash; 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 &mdash; 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 &mdash; 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 &mdash; 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 &mdash; 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 &mdash; 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 &mdash; 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))
// )

View File

@ -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) }
}
}
)
}
}
)
}

View File

@ -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)"
)
}
}
}

View File

@ -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"
)
}
}

View File

@ -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"
)
}
}
}

View File

@ -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"
)
}
}

View File

@ -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"
)
}
}

View File

@ -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()

View File

@ -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
}

View File

@ -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)

View File

@ -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)
}

View File

@ -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
}

View File

@ -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
)
}

View File

@ -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

View File

@ -26,7 +26,6 @@ include(
":kmath-core", ":kmath-core",
":kmath-coroutines", ":kmath-coroutines",
":kmath-functions", ":kmath-functions",
":kmath-polynomial",
":kmath-histograms", ":kmath-histograms",
":kmath-commons", ":kmath-commons",
":kmath-viktor", ":kmath-viktor",