Feature: Polynomials and rational functions #469

Merged
lounres merged 132 commits from feature/polynomials into dev 2022-07-28 18:04:06 +03:00
23 changed files with 2983 additions and 2969 deletions
Showing only changes of commit c6d1068df4 - Show all commits

View File

@ -1,389 +0,0 @@
/*
* Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.functions
import space.kscience.kmath.operations.*
import kotlin.js.JsName
import kotlin.jvm.JvmName
/**
* Abstraction of polynomials.
*/
public interface AbstractPolynomial<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")
public interface AbstractPolynomialSpace<C, P: AbstractPolynomial<C>> : Ring<P> {
/**
* Returns sum of the constant and the integer represented as constant (member of underlying ring).
*
* The operation is equivalent to adding [other] copies of unit of underlying ring to [this].
*/
public operator fun C.plus(other: Int): C
/**
* Returns difference between the constant and the integer represented as constant (member of underlying ring).
*
* The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this].
*/
public operator fun C.minus(other: Int): C
/**
* Returns product of the constant and the integer represented as constant (member of underlying ring).
*
* The operation is equivalent to sum of [other] copies of [this].
*/
public operator fun C.times(other: Int): C
/**
* Returns sum of the integer represented as constant (member of underlying ring) and the constant.
*
* The operation is equivalent to adding [this] copies of unit of underlying ring to [other].
*/
public operator fun Int.plus(other: C): C
/**
* Returns difference between the integer represented as constant (member of underlying ring) and the constant.
*
* The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other].
*/
public operator fun Int.minus(other: C): C
/**
* Returns product of the integer represented as constant (member of underlying ring) and the constant.
*
* The operation is equivalent to sum of [this] copies of [other].
*/
public operator fun Int.times(other: C): C
/**
* Returns sum of the polynomial and the integer represented as polynomial.
*
* The operation is equivalent to adding [other] copies of unit polynomial to [this].
*/
public operator fun P.plus(other: Int): P = addMultipliedBySquaring(this, one, other)
/**
* Returns difference between the polynomial and the integer represented as polynomial.
*
* The operation is equivalent to subtraction [other] copies of unit polynomial from [this].
*/
public operator fun P.minus(other: Int): P = addMultipliedBySquaring(this, one, -other)
/**
* Returns product of the polynomial and the integer represented as polynomial.
*
* The operation is equivalent to sum of [other] copies of [this].
*/
public operator fun P.times(other: Int): P = multiplyBySquaring(this, other)
/**
* Returns sum of the integer represented as 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 = addMultipliedBySquaring(other, one, this)
/**
* Returns difference between the integer represented as 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 = addMultipliedBySquaring(-other, one, this)
/**
* Returns product of the integer represented as polynomial and the polynomial.
*
* The operation is equivalent to sum of [this] copies of [other].
*/
public operator fun Int.times(other: P): P = multiplyBySquaring(other, this)
/**
* Returns the same constant.
*/
@JvmName("constantUnaryPlus")
@JsName("constantUnaryPlus")
public operator fun C.unaryPlus(): C = this
/**
* Returns negation of the constant.
*/
@JvmName("constantUnaryMinus")
@JsName("constantUnaryMinus")
public operator fun C.unaryMinus(): C
/**
* Returns sum of the constants.
*/
@JvmName("constantPlus")
@JsName("constantPlus")
public operator fun C.plus(other: C): C
/**
* Returns difference of the constants.
*/
@JvmName("constantMinus")
@JsName("constantMinus")
public operator fun C.minus(other: C): C
/**
* Returns product of the constants.
*/
@JvmName("constantTimes")
@JsName("constantTimes")
public operator fun C.times(other: C): C
/**
* Raises [arg] to the integer power [exponent].
*/
@JvmName("constantPower")
@JsName("constantPower")
public fun power(arg: C, exponent: UInt) : C
/**
* Check if the instant is zero constant.
*/
public fun C.isZero(): Boolean = this == constantZero
/**
* Check if the instant is NOT zero constant.
*/
public fun C.isNotZero(): Boolean = !isZero()
/**
* Check if the instant is unit constant.
*/
public fun C.isOne(): Boolean = this == constantOne
/**
* Check if the instant is NOT unit constant.
*/
public fun C.isNotOne(): Boolean = !isOne()
/**
* Check if the instant is minus unit constant.
*/
public fun C.isMinusOne(): Boolean = this == -constantOne
/**
* Check if the instant is NOT minus unit constant.
*/
public fun C.isNotMinusOne(): Boolean = !isMinusOne()
/**
* 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 polynomial and the polynomial.
*/
public operator fun C.plus(other: P): P
/**
* Returns difference between the constant represented as polynomial and the polynomial.
*/
public operator fun C.minus(other: P): P
/**
* Returns product of the constant represented as polynomial and the polynomial.
*/
public operator fun C.times(other: P): P
/**
* Returns sum of the constant represented as polynomial and the polynomial.
*/
public operator fun P.plus(other: C): P
/**
* Returns difference between the constant represented as polynomial and the polynomial.
*/
public operator fun P.minus(other: C): P
/**
* Returns product of the constant represented as polynomial and the polynomial.
*/
public operator fun P.times(other: C): P
/**
* 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 = exponentiationBySquaring(arg, exponent)
/**
* Check if the instant is zero polynomial.
*/
public fun P.isZero(): Boolean = this equalsTo zero
/**
* Check if the instant is NOT zero polynomial.
*/
public fun P.isNotZero(): Boolean = !isZero()
/**
* Check if the instant is unit polynomial.
*/
public fun P.isOne(): Boolean = this equalsTo one
/**
* Check if the instant is NOT unit polynomial.
*/
public fun P.isNotOne(): Boolean = !isOne()
/**
* Check if the instant is minus unit polynomial.
*/
public fun P.isMinusOne(): Boolean = this equalsTo -one
/**
* Check if the instant is NOT minus unit polynomial.
*/
public fun P.isNotMinusOne(): Boolean = !isMinusOne()
/**
* 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
/**
* Checks equality of the polynomials.
*/
public infix fun P.equalsTo(other: P): Boolean
/**
* Checks NOT equality of the polynomials.
*/
public infix fun P.notEqualsTo(other: P): Boolean = !(this equalsTo other)
/**
* 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
/**
* Checks if the instant is constant polynomial (of degree no more than 0) over considered ring.
*/
public fun P.isConstant(): Boolean = degree <= 0
/**
* Checks if the instant is **not** constant polynomial (of degree no more than 0) over considered ring.
*/
public fun P.isNotConstant(): Boolean = !isConstant()
/**
* Checks if the instant is constant non-zero polynomial (of degree no more than 0) over considered ring.
*/
public fun P.isNonZeroConstant(): Boolean = degree == 0
/**
* Checks if the instant is **not** constant non-zero polynomial (of degree no more than 0) over considered ring.
*/
public fun P.isNotNonZeroConstant(): Boolean = !isNonZeroConstant()
/**
* If polynomial is a constant polynomial represents and returns it as constant.
* Otherwise, (when the polynomial is not constant polynomial) returns `null`.
*/
public fun P.asConstantOrNull(): C?
/**
* If polynomial is a constant polynomial represents and returns it as constant.
* Otherwise, (when the polynomial is not constant polynomial) raises corresponding exception.
*/
public fun P.asConstant(): C = requireNotNull(asConstantOrNull()) { "Can not represent non-constant polynomial as a constant" }
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")
public interface AbstractPolynomialSpaceOverRing<C, P: AbstractPolynomial<C>, A: Ring<C>> : AbstractPolynomialSpace<C, P> {
public val ring: A
/**
* Returns sum of the constant and the integer represented as 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 { addMultipliedBySquaring(this@plus, one, other) }
/**
* Returns difference between the constant and the integer represented as 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 { addMultipliedBySquaring(this@minus, one, -other) }
/**
* Returns product of the constant and the integer represented as 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 { multiplyBySquaring(this@times, other) }
/**
* Returns sum of the integer represented as 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 { addMultipliedBySquaring(other, one, this@plus) }
/**
* Returns difference between the integer represented as 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 { addMultipliedBySquaring(-other, one, this@minus) }
/**
* Returns product of the integer represented as 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 { multiplyBySquaring(other, this@times) }
/**
* Returns negation of the constant.
*/
@JvmName("constantUnaryMinus")
public override operator fun C.unaryMinus(): C = ring { -this@unaryMinus }
/**
* Returns sum of the constants.
*/
@JvmName("constantPlus")
public override operator fun C.plus(other: C): C = ring { this@plus + other }
/**
* Returns difference of the constants.
*/
@JvmName("constantMinus")
public override operator fun C.minus(other: C): C = ring { this@minus - other }
/**
* Returns product of the constants.
*/
@JvmName("constantTimes")
public override operator fun C.times(other: C): C = ring { this@times * other }
/**
* Raises [arg] to the integer power [exponent].
*/
@JvmName("constantPower")
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
}

View File

@ -44,7 +44,7 @@ internal constructor(
* where `a`, `b` and `c` are corresponding [Symbol] objects. * where `a`, `b` and `c` are corresponding [Symbol] objects.
*/ */
public val coefficients: Map<Map<Symbol, UInt>, C> public val coefficients: Map<Map<Symbol, UInt>, C>
) : AbstractPolynomial<C> { ) : Polynomial<C> {
override fun toString(): String = "LabeledPolynomial$coefficients" override fun toString(): String = "LabeledPolynomial$coefficients"
} }
@ -116,7 +116,7 @@ public fun <C> C.asLabeledPolynomial() : LabeledPolynomial<C> = LabeledPolynomia
*/ */
public class LabeledPolynomialSpace<C, A : Ring<C>>( public class LabeledPolynomialSpace<C, A : Ring<C>>(
public override val ring: A, public override val ring: A,
) : AbstractPolynomialSpaceOverRing<C, LabeledPolynomial<C>, A> { ) : PolynomialSpaceOverRing<C, LabeledPolynomial<C>, A> {
public operator fun Symbol.plus(other: Int): LabeledPolynomial<C> = public operator fun Symbol.plus(other: Int): LabeledPolynomial<C> =
if (other == 0) LabeledPolynomial<C>(mapOf( if (other == 0) LabeledPolynomial<C>(mapOf(
mapOf(this@plus to 1U) to constantOne, mapOf(this@plus to 1U) to constantOne,

View File

@ -13,7 +13,7 @@ import space.kscience.kmath.operations.invoke
public class LabeledRationalFunction<C>( public class LabeledRationalFunction<C>(
public override val numerator: LabeledPolynomial<C>, public override val numerator: LabeledPolynomial<C>,
public override val denominator: LabeledPolynomial<C> public override val denominator: LabeledPolynomial<C>
) : AbstractRationalFunction<C, LabeledPolynomial<C>> { ) : RationalFunction<C, LabeledPolynomial<C>> {
override fun toString(): String = "LabeledRationalFunction${numerator.coefficients}/${denominator.coefficients}" override fun toString(): String = "LabeledRationalFunction${numerator.coefficients}/${denominator.coefficients}"
} }
@ -65,7 +65,7 @@ public class LabeledRationalFunction<C>(
public class LabeledRationalFunctionSpace<C, A: Ring<C>>( public class LabeledRationalFunctionSpace<C, A: Ring<C>>(
public val ring: A, public val ring: A,
) : ) :
AbstractRationalFunctionalSpaceOverPolynomialSpace< RationalFunctionalSpaceOverPolynomialSpace<
C, C,
LabeledPolynomial<C>, LabeledPolynomial<C>,
LabeledRationalFunction<C>, LabeledRationalFunction<C>,

View File

@ -0,0 +1,491 @@
/*
* 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.*
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
import kotlin.experimental.ExperimentalTypeInference
import kotlin.jvm.JvmName
import kotlin.math.max
import kotlin.math.min
/**
* Polynomial model without fixation on specific context they are applied to.
*
* @param coefficients constant is the leftmost coefficient.
*/
public data class ListPolynomial<C>(
/**
* List that collects coefficients of the polynomial. Every monomial `a x^d` is represented as a coefficients
* `a` placed into the list with index `d`. For example coefficients of polynomial `5 x^2 - 6` can be represented as
* ```
* 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 recommended not to put extra zeros at end of the list (as for `0x^3` and `0x^4` in the example), but is not
* prohibited.
*/
public val coefficients: List<C>
) : Polynomial<C> {
override fun toString(): String = "Polynomial$coefficients"
}
/**
* Returns a [ListPolynomial] instance with given [coefficients]. The collection of coefficients will be reversed if
* [reverse] parameter is true.
*/
@Suppress("FunctionName")
public fun <C> ListPolynomial(coefficients: List<C>, reverse: Boolean = false): ListPolynomial<C> =
ListPolynomial(with(coefficients) { if (reverse) reversed() else this })
/**
* Returns a [ListPolynomial] instance with given [coefficients]. The collection of coefficients will be reversed if
* [reverse] parameter is true.
*/
@Suppress("FunctionName")
public fun <C> ListPolynomial(vararg coefficients: C, reverse: Boolean = false): ListPolynomial<C> =
ListPolynomial(with(coefficients) { if (reverse) reversed() else toList() })
public fun <C> C.asPolynomial() : ListPolynomial<C> = ListPolynomial(listOf(this))
/**
* Space of univariate 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 open class ListPolynomialSpace<C, A : Ring<C>>(
public override val ring: A,
) : PolynomialSpaceOverRing<C, ListPolynomial<C>, A> {
/**
* Returns sum of the polynomial and the integer represented as polynomial.
*
* 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
val isResultZero = result.isZero()
when {
size == 0 && !isResultZero -> add(result)
size > 1 || !isResultZero -> this[0] = result
else -> clear()
}
}
)
/**
* Returns difference between the polynomial and the integer represented as 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
val isResultZero = result.isZero()
when {
size == 0 && !isResultZero -> add(result)
size > 1 || !isResultZero -> this[0] = result
else -> clear()
}
}
)
/**
* Returns product of the polynomial and the integer represented as polynomial.
*
* The operation is equivalent to sum of [other] copies of [this].
*/
public override operator fun ListPolynomial<C>.times(other: Int): ListPolynomial<C> =
if (other == 0) zero
else ListPolynomial(
coefficients
.applyAndRemoveZeros {
for (deg in indices) this[deg] = this[deg] * other
}
)
/**
* Returns sum of the integer represented as 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 }
val isResultZero = result.isZero()
when {
size == 0 && !isResultZero -> add(result)
size > 1 || !isResultZero -> this[0] = result
else -> clear()
}
}
)
/**
* Returns difference between the integer represented as polynomial and the polynomial.
*
* The operation is equivalent to subtraction [this] copies of unit polynomial from [other].
*/
public override operator fun Int.minus(other: ListPolynomial<C>): ListPolynomial<C> =
if (this == 0) other
else
ListPolynomial(
other.coefficients
.toMutableList()
.apply {
forEachIndexed { index, c -> if (index != 0) this[index] = -c }
val result = this@minus - getOrElse(0) { constantZero }
val isResultZero = result.isZero()
when {
size == 0 && !isResultZero -> add(result)
size > 1 || !isResultZero -> this[0] = result
else -> clear()
}
}
)
/**
* Returns product of the integer represented as polynomial and the polynomial.
*
* The operation is equivalent to sum of [this] copies of [other].
*/
public override operator fun Int.times(other: ListPolynomial<C>): ListPolynomial<C> =
if (this == 0) zero
else ListPolynomial(
other.coefficients
.applyAndRemoveZeros {
for (deg in indices) this[deg] = this@times * this[deg]
}
)
/**
* Returns sum of the constant represented as polynomial and the polynomial.
*/
public override operator fun C.plus(other: ListPolynomial<C>): ListPolynomial<C> =
if (this.isZero()) other
else 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)
val isResultZero = result.isZero()
when {
size == 0 && !isResultZero -> add(result)
size > 1 || !isResultZero -> this[0] = result
else -> clear()
}
}
)
}
/**
* Returns difference between the constant represented as polynomial and the polynomial.
*/
public override operator fun C.minus(other: ListPolynomial<C>): ListPolynomial<C> =
if (this.isZero()) other
else with(other.coefficients) {
if (isEmpty()) ListPolynomial(listOf(this@minus))
else ListPolynomial(
toMutableList()
.apply {
forEachIndexed { index, c -> if (index != 0) this[index] = -c }
val result = if (size == 0) this@minus else this@minus - get(0)
val isResultZero = result.isZero()
when {
size == 0 && !isResultZero -> add(result)
size > 1 || !isResultZero -> this[0] = result
else -> clear()
}
}
)
}
/**
* Returns product of the constant represented as polynomial and the polynomial.
*/
public override operator fun C.times(other: ListPolynomial<C>): ListPolynomial<C> =
if (this.isZero()) other
else ListPolynomial(
other.coefficients
.applyAndRemoveZeros {
for (deg in indices) this[deg] = this@times * this[deg]
}
)
/**
* Returns sum of the constant represented as polynomial and the polynomial.
*/
public override operator fun ListPolynomial<C>.plus(other: C): ListPolynomial<C> =
if (other.isZero()) this
else with(coefficients) {
if (isEmpty()) ListPolynomial(listOf(other))
else ListPolynomial(
toMutableList()
.apply {
val result = if (size == 0) other else get(0) + other
val isResultZero = result.isZero()
when {
size == 0 && !isResultZero -> add(result)
size > 1 || !isResultZero -> this[0] = result
else -> clear()
}
}
)
}
/**
* Returns difference between the constant represented as polynomial and the polynomial.
*/
public override operator fun ListPolynomial<C>.minus(other: C): ListPolynomial<C> =
if (other.isZero()) this
else with(coefficients) {
if (isEmpty()) ListPolynomial(listOf(-other))
else ListPolynomial(
toMutableList()
.apply {
val result = if (size == 0) other else get(0) - other
val isResultZero = result.isZero()
when {
size == 0 && !isResultZero -> add(result)
size > 1 || !isResultZero -> this[0] = result
else -> clear()
}
}
)
}
/**
* Returns product of the constant represented as polynomial and the polynomial.
*/
public override operator fun ListPolynomial<C>.times(other: C): ListPolynomial<C> =
if (other.isZero()) this
else ListPolynomial(
coefficients
.applyAndRemoveZeros {
for (deg in indices) this[deg] = this[deg] * other
}
)
/**
* 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(
Coefficients(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(
Coefficients(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 when {
thisDegree == -1 -> zero
otherDegree == -1 -> zero
else ->
ListPolynomial(
Coefficients(thisDegree + otherDegree + 1) { d ->
(max(0, d - otherDegree)..min(thisDegree, d))
.map { coefficients[it] * other.coefficients[d - it] }
.reduce { acc, rational -> acc + rational }
}
)
}
}
/**
* Check if the instant is zero polynomial.
*/
public override fun ListPolynomial<C>.isZero(): Boolean = coefficients.all { it.isZero() }
/**
* Check if the instant is unit polynomial.
*/
public override fun ListPolynomial<C>.isOne(): Boolean =
with(coefficients) {
isNotEmpty() && withIndex().all { (index, c) -> if (index == 0) c.isOne() else c.isZero() }
}
/**
* Check if the instant is minus unit polynomial.
*/
public override fun ListPolynomial<C>.isMinusOne(): Boolean =
with(coefficients) {
isNotEmpty() && withIndex().all { (index, c) -> if (index == 0) c.isMinusOne() else c.isZero() }
}
/**
* Instance of zero polynomial (zero of the polynomial ring).
*/
override val zero: ListPolynomial<C> = ListPolynomial(emptyList())
/**
* Instance of unit constant (unit of the underlying ring).
*/
override val one: ListPolynomial<C> = ListPolynomial(listOf(constantOne))
/**
* Checks equality of the polynomials.
*/
public override infix fun ListPolynomial<C>.equalsTo(other: ListPolynomial<C>): Boolean =
when {
this === other -> true
this.degree == other.degree -> (0..degree).all { coefficients[it] == other.coefficients[it] }
else -> false
}
/**
* 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.indexOfLast { it != constantZero }
/**
* If polynomial is a constant polynomial represents and returns it as constant.
* Otherwise, (when the polynomial is not constant polynomial) returns `null`.
*/
public override fun ListPolynomial<C>.asConstantOrNull(): C? =
with(coefficients) {
when {
isEmpty() -> constantZero
withIndex().all { (index, c) -> index == 0 || c.isZero() } -> first()
else -> null
}
}
@Suppress("NOTHING_TO_INLINE")
public inline fun ListPolynomial<C>.substitute(argument: C): C = this.substitute(ring, argument)
@Suppress("NOTHING_TO_INLINE")
public inline fun ListPolynomial<C>.substitute(argument: ListPolynomial<C>): ListPolynomial<C> = this.substitute(ring, argument)
@Suppress("NOTHING_TO_INLINE")
public inline fun ListPolynomial<C>.asFunction(): (C) -> C = { this.substitute(ring, it) }
@Suppress("NOTHING_TO_INLINE")
public inline fun ListPolynomial<C>.asFunctionOnConstants(): (C) -> C = { this.substitute(ring, it) }
@Suppress("NOTHING_TO_INLINE")
public inline fun ListPolynomial<C>.asFunctionOnPolynomials(): (ListPolynomial<C>) -> ListPolynomial<C> = { this.substitute(ring, it) }
/**
* Evaluates the polynomial for the given value [argument].
*/
@Suppress("NOTHING_TO_INLINE")
public inline operator fun ListPolynomial<C>.invoke(argument: C): C = this.substitute(ring, argument)
@Suppress("NOTHING_TO_INLINE")
public inline operator fun ListPolynomial<C>.invoke(argument: ListPolynomial<C>): ListPolynomial<C> = this.substitute(ring, argument)
// TODO: Move to other internal utilities with context receiver
@JvmName("applyAndRemoveZerosInternal")
internal inline fun MutableList<C>.applyAndRemoveZeros(block: MutableList<C>.() -> Unit) : MutableList<C> {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block()
while (isNotEmpty() && elementAt(lastIndex).isZero()) removeAt(lastIndex)
return this
}
internal inline fun List<C>.applyAndRemoveZeros(block: MutableList<C>.() -> Unit) : List<C> =
toMutableList().applyAndRemoveZeros(block)
@Suppress("FunctionName")
internal inline fun MutableCoefficients(size: Int, init: (index: Int) -> C): MutableList<C> {
val list = ArrayList<C>(size)
repeat(size) { index -> list.add(init(index)) }
with(list) { while (isNotEmpty() && elementAt(lastIndex).isZero()) removeAt(lastIndex) }
return list
}
@Suppress("FunctionName")
internal inline fun Coefficients(size: Int, init: (index: Int) -> C): List<C> = MutableCoefficients(size, init)
@OptIn(ExperimentalTypeInference::class)
internal inline fun buildCoefficients(@BuilderInference builderAction: MutableList<C>.() -> Unit): List<C> {
contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) }
return buildList {
builderAction()
while (isNotEmpty() && elementAt(lastIndex).isZero()) removeAt(lastIndex)
}
}
@OptIn(ExperimentalTypeInference::class)
internal inline fun buildCoefficients(capacity: Int, @BuilderInference builderAction: MutableList<C>.() -> Unit): List<C> {
contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) }
return buildList(capacity) {
builderAction()
while (isNotEmpty() && elementAt(lastIndex).isZero()) removeAt(lastIndex)
}
}
}
/**
* 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) }) }
}

View File

@ -0,0 +1,154 @@
/*
* 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
public data class ListRationalFunction<C> internal constructor (
public override val numerator: ListPolynomial<C>,
public override val denominator: ListPolynomial<C>
) : RationalFunction<C, ListPolynomial<C>> {
override fun toString(): String = "RationalFunction${numerator.coefficients}/${denominator.coefficients}"
}
// Waiting for context receivers :( TODO: Replace with context receivers when they will be available
//context(RationalFunctionSpace<C, A>)
//@Suppress("FunctionName")
//internal fun <C, A: Ring<C>> RationalFunction(numerator: Polynomial<C>, denominator: Polynomial<C>): RationalFunction<C> =
// if (denominator.isZero()) throw ArithmeticException("/ by zero")
// else RationalFunction<C>(numerator, denominator)
//context(RationalFunctionSpace<C, A>)
//@Suppress("FunctionName")
//public fun <C, A: Ring<C>> RationalFunction(numeratorCoefficients: List<C>, denominatorCoefficients: List<C>, reverse: Boolean = false): RationalFunction<C> =
// RationalFunction<C>(
// Polynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ),
// Polynomial( with(denominatorCoefficients) { if (reverse) reversed() else this } ).also { if (it.isZero()) }
// )
//context(RationalFunctionSpace<C, A>)
//@Suppress("FunctionName")
//public fun <C, A: Ring<C>> RationalFunction(numerator: Polynomial<C>): RationalFunction<C> =
// RationalFunction(numerator, onePolynomial)
//context(RationalFunctionSpace<C, A>)
//@Suppress("FunctionName")
//public fun <C, A: Ring<C>> RationalFunction(numeratorCoefficients: List<C>, reverse: Boolean = false): RationalFunction<C> =
// RationalFunction(
// Polynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } )
// )
public class ListRationalFunctionSpace<C, A : Ring<C>> (
public val ring: A,
) :
RationalFunctionalSpaceOverPolynomialSpace<
C,
ListPolynomial<C>,
ListRationalFunction<C>,
ListPolynomialSpace<C, A>,
>,
PolynomialSpaceOfFractions<
C,
ListPolynomial<C>,
ListRationalFunction<C>,
>() {
override val polynomialRing : ListPolynomialSpace<C, A> = ListPolynomialSpace(ring)
override fun constructRationalFunction(numerator: ListPolynomial<C>, denominator: ListPolynomial<C>): ListRationalFunction<C> =
ListRationalFunction(numerator, denominator)
/**
* Instance of zero rational function (zero of the rational functions ring).
*/
public override val zero: ListRationalFunction<C> = ListRationalFunction(polynomialZero, polynomialOne)
/**
* Instance of unit polynomial (unit of the rational functions ring).
*/
public override val one: ListRationalFunction<C> = ListRationalFunction(polynomialOne, polynomialOne)
// TODO: Разобрать
public operator fun ListRationalFunction<C>.div(other: ListRationalFunction<C>): ListRationalFunction<C> =
ListRationalFunction(
numerator * other.denominator,
denominator * other.numerator
)
public operator fun ListRationalFunction<C>.div(other: ListPolynomial<C>): ListRationalFunction<C> =
ListRationalFunction(
numerator,
denominator * other
)
public operator fun ListRationalFunction<C>.div(other: C): ListRationalFunction<C> =
ListRationalFunction(
numerator,
denominator * other
)
public operator fun ListRationalFunction<C>.div(other: Int): ListRationalFunction<C> =
ListRationalFunction(
numerator,
denominator * other
)
// operator fun invoke(arg: UnivariatePolynomial<T>): RationalFunction<T> =
// RationalFunction(
// numerator(arg),
// denominator(arg)
// )
//
// operator fun invoke(arg: RationalFunction<T>): RationalFunction<T> {
// val num = numerator invokeRFTakeNumerator arg
// val den = denominator invokeRFTakeNumerator arg
// val degreeDif = numeratorDegree - denominatorDegree
// return if (degreeDif > 0)
// RationalFunction(
// num,
// multiplyByPower(den, arg.denominator, degreeDif)
// )
// else
// RationalFunction(
// multiplyByPower(num, arg.denominator, -degreeDif),
// den
// )
// }
//
// override fun toString(): String = toString(UnivariatePolynomial.variableName)
//
// fun toString(withVariableName: String = UnivariatePolynomial.variableName): String =
// when(true) {
// numerator.isZero() -> "0"
// denominator.isOne() -> numerator.toString(withVariableName)
// else -> "${numerator.toStringWithBrackets(withVariableName)}/${denominator.toStringWithBrackets(withVariableName)}"
// }
//
// fun toStringWithBrackets(withVariableName: String = UnivariatePolynomial.variableName): String =
// when(true) {
// numerator.isZero() -> "0"
// denominator.isOne() -> numerator.toStringWithBrackets(withVariableName)
// else -> "(${numerator.toStringWithBrackets(withVariableName)}/${denominator.toStringWithBrackets(withVariableName)})"
// }
//
// fun toReversedString(withVariableName: String = UnivariatePolynomial.variableName): String =
// when(true) {
// numerator.isZero() -> "0"
// denominator.isOne() -> numerator.toReversedString(withVariableName)
// else -> "${numerator.toReversedStringWithBrackets(withVariableName)}/${denominator.toReversedStringWithBrackets(withVariableName)}"
// }
//
// fun toReversedStringWithBrackets(withVariableName: String = UnivariatePolynomial.variableName): String =
// when(true) {
// numerator.isZero() -> "0"
// denominator.isOne() -> numerator.toReversedStringWithBrackets(withVariableName)
// else -> "(${numerator.toReversedStringWithBrackets(withVariableName)}/${denominator.toReversedStringWithBrackets(withVariableName)})"
// }
//
// fun removeZeros() =
// RationalFunction(
// numerator.removeZeros(),
// denominator.removeZeros()
// )
}

