Minimise appearance of new feature, leave only upgrades.

This commit is contained in:
Gleb Minaev 2022-07-11 23:32:15 +03:00
parent 51dd72e48f
commit f726e6d0f1
13 changed files with 376 additions and 2839 deletions

View File

@ -1,387 +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.
*/
@file:Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress")
package space.kscience.kmath.functions
import space.kscience.kmath.operations.Ring
import space.kscience.kmath.operations.ScaleOperations
import space.kscience.kmath.operations.invoke
import kotlin.math.max
import kotlin.math.min
/**
* Represents univariate polynomial that stores its coefficients in a [List].
*
* @param C the type of constants.
*/
public data class ListPolynomial<C>(
/**
* List that contains coefficients of the polynomial. Every monomial `a x^d` is stored as a coefficient `a` placed
* into the list at index `d`. For example, coefficients of a polynomial `5 x^2 - 6` can be represented as
* ```
* listOf(
* -6, // -6 +
* 0, // 0 x +
* 5, // 5 x^2
* )
* ```
* and also as
* ```
* listOf(
* -6, // -6 +
* 0, // 0 x +
* 5, // 5 x^2
* 0, // 0 x^3
* 0, // 0 x^4
* )
* ```
* It is not prohibited to put extra zeros at end of the list (as for `0x^3` and `0x^4` in the example). But the
* longer the coefficients list the worse performance of arithmetical operations performed on it. Thus, it is
* recommended not to put (or even to remove) extra (or useless) coefficients at the end of the coefficients list.
*/
public val coefficients: List<C>
) : Polynomial<C> {
override fun toString(): String = "ListPolynomial$coefficients"
}
/**
* Arithmetic context for univariate polynomials with coefficients stored as a [List] constructed with the provided
* [ring] of constants.
*
* @param C the type of constants. Polynomials have them a coefficients in their terms.
* @param A type of provided underlying ring of constants. It's [Ring] of [C].
* @param ring underlying ring of constants of type [A].
*/
public open class ListPolynomialSpace<C, A : Ring<C>>(
public override val ring: A,
) : PolynomialSpaceOverRing<C, ListPolynomial<C>, A> {
/**
* Returns sum of the polynomial and the integer represented as a polynomial.
*
* The operation is equivalent to adding [other] copies of unit polynomial to [this].
*/
public override operator fun ListPolynomial<C>.plus(other: Int): ListPolynomial<C> =
if (other == 0) this
else
ListPolynomial(
coefficients
.toMutableList()
.apply {
val result = getOrElse(0) { constantZero } + other
if(size == 0) add(result)
else this[0] = result
}
)
/**
* Returns difference between the polynomial and the integer represented as a polynomial.
*
* The operation is equivalent to subtraction [other] copies of unit polynomial from [this].
*/
public override operator fun ListPolynomial<C>.minus(other: Int): ListPolynomial<C> =
if (other == 0) this
else
ListPolynomial(
coefficients
.toMutableList()
.apply {
val result = getOrElse(0) { constantZero } - other
if(size == 0) add(result)
else this[0] = result
}
)
/**
* Returns product of the polynomial and the integer represented as a polynomial.
*
* The operation is equivalent to sum of [other] copies of [this].
*/
public override operator fun ListPolynomial<C>.times(other: Int): ListPolynomial<C> =
when (other) {
0 -> zero
1 -> this
else -> ListPolynomial(
coefficients
.toMutableList()
.apply {
for (deg in indices) this[deg] = this[deg] * other
}
)
}
/**
* Returns sum of the integer represented as a polynomial and the polynomial.
*
* The operation is equivalent to adding [this] copies of unit polynomial to [other].
*/
public override operator fun Int.plus(other: ListPolynomial<C>): ListPolynomial<C> =
if (this == 0) other
else
ListPolynomial(
other.coefficients
.toMutableList()
.apply {
val result = this@plus + getOrElse(0) { constantZero }
if(size == 0) add(result)
else this[0] = result
}
)
/**
* Returns difference between the integer represented as a polynomial and the polynomial.
*
* The operation is equivalent to subtraction [this] copies of unit polynomial from [other].
*/
public override operator fun Int.minus(other: ListPolynomial<C>): ListPolynomial<C> =
ListPolynomial(
other.coefficients
.toMutableList()
.apply {
if (this@minus == 0) {
indices.forEach { this[it] = -this[it] }
} else {
(1..lastIndex).forEach { this[it] = -this[it] }
val result = this@minus - getOrElse(0) { constantZero }
if (size == 0) add(result)
else this[0] = result
}
}
)
/**
* Returns product of the integer represented as a polynomial and the polynomial.
*
* The operation is equivalent to sum of [this] copies of [other].
*/
public override operator fun Int.times(other: ListPolynomial<C>): ListPolynomial<C> =
when (this) {
0 -> zero
1 -> other
else -> ListPolynomial(
other.coefficients
.toMutableList()
.apply {
for (deg in indices) this[deg] = this@times * this[deg]
}
)
}
/**
* Returns sum of the constant represented as a polynomial and the polynomial.
*/
public override operator fun C.plus(other: ListPolynomial<C>): ListPolynomial<C> =
with(other.coefficients) {
if (isEmpty()) ListPolynomial(listOf(this@plus))
else ListPolynomial(
toMutableList()
.apply {
val result = if (size == 0) this@plus else this@plus + get(0)
if(size == 0) add(result)
else this[0] = result
}
)
}
/**
* Returns difference between the constant represented as a polynomial and the polynomial.
*/
public override operator fun C.minus(other: ListPolynomial<C>): ListPolynomial<C> =
with(other.coefficients) {
if (isEmpty()) ListPolynomial(listOf(this@minus))
else ListPolynomial(
toMutableList()
.apply {
(1 .. lastIndex).forEach { this[it] = -this[it] }
val result = if (size == 0) this@minus else this@minus - get(0)
if(size == 0) add(result)
else this[0] = result
}
)
}
/**
* Returns product of the constant represented as a polynomial and the polynomial.
*/
public override operator fun C.times(other: ListPolynomial<C>): ListPolynomial<C> =
ListPolynomial(
other.coefficients
.toMutableList()
.apply {
for (deg in indices) this[deg] = this@times * this[deg]
}
)
/**
* Returns sum of the constant represented as a polynomial and the polynomial.
*/
public override operator fun ListPolynomial<C>.plus(other: C): ListPolynomial<C> =
with(coefficients) {
if (isEmpty()) ListPolynomial(listOf(other))
else ListPolynomial(
toMutableList()
.apply {
val result = if (size == 0) other else get(0) + other
if(size == 0) add(result)
else this[0] = result
}
)
}
/**
* Returns difference between the constant represented as a polynomial and the polynomial.
*/
public override operator fun ListPolynomial<C>.minus(other: C): ListPolynomial<C> =
with(coefficients) {
if (isEmpty()) ListPolynomial(listOf(-other))
else ListPolynomial(
toMutableList()
.apply {
val result = if (size == 0) other else get(0) - other
if(size == 0) add(result)
else this[0] = result
}
)
}
/**
* Returns product of the constant represented as a polynomial and the polynomial.
*/
public override operator fun ListPolynomial<C>.times(other: C): ListPolynomial<C> =
ListPolynomial(
coefficients
.toMutableList()
.apply {
for (deg in indices) this[deg] = this[deg] * other
}
)
/**
* Converts the constant [value] to polynomial.
*/
public override fun number(value: C): ListPolynomial<C> = ListPolynomial(listOf(value))
/**
* Returns negation of the polynomial.
*/
public override operator fun ListPolynomial<C>.unaryMinus(): ListPolynomial<C> =
ListPolynomial(coefficients.map { -it })
/**
* Returns sum of the polynomials.
*/
public override operator fun ListPolynomial<C>.plus(other: ListPolynomial<C>): ListPolynomial<C> {
val thisDegree = degree
val otherDegree = other.degree
return ListPolynomial(
List(max(thisDegree, otherDegree) + 1) {
when {
it > thisDegree -> other.coefficients[it]
it > otherDegree -> coefficients[it]
else -> coefficients[it] + other.coefficients[it]
}
}
)
}
/**
* Returns difference of the polynomials.
*/
public override operator fun ListPolynomial<C>.minus(other: ListPolynomial<C>): ListPolynomial<C> {
val thisDegree = degree
val otherDegree = other.degree
return ListPolynomial(
List(max(thisDegree, otherDegree) + 1) {
when {
it > thisDegree -> -other.coefficients[it]
it > otherDegree -> coefficients[it]
else -> coefficients[it] - other.coefficients[it]
}
}
)
}
/**
* Returns product of the polynomials.
*/
public override operator fun ListPolynomial<C>.times(other: ListPolynomial<C>): ListPolynomial<C> {
val thisDegree = degree
val otherDegree = other.degree
return ListPolynomial(
List(thisDegree + otherDegree + 1) { d ->
(max(0, d - otherDegree)..min(thisDegree, d))
.map { coefficients[it] * other.coefficients[d - it] }
.reduce { acc, rational -> acc + rational }
}
)
}
/**
* Raises [arg] to the integer power [exponent].
*/ // TODO: To optimize boxing
override fun power(arg: ListPolynomial<C>, exponent: UInt): ListPolynomial<C> = super.power(arg, exponent)
/**
* Instance of zero polynomial (zero of the polynomial ring).
*/
override val zero: ListPolynomial<C> = ListPolynomial(emptyList())
/**
* Instance of unit polynomial (unit of the polynomial ring).
*/
override val one: ListPolynomial<C> by lazy { ListPolynomial(listOf(constantOne)) }
/**
* Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is
* zero, degree is -1.
*/
public override val ListPolynomial<C>.degree: Int get() = coefficients.lastIndex
// TODO: When context receivers will be ready move all of this substitutions and invocations to utilities with
// [ListPolynomialSpace] as a context receiver
/**
* Evaluates value of [this] polynomial on provided [argument].
*/
public inline fun ListPolynomial<C>.substitute(argument: C): C = substitute(ring, argument)
/**
* Substitutes provided polynomial [argument] into [this] polynomial.
*/
public inline fun ListPolynomial<C>.substitute(argument: ListPolynomial<C>): ListPolynomial<C> = substitute(ring, argument)
/**
* Represent [this] polynomial as a regular context-less function.
*/
public inline fun ListPolynomial<C>.asFunction(): (C) -> C = asFunctionOver(ring)
/**
* Represent [this] polynomial as a regular context-less function.
*/
public inline fun ListPolynomial<C>.asFunctionOfConstant(): (C) -> C = asFunctionOfConstantOver(ring)
/**
* Represent [this] polynomial as a regular context-less function.
*/
public inline fun ListPolynomial<C>.asFunctionOfPolynomial(): (ListPolynomial<C>) -> ListPolynomial<C> = asFunctionOfPolynomialOver(ring)
/**
* Evaluates value of [this] polynomial on provided [argument].
*/
public inline operator fun ListPolynomial<C>.invoke(argument: C): C = substitute(ring, argument)
/**
* Evaluates value of [this] polynomial on provided [argument].
*/
public inline operator fun ListPolynomial<C>.invoke(argument: ListPolynomial<C>): ListPolynomial<C> = substitute(ring, argument)
}
/**
* Space of polynomials constructed over ring.
*
* @param C the type of constants. Polynomials have them as a coefficients in their terms.
* @param A type of underlying ring of constants. It's [Ring] of [C].
* @param ring underlying ring of constants of type [A].
*/
public class ScalableListPolynomialSpace<C, A>(
ring: A,
) : ListPolynomialSpace<C, A>(ring), ScaleOperations<ListPolynomial<C>> where A : Ring<C>, A : ScaleOperations<C> {
override fun scale(a: ListPolynomial<C>, value: Double): ListPolynomial<C> =
ring { ListPolynomial(a.coefficients.map { scale(it, value) }) }
}

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, ListPolynomial<T>> { public interface PiecewisePolynomial<T : Comparable<T>> : Piecewise<T, Polynomial<T>> {
public val pieces: Collection<Pair<ClosedRange<T>, ListPolynomial<T>>> public val pieces: Collection<Pair<ClosedRange<T>, Polynomial<T>>>
override fun findPiece(arg: T): ListPolynomial<T>? override fun findPiece(arg: T): Polynomial<T>?
} }
/** /**
@ -38,11 +38,11 @@ public interface PiecewisePolynomial<T : Comparable<T>> : Piecewise<T, ListPolyn
*/ */
@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>, ListPolynomial<T>>>, pieces: Collection<Pair<ClosedRange<T>, Polynomial<T>>>,
): PiecewisePolynomial<T> = object : PiecewisePolynomial<T> { ): PiecewisePolynomial<T> = object : PiecewisePolynomial<T> {
override val pieces: Collection<Pair<ClosedRange<T>, ListPolynomial<T>>> = pieces override val pieces: Collection<Pair<ClosedRange<T>, Polynomial<T>>> = pieces
override fun findPiece(arg: T): ListPolynomial<T>? = pieces.firstOrNull { arg in it.first }?.second override fun findPiece(arg: T): Polynomial<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>, ListPolynomial<T>>>, override val pieces: List<Pair<ClosedRange<T>, Polynomial<T>>>,
) : PiecewisePolynomial<T> { ) : PiecewisePolynomial<T> {
override fun findPiece(arg: T): ListPolynomial<T>? { override fun findPiece(arg: T): Polynomial<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<ListPolynomial<T>> = arrayListOf() private val pieces: MutableList<Polynomial<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: ListPolynomial<T>) { public fun putRight(right: T, piece: Polynomial<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: ListPolynomial<T>) { public fun putLeft(left: T, piece: Polynomial<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

@ -3,500 +3,299 @@
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
@file:Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress", "PARAMETER_NAME_CHANGED_ON_OVERRIDE")
package space.kscience.kmath.functions package space.kscience.kmath.functions
import space.kscience.kmath.operations.Ring import space.kscience.kmath.operations.Ring
import space.kscience.kmath.operations.ScaleOperations
import space.kscience.kmath.operations.invoke import space.kscience.kmath.operations.invoke
import kotlin.js.JsName import kotlin.jvm.JvmInline
import kotlin.jvm.JvmName import kotlin.math.max
import kotlin.math.min
/** /**
* Abstraction of polynomials. * Represents univariate polynomial that stores its coefficients in a [List].
*/
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 C the type of constants.
* @param P the type of polynomials.
*/ */
@Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") // FIXME: Waiting for KT-31420 @JvmInline
public interface PolynomialSpace<C, P: Polynomial<C>> : Ring<P> { public value class Polynomial<C>(
/** /**
* Returns sum of the constant and the integer represented as a constant (member of underlying ring). * List that contains coefficients of the polynomial. Every monomial `a x^d` is stored as a coefficient `a` placed
* * into the list at index `d`. For example, coefficients of a polynomial `5 x^2 - 6` can be represented as
* 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 not prohibited to put extra zeros at end of the list (as for `0x^3` and `0x^4` in the example). But the
* longer the coefficients list the worse performance of arithmetical operations performed on it. Thus, it is
* recommended not to put (or even to remove) extra (or useless) coefficients at the end of the coefficients list.
*/ */
public operator fun C.plus(other: Int): C public val coefficients: List<C>
/** ) {
* Returns difference between the constant and the integer represented as a constant (member of underlying ring). override fun toString(): String = "ListPolynomial$coefficients"
* }
* The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this].
*/
public operator fun C.minus(other: Int): C
/**
* Returns product of the constant and the integer represented as a constant (member of underlying ring).
*
* The operation is equivalent to sum of [other] copies of [this].
*/
public operator fun C.times(other: Int): C
/**
* Arithmetic context for univariate polynomials with coefficients stored as a [List] constructed with the provided
* [ring] of constants.
*
* @param C the type of constants. Polynomials have them a coefficients in their terms.
* @param A type of provided underlying ring of constants. It's [Ring] of [C].
* @param ring underlying ring of constants of type [A].
*/
public open class ListPolynomialSpace<C, A : Ring<C>>(
/** /**
* Returns sum of the integer represented as a constant (member of underlying ring) and the constant. * Underlying ring of constants. Its operations on constants are inherited by local operations on constants.
*
* The operation is equivalent to adding [this] copies of unit of underlying ring to [other].
*/ */
public operator fun Int.plus(other: C): C public val ring: A,
/** ) : Ring<Polynomial<C>> {
* Returns difference between the integer represented as a constant (member of underlying ring) and the constant.
*
* The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other].
*/
public operator fun Int.minus(other: C): C
/**
* Returns product of the integer represented as a constant (member of underlying ring) and the constant.
*
* The operation is equivalent to sum of [this] copies of [other].
*/
public operator fun Int.times(other: C): C
/**
* Converts the integer [value] to constant.
*/
public fun constantNumber(value: Int): C = constantOne * value
/**
* Converts the integer to constant.
*/
public fun Int.asConstant(): C = constantNumber(this)
/**
* Returns sum of the polynomial and the integer represented as a polynomial.
*
* The operation is equivalent to adding [other] copies of unit polynomial to [this].
*/
public operator fun P.plus(other: Int): P = addMultipliedByDoubling(this, one, other)
/**
* Returns difference between the polynomial and the integer represented as a polynomial.
*
* The operation is equivalent to subtraction [other] copies of unit polynomial from [this].
*/
public operator fun P.minus(other: Int): P = addMultipliedByDoubling(this, one, -other)
/**
* Returns product of the polynomial and the integer represented as a polynomial.
*
* The operation is equivalent to sum of [other] copies of [this].
*/
public operator fun P.times(other: Int): P = multiplyByDoubling(this, other)
/**
* Returns sum of the integer represented as a polynomial and the polynomial.
*
* The operation is equivalent to adding [this] copies of unit polynomial to [other].
*/
public operator fun Int.plus(other: P): P = addMultipliedByDoubling(other, one, this)
/**
* Returns difference between the integer represented as a polynomial and the polynomial.
*
* The operation is equivalent to subtraction [this] copies of unit polynomial from [other].
*/
public operator fun Int.minus(other: P): P = addMultipliedByDoubling(-other, one, this)
/**
* Returns product of the integer represented as a polynomial and the polynomial.
*
* The operation is equivalent to sum of [this] copies of [other].
*/
public operator fun Int.times(other: P): P = multiplyByDoubling(other, this)
/**
* Converts the integer [value] to polynomial.
*/
public fun number(value: Int): P = number(constantNumber(value))
/**
* Converts the integer to polynomial.
*/
public fun Int.asPolynomial(): P = number(this)
/**
* Returns the same constant.
*/
@JvmName("unaryPlusConstant")
@JsName("unaryPlusConstant")
public operator fun C.unaryPlus(): C = this
/**
* Returns negation of the constant.
*/
@JvmName("unaryMinusConstant")
@JsName("unaryMinusConstant")
public operator fun C.unaryMinus(): C
/**
* Returns sum of the constants.
*/
@JvmName("plusConstantConstant")
@JsName("plusConstantConstant")
public operator fun C.plus(other: C): C
/**
* Returns difference of the constants.
*/
@JvmName("minusConstantConstant")
@JsName("minusConstantConstant")
public operator fun C.minus(other: C): C
/**
* Returns product of the constants.
*/
@JvmName("timesConstantConstant")
@JsName("timesConstantConstant")
public operator fun C.times(other: C): C
/**
* Raises [arg] to the integer power [exponent].
*/
@JvmName("powerConstant")
@JsName("powerConstant")
public fun power(arg: C, exponent: UInt) : C
/** /**
* Instance of zero constant (zero of the underlying ring). * Instance of zero constant (zero of the underlying ring).
*/ */
public val constantZero: C public val constantZero: C get() = ring.zero
/** /**
* Instance of unit constant (unit of the underlying ring). * Instance of unit constant (unit of the underlying ring).
*/ */
public val constantOne: C public val constantOne: C get() = ring.one
/** /**
* Returns sum of the constant represented as a polynomial and the polynomial. * Returns sum of the constant represented as a polynomial and the polynomial.
*/ */
public operator fun C.plus(other: P): P public operator fun C.plus(other: Polynomial<C>): Polynomial<C> =
with(ring) {
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)
if (size == 0) add(result)
else this[0] = result
}
)
}
}
/** /**
* Returns difference between the constant represented as a polynomial and the polynomial. * Returns difference between the constant represented as a polynomial and the polynomial.
*/ */
public operator fun C.minus(other: P): P public operator fun C.minus(other: Polynomial<C>): Polynomial<C> =
with(ring) {
with(other.coefficients) {
if (isEmpty()) Polynomial(listOf(this@minus))
else Polynomial(
toMutableList()
.apply {
(1..lastIndex).forEach { this[it] = -this[it] }
val result = if (size == 0) this@minus else this@minus - get(0)
if (size == 0) add(result)
else this[0] = result
}
)
}
}
/** /**
* Returns product of the constant represented as a polynomial and the polynomial. * Returns product of the constant represented as a polynomial and the polynomial.
*/ */
public operator fun C.times(other: P): P public operator fun C.times(other: Polynomial<C>): Polynomial<C> =
with(ring) {
Polynomial(
other.coefficients
.toMutableList()
.apply {
for (deg in indices) this[deg] = this@times * this[deg]
}
)
}
/** /**
* Returns sum of the constant represented as a polynomial and the polynomial. * Returns sum of the constant represented as a polynomial and the polynomial.
*/ */
public operator fun P.plus(other: C): P public operator fun Polynomial<C>.plus(other: C): Polynomial<C> =
with(ring) {
with(coefficients) {
if (isEmpty()) Polynomial(listOf(other))
else Polynomial(
toMutableList()
.apply {
val result = if (size == 0) other else get(0) + other
if (size == 0) add(result)
else this[0] = result
}
)
}
}
/** /**
* Returns difference between the constant represented as a polynomial and the polynomial. * Returns difference between the constant represented as a polynomial and the polynomial.
*/ */
public operator fun P.minus(other: C): P public operator fun Polynomial<C>.minus(other: C): Polynomial<C> =
with(ring) {
with(coefficients) {
if (isEmpty()) Polynomial(listOf(-other))
else Polynomial(
toMutableList()
.apply {
val result = if (size == 0) other else get(0) - other
if (size == 0) add(result)
else this[0] = result
}
)
}
}
/** /**
* Returns product of the constant represented as a polynomial and the polynomial. * Returns product of the constant represented as a polynomial and the polynomial.
*/ */
public operator fun P.times(other: C): P public operator fun Polynomial<C>.times(other: C): Polynomial<C> =
with(ring) {
Polynomial(
coefficients
.toMutableList()
.apply {
for (deg in indices) this[deg] = this[deg] * other
}
)
}
/** /**
* Converts the constant [value] to polynomial. * Converts the constant [value] to polynomial.
*/ */
public fun number(value: C): P = one * value public fun number(value: C): Polynomial<C> = Polynomial(listOf(value))
/** /**
* Converts the constant to polynomial. * Converts the constant to polynomial.
*/ */
public fun C.asPolynomial(): P = number(this) public fun C.asPolynomial(): Polynomial<C> = number(this)
/**
* 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 P.unaryMinus(): P public override operator fun Polynomial<C>.unaryMinus(): Polynomial<C> =
with(ring) {
Polynomial(coefficients.map { -it })
}
/** /**
* Returns sum of the polynomials. * Returns sum of the polynomials.
*/ */
public override operator fun P.plus(other: P): P public override operator fun Polynomial<C>.plus(other: Polynomial<C>): Polynomial<C> {
with(ring) {
val thisDegree = degree
val otherDegree = other.degree
return Polynomial(
List(max(thisDegree, otherDegree) + 1) {
when {
it > thisDegree -> other.coefficients[it]
it > otherDegree -> coefficients[it]
else -> coefficients[it] + other.coefficients[it]
}
}
)
}
}
/** /**
* Returns difference of the polynomials. * Returns difference of the polynomials.
*/ */
public override operator fun P.minus(other: P): P public override operator fun Polynomial<C>.minus(other: Polynomial<C>): Polynomial<C> {
with(ring) {
val thisDegree = degree
val otherDegree = other.degree
return Polynomial(
List(max(thisDegree, otherDegree) + 1) {
when {
it > thisDegree -> -other.coefficients[it]
it > otherDegree -> coefficients[it]
else -> coefficients[it] - other.coefficients[it]
}
}
)
}
}
/** /**
* Returns product of the polynomials. * Returns product of the polynomials.
*/ */
public override operator fun P.times(other: P): P public override operator fun Polynomial<C>.times(other: Polynomial<C>): Polynomial<C> {
with(ring) {
val thisDegree = degree
val otherDegree = other.degree
return Polynomial(
List(thisDegree + otherDegree + 1) { d ->
(max(0, d - otherDegree)..min(thisDegree, d))
.map { coefficients[it] * other.coefficients[d - it] }
.reduce { acc, rational -> acc + rational }
}
)
}
}
/** /**
* Raises [arg] to the integer power [exponent]. * Raises [arg] to the integer power [exponent].
*/ */ // TODO: To optimize boxing
public override fun power(arg: P, exponent: UInt) : P = exponentiateBySquaring(arg, exponent) override fun power(arg: Polynomial<C>, exponent: UInt): Polynomial<C> = exponentiateBySquaring(arg, exponent)
/** /**
* Instance of zero polynomial (zero of the polynomial ring). * Instance of zero polynomial (zero of the polynomial ring).
*/ */
public override val zero: P override val zero: Polynomial<C> = Polynomial(emptyList())
/** /**
* Instance of unit polynomial (unit of the polynomial ring). * Instance of unit polynomial (unit of the polynomial ring).
*/ */
public override val one: P override val one: Polynomial<C> by lazy { Polynomial(listOf(constantOne)) }
/** /**
* 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 val P.degree: Int public val Polynomial<C>.degree: Int get() = coefficients.lastIndex
override fun add(left: P, right: P): P = left + right override fun add(left: Polynomial<C>, right: Polynomial<C>): Polynomial<C> = left + right
override fun multiply(left: P, right: P): P = left * right override fun multiply(left: Polynomial<C>, right: Polynomial<C>): Polynomial<C> = left * right
// TODO: When context receivers will be ready move all of this substitutions and invocations to utilities with
// [ListPolynomialSpace] as a context receiver
/**
* Evaluates value of [this] polynomial on provided [argument].
*/
public inline fun Polynomial<C>.substitute(argument: C): C = substitute(ring, argument)
/**
* Represent [this] polynomial as a regular context-less function.
*/
public inline fun Polynomial<C>.asFunction(): (C) -> C = asFunctionOver(ring)
/**
* Evaluates value of [this] polynomial on provided [argument].
*/
public inline operator fun Polynomial<C>.invoke(argument: C): C = substitute(ring, argument)
} }
/** /**
* Abstraction of ring of polynomials of type [P] over ring of constants of type [C]. It also assumes that there is * Space of polynomials constructed over ring.
* 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 C the type of constants. Polynomials have them as a coefficients in their terms.
* @param P the type of polynomials. * @param A type of underlying ring of constants. It's [Ring] of [C].
* @param A the type of algebraic structure (precisely, of ring) provided for constants. * @param ring underlying ring of constants of type [A].
*/ */
@Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public class ScalableListPolynomialSpace<C, A>(
public interface PolynomialSpaceOverRing<C, P: Polynomial<C>, A: Ring<C>> : PolynomialSpace<C, P> { ring: A,
) : ListPolynomialSpace<C, A>(ring), ScaleOperations<Polynomial<C>> where A : Ring<C>, A : ScaleOperations<C> {
/** override fun scale(a: Polynomial<C>, value: Double): Polynomial<C> =
* Underlying ring of constants. Its operations on constants are inherited by local operations on constants. ring { Polynomial(a.coefficients.map { scale(it, value) }) }
*/
public val ring: A
/**
* Returns sum of the constant and the integer represented as a constant (member of underlying ring).
*
* The operation is equivalent to adding [other] copies of unit of underlying ring to [this].
*/
public override operator fun C.plus(other: Int): C = ring { addMultipliedByDoubling(this@plus, one, other) }
/**
* Returns difference between the constant and the integer represented as a constant (member of underlying ring).
*
* The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this].
*/
public override operator fun C.minus(other: Int): C = ring { addMultipliedByDoubling(this@minus, one, -other) }
/**
* Returns product of the constant and the integer represented as a constant (member of underlying ring).
*
* The operation is equivalent to sum of [other] copies of [this].
*/
public override operator fun C.times(other: Int): C = ring { multiplyByDoubling(this@times, other) }
/**
* Returns sum of the integer represented as a constant (member of underlying ring) and the constant.
*
* The operation is equivalent to adding [this] copies of unit of underlying ring to [other].
*/
public override operator fun Int.plus(other: C): C = ring { addMultipliedByDoubling(other, one, this@plus) }
/**
* Returns difference between the integer represented as a constant (member of underlying ring) and the constant.
*
* The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other].
*/
public override operator fun Int.minus(other: C): C = ring { addMultipliedByDoubling(-other, one, this@minus) }
/**
* Returns product of the integer represented as a constant (member of underlying ring) and the constant.
*
* The operation is equivalent to sum of [this] copies of [other].
*/
public override operator fun Int.times(other: C): C = ring { multiplyByDoubling(other, this@times) }
/**
* Returns negation of the constant.
*/
@JvmName("unaryMinusConstant")
public override operator fun C.unaryMinus(): C = ring { -this@unaryMinus }
/**
* Returns sum of the constants.
*/
@JvmName("plusConstantConstant")
public override operator fun C.plus(other: C): C = ring { this@plus + other }
/**
* Returns difference of the constants.
*/
@JvmName("minusConstantConstant")
public override operator fun C.minus(other: C): C = ring { this@minus - other }
/**
* Returns product of the constants.
*/
@JvmName("timesConstantConstant")
public override operator fun C.times(other: C): C = ring { this@times * other }
/**
* Raises [arg] to the integer power [exponent].
*/
@JvmName("powerConstant")
override fun power(arg: C, exponent: UInt): C = ring { power(arg, exponent) }
/**
* Instance of zero constant (zero of the underlying ring).
*/
public override val constantZero: C get() = ring.zero
/**
* Instance of unit constant (unit of the underlying ring).
*/
public override val constantOne: C get() = ring.one
}
/**
* Abstraction of ring of polynomials of type [P] of variables of type [V] and over ring of constants of type [C].
*
* @param C the type of constants. Polynomials have them as coefficients in their terms.
* @param V the type of variables. Polynomials have them in representations of terms.
* @param P the type of polynomials.
*/
@Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420
public interface MultivariatePolynomialSpace<C, V, P: Polynomial<C>>: PolynomialSpace<C, P> {
/**
* Returns sum of the variable represented as a monic monomial and the integer represented as a constant polynomial.
*/
@JvmName("plusVariableInt")
public operator fun V.plus(other: Int): P
/**
* Returns difference between the variable represented as a monic monomial and the integer represented as a constant polynomial.
*/
@JvmName("minusVariableInt")
public operator fun V.minus(other: Int): P
/**
* Returns product of the variable represented as a monic monomial and the integer represented as a constant polynomial.
*/
@JvmName("timesVariableInt")
public operator fun V.times(other: Int): P
/**
* Returns sum of the integer represented as a constant polynomial and the variable represented as a monic monomial.
*/
@JvmName("plusIntVariable")
public operator fun Int.plus(other: V): P
/**
* Returns difference between the integer represented as a constant polynomial and the variable represented as a monic monomial.
*/
@JvmName("minusIntVariable")
public operator fun Int.minus(other: V): P
/**
* Returns product of the integer represented as a constant polynomial and the variable represented as a monic monomial.
*/
@JvmName("timesIntVariable")
public operator fun Int.times(other: V): P
/**
* Returns sum of the variable represented as a monic monomial and the constant represented as a constant polynomial.
*/
@JvmName("plusVariableConstant")
public operator fun V.plus(other: C): P
/**
* Returns difference between the variable represented as a monic monomial and the constant represented as a constant polynomial.
*/
@JvmName("minusVariableConstant")
public operator fun V.minus(other: C): P
/**
* Returns product of the variable represented as a monic monomial and the constant represented as a constant polynomial.
*/
@JvmName("timesVariableConstant")
public operator fun V.times(other: C): P
/**
* Returns sum of the constant represented as a constant polynomial and the variable represented as a monic monomial.
*/
@JvmName("plusConstantVariable")
public operator fun C.plus(other: V): P
/**
* Returns difference between the constant represented as a constant polynomial and the variable represented as a monic monomial.
*/
@JvmName("minusConstantVariable")
public operator fun C.minus(other: V): P
/**
* Returns product of the constant represented as a constant polynomial and the variable represented as a monic monomial.
*/
@JvmName("timesConstantVariable")
public operator fun C.times(other: V): P
/**
* Represents the variable as a monic monomial.
*/
@JvmName("unaryPlusVariable")
public operator fun V.unaryPlus(): P
/**
* Returns negation of representation of the variable as a monic monomial.
*/
@JvmName("unaryMinusVariable")
public operator fun V.unaryMinus(): P
/**
* Returns sum of the variables represented as monic monomials.
*/
@JvmName("plusVariableVariable")
public operator fun V.plus(other: V): P
/**
* Returns difference between the variables represented as monic monomials.
*/
@JvmName("minusVariableVariable")
public operator fun V.minus(other: V): P
/**
* Returns product of the variables represented as monic monomials.
*/
@JvmName("timesVariableVariable")
public operator fun V.times(other: V): P
/**
* Represents the [variable] as a monic monomial.
*/
@JvmName("numberVariable")
public fun number(variable: V): P = +variable
/**
* Represents the variable as a monic monomial.
*/
@JvmName("asPolynomialVariable")
public fun V.asPolynomial(): P = number(this)
/**
* Returns sum of the variable represented as a monic monomial and the polynomial.
*/
@JvmName("plusVariablePolynomial")
public operator fun V.plus(other: P): P
/**
* Returns difference between the variable represented as a monic monomial and the polynomial.
*/
@JvmName("minusVariablePolynomial")
public operator fun V.minus(other: P): P
/**
* Returns product of the variable represented as a monic monomial and the polynomial.
*/
@JvmName("timesVariablePolynomial")
public operator fun V.times(other: P): P
/**
* Returns sum of the polynomial and the variable represented as a monic monomial.
*/
@JvmName("plusPolynomialVariable")
public operator fun P.plus(other: V): P
/**
* Returns difference between the polynomial and the variable represented as a monic monomial.
*/
@JvmName("minusPolynomialVariable")
public operator fun P.minus(other: V): P
/**
* Returns product of the polynomial and the variable represented as a monic monomial.
*/
@JvmName("timesPolynomialVariable")
public operator fun P.times(other: V): P
/**
* Map that associates variables (that appear in the polynomial in positive exponents) with their most exponents
* in which they are appeared in the polynomial.
*
* As consequence all values in the map are positive integers. Also, if the polynomial is constant, the map is empty.
* And keys of the map is the same as in [variables].
*/
public val P.degrees: Map<V, UInt>
/**
* Counts degree of the polynomial by the specified [variable].
*/
public fun P.degreeBy(variable: V): UInt = degrees.getOrElse(variable) { 0u }
/**
* Counts degree of the polynomial by the specified [variables].
*/
public fun P.degreeBy(variables: Collection<V>): UInt
/**
* Set of all variables that appear in the polynomial in positive exponents.
*/
public val P.variables: Set<V> get() = degrees.keys
/**
* Count of all variables that appear in the polynomial in positive exponents.
*/
public val P.countOfVariables: Int get() = variables.size
} }

View File

@ -9,101 +9,6 @@ import space.kscience.kmath.operations.*
// TODO: All of this should be moved to algebraic structures' place for utilities // TODO: All of this should be moved to algebraic structures' place for utilities
// FIXME: Move receiver to context receiver
/**
* Returns product of [arg] and integer [multiplier].
*
* @param arg the multiplicand.
* @param multiplier the integer multiplier.
* @return product of the multiplicand [arg] and the multiplier [multiplier].
* @author Gleb Minaev
*/
internal fun <C> Group<C>.multiplyByDoubling(arg: C, multiplier: Int): C =
if (multiplier >= 0) multiplyByDoubling(arg, multiplier.toUInt())
else multiplyByDoubling(-arg, (-multiplier).toUInt())
// FIXME: Move receiver to context receiver
/**
* Adds product of [arg] and [multiplier] to [base].
*
* @param base the augend.
* @param arg the multiplicand.
* @param multiplier the integer multiplier.
* @return sum of the augend [base] and product of the multiplicand [arg] and the multiplier [multiplier].
* @author Gleb Minaev
*/
internal fun <C> GroupOps<C>.addMultipliedByDoubling(base: C, arg: C, multiplier: Int): C =
if (multiplier >= 0) addMultipliedByDoubling(base, arg, multiplier.toUInt())
else addMultipliedByDoubling(base, -arg, (-multiplier).toUInt())
// FIXME: Move receiver to context receiver
/**
* Returns product of [arg] and integer [multiplier].
*
* This is implementation of variation of [exponentiation by squaring](https://en.wikipedia.org/wiki/Exponentiation_by_squaring)
*
* @param arg the multiplicand.
* @param multiplier the integer multiplier.
* @return product of the multiplicand [arg] and the multiplier [multiplier].
* @author Gleb Minaev
*/
internal tailrec fun <C> Group<C>.multiplyByDoubling(arg: C, multiplier: UInt): C =
when {
multiplier == 0u -> zero
multiplier == 1u -> arg
multiplier and 1u == 0u -> multiplyByDoubling(arg + arg, multiplier shr 1)
multiplier and 1u == 1u -> addMultipliedByDoubling(arg, arg + arg, multiplier shr 1)
else -> error("Error in multiplication group instant by unsigned integer: got reminder by division by 2 different from 0 and 1")
}
// FIXME: Move receiver to context receiver
/**
* Adds product of [arg] and [multiplier] to [base].
*
* This is implementation of variation of [exponentiation by squaring](https://en.wikipedia.org/wiki/Exponentiation_by_squaring)
*
* @param base the augend.
* @param arg the multiplicand.
* @param multiplier the integer multiplier.
* @return sum of the augend [base] and product of the multiplicand [arg] and the multiplier [multiplier].
* @author Gleb Minaev
*/
internal tailrec fun <C> GroupOps<C>.addMultipliedByDoubling(base: C, arg: C, multiplier: UInt): C =
when {
multiplier == 0u -> base
multiplier == 1u -> base + arg
multiplier and 1u == 0u -> addMultipliedByDoubling(base, arg + arg, multiplier shr 1)
multiplier and 1u == 1u -> addMultipliedByDoubling(base + arg, arg + arg, multiplier shr 1)
else -> error("Error in multiplication group instant by unsigned integer: got reminder by division by 2 different from 0 and 1")
}
// FIXME: Move receiver to context receiver
/**
* Raises [arg] to the integer power [exponent].
*
* @param arg the base of the power.
* @param exponent the exponent of the power.
* @return [arg] raised to the power [exponent].
* @author Gleb Minaev
*/
internal fun <C> Field<C>.exponentiateBySquaring(arg: C, exponent: Int): C =
if (exponent >= 0) exponentiateBySquaring(arg, exponent.toUInt())
else exponentiateBySquaring(one / arg, (-exponent).toUInt())
// FIXME: Move receiver to context receiver
/**
* Multiplies [base] and [arg] raised to the integer power [exponent].
*
* @param base the multiplicand.
* @param arg the base of the power.
* @param exponent the exponent of the power.
* @return product of [base] and [arg] raised to the power [exponent].
* @author Gleb Minaev
*/
internal fun <C> Field<C>.multiplyExponentiatedBySquaring(base: C, arg: C, exponent: Int): C =
if (exponent >= 0) multiplyExponentiatedBySquaring(base, arg, exponent.toUInt())
else multiplyExponentiatedBySquaring(base, one / arg, (-exponent).toUInt())
// FIXME: Move receiver to context receiver // FIXME: Move receiver to context receiver
/** /**
* Raises [arg] to the integer power [exponent]. * Raises [arg] to the integer power [exponent].

View File

@ -1,92 +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.Ring
/**
* Constructs a [ListPolynomial] instance with provided [coefficients]. The collection of coefficients will be reversed
* if [reverse] parameter is true.
*/
@Suppress("FunctionName")
public fun <C> ListPolynomial(coefficients: List<C>, reverse: Boolean = false): ListPolynomial<C> =
ListPolynomial(with(coefficients) { if (reverse) reversed() else this })
/**
* Constructs a [ListPolynomial] instance with provided [coefficients]. The collection of coefficients will be reversed
* if [reverse] parameter is true.
*/
@Suppress("FunctionName")
public fun <C> ListPolynomial(vararg coefficients: C, reverse: Boolean = false): ListPolynomial<C> =
ListPolynomial(with(coefficients) { if (reverse) reversed() else toList() })
/**
* Represents [this] constant as a [ListPolynomial].
*/
public fun <C> C.asListPolynomial() : ListPolynomial<C> = ListPolynomial(listOf(this))
// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available
/**
* Constructs [ListRationalFunction] instance with numerator and denominator constructed with provided
* [numeratorCoefficients] and [denominatorCoefficients]. The both collections of coefficients will be reversed if
* [reverse] parameter is true.
*/
@Suppress("FunctionName")
public fun <C> ListRationalFunction(numeratorCoefficients: List<C>, denominatorCoefficients: List<C>, reverse: Boolean = false): ListRationalFunction<C> =
ListRationalFunction<C>(
ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ),
ListPolynomial( with(denominatorCoefficients) { if (reverse) reversed() else this } )
)
/**
* Constructs [ListRationalFunction] instance with provided [numerator] and unit denominator.
*/
@Suppress("FunctionName")
public fun <C, A: Ring<C>> A.ListRationalFunction(numerator: ListPolynomial<C>): ListRationalFunction<C> =
ListRationalFunction<C>(numerator, ListPolynomial(listOf(one)))
/**
* Constructs [ListRationalFunction] instance with provided [numerator] and unit denominator.
*/
@Suppress("FunctionName")
public fun <C, A: Ring<C>> ListRationalFunctionSpace<C, A>.ListRationalFunction(numerator: ListPolynomial<C>): ListRationalFunction<C> =
ListRationalFunction<C>(numerator, polynomialOne)
/**
* Constructs [ListRationalFunction] instance with numerator constructed with provided [numeratorCoefficients] and unit
* denominator. The collection of numerator coefficients will be reversed if [reverse] parameter is true.
*/
@Suppress("FunctionName")
public fun <C, A: Ring<C>> A.ListRationalFunction(numeratorCoefficients: List<C>, reverse: Boolean = false): ListRationalFunction<C> =
ListRationalFunction<C>(
ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ),
ListPolynomial(listOf(one))
)
/**
* Constructs [ListRationalFunction] instance with numerator constructed with provided [numeratorCoefficients] and unit
* denominator. The collection of numerator coefficients will be reversed if [reverse] parameter is true.
*/
@Suppress("FunctionName")
public fun <C, A: Ring<C>> ListRationalFunctionSpace<C, A>.ListRationalFunction(numeratorCoefficients: List<C>, reverse: Boolean = false): ListRationalFunction<C> =
ListRationalFunction<C>(
ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ),
polynomialOne
)
/**
* Represents [this] constant as a rational function.
*/ // FIXME: When context receivers will be ready, delete this function and uncomment the following two
public fun <C, A: Ring<C>> C.asListRationalFunction(ring: A) : ListRationalFunction<C> = ring.ListRationalFunction(asListPolynomial())
///**
// * Represents [this] constant as a rational function.
// */
//context(A)
//public fun <C, A: Ring<C>> C.asListRationalFunction() : ListRationalFunction<C> = ListRationalFunction(asListPolynomial())
///**
// * Represents [this] constant as a rational function.
// */
//context(ListRationalFunctionSpace<C, A>)
//public fun <C, A: Ring<C>> C.asListRationalFunction() : ListRationalFunction<C> = ListRationalFunction(asListPolynomial())

