Feature: Polynomials and rational functions #469
@ -16,7 +16,7 @@ dependencies {
|
||||
implementation(project(":kmath-commons"))
|
||||
implementation(project(":kmath-complex"))
|
||||
implementation(project(":kmath-functions"))
|
||||
implementation(project(":kmath-polynomialX"))
|
||||
implementation(project(":kmath-polynomial"))
|
||||
implementation(project(":kmath-optimization"))
|
||||
implementation(project(":kmath-stat"))
|
||||
implementation(project(":kmath-viktor"))
|
||||
|
@ -10,13 +10,11 @@ kotlin.sourceSets {
|
||||
commonMain {
|
||||
dependencies {
|
||||
api(projects.kmathCore)
|
||||
api(projects.kmathFunctions)
|
||||
}
|
||||
}
|
||||
commonTest {
|
||||
dependencies {
|
||||
api(projects.testUtilsFunctions)
|
||||
api(projects.testUtilsPolynomialX)
|
||||
api(projects.testUtilsPolynomial)
|
||||
api(kotlin("test"))
|
||||
}
|
||||
}
|
@ -0,0 +1,387 @@
|
||||
/*
|
||||
* Copyright 2018-2021 KMath contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@file:Suppress("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<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.
|
||||
*/
|
||||
public val coefficients: List<C>
|
||||
) : Polynomial<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, 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
|
||||
.toMutableList()
|
||||
.apply {
|
||||
for (deg in indices) this[deg] = this[deg] * 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
|
||||
.toMutableList()
|
||||
.apply {
|
||||
for (deg in indices) this[deg] = this@times * this[deg]
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
.toMutableList()
|
||||
.apply {
|
||||
for (deg in indices) this[deg] = this@times * this[deg]
|
||||
}
|
||||
)
|
||||
|
||||
/**
|
||||
* 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
|
||||
.toMutableList()
|
||||
.apply {
|
||||
for (deg in indices) this[deg] = this[deg] * 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, 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) }) }
|
||||
}
|
@ -0,0 +1,502 @@
|
||||
/*
|
||||
* Copyright 2018-2021 KMath contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package space.kscience.kmath.functions
|
||||
|
||||
import space.kscience.kmath.operations.Ring
|
||||
import space.kscience.kmath.operations.invoke
|
||||
import kotlin.js.JsName
|
||||
import kotlin.jvm.JvmName
|
||||
|
||||
|
||||
/**
|
||||
* Abstraction of polynomials.
|
||||
*/
|
||||
public interface Polynomial<C>
|
||||
|
||||
/**
|
||||
* 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: Polynomial<C>> : 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].
|
||||
*/
|
||||
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].
|
||||
*/
|
||||
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].
|
||||
*/
|
||||
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].
|
||||
*/
|
||||
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].
|
||||
*/
|
||||
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].
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
public operator fun C.plus(other: P): P
|
||||
/**
|
||||
* Returns difference between the constant represented as a polynomial and the polynomial.
|
||||
*/
|
||||
public operator fun C.minus(other: P): P
|
||||
/**
|
||||
* Returns product of the constant represented as a polynomial and the polynomial.
|
||||
*/
|
||||
public operator fun C.times(other: P): P
|
||||
|
||||
/**
|
||||
* Returns sum of the constant represented as a polynomial and the polynomial.
|
||||
*/
|
||||
public operator fun P.plus(other: C): P
|
||||
/**
|
||||
* Returns difference between the constant represented as a polynomial and the polynomial.
|
||||
*/
|
||||
public operator fun P.minus(other: C): P
|
||||
/**
|
||||
* Returns product of the constant represented as a polynomial and the polynomial.
|
||||
*/
|
||||
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: Polynomial<C>, A: Ring<C>> : PolynomialSpace<C, P> {
|
||||
|
||||
/**
|
||||
* Underlying ring of constants. Its operations on constants are inherited by local operations on constants.
|
||||
*/
|
||||
public val ring: A
|
||||
|
||||
/**
|
||||
* Returns sum of the constant and the integer represented as a constant (member of underlying ring).
|
||||
*
|
||||
* The operation is equivalent to adding [other] copies of unit of underlying ring to [this].
|
||||
*/
|
||||
public override operator fun C.plus(other: Int): C = ring { addMultipliedByDoubling(this@plus, one, other) }
|
||||
/**
|
||||
* Returns difference between the constant and the integer represented as a constant (member of underlying ring).
|
||||
*
|
||||
* The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this].
|
||||
*/
|
||||
public override operator fun C.minus(other: Int): C = ring { addMultipliedByDoubling(this@minus, one, -other) }
|
||||
/**
|
||||
* Returns product of the constant and the integer represented as a constant (member of underlying ring).
|
||||
*
|
||||
* The operation is equivalent to sum of [other] copies of [this].
|
||||
*/
|
||||
public override operator fun C.times(other: Int): C = ring { multiplyByDoubling(this@times, other) }
|
||||
|
||||
/**
|
||||
* Returns sum of the integer represented as a constant (member of underlying ring) and the constant.
|
||||
*
|
||||
* The operation is equivalent to adding [this] copies of unit of underlying ring to [other].
|
||||
*/
|
||||
public override operator fun Int.plus(other: C): C = ring { addMultipliedByDoubling(other, one, this@plus) }
|
||||
/**
|
||||
* Returns difference between the integer represented as a constant (member of underlying ring) and the constant.
|
||||
*
|
||||
* The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other].
|
||||
*/
|
||||
public override operator fun Int.minus(other: C): C = ring { addMultipliedByDoubling(-other, one, this@minus) }
|
||||
/**
|
||||
* Returns product of the integer represented as a constant (member of underlying ring) and the constant.
|
||||
*
|
||||
* The operation is equivalent to sum of [this] copies of [other].
|
||||
*/
|
||||
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: Polynomial<C>>: PolynomialSpace<C, P> {
|
||||
/**
|
||||
* Returns sum of the variable represented as a monic monomial and the integer represented as a constant polynomial.
|
||||
*/
|
||||
@JvmName("plusVariableInt")
|
||||
public operator fun V.plus(other: Int): P
|
||||
/**
|
||||
* Returns difference between the variable represented as a monic monomial and the integer represented as a constant polynomial.
|
||||
*/
|
||||
@JvmName("minusVariableInt")
|
||||
public operator fun V.minus(other: Int): P
|
||||
/**
|
||||
* Returns product of the variable represented as a monic monomial and the integer represented as a constant polynomial.
|
||||
*/
|
||||
@JvmName("timesVariableInt")
|
||||
public operator fun V.times(other: Int): P
|
||||
|
||||
/**
|
||||
* Returns sum of the integer represented as a constant polynomial and the variable represented as a monic monomial.
|
||||
*/
|
||||
@JvmName("plusIntVariable")
|
||||
public operator fun Int.plus(other: V): P
|
||||
/**
|
||||
* Returns difference between the integer represented as a constant polynomial and the variable represented as a monic monomial.
|
||||
*/
|
||||
@JvmName("minusIntVariable")
|
||||
public operator fun Int.minus(other: V): P
|
||||
/**
|
||||
* Returns product of the integer represented as a constant polynomial and the variable represented as a monic monomial.
|
||||
*/
|
||||
@JvmName("timesIntVariable")
|
||||
public operator fun Int.times(other: V): P
|
||||
|
||||
/**
|
||||
* Returns sum of the variable represented as a monic monomial and the constant represented as a constant polynomial.
|
||||
*/
|
||||
@JvmName("plusVariableConstant")
|
||||
public operator fun V.plus(other: C): P
|
||||
/**
|
||||
* Returns difference between the variable represented as a monic monomial and the constant represented as a constant polynomial.
|
||||
*/
|
||||
@JvmName("minusVariableConstant")
|
||||
public operator fun V.minus(other: C): P
|
||||
/**
|
||||
* Returns product of the variable represented as a monic monomial and the constant represented as a constant polynomial.
|
||||
*/
|
||||
@JvmName("timesVariableConstant")
|
||||
public operator fun V.times(other: C): P
|
||||
|
||||
/**
|
||||
* Returns sum of the constant represented as a constant polynomial and the variable represented as a monic monomial.
|
||||
*/
|
||||
@JvmName("plusConstantVariable")
|
||||
public operator fun C.plus(other: V): P
|
||||
/**
|
||||
* Returns difference between the constant represented as a constant polynomial and the variable represented as a monic monomial.
|
||||
*/
|
||||
@JvmName("minusConstantVariable")
|
||||
public operator fun C.minus(other: V): P
|
||||
/**
|
||||
* Returns product of the constant represented as a constant polynomial and the variable represented as a monic monomial.
|
||||
*/
|
||||
@JvmName("timesConstantVariable")
|
||||
public operator fun C.times(other: V): P
|
||||
|
||||
/**
|
||||
* Represents the variable as a monic monomial.
|
||||
*/
|
||||
@JvmName("unaryPlusVariable")
|
||||
public operator fun V.unaryPlus(): P
|
||||
/**
|
||||
* Returns negation of representation of the variable as a monic monomial.
|
||||
*/
|
||||
@JvmName("unaryMinusVariable")
|
||||
public operator fun V.unaryMinus(): P
|
||||
/**
|
||||
* Returns sum of the variables represented as monic monomials.
|
||||
*/
|
||||
@JvmName("plusVariableVariable")
|
||||
public operator fun V.plus(other: V): P
|
||||
/**
|
||||
* Returns difference between the variables represented as monic monomials.
|
||||
*/
|
||||
@JvmName("minusVariableVariable")
|
||||
public operator fun V.minus(other: V): P
|
||||
/**
|
||||
* Returns product of the variables represented as monic monomials.
|
||||
*/
|
||||
@JvmName("timesVariableVariable")
|
||||
public operator fun V.times(other: V): P
|
||||
|
||||
/**
|
||||
* Represents the [variable] as a monic monomial.
|
||||
*/
|
||||
@JvmName("numberVariable")
|
||||
public fun number(variable: V): P = +variable
|
||||
/**
|
||||
* Represents the variable as a monic monomial.
|
||||
*/
|
||||
@JvmName("asPolynomialVariable")
|
||||
public fun V.asPolynomial(): P = number(this)
|
||||
|
||||
/**
|
||||
* Returns sum of the variable represented as a monic monomial and the polynomial.
|
||||
*/
|
||||
@JvmName("plusVariablePolynomial")
|
||||
public operator fun V.plus(other: P): P
|
||||
/**
|
||||
* Returns difference between the variable represented as a monic monomial and the polynomial.
|
||||
*/
|
||||
@JvmName("minusVariablePolynomial")
|
||||
public operator fun V.minus(other: P): P
|
||||
/**
|
||||
* Returns product of the variable represented as a monic monomial and the polynomial.
|
||||
*/
|
||||
@JvmName("timesVariablePolynomial")
|
||||
public operator fun V.times(other: P): P
|
||||
|
||||
/**
|
||||
* Returns sum of the polynomial and the variable represented as a monic monomial.
|
||||
*/
|
||||
@JvmName("plusPolynomialVariable")
|
||||
public operator fun P.plus(other: V): P
|
||||
/**
|
||||
* Returns difference between the polynomial and the variable represented as a monic monomial.
|
||||
*/
|
||||
@JvmName("minusPolynomialVariable")
|
||||
public operator fun P.minus(other: V): P
|
||||
/**
|
||||
* Returns product of the polynomial and the variable represented as a monic monomial.
|
||||
*/
|
||||
@JvmName("timesPolynomialVariable")
|
||||
public operator fun P.times(other: V): P
|
||||
|
||||
/**
|
||||
* 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
|
||||
}
|
@ -5,7 +5,8 @@
|
||||
|
||||
package space.kscience.kmath.functions
|
||||
|
||||
import space.kscience.kmath.operations.*
|
||||
import space.kscience.kmath.operations.Ring
|
||||
import space.kscience.kmath.operations.invoke
|
||||
import kotlin.js.JsName
|
||||
import kotlin.jvm.JvmName
|
||||
|
@ -8,9 +8,9 @@ package space.kscience.kmath.functions
|
||||
import space.kscience.kmath.expressions.Symbol
|
||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||
import space.kscience.kmath.operations.Field
|
||||
import space.kscience.kmath.operations.invoke
|
||||
import space.kscience.kmath.operations.Ring
|
||||
import space.kscience.kmath.operations.algebra
|
||||
import space.kscience.kmath.operations.invoke
|
||||
import kotlin.contracts.InvocationKind
|
||||
import kotlin.contracts.contract
|
||||
import kotlin.jvm.JvmName
|
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright 2018-2021 KMath contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package space.kscience.kmath.functions
|
||||
|
||||
import space.kscience.kmath.operations.Ring
|
||||
|
||||
|
||||
/**
|
||||
* 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())
|
@ -0,0 +1,255 @@
|
||||
/*
|
||||
* Copyright 2018-2021 KMath contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package space.kscience.kmath.functions
|
||||
|
||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||
import space.kscience.kmath.operations.*
|
||||
import kotlin.contracts.InvocationKind
|
||||
import kotlin.contracts.contract
|
||||
import kotlin.math.max
|
||||
import kotlin.math.pow
|
||||
|
||||
|
||||
/**
|
||||
* Creates a [ListPolynomialSpace] over a received ring.
|
||||
*/
|
||||
public 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)
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2018-2021 KMath contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package space.kscience.kmath.functions
|
||||
|
||||
|
||||
/**
|
||||
* Marks 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
|
@ -6,13 +6,13 @@
|
||||
package space.kscience.kmath.functions
|
||||
|
||||
import space.kscience.kmath.expressions.Symbol
|
||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||
import space.kscience.kmath.operations.algebra
|
||||
import space.kscience.kmath.operations.invoke
|
||||
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
|
||||
|
@ -11,15 +11,15 @@ import space.kscience.kmath.expressions.Symbol
|
||||
import space.kscience.kmath.functions.testUtils.IntModuloRing
|
||||
import space.kscience.kmath.functions.testUtils.Rational
|
||||
import space.kscience.kmath.functions.testUtils.RationalField
|
||||
import space.kscience.kmath.functions.testUtils.o
|
||||
import space.kscience.kmath.functions.testUtils.iota
|
||||
import space.kscience.kmath.functions.testUtils.m
|
||||
import kotlin.test.*
|
||||
import space.kscience.kmath.functions.testUtils.o
|
||||
import space.kscience.kmath.functions.testUtils.s
|
||||
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.functions.testUtils.t
|
||||
import space.kscience.kmath.functions.testUtils.s
|
||||
import space.kscience.kmath.functions.testUtils.iota
|
||||
import kotlin.test.*
|
||||
|
||||
|
||||
// TODO: Тесты на конвертацию.
|
@ -6,16 +6,15 @@
|
||||
package space.kscience.kmath.functions
|
||||
|
||||
import space.kscience.kmath.expressions.Symbol
|
||||
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.iota
|
||||
import space.kscience.kmath.functions.testUtils.x
|
||||
import space.kscience.kmath.functions.testUtils.y
|
||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||
import kotlin.test.Ignore
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import space.kscience.kmath.functions.testUtils.x
|
||||
import space.kscience.kmath.functions.testUtils.y
|
||||
import space.kscience.kmath.functions.testUtils.iota
|
||||
import space.kscience.kmath.functions.testUtils.assertEquals
|
||||
|
||||
class LabeledPolynomialUtilTest {
|
||||
@Test
|
@ -27,8 +27,8 @@ include(
|
||||
":kmath-coroutines",
|
||||
":kmath-functions",
|
||||
":test-utils-functions",
|
||||
":kmath-polynomialX",
|
||||
":test-utils-polynomialX",
|
||||
":kmath-polynomial",
|
||||
":test-utils-polynomial",
|
||||
":kmath-histograms",
|
||||
":kmath-commons",
|
||||
":kmath-viktor",
|
||||
|
@ -7,9 +7,7 @@ kotlin.sourceSets {
|
||||
commonMain {
|
||||
dependencies {
|
||||
api(projects.kmathCore)
|
||||
api(projects.kmathFunctions)
|
||||
api(projects.testUtilsFunctions)
|
||||
api(projects.kmathPolynomialX)
|
||||
api(projects.kmathPolynomial)
|
||||
api(kotlin("test"))
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user