View File

@ -43,7 +43,7 @@ internal constructor(
* contain any zeros on end, but can contain zeros on start or anywhere in middle. * contain any zeros on end, but can contain zeros on start or anywhere in middle.
*/ */
public val coefficients: Map<List<UInt>, C> public val coefficients: Map<List<UInt>, C>
) : AbstractPolynomial<C> { ) : Polynomial<C> {
override fun toString(): String = "NumberedPolynomial$coefficients" override fun toString(): String = "NumberedPolynomial$coefficients"
} }
@ -112,7 +112,7 @@ public fun <C> C.asNumberedPolynomial() : NumberedPolynomial<C> = NumberedPolyno
*/ */
public open class NumberedPolynomialSpace<C, A : Ring<C>>( public open class NumberedPolynomialSpace<C, A : Ring<C>>(
public final override val ring: A, public final override val ring: A,
) : AbstractPolynomialSpaceOverRing<C, NumberedPolynomial<C>, A> { ) : PolynomialSpaceOverRing<C, NumberedPolynomial<C>, A> {
/** /**
* Returns sum of the polynomial and the integer represented as polynomial. * Returns sum of the polynomial and the integer represented as polynomial.
* *

View File

@ -12,7 +12,7 @@ import kotlin.math.max
public class NumberedRationalFunction<C> internal constructor( public class NumberedRationalFunction<C> internal constructor(
public override val numerator: NumberedPolynomial<C>, public override val numerator: NumberedPolynomial<C>,
public override val denominator: NumberedPolynomial<C> public override val denominator: NumberedPolynomial<C>
) : AbstractRationalFunction<C, NumberedPolynomial<C>> { ) : RationalFunction<C, NumberedPolynomial<C>> {
override fun toString(): String = "NumberedRationalFunction${numerator.coefficients}/${denominator.coefficients}" override fun toString(): String = "NumberedRationalFunction${numerator.coefficients}/${denominator.coefficients}"
} }
@ -61,7 +61,7 @@ public class NumberedRationalFunction<C> internal constructor(
public class NumberedRationalFunctionSpace<C, A: Ring<C>> ( public class NumberedRationalFunctionSpace<C, A: Ring<C>> (
public val ring: A, public val ring: A,
) : ) :
AbstractRationalFunctionalSpaceOverPolynomialSpace< RationalFunctionalSpaceOverPolynomialSpace<
C, C,
NumberedPolynomial<C>, NumberedPolynomial<C>,
NumberedRationalFunction<C>, NumberedRationalFunction<C>,

View File

@ -27,10 +27,10 @@ public fun interface Piecewise<in T, out R> {
* @property pieces An ordered list of range-polynomial pairs. The list does not in general guarantee that there are no * @property pieces An ordered list of range-polynomial pairs. The list does not in general guarantee that there are no
* "holes" in it. * "holes" in it.
*/ */
public interface PiecewisePolynomial<T : Comparable<T>> : Piecewise<T, Polynomial<T>> { public interface PiecewisePolynomial<T : Comparable<T>> : Piecewise<T, ListPolynomial<T>> {
public val pieces: Collection<Pair<ClosedRange<T>, Polynomial<T>>> public val pieces: Collection<Pair<ClosedRange<T>, ListPolynomial<T>>>
override fun findPiece(arg: T): Polynomial<T>? override fun findPiece(arg: T): ListPolynomial<T>?
} }
/** /**
@ -38,11 +38,11 @@ public interface PiecewisePolynomial<T : Comparable<T>> : Piecewise<T, Polynomia
*/ */
@PerformancePitfall("findPiece method of resulting piecewise is slow") @PerformancePitfall("findPiece method of resulting piecewise is slow")
public fun <T : Comparable<T>> PiecewisePolynomial( public fun <T : Comparable<T>> PiecewisePolynomial(
pieces: Collection<Pair<ClosedRange<T>, Polynomial<T>>>, pieces: Collection<Pair<ClosedRange<T>, ListPolynomial<T>>>,
): PiecewisePolynomial<T> = object : PiecewisePolynomial<T> { ): PiecewisePolynomial<T> = object : PiecewisePolynomial<T> {
override val pieces: Collection<Pair<ClosedRange<T>, Polynomial<T>>> = pieces override val pieces: Collection<Pair<ClosedRange<T>, ListPolynomial<T>>> = pieces
override fun findPiece(arg: T): Polynomial<T>? = pieces.firstOrNull { arg in it.first }?.second override fun findPiece(arg: T): ListPolynomial<T>? = pieces.firstOrNull { arg in it.first }?.second
} }
/** /**
@ -50,10 +50,10 @@ public fun <T : Comparable<T>> PiecewisePolynomial(
* The pieces search is logarithmic. * The pieces search is logarithmic.
*/ */
private class OrderedPiecewisePolynomial<T : Comparable<T>>( private class OrderedPiecewisePolynomial<T : Comparable<T>>(
override val pieces: List<Pair<ClosedRange<T>, Polynomial<T>>>, override val pieces: List<Pair<ClosedRange<T>, ListPolynomial<T>>>,
) : PiecewisePolynomial<T> { ) : PiecewisePolynomial<T> {
override fun findPiece(arg: T): Polynomial<T>? { override fun findPiece(arg: T): ListPolynomial<T>? {
val index = pieces.binarySearch { (range, _) -> val index = pieces.binarySearch { (range, _) ->
when { when {
arg >= range.endInclusive -> -1 arg >= range.endInclusive -> -1
@ -74,7 +74,7 @@ private class OrderedPiecewisePolynomial<T : Comparable<T>>(
*/ */
public class PiecewiseBuilder<T : Comparable<T>>(delimiter: T) { public class PiecewiseBuilder<T : Comparable<T>>(delimiter: T) {
private val delimiters: MutableList<T> = arrayListOf(delimiter) private val delimiters: MutableList<T> = arrayListOf(delimiter)
private val pieces: MutableList<Polynomial<T>> = arrayListOf() private val pieces: MutableList<ListPolynomial<T>> = arrayListOf()
/** /**
* Dynamically adds a piece to the right side (beyond maximum argument value of previous piece) * Dynamically adds a piece to the right side (beyond maximum argument value of previous piece)
@ -82,7 +82,7 @@ public class PiecewiseBuilder<T : Comparable<T>>(delimiter: T) {
* @param right new rightmost position. If is less than current rightmost position, an error is thrown. * @param right new rightmost position. If is less than current rightmost position, an error is thrown.
* @param piece the sub-function. * @param piece the sub-function.
*/ */
public fun putRight(right: T, piece: Polynomial<T>) { public fun putRight(right: T, piece: ListPolynomial<T>) {
require(right > delimiters.last()) { "New delimiter should be to the right of old one" } require(right > delimiters.last()) { "New delimiter should be to the right of old one" }
delimiters += right delimiters += right
pieces += piece pieces += piece
@ -94,7 +94,7 @@ public class PiecewiseBuilder<T : Comparable<T>>(delimiter: T) {
* @param left the new leftmost position. If is less than current rightmost position, an error is thrown. * @param left the new leftmost position. If is less than current rightmost position, an error is thrown.
* @param piece the sub-function. * @param piece the sub-function.
*/ */
public fun putLeft(left: T, piece: Polynomial<T>) { public fun putLeft(left: T, piece: ListPolynomial<T>) {
require(left < delimiters.first()) { "New delimiter should be to the left of old one" } require(left < delimiters.first()) { "New delimiter should be to the left of old one" }
delimiters.add(0, left) delimiters.add(0, left)
pieces.add(0, piece) pieces.add(0, piece)

View File

@ -6,486 +6,384 @@
package space.kscience.kmath.functions package space.kscience.kmath.functions
import space.kscience.kmath.operations.* import space.kscience.kmath.operations.*
import kotlin.contracts.InvocationKind import kotlin.js.JsName
import kotlin.contracts.contract
import kotlin.experimental.ExperimentalTypeInference
import kotlin.jvm.JvmName import kotlin.jvm.JvmName
import kotlin.math.max
import kotlin.math.min
/** /**
* Polynomial model without fixation on specific context they are applied to. * Abstraction of polynomials.
*
* @param coefficients constant is the leftmost coefficient.
*/ */
public data class Polynomial<C>( 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")
public interface PolynomialSpace<C, P: Polynomial<C>> : Ring<P> {
/** /**
* List that collects coefficients of the polynomial. Every monomial `a x^d` is represented as a coefficients * Returns sum of the constant and the integer represented as constant (member of underlying ring).
* `a` placed into the list with index `d`. For example coefficients of polynomial `5 x^2 - 6` can be represented as *
* ``` * The operation is equivalent to adding [other] copies of unit of underlying ring to [this].
* 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 recommended not to put extra zeros at end of the list (as for `0x^3` and `0x^4` in the example), but is not
* prohibited.
*/ */
public val coefficients: List<C> public operator fun C.plus(other: Int): C
) : AbstractPolynomial<C> { /**
override fun toString(): String = "Polynomial$coefficients" * Returns difference between the constant and the integer represented as constant (member of underlying ring).
} *
* The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this].
*/
public operator fun C.minus(other: Int): C
/**
* Returns product of the constant and the integer represented as constant (member of underlying ring).
*
* The operation is equivalent to sum of [other] copies of [this].
*/
public operator fun C.times(other: Int): C
/** /**
* Returns a [Polynomial] instance with given [coefficients]. The collection of coefficients will be reversed if * Returns sum of the integer represented as constant (member of underlying ring) and the constant.
* [reverse] parameter is true. *
*/ * The operation is equivalent to adding [this] copies of unit of underlying ring to [other].
@Suppress("FunctionName") */
public fun <C> Polynomial(coefficients: List<C>, reverse: Boolean = false): Polynomial<C> = public operator fun Int.plus(other: C): C
Polynomial(with(coefficients) { if (reverse) reversed() else this }) /**
* Returns difference between the integer represented as constant (member of underlying ring) and the constant.
*
* The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other].
*/
public operator fun Int.minus(other: C): C
/**
* Returns product of the integer represented as constant (member of underlying ring) and the constant.
*
* The operation is equivalent to sum of [this] copies of [other].
*/
public operator fun Int.times(other: C): C
/**
* Returns a [Polynomial] instance with given [coefficients]. The collection of coefficients will be reversed if
* [reverse] parameter is true.
*/
@Suppress("FunctionName")
public fun <C> Polynomial(vararg coefficients: C, reverse: Boolean = false): Polynomial<C> =
Polynomial(with(coefficients) { if (reverse) reversed() else toList() })
public fun <C> C.asPolynomial() : Polynomial<C> = Polynomial(listOf(this))
/**
* Space of univariate 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 open class PolynomialSpace<C, A : Ring<C>>(
public override val ring: A,
) : AbstractPolynomialSpaceOverRing<C, Polynomial<C>, A> {
/** /**
* Returns sum of the polynomial and the integer represented as polynomial. * Returns sum of the polynomial and the integer represented as polynomial.
* *
* The operation is equivalent to adding [other] copies of unit polynomial to [this]. * The operation is equivalent to adding [other] copies of unit polynomial to [this].
*/ */
public override operator fun Polynomial<C>.plus(other: Int): Polynomial<C> = public operator fun P.plus(other: Int): P = addMultipliedBySquaring(this, one, other)
if (other == 0) this
else
Polynomial(
coefficients
.toMutableList()
.apply {
val result = getOrElse(0) { constantZero } + other
val isResultZero = result.isZero()
when {
size == 0 && !isResultZero -> add(result)
size > 1 || !isResultZero -> this[0] = result
else -> clear()
}
}
)
/** /**
* Returns difference between the polynomial and the integer represented as polynomial. * Returns difference between the polynomial and the integer represented as polynomial.
* *
* The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. * The operation is equivalent to subtraction [other] copies of unit polynomial from [this].
*/ */
public override operator fun Polynomial<C>.minus(other: Int): Polynomial<C> = public operator fun P.minus(other: Int): P = addMultipliedBySquaring(this, one, -other)
if (other == 0) this
else
Polynomial(
coefficients
.toMutableList()
.apply {
val result = getOrElse(0) { constantZero } - other
val isResultZero = result.isZero()
when {
size == 0 && !isResultZero -> add(result)
size > 1 || !isResultZero -> this[0] = result
else -> clear()
}
}
)
/** /**
* Returns product of the polynomial and the integer represented as polynomial. * Returns product of the polynomial and the integer represented as polynomial.
* *
* The operation is equivalent to sum of [other] copies of [this]. * The operation is equivalent to sum of [other] copies of [this].
*/ */
public override operator fun Polynomial<C>.times(other: Int): Polynomial<C> = public operator fun P.times(other: Int): P = multiplyBySquaring(this, other)
if (other == 0) zero
else Polynomial(
coefficients
.applyAndRemoveZeros {
for (deg in indices) this[deg] = this[deg] * other
}
)
/** /**
* Returns sum of the integer represented as polynomial and the polynomial. * Returns sum of the integer represented as polynomial and the polynomial.
* *
* The operation is equivalent to adding [this] copies of unit polynomial to [other]. * The operation is equivalent to adding [this] copies of unit polynomial to [other].
*/ */
public override operator fun Int.plus(other: Polynomial<C>): Polynomial<C> = public operator fun Int.plus(other: P): P = addMultipliedBySquaring(other, one, this)
if (this == 0) other
else
Polynomial(
other.coefficients
.toMutableList()
.apply {
val result = this@plus + getOrElse(0) { constantZero }
val isResultZero = result.isZero()
when {
size == 0 && !isResultZero -> add(result)
size > 1 || !isResultZero -> this[0] = result
else -> clear()
}
}
)
/** /**
* Returns difference between the integer represented as polynomial and the polynomial. * Returns difference between the integer represented as polynomial and the polynomial.
* *
* The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. * The operation is equivalent to subtraction [this] copies of unit polynomial from [other].
*/ */
public override operator fun Int.minus(other: Polynomial<C>): Polynomial<C> = public operator fun Int.minus(other: P): P = addMultipliedBySquaring(-other, one, this)
if (this == 0) other
else
Polynomial(
other.coefficients
.toMutableList()
.apply {
forEachIndexed { index, c -> if (index != 0) this[index] = -c }
val result = this@minus - getOrElse(0) { constantZero }
val isResultZero = result.isZero()
when {
size == 0 && !isResultZero -> add(result)
size > 1 || !isResultZero -> this[0] = result
else -> clear()
}
}
)
/** /**
* Returns product of the integer represented as polynomial and the polynomial. * Returns product of the integer represented as polynomial and the polynomial.
* *
* The operation is equivalent to sum of [this] copies of [other]. * The operation is equivalent to sum of [this] copies of [other].
*/ */
public override operator fun Int.times(other: Polynomial<C>): Polynomial<C> = public operator fun Int.times(other: P): P = multiplyBySquaring(other, this)
if (this == 0) zero
else Polynomial( /**
other.coefficients * Returns the same constant.
.applyAndRemoveZeros { */
for (deg in indices) this[deg] = this@times * this[deg] @JvmName("constantUnaryPlus")
} @JsName("constantUnaryPlus")
) public operator fun C.unaryPlus(): C = this
/**
* Returns negation of the constant.
*/
@JvmName("constantUnaryMinus")
@JsName("constantUnaryMinus")
public operator fun C.unaryMinus(): C
/**
* Returns sum of the constants.
*/
@JvmName("constantPlus")
@JsName("constantPlus")
public operator fun C.plus(other: C): C
/**
* Returns difference of the constants.
*/
@JvmName("constantMinus")
@JsName("constantMinus")
public operator fun C.minus(other: C): C
/**
* Returns product of the constants.
*/
@JvmName("constantTimes")
@JsName("constantTimes")
public operator fun C.times(other: C): C
/**
* Raises [arg] to the integer power [exponent].
*/
@JvmName("constantPower")
@JsName("constantPower")
public fun power(arg: C, exponent: UInt) : C
/**
* Check if the instant is zero constant.
*/
public fun C.isZero(): Boolean = this == constantZero
/**
* Check if the instant is NOT zero constant.
*/
public fun C.isNotZero(): Boolean = !isZero()
/**
* Check if the instant is unit constant.
*/
public fun C.isOne(): Boolean = this == constantOne
/**
* Check if the instant is NOT unit constant.
*/
public fun C.isNotOne(): Boolean = !isOne()
/**
* Check if the instant is minus unit constant.
*/
public fun C.isMinusOne(): Boolean = this == -constantOne
/**
* Check if the instant is NOT minus unit constant.
*/
public fun C.isNotMinusOne(): Boolean = !isMinusOne()
/**
* 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 polynomial and the polynomial. * Returns sum of the constant represented as polynomial and the polynomial.
*/ */
public override operator fun C.plus(other: Polynomial<C>): Polynomial<C> = public operator fun C.plus(other: P): P
if (this.isZero()) other
else with(other.coefficients) {
if (isEmpty()) Polynomial(listOf(this@plus))
else Polynomial(
toMutableList()
.apply {
val result = if (size == 0) this@plus else this@plus + get(0)
val isResultZero = result.isZero()
when {
size == 0 && !isResultZero -> add(result)
size > 1 || !isResultZero -> this[0] = result
else -> clear()
}
}
)
}
/** /**
* Returns difference between the constant represented as polynomial and the polynomial. * Returns difference between the constant represented as polynomial and the polynomial.
*/ */
public override operator fun C.minus(other: Polynomial<C>): Polynomial<C> = public operator fun C.minus(other: P): P
if (this.isZero()) other
else with(other.coefficients) {
if (isEmpty()) Polynomial(listOf(this@minus))
else Polynomial(
toMutableList()
.apply {
forEachIndexed { index, c -> if (index != 0) this[index] = -c }
val result = if (size == 0) this@minus else this@minus - get(0)
val isResultZero = result.isZero()
when {
size == 0 && !isResultZero -> add(result)
size > 1 || !isResultZero -> this[0] = result
else -> clear()
}
}
)
}
/** /**
* Returns product of the constant represented as polynomial and the polynomial. * Returns product of the constant represented as polynomial and the polynomial.
*/ */
public override operator fun C.times(other: Polynomial<C>): Polynomial<C> = public operator fun C.times(other: P): P
if (this.isZero()) other
else Polynomial(
other.coefficients
.applyAndRemoveZeros {
for (deg in indices) this[deg] = this@times * this[deg]
}
)
/** /**
* Returns sum of the constant represented as polynomial and the polynomial. * Returns sum of the constant represented as polynomial and the polynomial.
*/ */
public override operator fun Polynomial<C>.plus(other: C): Polynomial<C> = public operator fun P.plus(other: C): P
if (other.isZero()) this
else with(coefficients) {
if (isEmpty()) Polynomial(listOf(other))
else Polynomial(
toMutableList()
.apply {
val result = if (size == 0) other else get(0) + other
val isResultZero = result.isZero()
when {
size == 0 && !isResultZero -> add(result)
size > 1 || !isResultZero -> this[0] = result
else -> clear()
}
}
)
}
/** /**
* Returns difference between the constant represented as polynomial and the polynomial. * Returns difference between the constant represented as polynomial and the polynomial.
*/ */
public override operator fun Polynomial<C>.minus(other: C): Polynomial<C> = public operator fun P.minus(other: C): P
if (other.isZero()) this
else with(coefficients) {
if (isEmpty()) Polynomial(listOf(-other))
else Polynomial(
toMutableList()
.apply {
val result = if (size == 0) other else get(0) - other
val isResultZero = result.isZero()
when {
size == 0 && !isResultZero -> add(result)
size > 1 || !isResultZero -> this[0] = result
else -> clear()
}
}
)
}
/** /**
* Returns product of the constant represented as polynomial and the polynomial. * Returns product of the constant represented as polynomial and the polynomial.
*/ */
public override operator fun Polynomial<C>.times(other: C): Polynomial<C> = public operator fun P.times(other: C): P
if (other.isZero()) this
else Polynomial(
coefficients
.applyAndRemoveZeros {
for (deg in indices) this[deg] = this[deg] * other
}
)
/**
* Returns the same polynomial.
*/
public override operator fun P.unaryPlus(): P = this
/** /**
* Returns negation of the polynomial. * Returns negation of the polynomial.
*/ */
public override operator fun Polynomial<C>.unaryMinus(): Polynomial<C> = public override operator fun P.unaryMinus(): P
Polynomial(coefficients.map { -it })
/** /**
* Returns sum of the polynomials. * Returns sum of the polynomials.
*/ */
public override operator fun Polynomial<C>.plus(other: Polynomial<C>): Polynomial<C> { public override operator fun P.plus(other: P): P
val thisDegree = degree
val otherDegree = other.degree
return Polynomial(
Coefficients(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. * Returns difference of the polynomials.
*/ */
public override operator fun Polynomial<C>.minus(other: Polynomial<C>): Polynomial<C> { public override operator fun P.minus(other: P): P
val thisDegree = degree
val otherDegree = other.degree
return Polynomial(
Coefficients(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. * Returns product of the polynomials.
*/ */
public override operator fun Polynomial<C>.times(other: Polynomial<C>): Polynomial<C> { public override operator fun P.times(other: P): P
val thisDegree = degree /**
val otherDegree = other.degree * Raises [arg] to the integer power [exponent].
return when { */
thisDegree == -1 -> zero public override fun power(arg: P, exponent: UInt) : P = exponentiationBySquaring(arg, exponent)
otherDegree == -1 -> zero
else ->
Polynomial(
Coefficients(thisDegree + otherDegree + 1) { d ->
(max(0, d - otherDegree)..min(thisDegree, d))
.map { coefficients[it] * other.coefficients[d - it] }
.reduce { acc, rational -> acc + rational }
}
)
}
}
/** /**
* Check if the instant is zero polynomial. * Check if the instant is zero polynomial.
*/ */
public override fun Polynomial<C>.isZero(): Boolean = coefficients.all { it.isZero() } public fun P.isZero(): Boolean = this equalsTo zero
/**
* Check if the instant is NOT zero polynomial.
*/
public fun P.isNotZero(): Boolean = !isZero()
/** /**
* Check if the instant is unit polynomial. * Check if the instant is unit polynomial.
*/ */
public override fun Polynomial<C>.isOne(): Boolean = public fun P.isOne(): Boolean = this equalsTo one
with(coefficients) { /**
isNotEmpty() && withIndex().all { (index, c) -> if (index == 0) c.isOne() else c.isZero() } * Check if the instant is NOT unit polynomial.
} */
public fun P.isNotOne(): Boolean = !isOne()
/** /**
* Check if the instant is minus unit polynomial. * Check if the instant is minus unit polynomial.
*/ */
public override fun Polynomial<C>.isMinusOne(): Boolean = public fun P.isMinusOne(): Boolean = this equalsTo -one
with(coefficients) { /**
isNotEmpty() && withIndex().all { (index, c) -> if (index == 0) c.isMinusOne() else c.isZero() } * Check if the instant is NOT minus unit polynomial.
} */
public fun P.isNotMinusOne(): Boolean = !isMinusOne()
/** /**
* Instance of zero polynomial (zero of the polynomial ring). * Instance of zero polynomial (zero of the polynomial ring).
*/ */
override val zero: Polynomial<C> = Polynomial(emptyList()) public override val zero: P
/** /**
* Instance of unit constant (unit of the underlying ring). * Instance of unit polynomial (unit of the polynomial ring).
*/ */
override val one: Polynomial<C> = Polynomial(listOf(constantOne)) public override val one: P
/** /**
* Checks equality of the polynomials. * Checks equality of the polynomials.
*/ */
public override infix fun Polynomial<C>.equalsTo(other: Polynomial<C>): Boolean = public infix fun P.equalsTo(other: P): Boolean
when { /**
this === other -> true * Checks NOT equality of the polynomials.
this.degree == other.degree -> (0..degree).all { coefficients[it] == other.coefficients[it] } */
else -> false public infix fun P.notEqualsTo(other: P): Boolean = !(this equalsTo other)
}
/** /**
* Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is
* zero, degree is -1. * zero, degree is -1.
*/ */
public override val Polynomial<C>.degree: Int get() = coefficients.indexOfLast { it != constantZero } public val P.degree: Int
/**
* Checks if the instant is constant polynomial (of degree no more than 0) over considered ring.
*/
public fun P.isConstant(): Boolean = degree <= 0
/**
* Checks if the instant is **not** constant polynomial (of degree no more than 0) over considered ring.
*/
public fun P.isNotConstant(): Boolean = !isConstant()
/**
* Checks if the instant is constant non-zero polynomial (of degree no more than 0) over considered ring.
*/
public fun P.isNonZeroConstant(): Boolean = degree == 0
/**
* Checks if the instant is **not** constant non-zero polynomial (of degree no more than 0) over considered ring.
*/
public fun P.isNotNonZeroConstant(): Boolean = !isNonZeroConstant()
/** /**
* If polynomial is a constant polynomial represents and returns it as constant. * If polynomial is a constant polynomial represents and returns it as constant.
* Otherwise, (when the polynomial is not constant polynomial) returns `null`. * Otherwise, (when the polynomial is not constant polynomial) returns `null`.
*/ */
public override fun Polynomial<C>.asConstantOrNull(): C? = public fun P.asConstantOrNull(): C?
with(coefficients) {
when {
isEmpty() -> constantZero
withIndex().all { (index, c) -> index == 0 || c.isZero() } -> first()
else -> null
}
}
@Suppress("NOTHING_TO_INLINE")
public inline fun Polynomial<C>.substitute(argument: C): C = this.substitute(ring, argument)
@Suppress("NOTHING_TO_INLINE")
public inline fun Polynomial<C>.substitute(argument: Polynomial<C>): Polynomial<C> = this.substitute(ring, argument)
@Suppress("NOTHING_TO_INLINE")
public inline fun Polynomial<C>.asFunction(): (C) -> C = { this.substitute(ring, it) }
@Suppress("NOTHING_TO_INLINE")
public inline fun Polynomial<C>.asFunctionOnConstants(): (C) -> C = { this.substitute(ring, it) }
@Suppress("NOTHING_TO_INLINE")
public inline fun Polynomial<C>.asFunctionOnPolynomials(): (Polynomial<C>) -> Polynomial<C> = { this.substitute(ring, it) }
/** /**
* Evaluates the polynomial for the given value [argument]. * If polynomial is a constant polynomial represents and returns it as constant.
* Otherwise, (when the polynomial is not constant polynomial) raises corresponding exception.
*/ */
@Suppress("NOTHING_TO_INLINE") public fun P.asConstant(): C = requireNotNull(asConstantOrNull()) { "Can not represent non-constant polynomial as a constant" }
public inline operator fun Polynomial<C>.invoke(argument: C): C = this.substitute(ring, argument)
@Suppress("NOTHING_TO_INLINE")
public inline operator fun Polynomial<C>.invoke(argument: Polynomial<C>): Polynomial<C> = this.substitute(ring, argument)
// TODO: Move to other internal utilities with context receiver override fun add(left: P, right: P): P = left + right
@JvmName("applyAndRemoveZerosInternal") override fun multiply(left: P, right: P): P = left * right
internal inline fun MutableList<C>.applyAndRemoveZeros(block: MutableList<C>.() -> Unit) : MutableList<C> {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block()
while (isNotEmpty() && elementAt(lastIndex).isZero()) removeAt(lastIndex)
return this
}
internal inline fun List<C>.applyAndRemoveZeros(block: MutableList<C>.() -> Unit) : List<C> =
toMutableList().applyAndRemoveZeros(block)
@Suppress("FunctionName")
internal inline fun MutableCoefficients(size: Int, init: (index: Int) -> C): MutableList<C> {
val list = ArrayList<C>(size)
repeat(size) { index -> list.add(init(index)) }
with(list) { while (isNotEmpty() && elementAt(lastIndex).isZero()) removeAt(lastIndex) }
return list
}
@Suppress("FunctionName")
internal inline fun Coefficients(size: Int, init: (index: Int) -> C): List<C> = MutableCoefficients(size, init)
@OptIn(ExperimentalTypeInference::class)
internal inline fun buildCoefficients(@BuilderInference builderAction: MutableList<C>.() -> Unit): List<C> {
contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) }
return buildList {
builderAction()
while (isNotEmpty() && elementAt(lastIndex).isZero()) removeAt(lastIndex)
}
}
@OptIn(ExperimentalTypeInference::class)
internal inline fun buildCoefficients(capacity: Int, @BuilderInference builderAction: MutableList<C>.() -> Unit): List<C> {
contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) }
return buildList(capacity) {
builderAction()
while (isNotEmpty() && elementAt(lastIndex).isZero()) removeAt(lastIndex)
}
}
} }
/** /**
* Space of polynomials constructed over ring. * 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 a coefficients in their terms. * @param C the type of constants. Polynomials have them as coefficients in their terms.
* @param A type of underlying ring of constants. It's [Ring] of [C]. * @param P the type of polynomials.
* @param ring underlying ring of constants of type [A]. * @param A the type of algebraic structure (precisely, of ring) provided for constants.
*/ */
public class ScalablePolynomialSpace<C, A>( @Suppress("INAPPLICABLE_JVM_NAME")
ring: A, public interface PolynomialSpaceOverRing<C, P: Polynomial<C>, A: Ring<C>> : PolynomialSpace<C, P> {
) : PolynomialSpace<C, A>(ring), ScaleOperations<Polynomial<C>> where A : Ring<C>, A : ScaleOperations<C> {
override fun scale(a: Polynomial<C>, value: Double): Polynomial<C> = public val ring: A
ring { Polynomial(a.coefficients.map { scale(it, value) }) }
} /**
* Returns sum of the constant and the integer represented as 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 { addMultipliedBySquaring(this@plus, one, other) }
/**
* Returns difference between the constant and the integer represented as 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 { addMultipliedBySquaring(this@minus, one, -other) }
/**
* Returns product of the constant and the integer represented as 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 { multiplyBySquaring(this@times, other) }
/**
* Returns sum of the integer represented as 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 { addMultipliedBySquaring(other, one, this@plus) }
/**
* Returns difference between the integer represented as 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 { addMultipliedBySquaring(-other, one, this@minus) }
/**
* Returns product of the integer represented as 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 { multiplyBySquaring(other, this@times) }
/**
* Returns negation of the constant.
*/
@JvmName("constantUnaryMinus")
public override operator fun C.unaryMinus(): C = ring { -this@unaryMinus }
/**
* Returns sum of the constants.
*/
@JvmName("constantPlus")
public override operator fun C.plus(other: C): C = ring { this@plus + other }
/**
* Returns difference of the constants.
*/
@JvmName("constantMinus")
public override operator fun C.minus(other: C): C = ring { this@minus - other }
/**
* Returns product of the constants.
*/
@JvmName("constantTimes")
public override operator fun C.times(other: C): C = ring { this@times * other }
/**
* Raises [arg] to the integer power [exponent].
*/
@JvmName("constantPower")
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
}

View File

@ -17,7 +17,7 @@ public fun <C, A : Ring<C>> A.labeledRationalFunction(): LabeledRationalFunction
LabeledRationalFunctionSpace(this) LabeledRationalFunctionSpace(this)
/** /**
* Creates a [RationalFunctionSpace]'s scope over a received ring. * Creates a [LabeledRationalFunctionSpace]'s scope over a received ring.
*/ */
public inline fun <C, A : Ring<C>, R> A.labeledRationalFunction(block: LabeledRationalFunctionSpace<C, A>.() -> R): R { public inline fun <C, A : Ring<C>, R> A.labeledRationalFunction(block: LabeledRationalFunctionSpace<C, A>.() -> R): R {
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }

View File

@ -22,31 +22,31 @@ import kotlin.math.pow
// if (degree > -1) Polynomial(coefficients.subList(0, degree + 1)) else zero // if (degree > -1) Polynomial(coefficients.subList(0, degree + 1)) else zero
/** /**
* Creates a [PolynomialSpace] over a received ring. * Creates a [ListPolynomialSpace] over a received ring.
*/ */
public fun <C, A : Ring<C>> A.polynomial(): PolynomialSpace<C, A> = public fun <C, A : Ring<C>> A.listPolynomial(): ListPolynomialSpace<C, A> =
PolynomialSpace(this) ListPolynomialSpace(this)
/** /**
* Creates a [PolynomialSpace]'s scope over a received ring. * Creates a [ListPolynomialSpace]'s scope over a received ring.
*/ */
public inline fun <C, A : Ring<C>, R> A.polynomial(block: PolynomialSpace<C, A>.() -> R): R { public inline fun <C, A : Ring<C>, R> A.listPolynomial(block: ListPolynomialSpace<C, A>.() -> R): R {
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
return PolynomialSpace(this).block() return ListPolynomialSpace(this).block()
} }
/** /**
* Creates a [ScalablePolynomialSpace] over a received scalable ring. * Creates a [ScalableListPolynomialSpace] over a received scalable ring.
*/ */
public fun <C, A> A.scalablePolynomial(): ScalablePolynomialSpace<C, A> where A : Ring<C>, A : ScaleOperations<C> = public fun <C, A> A.scalableListPolynomial(): ScalableListPolynomialSpace<C, A> where A : Ring<C>, A : ScaleOperations<C> =
ScalablePolynomialSpace(this) ScalableListPolynomialSpace(this)
/** /**
* Creates a [ScalablePolynomialSpace]'s scope over a received scalable ring. * Creates a [ScalableListPolynomialSpace]'s scope over a received scalable ring.
*/ */
public inline fun <C, A, R> A.scalablePolynomial(block: ScalablePolynomialSpace<C, A>.() -> R): R where A : Ring<C>, A : ScaleOperations<C> { public inline fun <C, A, R> A.scalableListPolynomial(block: ScalableListPolynomialSpace<C, A>.() -> R): R where A : Ring<C>, A : ScaleOperations<C> {
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
return ScalablePolynomialSpace(this).block() return ScalableListPolynomialSpace(this).block()
} }
@Suppress("NOTHING_TO_INLINE") @Suppress("NOTHING_TO_INLINE")
@ -99,7 +99,7 @@ internal inline fun <C> multiplyAddingTo(
/** /**
* Evaluates the value of the given double polynomial for given double argument. * Evaluates the value of the given double polynomial for given double argument.
*/ */
public fun Polynomial<Double>.substitute(arg: Double): Double = public fun ListPolynomial<Double>.substitute(arg: Double): Double =
coefficients.reduceIndexedOrNull { index, acc, c -> coefficients.reduceIndexedOrNull { index, acc, c ->
acc + c * arg.pow(index) acc + c * arg.pow(index)
} ?: .0 } ?: .0
@ -109,7 +109,7 @@ public fun Polynomial<Double>.substitute(arg: Double): Double =
* *
* It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method).
*/ */
public fun <C> Polynomial<C>.substitute(ring: Ring<C>, arg: C): C = ring { public fun <C> ListPolynomial<C>.substitute(ring: Ring<C>, arg: C): C = ring {
if (coefficients.isEmpty()) return@ring zero if (coefficients.isEmpty()) return@ring zero
var result: C = coefficients.last() var result: C = coefficients.last()
for (j in coefficients.size - 2 downTo 0) { for (j in coefficients.size - 2 downTo 0) {
@ -118,11 +118,11 @@ public fun <C> Polynomial<C>.substitute(ring: Ring<C>, arg: C): C = ring {
return result return result
} }
public fun <C> Polynomial<C>.substitute(ring: Ring<C>, arg: Polynomial<C>) : Polynomial<C> = ring { public fun <C> ListPolynomial<C>.substitute(ring: Ring<C>, arg: ListPolynomial<C>) : ListPolynomial<C> = ring {
if (coefficients.isEmpty()) return Polynomial(emptyList()) if (coefficients.isEmpty()) return ListPolynomial(emptyList())
val thisDegree = coefficients.indexOfLast { it != zero } val thisDegree = coefficients.indexOfLast { it != zero }
if (thisDegree == -1) return Polynomial(emptyList()) if (thisDegree == -1) return ListPolynomial(emptyList())
val argDegree = arg.coefficients.indexOfLast { it != zero } val argDegree = arg.coefficients.indexOfLast { it != zero }
if (argDegree == -1) return coefficients[0].asPolynomial() if (argDegree == -1) return coefficients[0].asPolynomial()
val constantZero = zero val constantZero = zero
@ -145,27 +145,27 @@ public fun <C> Polynomial<C>.substitute(ring: Ring<C>, arg: Polynomial<C>) : Pol
} }
with(resultCoefs) { while (isNotEmpty() && elementAt(lastIndex) == constantZero) removeAt(lastIndex) } with(resultCoefs) { while (isNotEmpty() && elementAt(lastIndex) == constantZero) removeAt(lastIndex) }
return Polynomial<C>(resultCoefs) return ListPolynomial<C>(resultCoefs)
} }
/** /**
* Represent the polynomial as a regular context-less function. * Represent the polynomial as a regular context-less function.
*/ */
public fun <C, A : Ring<C>> Polynomial<C>.asFunction(ring: A): (C) -> C = { substitute(ring, it) } public fun <C, A : Ring<C>> ListPolynomial<C>.asFunction(ring: A): (C) -> C = { substitute(ring, it) }
/** /**
* Represent the polynomial as a regular context-less function. * Represent the polynomial as a regular context-less function.
*/ */
public fun <C, A : Ring<C>> Polynomial<C>.asPolynomialFunctionOver(ring: A): (Polynomial<C>) -> Polynomial<C> = { substitute(ring, it) } public fun <C, A : Ring<C>> ListPolynomial<C>.asPolynomialFunctionOver(ring: A): (ListPolynomial<C>) -> ListPolynomial<C> = { substitute(ring, it) }
/** /**
* Returns algebraic derivative of received polynomial. * Returns algebraic derivative of received polynomial.
*/ */
@UnstableKMathAPI @UnstableKMathAPI
public fun <C, A> Polynomial<C>.derivative( public fun <C, A> ListPolynomial<C>.derivative(
algebra: A, algebra: A,
): Polynomial<C> where A : Ring<C>, A : NumericAlgebra<C> = algebra { ): ListPolynomial<C> where A : Ring<C>, A : NumericAlgebra<C> = algebra {
Polynomial( ListPolynomial(
buildList(max(0, coefficients.size - 1)) { buildList(max(0, coefficients.size - 1)) {
for (deg in 1 .. coefficients.lastIndex) add(number(deg) * coefficients[deg]) for (deg in 1 .. coefficients.lastIndex) add(number(deg) * coefficients[deg])
while (isNotEmpty() && elementAt(lastIndex) == algebra.zero) removeAt(lastIndex) while (isNotEmpty() && elementAt(lastIndex) == algebra.zero) removeAt(lastIndex)
@ -177,12 +177,12 @@ public fun <C, A> Polynomial<C>.derivative(
* Returns algebraic derivative of received polynomial. * Returns algebraic derivative of received polynomial.
*/ */
@UnstableKMathAPI @UnstableKMathAPI
public fun <C, A> Polynomial<C>.nthDerivative( public fun <C, A> ListPolynomial<C>.nthDerivative(
algebra: A, algebra: A,
order: Int, order: Int,
): Polynomial<C> where A : Ring<C>, A : NumericAlgebra<C> = algebra { ): ListPolynomial<C> where A : Ring<C>, A : NumericAlgebra<C> = algebra {
require(order >= 0) { "Order of derivative must be non-negative" } require(order >= 0) { "Order of derivative must be non-negative" }
Polynomial( ListPolynomial(
buildList(max(0, coefficients.size - order)) { buildList(max(0, coefficients.size - order)) {
for (deg in order.. coefficients.lastIndex) for (deg in order.. coefficients.lastIndex)
add((deg - order + 1 .. deg).fold(coefficients[deg]) { acc, d -> acc * number(d) }) add((deg - order + 1 .. deg).fold(coefficients[deg]) { acc, d -> acc * number(d) })
@ -195,10 +195,10 @@ public fun <C, A> Polynomial<C>.nthDerivative(
* Returns algebraic antiderivative of received polynomial. * Returns algebraic antiderivative of received polynomial.
*/ */
@UnstableKMathAPI @UnstableKMathAPI
public fun <C, A> Polynomial<C>.antiderivative( public fun <C, A> ListPolynomial<C>.antiderivative(
algebra: A, algebra: A,
): Polynomial<C> where A : Field<C>, A : NumericAlgebra<C> = algebra { ): ListPolynomial<C> where A : Field<C>, A : NumericAlgebra<C> = algebra {
Polynomial( ListPolynomial(
buildList(coefficients.size + 1) { buildList(coefficients.size + 1) {
add(zero) add(zero)
coefficients.mapIndexedTo(this) { index, t -> t / number(index + 1) } coefficients.mapIndexedTo(this) { index, t -> t / number(index + 1) }
@ -211,12 +211,12 @@ public fun <C, A> Polynomial<C>.antiderivative(
* Returns algebraic antiderivative of received polynomial. * Returns algebraic antiderivative of received polynomial.
*/ */
@UnstableKMathAPI @UnstableKMathAPI
public fun <C, A> Polynomial<C>.nthAntiderivative( public fun <C, A> ListPolynomial<C>.nthAntiderivative(
algebra: A, algebra: A,
order: Int, order: Int,
): Polynomial<C> where A : Field<C>, A : NumericAlgebra<C> = algebra { ): ListPolynomial<C> where A : Field<C>, A : NumericAlgebra<C> = algebra {
require(order >= 0) { "Order of antiderivative must be non-negative" } require(order >= 0) { "Order of antiderivative must be non-negative" }
Polynomial( ListPolynomial(
buildList(coefficients.size + order) { buildList(coefficients.size + order) {
repeat(order) { add(zero) } repeat(order) { add(zero) }
coefficients.mapIndexedTo(this) { index, c -> (1..order).fold(c) { acc, i -> acc / number(index + i) } } coefficients.mapIndexedTo(this) { index, c -> (1..order).fold(c) { acc, i -> acc / number(index + i) } }
@ -229,7 +229,7 @@ public fun <C, A> Polynomial<C>.nthAntiderivative(
* Compute a definite integral of a given polynomial in a [range] * Compute a definite integral of a given polynomial in a [range]
*/ */
@UnstableKMathAPI @UnstableKMathAPI
public fun <C : Comparable<C>> Polynomial<C>.integrate( public fun <C : Comparable<C>> ListPolynomial<C>.integrate(
algebra: Field<C>, algebra: Field<C>,
range: ClosedRange<C>, range: ClosedRange<C>,
): C = algebra { ): C = algebra {

View File

@ -14,23 +14,23 @@ import kotlin.math.max
/** /**
* Creates a [RationalFunctionSpace] over a received ring. * Creates a [ListRationalFunctionSpace] over a received ring.
*/ */
public fun <C, A : Ring<C>> A.rationalFunction(): RationalFunctionSpace<C, A> = public fun <C, A : Ring<C>> A.listRationalFunction(): ListRationalFunctionSpace<C, A> =
RationalFunctionSpace(this) ListRationalFunctionSpace(this)
/** /**
* Creates a [RationalFunctionSpace]'s scope over a received ring. * Creates a [ListRationalFunctionSpace]'s scope over a received ring.
*/ */
public inline fun <C, A : Ring<C>, R> A.rationalFunction(block: RationalFunctionSpace<C, A>.() -> R): R { public inline fun <C, A : Ring<C>, R> A.listRationalFunction(block: ListRationalFunctionSpace<C, A>.() -> R): R {
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
return RationalFunctionSpace(this).block() return ListRationalFunctionSpace(this).block()
} }
/** /**
* Evaluates the value of the given double polynomial for given double argument. * Evaluates the value of the given double polynomial for given double argument.
*/ */
public fun RationalFunction<Double>.substitute(arg: Double): Double = public fun ListRationalFunction<Double>.substitute(arg: Double): Double =
numerator.substitute(arg) / denominator.substitute(arg) numerator.substitute(arg) / denominator.substitute(arg)
/** /**
@ -38,7 +38,7 @@ public fun RationalFunction<Double>.substitute(arg: Double): Double =
* *
* It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method).
*/ */
public fun <C> RationalFunction<C>.substitute(ring: Field<C>, arg: C): C = ring { public fun <C> ListRationalFunction<C>.substitute(ring: Field<C>, arg: C): C = ring {
numerator.substitute(ring, arg) / denominator.substitute(ring, arg) numerator.substitute(ring, arg) / denominator.substitute(ring, arg)
} }
@ -50,13 +50,13 @@ public fun <C> RationalFunction<C>.substitute(ring: Field<C>, arg: C): C = ring
* ``` * ```
* is returned. * is returned.
* *
* Used in [Polynomial.substitute] and [RationalFunction.substitute] for performance optimisation. * Used in [ListPolynomial.substitute] and [ListRationalFunction.substitute] for performance optimisation.
*/ // TODO: Дописать */ // TODO: Дописать
internal fun <C> Polynomial<C>.substituteRationalFunctionTakeNumerator(ring: Ring<C>, arg: RationalFunction<C>): Polynomial<C> = ring { internal fun <C> ListPolynomial<C>.substituteRationalFunctionTakeNumerator(ring: Ring<C>, arg: ListRationalFunction<C>): ListPolynomial<C> = ring {
if (coefficients.isEmpty()) return Polynomial(emptyList()) if (coefficients.isEmpty()) return ListPolynomial(emptyList())
val thisDegree = coefficients.indexOfLast { it != zero } val thisDegree = coefficients.indexOfLast { it != zero }
if (thisDegree == -1) return Polynomial(emptyList()) if (thisDegree == -1) return ListPolynomial(emptyList())
val thisDegreeLog2 = 31 - thisDegree.countLeadingZeroBits() val thisDegreeLog2 = 31 - thisDegree.countLeadingZeroBits()
val numeratorDegree = arg.numerator.coefficients.indexOfLast { it != zero } val numeratorDegree = arg.numerator.coefficients.indexOfLast { it != zero }
val denominatorDegree = arg.denominator.coefficients.indexOfLast { it != zero } val denominatorDegree = arg.denominator.coefficients.indexOfLast { it != zero }
@ -189,7 +189,7 @@ internal fun <C> Polynomial<C>.substituteRationalFunctionTakeNumerator(ring: Rin
return levelResultCoefs return levelResultCoefs
} }
return Polynomial( return ListPolynomial(
processLevelEdged( processLevelEdged(
level = thisDegreeLog2, level = thisDegreeLog2,
start = 0, start = 0,

View File

@ -17,7 +17,7 @@ public fun <C, A : Ring<C>> A.numberedRationalFunction(): NumberedRationalFuncti
NumberedRationalFunctionSpace(this) NumberedRationalFunctionSpace(this)
/** /**
* Creates a [RationalFunctionSpace]'s scope over a received ring. * Creates a [NumberedRationalFunctionSpace]'s scope over a received ring.
*/ */
public inline fun <C, A : Ring<C>, R> A.numberedRationalFunction(block: NumberedRationalFunctionSpace<C, A>.() -> R): R { public inline fun <C, A : Ring<C>, R> A.numberedRationalFunction(block: NumberedRationalFunctionSpace<C, A>.() -> R): R {
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }

View File

@ -7,7 +7,7 @@ package space.kscience.kmath.interpolation
import space.kscience.kmath.data.XYColumnarData import space.kscience.kmath.data.XYColumnarData
import space.kscience.kmath.functions.PiecewisePolynomial import space.kscience.kmath.functions.PiecewisePolynomial
import space.kscience.kmath.functions.Polynomial import space.kscience.kmath.functions.ListPolynomial
import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.operations.Field import space.kscience.kmath.operations.Field
import space.kscience.kmath.operations.invoke import space.kscience.kmath.operations.invoke
@ -32,7 +32,7 @@ public class LinearInterpolator<T : Comparable<T>>(override val algebra: Field<T
for (i in 0 until points.size - 1) { for (i in 0 until points.size - 1) {
val slope = (points.y[i + 1] - points.y[i]) / (points.x[i + 1] - points.x[i]) val slope = (points.y[i + 1] - points.y[i]) / (points.x[i + 1] - points.x[i])
val const = points.y[i] - slope * points.x[i] val const = points.y[i] - slope * points.x[i]
val polynomial = Polynomial(const, slope) val polynomial = ListPolynomial(const, slope)
putRight(points.x[i + 1], polynomial) putRight(points.x[i + 1], polynomial)
} }
} }

View File

@ -7,7 +7,7 @@ package space.kscience.kmath.interpolation
import space.kscience.kmath.data.XYColumnarData import space.kscience.kmath.data.XYColumnarData
import space.kscience.kmath.functions.PiecewisePolynomial import space.kscience.kmath.functions.PiecewisePolynomial
import space.kscience.kmath.functions.Polynomial import space.kscience.kmath.functions.ListPolynomial
import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.operations.Field import space.kscience.kmath.operations.Field
@ -61,7 +61,7 @@ public class SplineInterpolator<T : Comparable<T>>(
val x02 = x0 * x0 val x02 = x0 * x0
val x03 = x02 * x0 val x03 = x02 * x0
//Shift coefficients to represent absolute polynomial instead of one with an offset //Shift coefficients to represent absolute polynomial instead of one with an offset
val polynomial = Polynomial( val polynomial = ListPolynomial(
a - b * x0 + c * x02 - d * x03, a - b * x0 + c * x02 - d * x03,
b - 2 * c * x0 + 3 * d * x02, b - 2 * c * x0 + 3 * d * x02,
c - 3 * d * x0, c - 3 * d * x0,

View File

@ -0,0 +1,705 @@
/*
* Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.functions
import space.kscience.kmath.test.misc.*
import kotlin.test.*
class ListPolynomialTest {
@Test
fun test_Polynomial_Int_plus() {
RationalField.listPolynomial {
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(),
ListPolynomial(Rational(-2)) + 2,
"test 3"
)
assertEquals(
ListPolynomial(),
ListPolynomial<Rational>() + 0,
"test 4"
)
assertEquals(
ListPolynomial(Rational(-1), Rational(0), Rational(0), Rational(0)),
ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + 1,
"test 5"
)
assertEquals(
ListPolynomial(Rational(-1)),
ListPolynomial(Rational(-2)) + 1,
"test 6"
)
assertEquals(
ListPolynomial(Rational(2)),
ListPolynomial<Rational>() + 2,
"test 7"
)
}
}
@Test
fun test_Polynomial_Int_minus() {
RationalField.listPolynomial {
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(),
ListPolynomial(Rational(2)) - 2,
"test 3"
)
assertEquals(
ListPolynomial(),
ListPolynomial<Rational>() - 0,
"test 4"
)
assertEquals(
ListPolynomial(Rational(1), Rational(0), Rational(0), Rational(0)),
ListPolynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - 1,
"test 5"
)
assertEquals(
ListPolynomial(Rational(1)),
ListPolynomial(Rational(2)) - 1,
"test 6"
)
assertEquals(
ListPolynomial(Rational(-2)),
ListPolynomial<Rational>() - 2,
"test 7"
)
}
}
@Test
fun test_Polynomial_Int_times() {
IntModuloRing(35).listPolynomial {
assertEquals(
ListPolynomial(34, 2, 1, 20, 2),
ListPolynomial(22, 26, 13, 15, 26) * 27,
"test 1"
)
assertEquals(
ListPolynomial(),
ListPolynomial(7, 0, 49, 21, 14) * 15,
"test 2"
)
}
}
@Test
fun test_Int_Polynomial_plus() {
RationalField.listPolynomial {
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(),
2 + ListPolynomial(Rational(-2)),
"test 3"
)
assertEquals(
ListPolynomial(),
0 + ListPolynomial(),
"test 4"
)
assertEquals(
ListPolynomial(Rational(-1), Rational(0), Rational(0), Rational(0)),
1 + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)),
"test 5"
)
assertEquals(
ListPolynomial(Rational(-1)),
1 + ListPolynomial(Rational(-2)),
"test 6"
)
assertEquals(
ListPolynomial(Rational(2)),
2 + ListPolynomial(),
"test 7"
)
}
}
@Test
fun test_Int_Polynomial_minus() {
RationalField.listPolynomial {
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(),
-2 - ListPolynomial(Rational(-2)),
"test 3"
)
assertEquals(
ListPolynomial(),
0 - ListPolynomial(),
"test 4"
)
assertEquals(
ListPolynomial(Rational(1), Rational(0), Rational(0), Rational(0)),
-1 - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)),
"test 5"
)
assertEquals(
ListPolynomial(Rational(1)),
-1 - ListPolynomial(Rational(-2)),
"test 6"
)
assertEquals(
ListPolynomial(Rational(-2)),
-2 - ListPolynomial(),
"test 7"
)
}
}
@Test
fun test_Int_Polynomial_times() {
IntModuloRing(35).listPolynomial {
assertEquals(
ListPolynomial(34, 2, 1, 20, 2),
27 * ListPolynomial(22, 26, 13, 15, 26),
"test 1"
)
assertEquals(
ListPolynomial(),
15 * ListPolynomial(7, 0, 49, 21, 14),
"test 2"
)
}
}
@Test
fun test_Polynomial_Constant_plus() {
RationalField.listPolynomial {
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(),
ListPolynomial(Rational(-2)) + Rational(2),
"test 3"
)
assertEquals(
ListPolynomial(),
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.listPolynomial {
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(),
ListPolynomial(Rational(2)) - Rational(2),
"test 3"
)
assertEquals(
ListPolynomial(),
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).listPolynomial {
assertEquals(
ListPolynomial(34, 2, 1, 20, 2),
ListPolynomial(22, 26, 13, 15, 26) * number(27),
"test 1"
)
assertEquals(
ListPolynomial(),
ListPolynomial(7, 0, 49, 21, 14) * number(15),
"test 2"
)
}
}
@Test
fun test_Constant_Polynomial_plus() {
RationalField.listPolynomial {
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(2) + ListPolynomial(Rational(-2)),
"test 3"
)
assertEquals(
ListPolynomial(),
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.listPolynomial {
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(-2) - ListPolynomial(Rational(-2)),
"test 3"
)
assertEquals(
ListPolynomial(),
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).listPolynomial {
assertEquals(
ListPolynomial(34, 2, 1, 20, 2),
27 * ListPolynomial(22, 26, 13, 15, 26),
"test 1"
)
assertEquals(
ListPolynomial(),
15 * ListPolynomial(7, 0, 49, 21, 14),
"test 2"
)
}
}
@Test
fun test_Polynomial_unaryMinus() {
RationalField.listPolynomial {
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.listPolynomial {
// (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)),
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(),
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.listPolynomial {
// (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)),
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(),
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).listPolynomial {
// (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(),
ListPolynomial(5, -25, 10) * ListPolynomial(21, 14, -7),
"test 2"
)
}
}
@Test
fun test_Polynomial_isZero() {
RationalField.listPolynomial {
assertTrue("test 1") { ListPolynomial<Rational>().isZero() }
assertTrue("test 2") { ListPolynomial<Rational>(Rational(0)).isZero() }
assertTrue("test 3") { ListPolynomial<Rational>(Rational(0), Rational(0)).isZero() }
assertTrue("test 4") { ListPolynomial<Rational>(Rational(0), Rational(0), Rational(0))
.isZero() }
assertFalse("test 5") { ListPolynomial<Rational>(Rational(3, 5)).isZero() }
assertFalse("test 6") { ListPolynomial<Rational>(Rational(3, 5), Rational(0))
.isZero() }
assertFalse("test 7") { ListPolynomial<Rational>(Rational(0), Rational(3, 5), Rational(0))
.isZero() }
}
}
@Test
fun test_Polynomial_isOne() {
RationalField.listPolynomial {
assertFalse("test 1") { ListPolynomial<Rational>().isOne() }
assertFalse("test 2") { ListPolynomial(Rational(0)).isOne() }
assertFalse("test 3") { ListPolynomial(Rational(0), Rational(0)).isOne() }
assertFalse("test 4") { ListPolynomial(Rational(0), Rational(0), Rational(0))
.isOne() }
assertFalse("test 5") { ListPolynomial(Rational(3, 5)).isOne() }
assertTrue("test 6") { ListPolynomial(Rational(5, 5)).isOne() }
assertFalse("test 7") { ListPolynomial(Rational(3, 5), Rational(0)).isOne() }
assertTrue("test 8") { ListPolynomial(Rational(3, 3), Rational(0)).isOne() }
assertFalse("test 9") { ListPolynomial(Rational(0), Rational(3, 5), Rational(0))
.isOne() }
assertFalse("test 10") { ListPolynomial(Rational(0), Rational(5, 5), Rational(0))
.isOne() }
assertFalse("test 11") { ListPolynomial(Rational(1), Rational(3, 5), Rational(0))
.isOne() }
assertFalse("test 12") { ListPolynomial(Rational(1), Rational(5, 5), Rational(0))
.isOne() }
}
}
@Test
fun test_Polynomial_isMinusOne() {
RationalField.listPolynomial {
assertFalse("test 1") { ListPolynomial<Rational>().isMinusOne() }
assertFalse("test 2") { ListPolynomial(Rational(0)).isMinusOne() }
assertFalse("test 3") { ListPolynomial(Rational(0), Rational(0)).isMinusOne() }
assertFalse("test 4") { ListPolynomial(Rational(0), Rational(0), Rational(0))
.isMinusOne() }
assertFalse("test 5") { ListPolynomial(Rational(3, 5)).isMinusOne() }
assertTrue("test 6") { ListPolynomial(Rational(-5, 5)).isMinusOne() }
assertFalse("test 7") { ListPolynomial(Rational(3, 5), Rational(0)).isMinusOne() }
assertTrue("test 8") { ListPolynomial(Rational(-3, 3), Rational(0)).isMinusOne() }
assertFalse("test 9") { ListPolynomial(Rational(0), Rational(3, 5), Rational(0))
.isMinusOne() }
assertFalse("test 10") { ListPolynomial(Rational(0), Rational(5, -5), Rational(0))
.isMinusOne() }
assertFalse("test 11") { ListPolynomial(Rational(-1), Rational(3, 5), Rational(0))
.isMinusOne() }
assertFalse("test 12") { ListPolynomial(Rational(-1), Rational(5, -5), Rational(0))
.isMinusOne() }
}
}
@Test
fun test_Polynomial_Polynomial_equalsTo() {
RationalField.listPolynomial {
assertTrue("test 1") {
ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) equalsTo
ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7))
}
assertTrue("test 2") {
ListPolynomial(Rational(5, 9), Rational(0), Rational(-8, 7)) equalsTo
ListPolynomial(Rational(5, 9), Rational(0), Rational(-8, 7))
}
assertTrue("test 3") {
ListPolynomial(Rational(0), Rational(0), Rational(-8, 7), Rational(0), Rational(0)) equalsTo
ListPolynomial(Rational(0), Rational(0), Rational(-8, 7))
}
assertFalse("test 4") {
ListPolynomial(Rational(5, 9), Rational(5, 7), Rational(-8, 7)) equalsTo
ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7))
}
assertFalse("test 5") {
ListPolynomial(Rational(8, 3), Rational(0), Rational(-8, 7)) equalsTo
ListPolynomial(Rational(5, 9), Rational(0), Rational(-8, 7))
}
assertFalse("test 6") {
ListPolynomial(Rational(0), Rational(0), Rational(-8, 7), Rational(0), Rational(0)) equalsTo
ListPolynomial(Rational(0), Rational(0), Rational(8, 7))
}
}
}
@Test
fun test_Polynomial_degree() {
RationalField.listPolynomial {
assertEquals(
2,
ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)).degree,
"test 1"
)
assertEquals(
-1,
ListPolynomial<Rational>().degree,
"test 2"
)
assertEquals(
-1,
ListPolynomial(Rational(0)).degree,
"test 3"
)
assertEquals(
-1,
ListPolynomial(Rational(0), Rational(0)).degree,
"test 4"
)
assertEquals(
-1,
ListPolynomial(Rational(0), Rational(0), Rational(0)).degree,
"test 5"
)
assertEquals(
0,
ListPolynomial(Rational(5, 9)).degree,
"test 6"
)
assertEquals(
0,
ListPolynomial(Rational(5, 9), Rational(0)).degree,
"test 7"
)
assertEquals(
0,
ListPolynomial(Rational(5, 9), Rational(0), Rational(0)).degree,
"test 8"
)
assertEquals(
2,
ListPolynomial(Rational(0), Rational(0), Rational(-8, 7)).degree,
"test 9"
)
assertEquals(
2,
ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7), Rational(0), Rational(0)).degree,
"test 10"
)
assertEquals(
2,
ListPolynomial(Rational(0), Rational(0), Rational(-8, 7), Rational(0), Rational(0)).degree,
"test 11"
)
}
}
@Test
fun test_Polynomial_asConstantOrNull() {
RationalField.listPolynomial {
assertEquals(
Rational(0),
ListPolynomial<Rational>().asConstantOrNull(),
"test 1"
)
assertEquals(
Rational(0),
ListPolynomial(Rational(0)).asConstantOrNull(),
"test 2"
)
assertEquals(
Rational(0),
ListPolynomial(Rational(0), Rational(0)).asConstantOrNull(),
"test 3"
)
assertEquals(
Rational(0),
ListPolynomial(Rational(0), Rational(0), Rational(0)).asConstantOrNull(),
"test 4"
)
assertEquals(
Rational(-7, 9),
ListPolynomial(Rational(-7, 9)).asConstantOrNull(),
"test 5"
)
assertEquals(
Rational(-7, 9),
ListPolynomial(Rational(-7, 9), Rational(0)).asConstantOrNull(),
"test 6"
)
assertEquals(
Rational(-7, 9),
ListPolynomial(Rational(-7, 9), Rational(0), Rational(0)).asConstantOrNull(),
"test 7"
)
assertEquals(
null,
ListPolynomial(Rational(0), Rational(-7, 9)).asConstantOrNull(),
"test 8"
)
assertEquals(
null,
ListPolynomial(Rational(0), Rational(-7, 9), Rational(0)).asConstantOrNull(),
"test 9"
)
assertEquals(
null,
ListPolynomial(Rational(0), Rational(0), Rational(-7, 9)).asConstantOrNull(),
"test 10"
)
assertEquals(
null,
ListPolynomial(Rational(4, 15), Rational(0), Rational(-7, 9)).asConstantOrNull(),
"test 11"
)
assertEquals(
null,
ListPolynomial(Rational(4, 15), Rational(0), Rational(-7, 9), Rational(0))
.asConstantOrNull(),
"test 12"
)
}
}
}

View File

@ -0,0 +1,229 @@
/*
* Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.functions
import space.kscience.kmath.test.misc.Rational
import space.kscience.kmath.test.misc.RationalField
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
class ListPolynomialUtilTest {
@Test
fun test_substitute_Double() {
val polynomial = ListPolynomial(1.0, -2.0, 1.0)
assertEquals(0.0, polynomial.substitute(1.0), 0.001)
}
@Test
fun test_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_substitute_Polynomial() {
assertEquals(
ListPolynomial(),
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)),
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)),
ListPolynomial(Rational(0), Rational(9, 4), Rational(1, 3), Rational(0))
.substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(0))),
"test 6"
)
}
@Test
fun test_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)),
ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).derivative(RationalField),
"test 4"
)
}
@Test
fun test_nthDerivative() {
assertEquals(
ListPolynomial(Rational(-2), Rational(2)),
ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 1),
"test 1"
)
assertFailsWith<IllegalArgumentException>("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)),
ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).nthDerivative(RationalField, 2),
"test 9"
)
}
@Test
fun test_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)),
ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).antiderivative(RationalField),
"test 4"
)
}
@Test
fun test_nthAntiderivative() {
assertEquals(
ListPolynomial(Rational(0), Rational(1), Rational(-1), Rational(1, 3)),
ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 1),
"test 1"
)
assertFailsWith<IllegalArgumentException>("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)),
ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).nthAntiderivative(RationalField, 2),
"test 9"
)
}
}

View File

@ -1,691 +0,0 @@
/*
* Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.functions
import space.kscience.kmath.test.misc.*
import kotlin.test.*
class PolynomialTest {
@Test
fun test_Polynomial_Int_plus() {
RationalField.polynomial {
assertEquals(
Polynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)),
Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + -3,
"test 1"
)
assertEquals(
Polynomial(Rational(0), Rational(0), Rational(0), Rational(0)),
Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + 2,
"test 2"
)
assertEquals(
Polynomial(),
Polynomial(Rational(-2)) + 2,
"test 3"
)
assertEquals(
Polynomial(),
Polynomial<Rational>() + 0,
"test 4"
)
assertEquals(
Polynomial(Rational(-1), Rational(0), Rational(0), Rational(0)),
Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + 1,
"test 5"
)
assertEquals(
Polynomial(Rational(-1)),
Polynomial(Rational(-2)) + 1,
"test 6"
)
assertEquals(
Polynomial(Rational(2)),
Polynomial<Rational>() + 2,
"test 7"
)
}
}
@Test
fun test_Polynomial_Int_minus() {
RationalField.polynomial {
assertEquals(
Polynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)),
Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - -3,
"test 1"
)
assertEquals(
Polynomial(Rational(0), Rational(0), Rational(0), Rational(0)),
Polynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - 2,
"test 2"
)
assertEquals(
Polynomial(),
Polynomial(Rational(2)) - 2,
"test 3"
)
assertEquals(
Polynomial(),
Polynomial<Rational>() - 0,
"test 4"
)
assertEquals(
Polynomial(Rational(1), Rational(0), Rational(0), Rational(0)),
Polynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - 1,
"test 5"
)
assertEquals(
Polynomial(Rational(1)),
Polynomial(Rational(2)) - 1,
"test 6"
)
assertEquals(
Polynomial(Rational(-2)),
Polynomial<Rational>() - 2,
"test 7"
)
}
}
@Test
fun test_Polynomial_Int_times() {
IntModuloRing(35).polynomial {
assertEquals(
Polynomial(34, 2, 1, 20, 2),
Polynomial(22, 26, 13, 15, 26) * 27,
"test 1"
)
assertEquals(
Polynomial(),
Polynomial(7, 0, 49, 21, 14) * 15,
"test 2"
)
}
}
@Test
fun test_Int_Polynomial_plus() {
RationalField.polynomial {
assertEquals(
Polynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)),
-3 + Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)),
"test 1"
)
assertEquals(
Polynomial(Rational(0), Rational(0), Rational(0), Rational(0)),
2 + Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)),
"test 2"
)
assertEquals(
Polynomial(),
2 + Polynomial(Rational(-2)),
"test 3"
)
assertEquals(
Polynomial(),
0 + Polynomial(),
"test 4"
)
assertEquals(
Polynomial(Rational(-1), Rational(0), Rational(0), Rational(0)),
1 + Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)),
"test 5"
)
assertEquals(
Polynomial(Rational(-1)),
1 + Polynomial(Rational(-2)),
"test 6"
)
assertEquals(
Polynomial(Rational(2)),
2 + Polynomial(),
"test 7"
)
}
}
@Test
fun test_Int_Polynomial_minus() {
RationalField.polynomial {
assertEquals(
Polynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)),
3 - Polynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)),
"test 1"
)
assertEquals(
Polynomial(Rational(0), Rational(0), Rational(0), Rational(0)),
-2 - Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)),
"test 2"
)
assertEquals(
Polynomial(),
-2 - Polynomial(Rational(-2)),
"test 3"
)
assertEquals(
Polynomial(),
0 - Polynomial(),
"test 4"
)
assertEquals(
Polynomial(Rational(1), Rational(0), Rational(0), Rational(0)),
-1 - Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)),
"test 5"
)
assertEquals(
Polynomial(Rational(1)),
-1 - Polynomial(Rational(-2)),
"test 6"
)
assertEquals(
Polynomial(Rational(-2)),
-2 - Polynomial(),
"test 7"
)
}
}
@Test
fun test_Int_Polynomial_times() {
IntModuloRing(35).polynomial {
assertEquals(
Polynomial(34, 2, 1, 20, 2),
27 * Polynomial(22, 26, 13, 15, 26),
"test 1"
)
assertEquals(
Polynomial(),
15 * Polynomial(7, 0, 49, 21, 14),
"test 2"
)
}
}
@Test
fun test_Polynomial_Constant_plus() {
RationalField.polynomial {
assertEquals(
Polynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)),
Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + Rational(-3),
"test 1"
)
assertEquals(
Polynomial(Rational(0), Rational(0), Rational(0), Rational(0)),
Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + Rational(2),
"test 2"
)
assertEquals(
Polynomial(),
Polynomial(Rational(-2)) + Rational(2),
"test 3"
)
assertEquals(
Polynomial(),
Polynomial<Rational>() + Rational(0),
"test 4"
)
assertEquals(
Polynomial(Rational(-1), Rational(0), Rational(0), Rational(0)),
Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + Rational(1),
"test 5"
)
assertEquals(
Polynomial(Rational(-1)),
Polynomial(Rational(-2)) + Rational(1),
"test 6"
)
assertEquals(
Polynomial(Rational(2)),
Polynomial<Rational>() + Rational(2),
"test 7"
)
}
}
@Test
fun test_Polynomial_Constant_minus() {
RationalField.polynomial {
assertEquals(
Polynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)),
Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - Rational(-3),
"test 1"
)
assertEquals(
Polynomial(Rational(0), Rational(0), Rational(0), Rational(0)),
Polynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - Rational(2),
"test 2"
)
assertEquals(
Polynomial(),
Polynomial(Rational(2)) - Rational(2),
"test 3"
)
assertEquals(
Polynomial(),
Polynomial<Rational>() - Rational(0),
"test 4"
)
assertEquals(
Polynomial(Rational(1), Rational(0), Rational(0), Rational(0)),
Polynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - Rational(1),
"test 5"
)
assertEquals(
Polynomial(Rational(1)),
Polynomial(Rational(2)) - Rational(1),
"test 6"
)
assertEquals(
Polynomial(Rational(-2)),
Polynomial<Rational>() - Rational(2),
"test 7"
)
}
}
@Test
fun test_Polynomial_Constant_times() {
IntModuloRing(35).polynomial {
assertEquals(
Polynomial(34, 2, 1, 20, 2),
Polynomial(22, 26, 13, 15, 26) * number(27),
"test 1"
)
assertEquals(
Polynomial(),
Polynomial(7, 0, 49, 21, 14) * number(15),
"test 2"
)
}
}
@Test
fun test_Constant_Polynomial_plus() {
RationalField.polynomial {
assertEquals(
Polynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)),
Rational(-3) + Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)),
"test 1"
)
assertEquals(
Polynomial(Rational(0), Rational(0), Rational(0), Rational(0)),
Rational(2) + Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)),
"test 2"
)
assertEquals(
Polynomial(),
Rational(2) + Polynomial(Rational(-2)),
"test 3"
)
assertEquals(
Polynomial(),
Rational(0) + Polynomial(),
"test 4"
)
assertEquals(
Polynomial(Rational(-1), Rational(0), Rational(0), Rational(0)),
Rational(1) + Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)),
"test 5"
)
assertEquals(
Polynomial(Rational(-1)),
Rational(1) + Polynomial(Rational(-2)),
"test 6"
)
assertEquals(
Polynomial(Rational(2)),
Rational(2) + Polynomial(),
"test 7"
)
}
}
@Test
fun test_Constant_Polynomial_minus() {
RationalField.polynomial {
assertEquals(
Polynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)),
Rational(3) - Polynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)),
"test 1"
)
assertEquals(
Polynomial(Rational(0), Rational(0), Rational(0), Rational(0)),
Rational(-2) - Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)),
"test 2"
)
assertEquals(
Polynomial(),
Rational(-2) - Polynomial(Rational(-2)),
"test 3"
)
assertEquals(
Polynomial(),
Rational(0) - Polynomial(),
"test 4"
)
assertEquals(
Polynomial(Rational(1), Rational(0), Rational(0), Rational(0)),
Rational(-1) - Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)),
"test 5"
)
assertEquals(
Polynomial(Rational(1)),
Rational(-1) - Polynomial(Rational(-2)),
"test 6"
)
assertEquals(
Polynomial(Rational(-2)),
Rational(-2) - Polynomial(),
"test 7"
)
}
}
@Test
fun test_Constant_Polynomial_times() {
IntModuloRing(35).polynomial {
assertEquals(
Polynomial(34, 2, 1, 20, 2),
27 * Polynomial(22, 26, 13, 15, 26),
"test 1"
)
assertEquals(
Polynomial(),
15 * Polynomial(7, 0, 49, 21, 14),
"test 2"
)
}
}
@Test
fun test_Polynomial_unaryMinus() {
RationalField.polynomial {
assertEquals(
Polynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)),
-Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)),
"test 1"
)
assertEquals(
Polynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7), Rational(0), Rational(0)),
-Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7), Rational(0), Rational(0)),
"test 2"
)
}
}
@Test
fun test_Polynomial_Polynomial_plus() {
RationalField.polynomial {
// (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(
Polynomial(Rational(-10, 63), Rational(37, 9), Rational(-29, 56)),
Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) +
Polynomial(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(
Polynomial(Rational(-2, 9), Rational(-5, 12), Rational(2, 4)),
Polynomial(Rational(-2, 9), Rational(-8, 3)) +
Polynomial(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(
Polynomial(Rational(-18, 7), Rational(-23, 6), Rational(2, 3)),
Polynomial(Rational(-4, 7), Rational(-2, 6), Rational(0), Rational(0)) +
Polynomial(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(
Polynomial(),
Polynomial(Rational(-2, 4), Rational(-6, 9), Rational(-4, 9)) +
Polynomial(Rational(2, 4), Rational(6, 9), Rational(4, 9)),
"test 4"
)
}
}
@Test
fun test_Polynomial_Polynomial_minus() {
RationalField.polynomial {
// (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(
Polynomial(Rational(80, 63), Rational(-53, 9), Rational(-99, 56)),
Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) -
Polynomial(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(
Polynomial(Rational(-2, 9), Rational(-59, 12), Rational(-2, 4)),
Polynomial(Rational(-2, 9), Rational(-8, 3)) -
Polynomial(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(
Polynomial(Rational(10, 7), Rational(19, 6), Rational(-2, 3)),
Polynomial(Rational(-4, 7), Rational(-2, 6), Rational(0), Rational(0)) -
Polynomial(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(
Polynomial(),
Polynomial(Rational(-2, 4), Rational(-6, 9), Rational(-4, 9)) -
Polynomial(Rational(-2, 4), Rational(-6, 9), Rational(-4, 9)),
"test 4"
)
}
}
@Test
fun test_Polynomial_Polynomial_times() {
IntModuloRing(35).polynomial {
// (1 + x + x^2) * (1 - x + x^2) ?= 1 + x^2 + x^4
assertEquals(
Polynomial(1, 0, 1, 0, 1),
Polynomial(1, -1, 1) * Polynomial(1, 1, 1),
"test 1"
)
// Spoiler: 5 * 7 = 0
assertEquals(
Polynomial(),
Polynomial(5, -25, 10) * Polynomial(21, 14, -7),
"test 2"
)
}
}
@Test
fun test_Polynomial_isZero() {
RationalField.polynomial {
assertTrue("test 1") { Polynomial<Rational>().isZero() }
assertTrue("test 2") { Polynomial<Rational>(Rational(0)).isZero() }
assertTrue("test 3") { Polynomial<Rational>(Rational(0), Rational(0)).isZero() }
assertTrue("test 4") { Polynomial<Rational>(Rational(0), Rational(0), Rational(0)).isZero() }
assertFalse("test 5") { Polynomial<Rational>(Rational(3, 5)).isZero() }
assertFalse("test 6") { Polynomial<Rational>(Rational(3, 5), Rational(0)).isZero() }
assertFalse("test 7") { Polynomial<Rational>(Rational(0), Rational(3, 5), Rational(0)).isZero() }
}
}
@Test
fun test_Polynomial_isOne() {
RationalField.polynomial {
assertFalse("test 1") { Polynomial<Rational>().isOne() }
assertFalse("test 2") { Polynomial(Rational(0)).isOne() }
assertFalse("test 3") { Polynomial(Rational(0), Rational(0)).isOne() }
assertFalse("test 4") { Polynomial(Rational(0), Rational(0), Rational(0)).isOne() }
assertFalse("test 5") { Polynomial(Rational(3, 5)).isOne() }
assertTrue("test 6") { Polynomial(Rational(5, 5)).isOne() }
assertFalse("test 7") { Polynomial(Rational(3, 5), Rational(0)).isOne() }
assertTrue("test 8") { Polynomial(Rational(3, 3), Rational(0)).isOne() }
assertFalse("test 9") { Polynomial(Rational(0), Rational(3, 5), Rational(0)).isOne() }
assertFalse("test 10") { Polynomial(Rational(0), Rational(5, 5), Rational(0)).isOne() }
assertFalse("test 11") { Polynomial(Rational(1), Rational(3, 5), Rational(0)).isOne() }
assertFalse("test 12") { Polynomial(Rational(1), Rational(5, 5), Rational(0)).isOne() }
}
}
@Test
fun test_Polynomial_isMinusOne() {
RationalField.polynomial {
assertFalse("test 1") { Polynomial<Rational>().isMinusOne() }
assertFalse("test 2") { Polynomial(Rational(0)).isMinusOne() }
assertFalse("test 3") { Polynomial(Rational(0), Rational(0)).isMinusOne() }
assertFalse("test 4") { Polynomial(Rational(0), Rational(0), Rational(0)).isMinusOne() }
assertFalse("test 5") { Polynomial(Rational(3, 5)).isMinusOne() }
assertTrue("test 6") { Polynomial(Rational(-5, 5)).isMinusOne() }
assertFalse("test 7") { Polynomial(Rational(3, 5), Rational(0)).isMinusOne() }
assertTrue("test 8") { Polynomial(Rational(-3, 3), Rational(0)).isMinusOne() }
assertFalse("test 9") { Polynomial(Rational(0), Rational(3, 5), Rational(0)).isMinusOne() }
assertFalse("test 10") { Polynomial(Rational(0), Rational(5, -5), Rational(0)).isMinusOne() }
assertFalse("test 11") { Polynomial(Rational(-1), Rational(3, 5), Rational(0)).isMinusOne() }
assertFalse("test 12") { Polynomial(Rational(-1), Rational(5, -5), Rational(0)).isMinusOne() }
}
}
@Test
fun test_Polynomial_equalsTo() {
RationalField.polynomial {
assertTrue("test 1") {
Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) equalsTo
Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7))
}
assertTrue("test 2") {
Polynomial(Rational(5, 9), Rational(0), Rational(-8, 7)) equalsTo
Polynomial(Rational(5, 9), Rational(0), Rational(-8, 7))
}
assertTrue("test 3") {
Polynomial(Rational(0), Rational(0), Rational(-8, 7), Rational(0), Rational(0)) equalsTo
Polynomial(Rational(0), Rational(0), Rational(-8, 7))
}
assertFalse("test 4") {
Polynomial(Rational(5, 9), Rational(5, 7), Rational(-8, 7)) equalsTo
Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7))
}
assertFalse("test 5") {
Polynomial(Rational(8, 3), Rational(0), Rational(-8, 7)) equalsTo
Polynomial(Rational(5, 9), Rational(0), Rational(-8, 7))
}
assertFalse("test 6") {
Polynomial(Rational(0), Rational(0), Rational(-8, 7), Rational(0), Rational(0)) equalsTo
Polynomial(Rational(0), Rational(0), Rational(8, 7))
}
}
}
@Test
fun test_Polynomial_degree() {
RationalField.polynomial {
assertEquals(
2,
Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)).degree,
"test 1"
)
assertEquals(
-1,
Polynomial<Rational>().degree,
"test 2"
)
assertEquals(
-1,
Polynomial(Rational(0)).degree,
"test 3"
)
assertEquals(
-1,
Polynomial(Rational(0), Rational(0)).degree,
"test 4"
)
assertEquals(
-1,
Polynomial(Rational(0), Rational(0), Rational(0)).degree,
"test 5"
)
assertEquals(
0,
Polynomial(Rational(5, 9)).degree,
"test 6"
)
assertEquals(
0,
Polynomial(Rational(5, 9), Rational(0)).degree,
"test 7"
)
assertEquals(
0,
Polynomial(Rational(5, 9), Rational(0), Rational(0)).degree,
"test 8"
)
assertEquals(
2,
Polynomial(Rational(0), Rational(0), Rational(-8, 7)).degree,
"test 9"
)
assertEquals(
2,
Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7), Rational(0), Rational(0)).degree,
"test 10"
)
assertEquals(
2,
Polynomial(Rational(0), Rational(0), Rational(-8, 7), Rational(0), Rational(0)).degree,
"test 11"
)
}
}
@Test
fun test_Polynomial_asConstantOrNull() {
RationalField.polynomial {
assertEquals(
Rational(0),
Polynomial<Rational>().asConstantOrNull(),
"test 1"
)
assertEquals(
Rational(0),
Polynomial(Rational(0)).asConstantOrNull(),
"test 2"
)
assertEquals(
Rational(0),
Polynomial(Rational(0), Rational(0)).asConstantOrNull(),
"test 3"
)
assertEquals(
Rational(0),
Polynomial(Rational(0), Rational(0), Rational(0)).asConstantOrNull(),
"test 4"
)
assertEquals(
Rational(-7, 9),
Polynomial(Rational(-7, 9)).asConstantOrNull(),
"test 5"
)
assertEquals(
Rational(-7, 9),
Polynomial(Rational(-7, 9), Rational(0)).asConstantOrNull(),
"test 6"
)
assertEquals(
Rational(-7, 9),
Polynomial(Rational(-7, 9), Rational(0), Rational(0)).asConstantOrNull(),
"test 7"
)
assertEquals(
null,
Polynomial(Rational(0), Rational(-7, 9)).asConstantOrNull(),
"test 8"
)
assertEquals(
null,
Polynomial(Rational(0), Rational(-7, 9), Rational(0)).asConstantOrNull(),
"test 9"
)
assertEquals(
null,
Polynomial(Rational(0), Rational(0), Rational(-7, 9)).asConstantOrNull(),
"test 10"
)
assertEquals(
null,
Polynomial(Rational(4, 15), Rational(0), Rational(-7, 9)).asConstantOrNull(),
"test 11"
)
assertEquals(
null,
Polynomial(Rational(4, 15), Rational(0), Rational(-7, 9), Rational(0)).asConstantOrNull(),
"test 12"
)
}
}
}

View File

@ -1,229 +0,0 @@
/*
* Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.functions
import space.kscience.kmath.test.misc.Rational
import space.kscience.kmath.test.misc.RationalField
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
class PolynomialUtilTest {
@Test
fun test_substitute_Double() {
val polynomial = Polynomial(1.0, -2.0, 1.0)
assertEquals(0.0, polynomial.substitute(1.0), 0.001)
}
@Test
fun test_substitute_Constant() {
assertEquals(
Rational(0),
Polynomial(Rational(1), Rational(-2), Rational(1)).substitute(RationalField, Rational(1)),
"test 1"
)
assertEquals(
Rational(25057, 21000),
Polynomial(Rational(5,8), Rational(8, 3), Rational(4, 7), Rational(3, 2))
.substitute(RationalField, Rational(1, 5)),
"test 2"
)
assertEquals(
Rational(2983, 5250),
Polynomial(Rational(0), Rational(8, 3), Rational(4, 7), Rational(3, 2))
.substitute(RationalField, Rational(1, 5)),
"test 3"
)
assertEquals(
Rational(4961, 4200),
Polynomial(Rational(5,8), Rational(8, 3), Rational(4, 7), Rational(0))
.substitute(RationalField, Rational(1, 5)),
"test 4"
)
assertEquals(
Rational(3511, 3000),
Polynomial(Rational(5,8), Rational(8, 3), Rational(0), Rational(3, 2))
.substitute(RationalField, Rational(1, 5)),
"test 5"
)
}
@Test
fun test_substitute_Polynomial() {
assertEquals(
Polynomial(),
Polynomial(Rational(1), Rational(-2), Rational(1)).substitute(RationalField, Polynomial(Rational(1))),
"test 1"
)
assertEquals(
Polynomial(Rational(709, 378), Rational(155, 252), Rational(19, 525), Rational(2, 875)),
Polynomial(Rational(1, 7), Rational(9, 4), Rational(1, 3), Rational(2, 7))
.substitute(RationalField, Polynomial(Rational(6, 9), Rational(1, 5))),
"test 2"
)
assertEquals(
Polynomial(Rational(655, 378), Rational(155, 252), Rational(19, 525), Rational(2, 875)),
Polynomial(Rational(0), Rational(9, 4), Rational(1, 3), Rational(2, 7))
.substitute(RationalField, Polynomial(Rational(6, 9), Rational(1, 5))),
"test 3"
)
assertEquals(
Polynomial(Rational(677, 378), Rational(97, 180), Rational(1, 75)),
Polynomial(Rational(1, 7), Rational(9, 4), Rational(1, 3), Rational(0))
.substitute(RationalField, Polynomial(Rational(6, 9), Rational(1, 5))),
"test 4"
)
assertEquals(
Polynomial(Rational(653, 378), Rational(221, 420), Rational(4, 175), Rational(2, 875)),
Polynomial(Rational(1, 7), Rational(9, 4), Rational(0), Rational(2, 7))
.substitute(RationalField, Polynomial(Rational(6, 9), Rational(1, 5))),
"test 5"
)
assertEquals(
Polynomial(Rational(89, 54)),
Polynomial(Rational(0), Rational(9, 4), Rational(1, 3), Rational(0))
.substitute(RationalField, Polynomial(Rational(6, 9), Rational(0))),
"test 6"
)
}
@Test
fun test_derivative() {
assertEquals(
Polynomial(Rational(-2), Rational(2)),
Polynomial(Rational(1), Rational(-2), Rational(1)).derivative(RationalField),
"test 1"
)
assertEquals(
Polynomial(Rational(-8, 3), Rational(8, 9), Rational(15, 7), Rational(-20, 9)),
Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).derivative(RationalField),
"test 2"
)
assertEquals(
Polynomial(Rational(0), Rational(8, 9), Rational(15, 7), Rational(-20, 9)),
Polynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).derivative(RationalField),
"test 3"
)
assertEquals(
Polynomial(Rational(-8, 3), Rational(8, 9), Rational(15, 7)),
Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).derivative(RationalField),
"test 4"
)
}
@Test
fun test_nthDerivative() {
assertEquals(
Polynomial(Rational(-2), Rational(2)),
Polynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 1),
"test 1"
)
assertFailsWith<IllegalArgumentException>("test2") {
Polynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, -1)
}
assertEquals(
Polynomial(Rational(1), Rational(-2), Rational(1)),
Polynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 0),
"test 3"
)
assertEquals(
Polynomial(Rational(2)),
Polynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 2),
"test 4"
)
assertEquals(
Polynomial(),
Polynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 3),
"test 5"
)
assertEquals(
Polynomial(),
Polynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 4),
"test 6"
)
assertEquals(
Polynomial(Rational(8, 9), Rational(30, 7), Rational(-20, 3)),
Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthDerivative(RationalField, 2),
"test 7"
)
assertEquals(
Polynomial(Rational(8, 9), Rational(30, 7), Rational(-20, 3)),
Polynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthDerivative(RationalField, 2),
"test 8"
)
assertEquals(
Polynomial(Rational(8, 9), Rational(30, 7)),
Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).nthDerivative(RationalField, 2),
"test 9"
)
}
@Test
fun test_antiderivative() {
assertEquals(
Polynomial(Rational(0), Rational(1), Rational(-1), Rational(1, 3)),
Polynomial(Rational(1), Rational(-2), Rational(1)).antiderivative(RationalField),
"test 1"
)
assertEquals(
Polynomial(Rational(0), Rational(1, 5), Rational(-4, 3), Rational(4, 27), Rational(5, 28), Rational(-1, 9)),
Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).antiderivative(RationalField),
"test 2"
)
assertEquals(
Polynomial(Rational(0), Rational(0), Rational(0), Rational(4, 27), Rational(5, 28), Rational(-1, 9)),
Polynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).antiderivative(RationalField),
"test 3"
)
assertEquals(
Polynomial(Rational(0), Rational(1, 5), Rational(-4, 3), Rational(4, 27), Rational(5, 28)),
Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).antiderivative(RationalField),
"test 4"
)
}
@Test
fun test_nthAntiderivative() {
assertEquals(
Polynomial(Rational(0), Rational(1), Rational(-1), Rational(1, 3)),
Polynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 1),
"test 1"
)
assertFailsWith<IllegalArgumentException>("test2") {
Polynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, -1)
}
assertEquals(
Polynomial(Rational(1), Rational(-2), Rational(1)),
Polynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 0),
"test 3"
)
assertEquals(
Polynomial(Rational(0), Rational(0), Rational(1, 2), Rational(-1, 3), Rational(1, 12)),
Polynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 2),
"test 4"
)
assertEquals(
Polynomial(Rational(0), Rational(0), Rational(0), Rational(1, 6), Rational(-1, 12), Rational(1, 60)),
Polynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 3),
"test 5"
)
assertEquals(
Polynomial(Rational(0), Rational(0), Rational(0), Rational(0), Rational(1, 24), Rational(-1, 60), Rational(1, 360)),
Polynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 4),
"test 6"
)
assertEquals(
Polynomial(Rational(0), Rational(0), Rational(1, 10), Rational(-4, 9), Rational(1, 27), Rational(1, 28), Rational(-1, 54)),
Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthAntiderivative(RationalField, 2),
"test 7"
)
assertEquals(
Polynomial(Rational(0), Rational(0), Rational(0), Rational(0), Rational(1, 27), Rational(1, 28), Rational(-1, 54)),
Polynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthAntiderivative(RationalField, 2),
"test 8"
)
assertEquals(
Polynomial(Rational(0), Rational(0), Rational(1, 10), Rational(-4, 9), Rational(1, 27), Rational(1, 28)),
Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).nthAntiderivative(RationalField, 2),
"test 9"
)
}
}

View File

@ -5,7 +5,7 @@
package space.kscience.kmath.integration package space.kscience.kmath.integration
import space.kscience.kmath.functions.Polynomial import space.kscience.kmath.functions.ListPolynomial
import space.kscience.kmath.functions.integrate import space.kscience.kmath.functions.integrate
import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.DoubleField
@ -19,7 +19,7 @@ class SplineIntegralTest {
@Test @Test
fun integratePolynomial(){ fun integratePolynomial(){
val polynomial = Polynomial(1.0, 2.0, 3.0) val polynomial = ListPolynomial(1.0, 2.0, 3.0)
val integral = polynomial.integrate(DoubleField,1.0..2.0) val integral = polynomial.integrate(DoubleField,1.0..2.0)
assertEquals(11.0, integral, 0.001) assertEquals(11.0, integral, 0.001)
} }

View File

@ -5,8 +5,8 @@
package space.kscience.kmath.test.misc package space.kscience.kmath.test.misc
import space.kscience.kmath.functions.Polynomial import space.kscience.kmath.functions.ListPolynomial
import space.kscience.kmath.functions.PolynomialSpace import space.kscience.kmath.functions.ListPolynomialSpace
import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.operations.Ring import space.kscience.kmath.operations.Ring
@ -134,9 +134,9 @@ class IntModuloRing : Ring<IntModulo> {
inline fun IntModulo.div(arg: IntModulo): IntModulo = this / arg inline fun IntModulo.div(arg: IntModulo): IntModulo = this / arg
} }
fun PolynomialSpace<IntModulo, IntModuloRing>.number(arg: Int) = IntModulo(arg, ring.modulus, toCheckInput = false) fun ListPolynomialSpace<IntModulo, IntModuloRing>.number(arg: Int) = IntModulo(arg, ring.modulus, toCheckInput = false)
fun PolynomialSpace<IntModulo, IntModuloRing>.Polynomial(vararg coefs: Int): Polynomial<IntModulo> = fun ListPolynomialSpace<IntModulo, IntModuloRing>.ListPolynomial(vararg coefs: Int): ListPolynomial<IntModulo> =
Polynomial(coefs.map { IntModulo(it, ring.modulus) }) ListPolynomial(coefs.map { IntModulo(it, ring.modulus) })
fun IntModuloRing.Polynomial(vararg coefs: Int): Polynomial<IntModulo> = fun IntModuloRing.ListPolynomial(vararg coefs: Int): ListPolynomial<IntModulo> =
Polynomial(coefs.map { IntModulo(it, modulus) }) ListPolynomial(coefs.map { IntModulo(it, modulus) })