View File

@ -1,255 +0,0 @@
/*
* Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.functions
import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.operations.*
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
import kotlin.math.max
import kotlin.math.pow
/**
* Creates a [ListPolynomialSpace] over a received ring.
*/
public inline val <C, A : Ring<C>> A.listPolynomialSpace: ListPolynomialSpace<C, A>
get() = ListPolynomialSpace(this)
/**
* Creates a [ListPolynomialSpace]'s scope over a received ring.
*/ // TODO: When context will be ready move [ListPolynomialSpace] and add [A] to context receivers of [block]
public inline fun <C, A : Ring<C>, R> A.listPolynomialSpace(block: ListPolynomialSpace<C, A>.() -> R): R {
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
return ListPolynomialSpace(this).block()
}
/**
* Creates a [ScalableListPolynomialSpace] over a received scalable ring.
*/
public inline val <C, A> A.scalableListPolynomialSpace: ScalableListPolynomialSpace<C, A> where A : Ring<C>, A : ScaleOperations<C>
get() = ScalableListPolynomialSpace(this)
/**
* Creates a [ScalableListPolynomialSpace]'s scope over a received scalable ring.
*/ // TODO: When context will be ready move [ListPolynomialSpace] and add [A] to context receivers of [block]
public inline fun <C, A, R> A.scalableListPolynomialSpace(block: ScalableListPolynomialSpace<C, A>.() -> R): R where A : Ring<C>, A : ScaleOperations<C> {
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
return ScalableListPolynomialSpace(this).block()
}
/**
* Creates a [ListRationalFunctionSpace] over a received ring.
*/
public inline val <C, A : Ring<C>> A.listRationalFunctionSpace: ListRationalFunctionSpace<C, A>
get() = ListRationalFunctionSpace(this)
/**
* Creates a [ListRationalFunctionSpace]'s scope over a received ring.
*/ // TODO: When context will be ready move [ListRationalFunctionSpace] and add [A] to context receivers of [block]
public inline fun <C, A : Ring<C>, R> A.listRationalFunctionSpace(block: ListRationalFunctionSpace<C, A>.() -> R): R {
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
return ListRationalFunctionSpace(this).block()
}
/**
* Evaluates value of [this] Double polynomial on provided Double argument.
*/
public fun ListPolynomial<Double>.substitute(arg: Double): Double =
coefficients.reduceIndexedOrNull { index, acc, c ->
acc + c * arg.pow(index)
} ?: .0
/**
* Evaluates value of [this] polynomial on provided argument.
*
* It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method).
*/
public fun <C> ListPolynomial<C>.substitute(ring: Ring<C>, arg: C): C = ring {
if (coefficients.isEmpty()) return zero
var result: C = coefficients.last()
for (j in coefficients.size - 2 downTo 0) {
result = (arg * result) + coefficients[j]
}
return result
}
/**
* Substitutes provided polynomial [arg] into [this] polynomial.
*
* It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method).
*/ // TODO: To optimize boxing
public fun <C> ListPolynomial<C>.substitute(ring: Ring<C>, arg: ListPolynomial<C>) : ListPolynomial<C> =
ring.listPolynomialSpace {
if (coefficients.isEmpty()) return zero
var result: ListPolynomial<C> = coefficients.last().asPolynomial()
for (j in coefficients.size - 2 downTo 0) {
result = (arg * result) + coefficients[j]
}
return result
}
/**
* Substitutes provided rational function [arg] into [this] polynomial.
*
* It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method).
*/ // TODO: To optimize boxing
public fun <C> ListPolynomial<C>.substitute(ring: Ring<C>, arg: ListRationalFunction<C>) : ListRationalFunction<C> =
ring.listRationalFunctionSpace {
if (coefficients.isEmpty()) return zero
var result: ListRationalFunction<C> = coefficients.last().asRationalFunction()
for (j in coefficients.size - 2 downTo 0) {
result = (arg * result) + coefficients[j]
}
return result
}
/**
* Evaluates value of [this] Double rational function in provided Double argument.
*/
public fun ListRationalFunction<Double>.substitute(arg: Double): Double =
numerator.substitute(arg) / denominator.substitute(arg)
/**
* Evaluates value of [this] polynomial for provided argument.
*
* It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method).
*/
public fun <C> ListRationalFunction<C>.substitute(ring: Field<C>, arg: C): C = ring {
numerator.substitute(ring, arg) / denominator.substitute(ring, arg)
}
/**
* Substitutes provided polynomial [arg] into [this] rational function.
*/ // TODO: To optimize boxing
public fun <C> ListRationalFunction<C>.substitute(ring: Ring<C>, arg: ListPolynomial<C>) : ListRationalFunction<C> =
ring.listRationalFunctionSpace {
numerator.substitute(ring, arg) / denominator.substitute(ring, arg)
}
/**
* Substitutes provided rational function [arg] into [this] rational function.
*/ // TODO: To optimize boxing
public fun <C> ListRationalFunction<C>.substitute(ring: Ring<C>, arg: ListRationalFunction<C>) : ListRationalFunction<C> =
ring.listRationalFunctionSpace {
numerator.substitute(ring, arg) / denominator.substitute(ring, arg)
}
/**
* Represent [this] polynomial as a regular context-less function.
*/
public fun <C, A : Ring<C>> ListPolynomial<C>.asFunctionOver(ring: A): (C) -> C = { substitute(ring, it) }
/**
* Represent [this] polynomial as a regular context-less function.
*/
public fun <C, A : Ring<C>> ListPolynomial<C>.asFunctionOfConstantOver(ring: A): (C) -> C = { substitute(ring, it) }
/**
* Represent [this] polynomial as a regular context-less function.
*/
public fun <C, A : Ring<C>> ListPolynomial<C>.asFunctionOfPolynomialOver(ring: A): (ListPolynomial<C>) -> ListPolynomial<C> = { substitute(ring, it) }
/**
* Represent [this] polynomial as a regular context-less function.
*/
public fun <C, A : Ring<C>> ListPolynomial<C>.asFunctionOfRationalFunctionOver(ring: A): (ListRationalFunction<C>) -> ListRationalFunction<C> = { substitute(ring, it) }
/**
* Represent [this] rational function as a regular context-less function.
*/
public fun <C, A : Field<C>> ListRationalFunction<C>.asFunctionOver(ring: A): (C) -> C = { substitute(ring, it) }
/**
* Represent [this] rational function as a regular context-less function.
*/
public fun <C, A : Field<C>> ListRationalFunction<C>.asFunctionOfConstantOver(ring: A): (C) -> C = { substitute(ring, it) }
/**
* Represent [this] rational function as a regular context-less function.
*/
public fun <C, A : Ring<C>> ListRationalFunction<C>.asFunctionOfPolynomialOver(ring: A): (ListPolynomial<C>) -> ListRationalFunction<C> = { substitute(ring, it) }
/**
* Represent [this] rational function as a regular context-less function.
*/
public fun <C, A : Ring<C>> ListRationalFunction<C>.asFunctionOfRationalFunctionOver(ring: A): (ListRationalFunction<C>) -> ListRationalFunction<C> = { substitute(ring, it) }
/**
* Returns algebraic derivative of received polynomial.
*/
@UnstableKMathAPI
public fun <C, A> ListPolynomial<C>.derivative(
ring: A,
): ListPolynomial<C> where A : Ring<C>, A : NumericAlgebra<C> = ring {
ListPolynomial(
buildList(max(0, coefficients.size - 1)) {
for (deg in 1 .. coefficients.lastIndex) add(number(deg) * coefficients[deg])
}
)
}
/**
* Returns algebraic derivative of received polynomial of specified [order]. The [order] should be non-negative integer.
*/
@UnstableKMathAPI
public fun <C, A> ListPolynomial<C>.nthDerivative(
ring: A,
order: Int,
): ListPolynomial<C> where A : Ring<C>, A : NumericAlgebra<C> = ring {
require(order >= 0) { "Order of derivative must be non-negative" }
ListPolynomial(
buildList(max(0, coefficients.size - order)) {
for (deg in order.. coefficients.lastIndex)
add((deg - order + 1 .. deg).fold(coefficients[deg]) { acc, d -> acc * number(d) })
}
)
}
/**
* Returns algebraic antiderivative of received polynomial.
*/
@UnstableKMathAPI
public fun <C, A> ListPolynomial<C>.antiderivative(
ring: A,
): ListPolynomial<C> where A : Field<C>, A : NumericAlgebra<C> = ring {
ListPolynomial(
buildList(coefficients.size + 1) {
add(zero)
coefficients.mapIndexedTo(this) { index, t -> t / number(index + 1) }
}
)
}
/**
* Returns algebraic antiderivative of received polynomial of specified [order]. The [order] should be non-negative integer.
*/
@UnstableKMathAPI
public fun <C, A> ListPolynomial<C>.nthAntiderivative(
ring: A,
order: Int,
): ListPolynomial<C> where A : Field<C>, A : NumericAlgebra<C> = ring {
require(order >= 0) { "Order of antiderivative must be non-negative" }
ListPolynomial(
buildList(coefficients.size + order) {
repeat(order) { add(zero) }
coefficients.mapIndexedTo(this) { index, c -> (1..order).fold(c) { acc, i -> acc / number(index + i) } }
}
)
}
/**
* Computes a definite integral of [this] polynomial in the specified [range].
*/
@UnstableKMathAPI
public fun <C : Comparable<C>> ListPolynomial<C>.integrate(
ring: Field<C>,
range: ClosedRange<C>,
): C = ring {
val antiderivative = antiderivative(ring)
antiderivative.substitute(ring, range.endInclusive) - antiderivative.substitute(ring, range.start)
}

