Iaroslav Postovalov e9c31b7827
Merge branch 'master' into dev
# Conflicts:
#	README.md
#	build.gradle.kts
#	examples/src/main/kotlin/space/kscience/kmath/stat/DistributionBenchmark.kt
#	examples/src/main/kotlin/space/kscience/kmath/structures/ParallelRealNDField.kt
#	kmath-ast/README.md
#	kmath-ast/build.gradle.kts
#	kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/MstExpression.kt
#	kmath-complex/README.md
#	kmath-complex/build.gradle.kts
#	kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/ComplexNDField.kt
#	kmath-core/README.md
#	kmath-core/build.gradle.kts
#	kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/MST.kt
#	kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/MstAlgebra.kt
#	kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/RealNDField.kt
#	kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/RealBufferField.kt
#	kmath-coroutines/build.gradle.kts
#	kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingRealChain.kt
#	kmath-coroutines/src/jvmMain/kotlin/space/kscience/kmath/structures/LazyNDStructure.kt
#	kmath-dimensions/src/commonTest/kotlin/kscience/dimensions/DMatrixContextTest.kt
#	kmath-for-real/README.md
#	kmath-functions/README.md
#	kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt
#	kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LoessInterpolator.kt
#	kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/XYPointSet.kt
#	kmath-geometry/build.gradle.kts
#	kmath-nd4j/README.md
#	kmath-nd4j/build.gradle.kts
#	kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/FactorizedDistribution.kt
#	kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Distribution.kt
#	kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Fitting.kt
#	kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/OptimizationProblem.kt
#	kmath-stat/src/jvmMain/kotlin/space/kscience/kmath/stat/distributions.kt
#	kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorNDStructure.kt
2021-04-16 18:02:44 +07:00

96 lines
3.2 KiB
Kotlin

/*
* Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.functions
import space.kscience.kmath.operations.Group
import space.kscience.kmath.operations.Ring
import space.kscience.kmath.operations.ScaleOperations
import space.kscience.kmath.operations.invoke
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
import kotlin.math.max
import kotlin.math.pow
/**
* Polynomial coefficients model without fixation on specific context they are applied to.
*
* @param coefficients constant is the leftmost coefficient.
*/
public class Polynomial<T : Any>(public val coefficients: List<T>)
/**
* Returns a [Polynomial] instance with given [coefficients].
*/
@Suppress("FunctionName")
public fun <T : Any> Polynomial(vararg coefficients: T): Polynomial<T> = Polynomial(coefficients.toList())
/**
* Evaluates the value of the given double polynomial for given double argument.
*/
public fun Polynomial<Double>.value(): Double = coefficients.reduceIndexed { index, acc, d -> acc + d.pow(index) }
/**
* Evaluates the value of the given polynomial for given argument.
*/
public fun <T : Any, C : Ring<T>> Polynomial<T>.value(ring: C, arg: T): T = ring {
if (coefficients.isEmpty()) return@ring zero
var res = coefficients.first()
var powerArg = arg
for (index in 1 until coefficients.size) {
res += coefficients[index] * powerArg
// recalculating power on each step to avoid power costs on long polynomials
powerArg *= arg
}
res
}
/**
* Represent the polynomial as a regular context-less function.
*/
public fun <T : Any, C : Ring<T>> Polynomial<T>.asFunction(ring: C): (T) -> T = { value(ring, it) }
/**
* Space of polynomials.
*
* @param T the type of operated polynomials.
* @param C the intersection of [Ring] of [T] and [ScaleOperations] of [T].
* @param ring the [C] instance.
*/
public class PolynomialSpace<T : Any, C>(
private val ring: C,
) : Group<Polynomial<T>>, ScaleOperations<Polynomial<T>> where C : Ring<T>, C : ScaleOperations<T> {
public override val zero: Polynomial<T> = Polynomial(emptyList())
override fun Polynomial<T>.unaryMinus(): Polynomial<T> = ring {
Polynomial(coefficients.map { -it })
}
public override fun add(a: Polynomial<T>, b: Polynomial<T>): Polynomial<T> {
val dim = max(a.coefficients.size, b.coefficients.size)
return ring {
Polynomial(List(dim) { index ->
a.coefficients.getOrElse(index) { zero } + b.coefficients.getOrElse(index) { zero }
})
}
}
public override fun scale(a: Polynomial<T>, value: Double): Polynomial<T> =
ring { Polynomial(List(a.coefficients.size) { index -> a.coefficients[index] * value }) }
/**
* Evaluates the polynomial for the given value [arg].
*/
public operator fun Polynomial<T>.invoke(arg: T): T = value(ring, arg)
}
public inline fun <T : Any, C, R> C.polynomial(block: PolynomialSpace<T, C>.() -> R): R where C : Ring<T>, C : ScaleOperations<T> {
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
return PolynomialSpace(this).block()
}