View File

@ -1,22 +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
/**
* Marks declarations that give access to internal entities of polynomials delicate structure. Thus, it allows to
* optimize performance a bit by skipping standard steps, but such skips may cause critical errors if something is
* implemented badly. Make sure you fully read and understand documentation and don't break internal contracts.
*/
@RequiresOptIn(
message = "This declaration gives access to delicate internal structure of polynomials. " +
"It allows to optimize performance by skipping unnecessary arguments check. " +
"But at the same time makes it easy to make a mistake " +
"that will cause wrong computation result or even runtime error. " +
"Make sure you fully read and understand documentation.",
level = RequiresOptIn.Level.ERROR
)
public annotation class DelicatePolynomialAPI

View File

@ -0,0 +1,28 @@
/*
* 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
/**
* Constructs a [Polynomial] instance with provided [coefficients]. The collection of coefficients will be reversed
* if [reverse] parameter is true.
*/
@Suppress("FunctionName")
public fun <C> ListPolynomial(coefficients: List<C>, reverse: Boolean = false): Polynomial<C> =
Polynomial(with(coefficients) { if (reverse) reversed() else this })
/**
* Constructs a [Polynomial] instance with provided [coefficients]. The collection of coefficients will be reversed
* if [reverse] parameter is true.
*/
@Suppress("FunctionName")
public fun <C> ListPolynomial(vararg coefficients: C, reverse: Boolean = false): Polynomial<C> =
Polynomial(with(coefficients) { if (reverse) reversed() else toList() })
/**
* Represents [this] constant as a [Polynomial].
*/
public fun <C> C.asListPolynomial() : Polynomial<C> = Polynomial(listOf(this))

View File

@ -0,0 +1,111 @@
/*
* Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.functions
import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.operations.*
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
import kotlin.math.max
import kotlin.math.pow
/**
* Creates a [ListPolynomialSpace] over a received ring.
*/
public inline val <C, A : Ring<C>> A.listPolynomialSpace: ListPolynomialSpace<C, A>
get() = ListPolynomialSpace(this)
/**
* Creates a [ListPolynomialSpace]'s scope over a received ring.
*/ // TODO: When context will be ready move [ListPolynomialSpace] and add [A] to context receivers of [block]
public inline fun <C, A : Ring<C>, R> A.listPolynomialSpace(block: ListPolynomialSpace<C, A>.() -> R): R {
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
return ListPolynomialSpace(this).block()
}
/**
* Creates a [ScalableListPolynomialSpace] over a received scalable ring.
*/
public inline val <C, A> A.scalableListPolynomialSpace: ScalableListPolynomialSpace<C, A> where A : Ring<C>, A : ScaleOperations<C>
get() = ScalableListPolynomialSpace(this)
/**
* Creates a [ScalableListPolynomialSpace]'s scope over a received scalable ring.
*/ // TODO: When context will be ready move [ListPolynomialSpace] and add [A] to context receivers of [block]
public inline fun <C, A, R> A.scalableListPolynomialSpace(block: ScalableListPolynomialSpace<C, A>.() -> R): R where A : Ring<C>, A : ScaleOperations<C> {
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
return ScalableListPolynomialSpace(this).block()
}
/**
* Evaluates value of [this] Double polynomial on provided Double argument.
*/
public fun Polynomial<Double>.substitute(arg: Double): Double =
coefficients.reduceIndexedOrNull { index, acc, c ->
acc + c * arg.pow(index)
} ?: .0
/**
* Evaluates value of [this] polynomial on provided argument.
*
* It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method).
*/
public fun <C> Polynomial<C>.substitute(ring: Ring<C>, arg: C): C = ring {
if (coefficients.isEmpty()) return zero
var result: C = coefficients.last()
for (j in coefficients.size - 2 downTo 0) {
result = (arg * result) + coefficients[j]
}
return result
}
/**
* Represent [this] polynomial as a regular context-less function.
*/
public fun <C, A : Ring<C>> Polynomial<C>.asFunctionOver(ring: A): (C) -> C = { substitute(ring, it) }
/**
* Returns algebraic derivative of received polynomial.
*/
@UnstableKMathAPI
public fun <C, A> Polynomial<C>.derivative(
ring: A,
): Polynomial<C> where A : Ring<C>, A : NumericAlgebra<C> = ring {
Polynomial(
buildList(max(0, coefficients.size - 1)) {
for (deg in 1 .. coefficients.lastIndex) add(number(deg) * coefficients[deg])
}
)
}
/**
* Returns algebraic antiderivative of received polynomial.
*/
@UnstableKMathAPI
public fun <C, A> Polynomial<C>.antiderivative(
ring: A,
): Polynomial<C> where A : Field<C>, A : NumericAlgebra<C> = ring {
Polynomial(
buildList(coefficients.size + 1) {
add(zero)
coefficients.mapIndexedTo(this) { index, t -> t / number(index + 1) }
}
)
}
/**
* Computes a definite integral of [this] polynomial in the specified [range].
*/
@UnstableKMathAPI
public fun <C : Comparable<C>> Polynomial<C>.integrate(
ring: Field<C>,
range: ClosedRange<C>,
): C {
val antiderivative = antiderivative(ring)
return ring { antiderivative.substitute(ring, range.endInclusive) - antiderivative.substitute(ring, range.start) }
}

View File

@ -26,286 +26,6 @@ object ExprRing : Field<Expr> {
} }
class AlgebraicStubTest { class AlgebraicStubTest {
@Test
fun test_addMultipliedBySquaring_for_UInt() {
ExprRing {
assertEquals(
"57",
addMultipliedByDoubling(Expr("57"), Expr("179"), 0u).expr,
"tried addMultipliedBySquaring(57, 179, 0u)"
)
assertEquals(
"(57 + 179)",
addMultipliedByDoubling(Expr("57"), Expr("179"), 1u).expr,
"tried addMultipliedBySquaring(57, 179, 1u)"
)
assertEquals(
"(57 + (179 + 179))",
addMultipliedByDoubling(Expr("57"), Expr("179"), 2u).expr,
"tried addMultipliedBySquaring(57, 179, 2u)"
)
assertEquals(
"((57 + 179) + (179 + 179))",
addMultipliedByDoubling(Expr("57"), Expr("179"), 3u).expr,
"tried addMultipliedBySquaring(57, 179, 3u)"
)
assertEquals(
"(57 + ((179 + 179) + (179 + 179)))",
addMultipliedByDoubling(Expr("57"), Expr("179"), 4u).expr,
"tried addMultipliedBySquaring(57, 179, 4u)"
)
assertEquals(
"((57 + 179) + ((179 + 179) + (179 + 179)))",
addMultipliedByDoubling(Expr("57"), Expr("179"), 5u).expr,
"tried addMultipliedBySquaring(57, 179, 5u)"
)
assertEquals(
"((57 + (179 + 179)) + ((179 + 179) + (179 + 179)))",
addMultipliedByDoubling(Expr("57"), Expr("179"), 6u).expr,
"tried addMultipliedBySquaring(57, 179, 6u)"
)
assertEquals(
"(((57 + 179) + (179 + 179)) + ((179 + 179) + (179 + 179)))",
addMultipliedByDoubling(Expr("57"), Expr("179"), 7u).expr,
"tried addMultipliedBySquaring(57, 179, 7u)"
)
assertEquals(
"(57 + (((179 + 179) + (179 + 179)) + ((179 + 179) + (179 + 179))))",
addMultipliedByDoubling(Expr("57"), Expr("179"), 8u).expr,
"tried addMultipliedBySquaring(57, 179, 8u)"
)
}
}
@Test
fun test_multiplyBySquaring_for_UInt() {
ExprRing {
assertEquals(
"0",
multiplyByDoubling(Expr("57"), 0u).expr,
"tried multiplyBySquaring(57, 0u)"
)
assertEquals(
"57",
multiplyByDoubling(Expr("57"), 1u).expr,
"tried multiplyBySquaring(57, 1u)"
)
assertEquals(
"(57 + 57)",
multiplyByDoubling(Expr("57"), 2u).expr,
"tried multiplyBySquaring(57, 2u)"
)
assertEquals(
"(57 + (57 + 57))",
multiplyByDoubling(Expr("57"), 3u).expr,
"tried multiplyBySquaring(57, 3u)"
)
assertEquals(
"((57 + 57) + (57 + 57))",
multiplyByDoubling(Expr("57"), 4u).expr,
"tried multiplyBySquaring(57, 4u)"
)
assertEquals(
"(57 + ((57 + 57) + (57 + 57)))",
multiplyByDoubling(Expr("57"), 5u).expr,
"tried multiplyBySquaring(57, 5u)"
)
assertEquals(
"((57 + 57) + ((57 + 57) + (57 + 57)))",
multiplyByDoubling(Expr("57"), 6u).expr,
"tried multiplyBySquaring(57, 6u)"
)
assertEquals(
"((57 + (57 + 57)) + ((57 + 57) + (57 + 57)))",
multiplyByDoubling(Expr("57"), 7u).expr,
"tried multiplyBySquaring(57, 7u)"
)
assertEquals(
"(((57 + 57) + (57 + 57)) + ((57 + 57) + (57 + 57)))",
multiplyByDoubling(Expr("57"), 8u).expr,
"tried multiplyBySquaring(57, 8u)"
)
}
}
@Test
fun test_addMultipliedBySquaring_for_Int() {
ExprRing {
assertEquals(
"57",
addMultipliedByDoubling(Expr("57"), Expr("179"), 0).expr,
"tried addMultipliedBySquaring(57, 179, 0)"
)
assertEquals(
"(57 + 179)",
addMultipliedByDoubling(Expr("57"), Expr("179"), 1).expr,
"tried addMultipliedBySquaring(57, 179, 1)"
)
assertEquals(
"(57 + -179)",
addMultipliedByDoubling(Expr("57"), Expr("179"), -1).expr,
"tried addMultipliedBySquaring(57, 179, -1)"
)
assertEquals(
"(57 + (179 + 179))",
addMultipliedByDoubling(Expr("57"), Expr("179"), 2).expr,
"tried addMultipliedBySquaring(57, 179, 2)"
)
assertEquals(
"(57 + (-179 + -179))",
addMultipliedByDoubling(Expr("57"), Expr("179"), -2).expr,
"tried addMultipliedBySquaring(57, 179, -2)"
)
assertEquals(
"((57 + 179) + (179 + 179))",
addMultipliedByDoubling(Expr("57"), Expr("179"), 3).expr,
"tried addMultipliedBySquaring(57, 179, 3)"
)
assertEquals(
"((57 + -179) + (-179 + -179))",
addMultipliedByDoubling(Expr("57"), Expr("179"), -3).expr,
"tried addMultipliedBySquaring(57, 179, -3)"
)
assertEquals(
"(57 + ((179 + 179) + (179 + 179)))",
addMultipliedByDoubling(Expr("57"), Expr("179"), 4).expr,
"tried addMultipliedBySquaring(57, 179, 4)"
)
assertEquals(
"(57 + ((-179 + -179) + (-179 + -179)))",
addMultipliedByDoubling(Expr("57"), Expr("179"), -4).expr,
"tried addMultipliedBySquaring(57, 179, -4)"
)
assertEquals(
"((57 + 179) + ((179 + 179) + (179 + 179)))",
addMultipliedByDoubling(Expr("57"), Expr("179"), 5).expr,
"tried addMultipliedBySquaring(57, 179, 5)"
)
assertEquals(
"((57 + -179) + ((-179 + -179) + (-179 + -179)))",
addMultipliedByDoubling(Expr("57"), Expr("179"), -5).expr,
"tried addMultipliedBySquaring(57, 179, -5)"
)
assertEquals(
"((57 + (179 + 179)) + ((179 + 179) + (179 + 179)))",
addMultipliedByDoubling(Expr("57"), Expr("179"), 6).expr,
"tried addMultipliedBySquaring(57, 179, 6)"
)
assertEquals(
"((57 + (-179 + -179)) + ((-179 + -179) + (-179 + -179)))",
addMultipliedByDoubling(Expr("57"), Expr("179"), -6).expr,
"tried addMultipliedBySquaring(57, 179, -6)"
)
assertEquals(
"(((57 + 179) + (179 + 179)) + ((179 + 179) + (179 + 179)))",
addMultipliedByDoubling(Expr("57"), Expr("179"), 7).expr,
"tried addMultipliedBySquaring(57, 179, 7)"
)
assertEquals(
"(((57 + -179) + (-179 + -179)) + ((-179 + -179) + (-179 + -179)))",
addMultipliedByDoubling(Expr("57"), Expr("179"), -7).expr,
"tried addMultipliedBySquaring(57, 179, -7)"
)
assertEquals(
"(57 + (((179 + 179) + (179 + 179)) + ((179 + 179) + (179 + 179))))",
addMultipliedByDoubling(Expr("57"), Expr("179"), 8).expr,
"tried addMultipliedBySquaring(57, 179, 8)"
)
assertEquals(
"(57 + (((-179 + -179) + (-179 + -179)) + ((-179 + -179) + (-179 + -179))))",
addMultipliedByDoubling(Expr("57"), Expr("179"), -8).expr,
"tried addMultipliedBySquaring(57, 179, -8)"
)
}
}
@Test
fun test_multiplyBySquaring_for_Int() {
ExprRing {
assertEquals(
"0",
multiplyByDoubling(Expr("57"), 0).expr,
"tried multiplyBySquaring(57, 0)"
)
assertEquals(
"57",
multiplyByDoubling(Expr("57"), 1).expr,
"tried multiplyBySquaring(57, 1)"
)
assertEquals(
"-57",
multiplyByDoubling(Expr("57"), -1).expr,
"tried multiplyBySquaring(57, -1)"
)
assertEquals(
"(57 + 57)",
multiplyByDoubling(Expr("57"), 2).expr,
"tried multiplyBySquaring(57, 2)"
)
assertEquals(
"(-57 + -57)",
multiplyByDoubling(Expr("57"), -2).expr,
"tried multiplyBySquaring(57, -2)"
)
assertEquals(
"(57 + (57 + 57))",
multiplyByDoubling(Expr("57"), 3).expr,
"tried multiplyBySquaring(57, 3)"
)
assertEquals(
"(-57 + (-57 + -57))",
multiplyByDoubling(Expr("57"), -3).expr,
"tried multiplyBySquaring(57, -3)"
)
assertEquals(
"((57 + 57) + (57 + 57))",
multiplyByDoubling(Expr("57"), 4).expr,
"tried multiplyBySquaring(57, 4)"
)
assertEquals(
"((-57 + -57) + (-57 + -57))",
multiplyByDoubling(Expr("57"), -4).expr,
"tried multiplyBySquaring(57, -4)"
)
assertEquals(
"(57 + ((57 + 57) + (57 + 57)))",
multiplyByDoubling(Expr("57"), 5).expr,
"tried multiplyBySquaring(57, 5)"
)
assertEquals(
"(-57 + ((-57 + -57) + (-57 + -57)))",
multiplyByDoubling(Expr("57"), -5).expr,
"tried multiplyBySquaring(57, -5)"
)
assertEquals(
"((57 + 57) + ((57 + 57) + (57 + 57)))",
multiplyByDoubling(Expr("57"), 6).expr,
"tried multiplyBySquaring(57, 6)"
)
assertEquals(
"((-57 + -57) + ((-57 + -57) + (-57 + -57)))",
multiplyByDoubling(Expr("57"), -6).expr,
"tried multiplyBySquaring(57, -6)"
)
assertEquals(
"((57 + (57 + 57)) + ((57 + 57) + (57 + 57)))",
multiplyByDoubling(Expr("57"), 7).expr,
"tried multiplyBySquaring(57, 7)"
)
assertEquals(
"((-57 + (-57 + -57)) + ((-57 + -57) + (-57 + -57)))",
multiplyByDoubling(Expr("57"), -7).expr,
"tried multiplyBySquaring(57, -7)"
)
assertEquals(
"(((57 + 57) + (57 + 57)) + ((57 + 57) + (57 + 57)))",
multiplyByDoubling(Expr("57"), 8).expr,
"tried multiplyBySquaring(57, 8)"
)
assertEquals(
"(((-57 + -57) + (-57 + -57)) + ((-57 + -57) + (-57 + -57)))",
multiplyByDoubling(Expr("57"), -8).expr,
"tried multiplyBySquaring(57, -8)"
)
}
}
@Test @Test
fun test_multiplyExponentiationBySquaring_for_UInt() { fun test_multiplyExponentiationBySquaring_for_UInt() {
ExprRing { ExprRing {
@ -406,184 +126,4 @@ class AlgebraicStubTest {
) )
} }
} }
@Test
fun test_multiplyExponentiationBySquaring_for_Int() {
ExprRing {
assertEquals(
"57",
multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 0).expr,
"tried multiplyExponentiationBySquaring(57, 179, 0)"
)
assertEquals(
"(57 * 179)",
multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 1).expr,
"tried multiplyExponentiationBySquaring(57, 179, 1)"
)
assertEquals(
"(57 * (1 / 179))",
multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -1).expr,
"tried multiplyExponentiationBySquaring(57, 179, -1)"
)
assertEquals(
"(57 * (179 * 179))",
multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 2).expr,
"tried multiplyExponentiationBySquaring(57, 179, 2)"
)
assertEquals(
"(57 * ((1 / 179) * (1 / 179)))",
multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -2).expr,
"tried multiplyExponentiationBySquaring(57, 179, -2)"
)
assertEquals(
"((57 * 179) * (179 * 179))",
multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 3).expr,
"tried multiplyExponentiationBySquaring(57, 179, 3)"
)
assertEquals(
"((57 * (1 / 179)) * ((1 / 179) * (1 / 179)))",
multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -3).expr,
"tried multiplyExponentiationBySquaring(57, 179, -3)"
)
assertEquals(
"(57 * ((179 * 179) * (179 * 179)))",
multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 4).expr,
"tried multiplyExponentiationBySquaring(57, 179, 4)"
)
assertEquals(
"(57 * (((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179))))",
multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -4).expr,
"tried multiplyExponentiationBySquaring(57, 179, -4)"
)
assertEquals(
"((57 * 179) * ((179 * 179) * (179 * 179)))",
multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 5).expr,
"tried multiplyExponentiationBySquaring(57, 179, 5)"
)
assertEquals(
"((57 * (1 / 179)) * (((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179))))",
multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -5).expr,
"tried multiplyExponentiationBySquaring(57, 179, -5)"
)
assertEquals(
"((57 * (179 * 179)) * ((179 * 179) * (179 * 179)))",
multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 6).expr,
"tried multiplyExponentiationBySquaring(57, 179, 6)"
)
assertEquals(
"((57 * ((1 / 179) * (1 / 179))) * (((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179))))",
multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -6).expr,
"tried multiplyExponentiationBySquaring(57, 179, -6)"
)
assertEquals(
"(((57 * 179) * (179 * 179)) * ((179 * 179) * (179 * 179)))",
multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 7).expr,
"tried multiplyExponentiationBySquaring(57, 179, 7)"
)
assertEquals(
"(((57 * (1 / 179)) * ((1 / 179) * (1 / 179))) * (((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179))))",
multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -7).expr,
"tried multiplyExponentiationBySquaring(57, 179, -7)"
)
assertEquals(
"(57 * (((179 * 179) * (179 * 179)) * ((179 * 179) * (179 * 179))))",
multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 8).expr,
"tried multiplyExponentiationBySquaring(57, 179, 8)"
)
assertEquals(
"(57 * ((((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179))) * (((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179)))))",
multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -8).expr,
"tried multiplyExponentiationBySquaring(57, 179, -8)"
)
}
}
@Test
fun test_exponentiationBySquaring_for_Int() {
ExprRing {
assertEquals(
"0",
exponentiateBySquaring(Expr("57"), 0).expr,
"tried exponentiationBySquaring(57, 0)"
)
assertEquals(
"57",
exponentiateBySquaring(Expr("57"), 1).expr,
"tried exponentiationBySquaring(57, 1)"
)
assertEquals(
"(1 / 57)",
exponentiateBySquaring(Expr("57"), -1).expr,
"tried exponentiationBySquaring(57, -1)"
)
assertEquals(
"(57 * 57)",
exponentiateBySquaring(Expr("57"), 2).expr,
"tried exponentiationBySquaring(57, 2)"
)
assertEquals(
"((1 / 57) * (1 / 57))",
exponentiateBySquaring(Expr("57"), -2).expr,
"tried exponentiationBySquaring(57, -2)"
)
assertEquals(
"(57 * (57 * 57))",
exponentiateBySquaring(Expr("57"), 3).expr,
"tried exponentiationBySquaring(57, 3)"
)
assertEquals(
"((1 / 57) * ((1 / 57) * (1 / 57)))",
exponentiateBySquaring(Expr("57"), -3).expr,
"tried exponentiationBySquaring(57, -3)"
)
assertEquals(
"((57 * 57) * (57 * 57))",
exponentiateBySquaring(Expr("57"), 4).expr,
"tried exponentiationBySquaring(57, 4)"
)
assertEquals(
"(((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57)))",
exponentiateBySquaring(Expr("57"), -4).expr,
"tried exponentiationBySquaring(57, -4)"
)
assertEquals(
"(57 * ((57 * 57) * (57 * 57)))",
exponentiateBySquaring(Expr("57"), 5).expr,
"tried exponentiationBySquaring(57, 5)"
)
assertEquals(
"((1 / 57) * (((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57))))",
exponentiateBySquaring(Expr("57"), -5).expr,
"tried exponentiationBySquaring(57, -5)"
)
assertEquals(
"((57 * 57) * ((57 * 57) * (57 * 57)))",
exponentiateBySquaring(Expr("57"), 6).expr,
"tried exponentiationBySquaring(57, 6)"
)
assertEquals(
"(((1 / 57) * (1 / 57)) * (((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57))))",
exponentiateBySquaring(Expr("57"), -6).expr,
"tried exponentiationBySquaring(57, -6)"
)
assertEquals(
"((57 * (57 * 57)) * ((57 * 57) * (57 * 57)))",
exponentiateBySquaring(Expr("57"), 7).expr,
"tried exponentiationBySquaring(57, 7)"
)
assertEquals(
"(((1 / 57) * ((1 / 57) * (1 / 57))) * (((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57))))",
exponentiateBySquaring(Expr("57"), -7).expr,
"tried exponentiationBySquaring(57, -7)"
)
assertEquals(
"(((57 * 57) * (57 * 57)) * ((57 * 57) * (57 * 57)))",
exponentiateBySquaring(Expr("57"), 8).expr,
"tried exponentiationBySquaring(57, 8)"
)
assertEquals(
"((((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57))) * (((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57))))",
exponentiateBySquaring(Expr("57"), -8).expr,
"tried exponentiationBySquaring(57, -8)"
)
}
}
} }

View File

@ -7,252 +7,11 @@
package space.kscience.kmath.functions package space.kscience.kmath.functions
import space.kscience.kmath.functions.testUtils.IntModuloRing import space.kscience.kmath.functions.testUtils.*
import space.kscience.kmath.functions.testUtils.ListPolynomial
import space.kscience.kmath.functions.testUtils.Rational
import space.kscience.kmath.functions.testUtils.RationalField
import kotlin.test.* import kotlin.test.*
class ListPolynomialTest { class ListPolynomialTest {
@Test
fun test_Polynomial_Int_plus() {
RationalField.listPolynomialSpace {
assertEquals(
ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)),
ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + -3,
"test 1"
)
assertEquals(
ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)),
ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + 2,
"test 2"
)
assertEquals(
ListPolynomial(Rational(0)),
ListPolynomial(Rational(-2)) + 2,
"test 3"
)
val polynomial_4 = ListPolynomial<Rational>()
assertSame(
polynomial_4,
polynomial_4 + 0,
"test 4"
)
val polynomial_5 = ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7))
assertSame(
polynomial_5,
polynomial_5 + 0,
"test 5"
)
assertEquals(
ListPolynomial(Rational(-1), Rational(0), Rational(0), Rational(0)),
ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + 1,
"test 6"
)
assertEquals(
ListPolynomial(Rational(-1)),
ListPolynomial(Rational(-2)) + 1,
"test 7"
)
assertEquals(
ListPolynomial(Rational(2)),
ListPolynomial<Rational>() + 2,
"test 8"
)
}
}
@Test
fun test_Polynomial_Int_minus() {
RationalField.listPolynomialSpace {
assertEquals(
ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)),
ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - -3,
"test 1"
)
assertEquals(
ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)),
ListPolynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - 2,
"test 2"
)
assertEquals(
ListPolynomial(Rational(0)),
ListPolynomial(Rational(2)) - 2,
"test 3"
)
val polynomial_4 = ListPolynomial<Rational>()
assertSame(
polynomial_4,
polynomial_4 - 0,
"test 4"
)
val polynomial_5 = ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7))
assertEquals(
polynomial_5,
polynomial_5 - 0,
"test 5"
)
assertEquals(
ListPolynomial(Rational(1), Rational(0), Rational(0), Rational(0)),
ListPolynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - 1,
"test 6"
)
assertEquals(
ListPolynomial(Rational(1)),
ListPolynomial(Rational(2)) - 1,
"test 7"
)
assertEquals(
ListPolynomial(Rational(-2)),
ListPolynomial<Rational>() - 2,
"test 8"
)
}
}
@Test
fun test_Polynomial_Int_times() {
IntModuloRing(35).listPolynomialSpace {
assertEquals(
ListPolynomial(34, 2, 1, 20, 2),
ListPolynomial(22, 26, 13, 15, 26) * 27,
"test 1"
)
assertEquals(
ListPolynomial(0, 0, 0, 0, 0),
ListPolynomial(7, 0, 49, 21, 14) * 15,
"test 2"
)
val polynomial = ListPolynomial(22, 26, 13, 15, 26)
assertSame(
zero,
polynomial * 0,
"test 3"
)
assertSame(
polynomial,
polynomial * 1,
"test 4"
)
}
}
@Test
fun test_Int_Polynomial_plus() {
RationalField.listPolynomialSpace {
assertEquals(
ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)),
-3 + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)),
"test 1"
)
assertEquals(
ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)),
2 + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)),
"test 2"
)
assertEquals(
ListPolynomial(Rational(0)),
2 + ListPolynomial(Rational(-2)),
"test 3"
)
val polynomial_4 = ListPolynomial<Rational>()
assertSame(
polynomial_4,
0 + polynomial_4,
"test 4"
)
val polynomial_5 = ListPolynomial<Rational>(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7))
assertSame(
polynomial_5,
0 + polynomial_5,
"test 5"
)
assertEquals(
ListPolynomial(Rational(-1), Rational(0), Rational(0), Rational(0)),
1 + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)),
"test 6"
)
assertEquals(
ListPolynomial(Rational(-1)),
1 + ListPolynomial(Rational(-2)),
"test 7"
)
assertEquals(
ListPolynomial(Rational(2)),
2 + ListPolynomial(),
"test 8"
)
}
}
@Test
fun test_Int_Polynomial_minus() {
RationalField.listPolynomialSpace {
assertEquals(
ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)),
3 - ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)),
"test 1"
)
assertEquals(
ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)),
-2 - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)),
"test 2"
)
assertEquals(
ListPolynomial(Rational(0)),
-2 - ListPolynomial(Rational(-2)),
"test 3"
)
assertEquals(
ListPolynomial(Rational(-32, 9), Rational(-8, -9), Rational(8, 7)),
0 - ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)),
"test 4"
)
assertEquals(
ListPolynomial(),
0 - ListPolynomial(),
"test 5"
)
assertEquals(
ListPolynomial(Rational(1), Rational(0), Rational(0), Rational(0)),
-1 - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)),
"test 6"
)
assertEquals(
ListPolynomial(Rational(1)),
-1 - ListPolynomial(Rational(-2)),
"test 7"
)
assertEquals(
ListPolynomial(Rational(-2)),
-2 - ListPolynomial(),
"test 8"
)
}
}
@Test
fun test_Int_Polynomial_times() {
IntModuloRing(35).listPolynomialSpace {
assertEquals(
ListPolynomial(34, 2, 1, 20, 2),
27 * ListPolynomial(22, 26, 13, 15, 26),
"test 1"
)
assertEquals(
ListPolynomial(0, 0, 0, 0, 0),
15 * ListPolynomial(7, 0, 49, 21, 14),
"test 2"
)
val polynomial = ListPolynomial(22, 26, 13, 15, 26)
assertSame(
zero,
0 * polynomial,
"test 3"
)
assertSame(
polynomial,
1 * polynomial,
"test 4"
)
}
}
@Test @Test
fun test_Polynomial_Constant_plus() { fun test_Polynomial_Constant_plus() {
RationalField.listPolynomialSpace { RationalField.listPolynomialSpace {
@ -338,12 +97,12 @@ class ListPolynomialTest {
IntModuloRing(35).listPolynomialSpace { IntModuloRing(35).listPolynomialSpace {
assertEquals( assertEquals(
ListPolynomial(34, 2, 1, 20, 2), ListPolynomial(34, 2, 1, 20, 2),
ListPolynomial(22, 26, 13, 15, 26) * 27.asConstant(), ListPolynomial(22, 26, 13, 15, 26) * m(27),
"test 1" "test 1"
) )
assertEquals( assertEquals(
ListPolynomial(0, 0, 0, 0, 0), ListPolynomial(0, 0, 0, 0, 0),
ListPolynomial(7, 0, 49, 21, 14) * 15.asConstant(), ListPolynomial(7, 0, 49, 21, 14) * m(15),
"test 2" "test 2"
) )
} }
@ -433,12 +192,12 @@ class ListPolynomialTest {
IntModuloRing(35).listPolynomialSpace { IntModuloRing(35).listPolynomialSpace {
assertEquals( assertEquals(
ListPolynomial(34, 2, 1, 20, 2), ListPolynomial(34, 2, 1, 20, 2),
27 * ListPolynomial(22, 26, 13, 15, 26), m(27) * ListPolynomial(22, 26, 13, 15, 26),
"test 1" "test 1"
) )
assertEquals( assertEquals(
ListPolynomial(0, 0, 0, 0, 0), ListPolynomial(0, 0, 0, 0, 0),
15 * ListPolynomial(7, 0, 49, 21, 14), m(15) * ListPolynomial(7, 0, 49, 21, 14),
"test 2" "test 2"
) )
} }

View File

@ -5,11 +5,9 @@
package space.kscience.kmath.functions package space.kscience.kmath.functions
import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.functions.testUtils.Rational import space.kscience.kmath.functions.testUtils.Rational
import space.kscience.kmath.functions.testUtils.RationalField import space.kscience.kmath.functions.testUtils.RationalField
import space.kscience.kmath.functions.testUtils.assertFailsWithTypeAndMessage import space.kscience.kmath.misc.UnstableKMathAPI
import kotlin.test.Ignore
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
@ -88,754 +86,6 @@ class ListPolynomialUtilTest {
) )
} }
@Test @Test
fun test_Polynomial_substitute_Polynomial() {
assertEquals(
ListPolynomial(Rational(0)),
ListPolynomial(Rational(1), Rational(-2), Rational(1)).substitute(RationalField, ListPolynomial(Rational(1))),
"test 1"
)
assertEquals(
ListPolynomial(Rational(709, 378), Rational(155, 252), Rational(19, 525), Rational(2, 875)),
ListPolynomial(Rational(1, 7), Rational(9, 4), Rational(1, 3), Rational(2, 7))
.substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(1, 5))),
"test 2"
)
assertEquals(
ListPolynomial(Rational(655, 378), Rational(155, 252), Rational(19, 525), Rational(2, 875)),
ListPolynomial(Rational(0), Rational(9, 4), Rational(1, 3), Rational(2, 7))
.substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(1, 5))),
"test 3"
)
assertEquals(
ListPolynomial(Rational(677, 378), Rational(97, 180), Rational(1, 75), Rational(0)),
ListPolynomial(Rational(1, 7), Rational(9, 4), Rational(1, 3), Rational(0))
.substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(1, 5))),
"test 4"
)
assertEquals(
ListPolynomial(Rational(653, 378), Rational(221, 420), Rational(4, 175), Rational(2, 875)),
ListPolynomial(Rational(1, 7), Rational(9, 4), Rational(0), Rational(2, 7))
.substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(1, 5))),
"test 5"
)
assertEquals(
ListPolynomial(Rational(89, 54), Rational(0), Rational(0), Rational(0)),
ListPolynomial(Rational(0), Rational(9, 4), Rational(1, 3), Rational(0))
.substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(0))),
"test 6"
)
}
@Test
@Ignore // FIXME: This tests work only for sane realisations of the substitutions. Currently, it is not.
// Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should return denominator r^deg(p),
// not r^(deg(p)(deg(p)+1)/2) as it is now.
fun test_Polynomial_substitute_RationalFunction() {
assertEquals(
ListRationalFunction(ListPolynomial(Rational(0)), ListPolynomial(Rational(1))),
ListPolynomial(Rational(1), Rational(-2), Rational(1))
.substitute(RationalField, ListRationalFunction(ListPolynomial(Rational(1)), ListPolynomial(Rational(1)))),
"test 1"
)
assertEquals(
ListRationalFunction(
ListPolynomial(
Rational(66349, 243),
Rational(-17873, 405),
Rational(173533, 3780),
Rational(-91141, 567),
Rational(5773909, 105840),
Rational(-23243, 630),
Rational(1573, 27)
),
ListPolynomial(
Rational(169, 81),
Rational(-130, 27),
Rational(115, 18),
Rational(-797, 54),
Rational(1985, 144),
Rational(-55, 6),
Rational(121, 9)
)
),
ListPolynomial(
Rational(13, 3),
Rational(-9, 5),
Rational(5, 5)
).substitute(RationalField,
ListRationalFunction(
ListPolynomial(
Rational(15, 1),
Rational(6, 9),
Rational(-3, 7)
),
ListPolynomial(
Rational(-13, 9),
Rational(10, 6),
Rational(-10, 8),
Rational(11, 3)
)
)
),
"test 2"
)
assertEquals(
ListRationalFunction(
ListPolynomial(
Rational(0, 1),
Rational(0, 1),
Rational(-14, 9),
Rational(31, 14),
Rational(-5077, 980),
Rational(99, 35)
),
ListPolynomial(
Rational(0, 1),
Rational(0, 1),
Rational(25, 9),
Rational(-25, 6),
Rational(1985, 144),
Rational(-55, 6),
Rational(121, 9)
)
),
ListPolynomial(
Rational(0),
Rational(-9, 5),
Rational(5, 5)
).substitute(RationalField,
ListRationalFunction(
ListPolynomial(
Rational(0),
Rational(6, 9),
Rational(-3, 7)
),
ListPolynomial(
Rational(0),
Rational(10, 6),
Rational(-10, 8),
Rational(11, 3)
)
)
),
"test 3"
)
assertEquals(
ListRationalFunction(
ListPolynomial(
Rational(-898, 27),
Rational(271, 45),
Rational(-65, 12) ,
Rational(0),
Rational(0),
Rational(0),
Rational(0)
),
ListPolynomial(
Rational(-13, 9),
Rational(5, 3),
Rational(-5, 4),
Rational(0),
Rational(0),
Rational(0),
Rational(0)
)
),
ListPolynomial(
Rational(13, 3),
Rational(-9, 5),
Rational(0)
).substitute(RationalField,
ListRationalFunction(
ListPolynomial(
Rational(15, 1),
Rational(6, 9),
Rational(0)
),
ListPolynomial(
Rational(-13, 9),
Rational(10, 6),
Rational(-10, 8),
Rational(0)
)
)
),
"test 4"
)
assertEquals(
ListRationalFunction(
ListPolynomial(
Rational(56872, 243),
Rational(0, 1),
Rational(-90, 7),
Rational(-3718, 81),
Rational(9, 49),
Rational(0, 1),
Rational(1573, 27)
),
ListPolynomial(
Rational(169, 81),
Rational(0, 1),
Rational(0, 1),
Rational(-286, 27),
Rational(0, 1),
Rational(0, 1),
Rational(121, 9)
)
),
ListPolynomial(
Rational(13, 3),
Rational(0),
Rational(5, 5)
).substitute(RationalField,
ListRationalFunction(
ListPolynomial(
Rational(15, 1),
Rational(0),
Rational(-3, 7)
),
ListPolynomial(
Rational(-13, 9),
Rational(0),
Rational(0),
Rational(11, 3)
)
)
),
"test 5"
)
}
@Test
fun test_RationalFunction_substitute_Double() {
assertEquals(
0.0,
ListRationalFunction(
ListPolynomial(1.0, -2.0, 1.0),
ListPolynomial(-6.302012278484357, 5.831971885376948, -9.271604788393432, 5.494387848015814, -3.7187384450880785)
).substitute(1.0),
0.001,
"test 1"
)
assertEquals(
2.693702616649797,
ListRationalFunction(
ListPolynomial(-5.848840571263625, -1.660411278951134, -3.793740946372443, -9.624569269490076),
ListPolynomial(-2.9680680215311073, -1.862973627119981, 4.776550592888336, -2.7320154512368466)
).substitute(-7.53452770353279),
0.001,
"test 2"
)
assertEquals(
2.692226268901378,
ListRationalFunction(
ListPolynomial(0.0, -1.660411278951134, -3.793740946372443, -9.624569269490076),
ListPolynomial(0.0, -1.862973627119981, 4.776550592888336, -2.7320154512368466)
).substitute(-7.53452770353279),
0.001,
"test 3"
)
assertEquals(
-0.7394904842099175,
ListRationalFunction(
ListPolynomial(-5.848840571263625, -1.660411278951134, -3.793740946372443, 0.0),
ListPolynomial(-2.9680680215311073, -1.862973627119981, 4.776550592888336, 0.0)
).substitute(-7.53452770353279),
0.001,
"test 4"
)
assertEquals(
3.526835209398159,
ListRationalFunction(
ListPolynomial(-5.848840571263625, 0.0, 0.0, -9.624569269490076),
ListPolynomial(-2.9680680215311073, 0.0, 0.0, -2.7320154512368466)
).substitute(-7.53452770353279),
0.001,
"test 5"
)
}
@Test
fun test_RationalFunction_substitute_Constant() {
assertEquals(
Rational(0),
ListRationalFunction(
ListPolynomial(Rational(1), Rational(-2), Rational(1)),
ListPolynomial(Rational(1)),
).substitute(RationalField, Rational(1)),
"test 1"
)
assertEquals(
Rational(1149615, 61306),
ListRationalFunction(
ListPolynomial(Rational(17, 7), Rational(18, 3), Rational(18, 8), Rational(9, 1)),
ListPolynomial(Rational(11, 9), Rational(-6, 5), Rational(-12, 7), Rational(2, 1)),
).substitute(RationalField, Rational(-7, 8)),
"test 2"
)
assertEquals(
Rational(3495, 586),
ListRationalFunction(
ListPolynomial(Rational(0), Rational(18, 3), Rational(18, 8), Rational(9, 1)),
ListPolynomial(Rational(0), Rational(-6, 5), Rational(-12, 7), Rational(2, 1)),
).substitute(RationalField, Rational(-7, 8)),
"test 3"
)
assertEquals(
Rational(-88605, 77392),
ListRationalFunction(
ListPolynomial(Rational(17, 7), Rational(18, 3), Rational(18, 8), Rational(0)),
ListPolynomial(Rational(11, 9), Rational(-6, 5), Rational(-12, 7), Rational(0)),
).substitute(RationalField, Rational(-7, 8)),
"test 4"
)
assertEquals(
Rational(116145, 3794),
ListRationalFunction(
ListPolynomial(Rational(17, 7), Rational(0), Rational(0), Rational(9, 1)),
ListPolynomial(Rational(11, 9), Rational(0), Rational(0), Rational(2, 1)),
).substitute(RationalField, Rational(-7, 8)),
"test 5"
)
}
@Test
fun test_RationalFunction_substitute_Polynomial() {
assertEquals(
ListRationalFunction(
ListPolynomial(Rational(0)),
ListPolynomial(Rational(1))
),
ListRationalFunction(
ListPolynomial(Rational(1), Rational(-2), Rational(1)),
ListPolynomial(Rational(1)),
).substitute(RationalField, ListPolynomial(Rational(1))),
"test 1"
)
assertEquals(
ListRationalFunction(
ListPolynomial(
Rational(-283303, 36),
Rational(-23593, 24),
Rational(368713, 192),
Rational(1455, 8),
Rational(-272171, 1536),
Rational(-2149, 192),
Rational(469, 64),
Rational(11, 48),
Rational(-11, 96)
),
ListPolynomial(
Rational(5797, 12),
Rational(595, 16),
Rational(-5285, 72),
Rational(-745, 192),
Rational(1105, 288),
Rational(5, 48),
Rational(-5, 72)
)
),
ListRationalFunction(
ListPolynomial(
Rational(2, 9),
Rational(11, 3),
Rational(-9, 4),
Rational(-6, 1),
Rational(-11, 6)
),
ListPolynomial(
Rational(-2, 3),
Rational(-15, 4),
Rational(5, 9),
Rational(-5, 9)
)
).substitute(RationalField,
ListPolynomial(
Rational(-9, 1),
Rational(-1, 4),
Rational(2, 4)
)
),
"test 2"
)
assertEquals(
ListRationalFunction(
ListPolynomial(
Rational(0, 1),
Rational(-11, 12),
Rational(325, 192),
Rational(21, 32),
Rational(-1739, 1536),
Rational(227, 192),
Rational(-59, 64),
Rational(11, 48),
Rational(-11, 96)
),
ListPolynomial(
Rational(0, 1),
Rational(15, 16),
Rational(-265, 144),
Rational(-25, 192),
Rational(25, 288),
Rational(5, 48),
Rational(-5, 72)
)
),
ListRationalFunction(
ListPolynomial(
Rational(0, 9),
Rational(11, 3),
Rational(-9, 4),
Rational(-6, 1),
Rational(-11, 6)
),
ListPolynomial(
Rational(0, 3),
Rational(-15, 4),
Rational(5, 9),
Rational(-5, 9)
)
).substitute(RationalField,
ListPolynomial(
Rational(0, 1),
Rational(-1, 4),
Rational(2, 4)
)
),
"test 3"
)
assertEquals(
ListRationalFunction(
ListPolynomial(
Rational(149723, 36),
Rational(8483, 24),
Rational(639, 64),
Rational(3, 32),
Rational(0),
Rational(0),
Rational(0),
Rational(0),
Rational(0)
),
ListPolynomial(
Rational(937, 12),
Rational(55, 16),
Rational(5, 144),
Rational(0),
Rational(0),
Rational(0),
Rational(0)
)
),
ListRationalFunction(
ListPolynomial(
Rational(2, 9),
Rational(11, 3),
Rational(-9, 4),
Rational(-6, 1),
Rational(0)
),
ListPolynomial(
Rational(-2, 3),
Rational(-15, 4),
Rational(5, 9),
Rational(0)
)
).substitute(RationalField,
ListPolynomial(
Rational(-9, 1),
Rational(-1, 4),
Rational(0)
)
),
"test 4"
)
assertEquals(
ListRationalFunction(
ListPolynomial(
Rational(-216509, 18),
Rational(0, 1),
Rational(2673, 1),
Rational(0, 1),
Rational(-891, 4),
Rational(0, 1),
Rational(33, 4),
Rational(0, 1),
Rational(-11, 96)
),
ListPolynomial(
Rational(1213, 3),
Rational(0, 1),
Rational(-135, 2),
Rational(0, 1),
Rational(15, 4),
Rational(0, 1),
Rational(-5, 72)
)
),
ListRationalFunction(
ListPolynomial(
Rational(2, 9),
Rational(0),
Rational(0),
Rational(0),
Rational(-11, 6)
),
ListPolynomial(
Rational(-2, 3),
Rational(0),
Rational(0),
Rational(-5, 9)
)
).substitute(RationalField,
ListPolynomial(
Rational(-9, 1),
Rational(0),
Rational(2, 4)
)
),
"test 5"
)
}
@Test
@Ignore // FIXME: This tests work only for sane realisations of the substitutions. Currently, it is not.
// Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should return denominator r^deg(p),
// not r^(deg(p)(deg(p)+1)/2) as it is now.
fun test_RationalFunction_substitute_RationalFunction() {
assertEquals(
ListRationalFunction(
ListPolynomial(Rational(0)),
ListPolynomial(Rational(1))
),
ListRationalFunction(
ListPolynomial(Rational(1), Rational(-2), Rational(1)),
ListPolynomial(Rational(1))
).substitute(RationalField,
ListRationalFunction(
ListPolynomial(Rational(1)),
ListPolynomial(Rational(1))
)
),
"test 1"
)
assertEquals(
ListRationalFunction(
ListPolynomial(
Rational(130087, 3888),
Rational(-2866333, 65610),
Rational(-5076229, 97200),
Rational(222136997, 3280500),
Rational(754719329, 20995200),
Rational(-12010283, 324000),
Rational(-2011967, 172800),
Rational(18607, 2880),
Rational(4705, 4096)
),
ListPolynomial(
Rational(-143820355, 3779136),
Rational(73886869, 1574640),
Rational(1440175193, 15746400),
Rational(-5308968857, 52488000),
Rational(-186910083731, 2099520000),
Rational(125043463, 1555200),
Rational(5299123, 388800),
Rational(-213757, 15360),
Rational(1380785, 147456)
)
),
ListRationalFunction(
ListPolynomial(
Rational(1, 1),
Rational(-10, 5),
Rational(18, 8),
Rational(-8, 8)
),
ListPolynomial(
Rational(-14, 8),
Rational(-14, 8),
Rational(-19, 6),
Rational(14, 3),
Rational(8, 9)
)
).substitute(RationalField,
ListRationalFunction(
ListPolynomial(
Rational(14, 9),
Rational(-2, 5),
Rational(-14, 7)
),
ListPolynomial(
Rational(-6, 4),
Rational(5, 9),
Rational(1, 8)
)
)
),
"test 2"
)
assertEquals(
ListRationalFunction(
ListPolynomial(
Rational(0, 1),
Rational(0, 1),
Rational(0, 1),
Rational(0, 1),
Rational(5173, 18225),
Rational(904291, 364500),
Rational(283127, 43200),
Rational(37189, 5760),
Rational(147, 128)
),
ListPolynomial(
Rational(0, 1),
Rational(0, 1),
Rational(0, 1),
Rational(0, 1),
Rational(-163589, 911250),
Rational(-881831, 291600),
Rational(-10722229, 777600),
Rational(-640921, 46080),
Rational(86303, 9216)
)
),
ListRationalFunction(
ListPolynomial(
Rational(0),
Rational(-10, 5),
Rational(18, 8),
Rational(-8, 8)
),
ListPolynomial(
Rational(0),
Rational(-14, 8),
Rational(-19, 6),
Rational(14, 3),
Rational(8, 9)
)
).substitute(RationalField,
ListRationalFunction(
ListPolynomial(
Rational(0),
Rational(-2, 5),
Rational(-14, 7)
),
ListPolynomial(
Rational(0),
Rational(5, 9),
Rational(1, 8)
)
)
),
"test 3"
)
assertEquals(
ListRationalFunction(
ListPolynomial(
Rational(445, 16),
Rational(-2011, 54),
Rational(1359199, 72900),
Rational(-135733, 32805),
Rational(2254, 6561),
Rational(0, 1),
Rational(0, 1),
Rational(0, 1),
Rational(0, 1)
),
ListPolynomial(
Rational(-2018387, 46656),
Rational(82316437, 1574640),
Rational(-9335047, 393660),
Rational(15765889, 3280500),
Rational(-242089, 656100),
Rational(0, 1),
Rational(0, 1),
Rational(0, 1),
Rational(0, 1)
)
),
ListRationalFunction(
ListPolynomial(
Rational(1, 1),
Rational(-10, 5),
Rational(18, 8),
Rational(0)
),
ListPolynomial(
Rational(-14, 8),
Rational(-14, 8),
Rational(-19, 6),
Rational(14, 3),
Rational(0)
)
).substitute(RationalField,
ListRationalFunction(
ListPolynomial(
Rational(14, 9),
Rational(-2, 5),
Rational(0)
),
ListPolynomial(
Rational(-6, 4),
Rational(5, 9),
Rational(0)
)
)
),
"test 4"
)
assertEquals(
ListRationalFunction(
ListPolynomial(
Rational(41635, 3888),
Rational(0, 1),
Rational(-279187, 11664),
Rational(0, 1),
Rational(103769, 3456),
Rational(0, 1),
Rational(-11017, 768),
Rational(0, 1),
Rational(4097, 4096)
),
ListPolynomial(
Rational(-13811791, 3779136),
Rational(0, 1),
Rational(-9999395, 419904),
Rational(0, 1),
Rational(6376601, 124416),
Rational(0, 1),
Rational(-3668315, 82944),
Rational(0, 1),
Rational(2097089, 147456)
)
),
ListRationalFunction(
ListPolynomial(
Rational(1, 1),
Rational(0),
Rational(0),
Rational(-8, 8)
),
ListPolynomial(
Rational(-14, 8),
Rational(0),
Rational(0),
Rational(0),
Rational(8, 9)
)
).substitute(RationalField,
ListRationalFunction(
ListPolynomial(
Rational(14, 9),
Rational(0),
Rational(-14, 7)
),
ListPolynomial(
Rational(-6, 4),
Rational(0),
Rational(1, 8)
)
)
),
"test 5"
)
}
@Test
fun test_Polynomial_derivative() { fun test_Polynomial_derivative() {
assertEquals( assertEquals(
ListPolynomial(Rational(-2), Rational(2)), ListPolynomial(Rational(-2), Rational(2)),
@ -859,55 +109,6 @@ class ListPolynomialUtilTest {
) )
} }
@Test @Test
fun test_Polynomial_nthDerivative() {
assertEquals(
ListPolynomial(Rational(-2), Rational(2)),
ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 1),
"test 1"
)
assertFailsWithTypeAndMessage<IllegalArgumentException>(
"Order of derivative must be non-negative",
"test2"
) {
ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, -1)
}
assertEquals(
ListPolynomial(Rational(1), Rational(-2), Rational(1)),
ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 0),
"test 3"
)
assertEquals(
ListPolynomial(Rational(2)),
ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 2),
"test 4"
)
assertEquals(
ListPolynomial(),
ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 3),
"test 5"
)
assertEquals(
ListPolynomial(),
ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 4),
"test 6"
)
assertEquals(
ListPolynomial(Rational(8, 9), Rational(30, 7), Rational(-20, 3)),
ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthDerivative(RationalField, 2),
"test 7"
)
assertEquals(
ListPolynomial(Rational(8, 9), Rational(30, 7), Rational(-20, 3)),
ListPolynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthDerivative(RationalField, 2),
"test 8"
)
assertEquals(
ListPolynomial(Rational(8, 9), Rational(30, 7), Rational(0)),
ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).nthDerivative(RationalField, 2),
"test 9"
)
}
@Test
fun test_Polynomial_antiderivative() { fun test_Polynomial_antiderivative() {
assertEquals( assertEquals(
ListPolynomial(Rational(0), Rational(1), Rational(-1), Rational(1, 3)), ListPolynomial(Rational(0), Rational(1), Rational(-1), Rational(1, 3)),
@ -930,53 +131,4 @@ class ListPolynomialUtilTest {
"test 4" "test 4"
) )
} }
@Test
fun test_Polynomial_nthAntiderivative() {
assertEquals(
ListPolynomial(Rational(0), Rational(1), Rational(-1), Rational(1, 3)),
ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 1),
"test 1"
)
assertFailsWithTypeAndMessage<IllegalArgumentException>(
"Order of antiderivative must be non-negative",
"test2"
) {
ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, -1)
}
assertEquals(
ListPolynomial(Rational(1), Rational(-2), Rational(1)),
ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 0),
"test 3"
)
assertEquals(
ListPolynomial(Rational(0), Rational(0), Rational(1, 2), Rational(-1, 3), Rational(1, 12)),
ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 2),
"test 4"
)
assertEquals(
ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(1, 6), Rational(-1, 12), Rational(1, 60)),
ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 3),
"test 5"
)
assertEquals(
ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0), Rational(1, 24), Rational(-1, 60), Rational(1, 360)),
ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 4),
"test 6"
)
assertEquals(
ListPolynomial(Rational(0), Rational(0), Rational(1, 10), Rational(-4, 9), Rational(1, 27), Rational(1, 28), Rational(-1, 54)),
ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthAntiderivative(RationalField, 2),
"test 7"
)
assertEquals(
ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0), Rational(1, 27), Rational(1, 28), Rational(-1, 54)),
ListPolynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthAntiderivative(RationalField, 2),
"test 8"
)
assertEquals(
ListPolynomial(Rational(0), Rational(0), Rational(1, 10), Rational(-4, 9), Rational(1, 27), Rational(1, 28), Rational(0)),
ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).nthAntiderivative(RationalField, 2),
"test 9"
)
}
} }

View File

@ -5,15 +5,14 @@
package space.kscience.kmath.functions.testUtils package space.kscience.kmath.functions.testUtils
import space.kscience.kmath.functions.ListPolynomial import space.kscience.kmath.functions.Polynomial
import space.kscience.kmath.functions.ListPolynomialSpace import space.kscience.kmath.functions.ListPolynomialSpace
import space.kscience.kmath.functions.PolynomialSpaceOverRing
public fun ListPolynomialSpace<IntModulo, IntModuloRing>.ListPolynomial(vararg coefs: Int): ListPolynomial<IntModulo> = public fun ListPolynomialSpace<IntModulo, IntModuloRing>.ListPolynomial(vararg coefs: Int): Polynomial<IntModulo> =
ListPolynomial(coefs.map { IntModulo(it, ring.modulus) }) Polynomial(coefs.map { IntModulo(it, ring.modulus) })
public fun IntModuloRing.ListPolynomial(vararg coefs: Int): ListPolynomial<IntModulo> = public fun IntModuloRing.ListPolynomial(vararg coefs: Int): Polynomial<IntModulo> =
ListPolynomial(coefs.map { IntModulo(it, modulus) }) Polynomial(coefs.map { IntModulo(it, modulus) })
public fun IntModuloRing.m(arg: Int): IntModulo = IntModulo(arg, modulus) public fun IntModuloRing.m(arg: Int): IntModulo = IntModulo(arg, modulus)
public fun PolynomialSpaceOverRing<IntModulo, *, IntModuloRing>.m(arg: Int): IntModulo = IntModulo(arg, ring.modulus) public fun ListPolynomialSpace<IntModulo, IntModuloRing>.m(arg: Int): IntModulo = IntModulo(arg, ring.modulus)