diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt deleted file mode 100644 index 76e1a6bb6..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt +++ /dev/null @@ -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( - /** - * 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 -) : Polynomial { - 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>( - public override val ring: A, -) : PolynomialSpaceOverRing, 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.plus(other: Int): ListPolynomial = - 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.minus(other: Int): ListPolynomial = - 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.times(other: Int): ListPolynomial = - 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): ListPolynomial = - 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): ListPolynomial = - 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): ListPolynomial = - 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): ListPolynomial = - 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): ListPolynomial = - 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): ListPolynomial = - 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.plus(other: C): ListPolynomial = - 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.minus(other: C): ListPolynomial = - 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.times(other: C): ListPolynomial = - 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 = ListPolynomial(listOf(value)) - - /** - * Returns negation of the polynomial. - */ - public override operator fun ListPolynomial.unaryMinus(): ListPolynomial = - ListPolynomial(coefficients.map { -it }) - /** - * Returns sum of the polynomials. - */ - public override operator fun ListPolynomial.plus(other: ListPolynomial): ListPolynomial { - 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.minus(other: ListPolynomial): ListPolynomial { - 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.times(other: ListPolynomial): ListPolynomial { - 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, exponent: UInt): ListPolynomial = super.power(arg, exponent) - - /** - * Instance of zero polynomial (zero of the polynomial ring). - */ - override val zero: ListPolynomial = ListPolynomial(emptyList()) - /** - * Instance of unit polynomial (unit of the polynomial ring). - */ - override val one: ListPolynomial 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.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.substitute(argument: C): C = substitute(ring, argument) - /** - * Substitutes provided polynomial [argument] into [this] polynomial. - */ - public inline fun ListPolynomial.substitute(argument: ListPolynomial): ListPolynomial = substitute(ring, argument) - - /** - * Represent [this] polynomial as a regular context-less function. - */ - public inline fun ListPolynomial.asFunction(): (C) -> C = asFunctionOver(ring) - /** - * Represent [this] polynomial as a regular context-less function. - */ - public inline fun ListPolynomial.asFunctionOfConstant(): (C) -> C = asFunctionOfConstantOver(ring) - /** - * Represent [this] polynomial as a regular context-less function. - */ - public inline fun ListPolynomial.asFunctionOfPolynomial(): (ListPolynomial) -> ListPolynomial = asFunctionOfPolynomialOver(ring) - - /** - * Evaluates value of [this] polynomial on provided [argument]. - */ - public inline operator fun ListPolynomial.invoke(argument: C): C = substitute(ring, argument) - /** - * Evaluates value of [this] polynomial on provided [argument]. - */ - public inline operator fun ListPolynomial.invoke(argument: ListPolynomial): ListPolynomial = 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( - ring: A, -) : ListPolynomialSpace(ring), ScaleOperations> where A : Ring, A : ScaleOperations { - override fun scale(a: ListPolynomial, value: Double): ListPolynomial = - ring { ListPolynomial(a.coefficients.map { scale(it, value) }) } -} diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt index 612b00535..cfd21d552 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt @@ -27,10 +27,10 @@ public fun interface Piecewise { * @property pieces An ordered list of range-polynomial pairs. The list does not in general guarantee that there are no * "holes" in it. */ -public interface PiecewisePolynomial> : Piecewise> { - public val pieces: Collection, ListPolynomial>> +public interface PiecewisePolynomial> : Piecewise> { + public val pieces: Collection, Polynomial>> - override fun findPiece(arg: T): ListPolynomial? + override fun findPiece(arg: T): Polynomial? } /** @@ -38,11 +38,11 @@ public interface PiecewisePolynomial> : Piecewise> PiecewisePolynomial( - pieces: Collection, ListPolynomial>>, + pieces: Collection, Polynomial>>, ): PiecewisePolynomial = object : PiecewisePolynomial { - override val pieces: Collection, ListPolynomial>> = pieces + override val pieces: Collection, Polynomial>> = pieces - override fun findPiece(arg: T): ListPolynomial? = pieces.firstOrNull { arg in it.first }?.second + override fun findPiece(arg: T): Polynomial? = pieces.firstOrNull { arg in it.first }?.second } /** @@ -50,10 +50,10 @@ public fun > PiecewisePolynomial( * The pieces search is logarithmic. */ private class OrderedPiecewisePolynomial>( - override val pieces: List, ListPolynomial>>, + override val pieces: List, Polynomial>>, ) : PiecewisePolynomial { - override fun findPiece(arg: T): ListPolynomial? { + override fun findPiece(arg: T): Polynomial? { val index = pieces.binarySearch { (range, _) -> when { arg >= range.endInclusive -> -1 @@ -74,7 +74,7 @@ private class OrderedPiecewisePolynomial>( */ public class PiecewiseBuilder>(delimiter: T) { private val delimiters: MutableList = arrayListOf(delimiter) - private val pieces: MutableList> = arrayListOf() + private val pieces: MutableList> = arrayListOf() /** * Dynamically adds a piece to the right side (beyond maximum argument value of previous piece) @@ -82,7 +82,7 @@ public class PiecewiseBuilder>(delimiter: T) { * @param right new rightmost position. If is less than current rightmost position, an error is thrown. * @param piece the sub-function. */ - public fun putRight(right: T, piece: ListPolynomial) { + public fun putRight(right: T, piece: Polynomial) { require(right > delimiters.last()) { "New delimiter should be to the right of old one" } delimiters += right pieces += piece @@ -94,7 +94,7 @@ public class PiecewiseBuilder>(delimiter: T) { * @param left the new leftmost position. If is less than current rightmost position, an error is thrown. * @param piece the sub-function. */ - public fun putLeft(left: T, piece: ListPolynomial) { + public fun putLeft(left: T, piece: Polynomial) { require(left < delimiters.first()) { "New delimiter should be to the left of old one" } delimiters.add(0, left) pieces.add(0, piece) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt index 61ea5a342..fec4776d9 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt @@ -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. */ +@file:Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") + 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.js.JsName -import kotlin.jvm.JvmName +import kotlin.jvm.JvmInline +import kotlin.math.max +import kotlin.math.min /** - * Abstraction of polynomials. - */ -public interface Polynomial - -/** - * Abstraction of ring of polynomials of type [P] over ring of constants of type [C]. + * Represents univariate polynomial that stores its coefficients in a [List]. * - * @param C the type of constants. Polynomials have them as coefficients in their terms. - * @param P the type of polynomials. + * @param C the type of constants. */ -@Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") // FIXME: Waiting for KT-31420 -public interface PolynomialSpace> : Ring

{ +@JvmInline +public value class Polynomial( /** - * 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]. + * 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 operator fun C.plus(other: Int): C - /** - * Returns difference between the constant and the integer represented as a constant (member of underlying ring). - * - * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. - */ - public operator fun C.minus(other: Int): C - /** - * Returns product of the constant and the integer represented as a constant (member of underlying ring). - * - * The operation is equivalent to sum of [other] copies of [this]. - */ - public operator fun C.times(other: Int): C + public val coefficients: List +) { + 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>( /** - * 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]. + * Underlying ring of constants. Its operations on constants are inherited by local operations on constants. */ - public operator fun Int.plus(other: C): C - /** - * Returns difference between the integer represented as a constant (member of underlying ring) and the constant. - * - * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. - */ - public operator fun Int.minus(other: C): C - /** - * Returns product of the integer represented as a constant (member of underlying ring) and the constant. - * - * The operation is equivalent to sum of [this] copies of [other]. - */ - public operator fun Int.times(other: C): C - - /** - * Converts the integer [value] to constant. - */ - public fun constantNumber(value: Int): C = constantOne * value - /** - * Converts the integer to constant. - */ - public fun Int.asConstant(): C = constantNumber(this) - - /** - * Returns sum of the polynomial and the integer represented as a polynomial. - * - * The operation is equivalent to adding [other] copies of unit polynomial to [this]. - */ - public operator fun P.plus(other: Int): P = addMultipliedByDoubling(this, one, other) - /** - * Returns difference between the polynomial and the integer represented as a polynomial. - * - * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. - */ - public operator fun P.minus(other: Int): P = addMultipliedByDoubling(this, one, -other) - /** - * Returns product of the polynomial and the integer represented as a polynomial. - * - * The operation is equivalent to sum of [other] copies of [this]. - */ - public operator fun P.times(other: Int): P = multiplyByDoubling(this, other) - - /** - * Returns sum of the integer represented as a polynomial and the polynomial. - * - * The operation is equivalent to adding [this] copies of unit polynomial to [other]. - */ - public operator fun Int.plus(other: P): P = addMultipliedByDoubling(other, one, this) - /** - * Returns difference between the integer represented as a polynomial and the polynomial. - * - * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. - */ - public operator fun Int.minus(other: P): P = addMultipliedByDoubling(-other, one, this) - /** - * Returns product of the integer represented as a polynomial and the polynomial. - * - * The operation is equivalent to sum of [this] copies of [other]. - */ - public operator fun Int.times(other: P): P = multiplyByDoubling(other, this) - - /** - * Converts the integer [value] to polynomial. - */ - public fun number(value: Int): P = number(constantNumber(value)) - /** - * Converts the integer to polynomial. - */ - public fun Int.asPolynomial(): P = number(this) - - /** - * Returns the same constant. - */ - @JvmName("unaryPlusConstant") - @JsName("unaryPlusConstant") - public operator fun C.unaryPlus(): C = this - /** - * Returns negation of the constant. - */ - @JvmName("unaryMinusConstant") - @JsName("unaryMinusConstant") - public operator fun C.unaryMinus(): C - /** - * Returns sum of the constants. - */ - @JvmName("plusConstantConstant") - @JsName("plusConstantConstant") - public operator fun C.plus(other: C): C - /** - * Returns difference of the constants. - */ - @JvmName("minusConstantConstant") - @JsName("minusConstantConstant") - public operator fun C.minus(other: C): C - /** - * Returns product of the constants. - */ - @JvmName("timesConstantConstant") - @JsName("timesConstantConstant") - public operator fun C.times(other: C): C - /** - * Raises [arg] to the integer power [exponent]. - */ - @JvmName("powerConstant") - @JsName("powerConstant") - public fun power(arg: C, exponent: UInt) : C + public val ring: A, +) : 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). */ - public val constantOne: C + public val constantOne: C get() = ring.one /** * 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): Polynomial = + 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. */ - public operator fun C.minus(other: P): P + public operator fun C.minus(other: Polynomial): Polynomial = + 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. */ - public operator fun C.times(other: P): P + public operator fun C.times(other: Polynomial): Polynomial = + 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. */ - public operator fun P.plus(other: C): P + public operator fun Polynomial.plus(other: C): Polynomial = + 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. */ - public operator fun P.minus(other: C): P + public operator fun Polynomial.minus(other: C): Polynomial = + 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. */ - public operator fun P.times(other: C): P + public operator fun Polynomial.times(other: C): Polynomial = + with(ring) { + Polynomial( + coefficients + .toMutableList() + .apply { + for (deg in indices) this[deg] = this[deg] * other + } + ) + } /** * Converts the constant [value] to polynomial. */ - public fun number(value: C): P = one * value + public fun number(value: C): Polynomial = Polynomial(listOf(value)) /** * Converts the constant to polynomial. */ - public fun C.asPolynomial(): P = number(this) + public fun C.asPolynomial(): Polynomial = number(this) - /** - * Returns the same polynomial. - */ - public override operator fun P.unaryPlus(): P = this /** * Returns negation of the polynomial. */ - public override operator fun P.unaryMinus(): P + public override operator fun Polynomial.unaryMinus(): Polynomial = + with(ring) { + Polynomial(coefficients.map { -it }) + } /** * Returns sum of the polynomials. */ - public override operator fun P.plus(other: P): P + public override operator fun Polynomial.plus(other: Polynomial): Polynomial { + 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. */ - public override operator fun P.minus(other: P): P + public override operator fun Polynomial.minus(other: Polynomial): Polynomial { + 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. */ - public override operator fun P.times(other: P): P + public override operator fun Polynomial.times(other: Polynomial): Polynomial { + 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]. - */ - public override fun power(arg: P, exponent: UInt) : P = exponentiateBySquaring(arg, exponent) + */ // TODO: To optimize boxing + override fun power(arg: Polynomial, exponent: UInt): Polynomial = exponentiateBySquaring(arg, exponent) /** * Instance of zero polynomial (zero of the polynomial ring). */ - public override val zero: P + override val zero: Polynomial = Polynomial(emptyList()) /** * Instance of unit polynomial (unit of the polynomial ring). */ - public override val one: P + override val one: Polynomial by lazy { Polynomial(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 val P.degree: Int + public val Polynomial.degree: Int get() = coefficients.lastIndex - override fun add(left: P, right: P): P = left + right - override fun multiply(left: P, right: P): P = left * right + override fun add(left: Polynomial, right: Polynomial): Polynomial = left + right + override fun multiply(left: Polynomial, right: Polynomial): Polynomial = 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.substitute(argument: C): C = substitute(ring, argument) + + /** + * Represent [this] polynomial as a regular context-less function. + */ + public inline fun Polynomial.asFunction(): (C) -> C = asFunctionOver(ring) + + /** + * Evaluates value of [this] polynomial on provided [argument]. + */ + public inline operator fun Polynomial.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 - * provided [ring] (of type [A]), that provides constant-wise operations. + * Space of polynomials constructed over ring. * - * @param C the type of constants. Polynomials have them as coefficients in their terms. - * @param P the type of polynomials. - * @param A the type of algebraic structure (precisely, of ring) provided for constants. + * @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]. */ -@Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 -public interface PolynomialSpaceOverRing, A: Ring> : PolynomialSpace { - - /** - * Underlying ring of constants. Its operations on constants are inherited by local operations on constants. - */ - public val ring: A - - /** - * Returns sum of the constant and the integer represented as a constant (member of underlying ring). - * - * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. - */ - public override operator fun C.plus(other: Int): C = ring { addMultipliedByDoubling(this@plus, one, other) } - /** - * Returns difference between the constant and the integer represented as a constant (member of underlying ring). - * - * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. - */ - public override operator fun C.minus(other: Int): C = ring { addMultipliedByDoubling(this@minus, one, -other) } - /** - * Returns product of the constant and the integer represented as a constant (member of underlying ring). - * - * The operation is equivalent to sum of [other] copies of [this]. - */ - public override operator fun C.times(other: Int): C = ring { multiplyByDoubling(this@times, other) } - - /** - * Returns sum of the integer represented as a constant (member of underlying ring) and the constant. - * - * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. - */ - public override operator fun Int.plus(other: C): C = ring { addMultipliedByDoubling(other, one, this@plus) } - /** - * Returns difference between the integer represented as a constant (member of underlying ring) and the constant. - * - * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. - */ - public override operator fun Int.minus(other: C): C = ring { addMultipliedByDoubling(-other, one, this@minus) } - /** - * Returns product of the integer represented as a constant (member of underlying ring) and the constant. - * - * The operation is equivalent to sum of [this] copies of [other]. - */ - public override operator fun Int.times(other: C): C = ring { multiplyByDoubling(other, this@times) } - - /** - * Returns negation of the constant. - */ - @JvmName("unaryMinusConstant") - public override operator fun C.unaryMinus(): C = ring { -this@unaryMinus } - /** - * Returns sum of the constants. - */ - @JvmName("plusConstantConstant") - public override operator fun C.plus(other: C): C = ring { this@plus + other } - /** - * Returns difference of the constants. - */ - @JvmName("minusConstantConstant") - public override operator fun C.minus(other: C): C = ring { this@minus - other } - /** - * Returns product of the constants. - */ - @JvmName("timesConstantConstant") - public override operator fun C.times(other: C): C = ring { this@times * other } - /** - * Raises [arg] to the integer power [exponent]. - */ - @JvmName("powerConstant") - override fun power(arg: C, exponent: UInt): C = ring { power(arg, exponent) } - - /** - * Instance of zero constant (zero of the underlying ring). - */ - public override val constantZero: C get() = ring.zero - /** - * Instance of unit constant (unit of the underlying ring). - */ - public override val constantOne: C get() = ring.one +public class ScalableListPolynomialSpace( + ring: A, +) : ListPolynomialSpace(ring), ScaleOperations> where A : Ring, A : ScaleOperations { + override fun scale(a: Polynomial, value: Double): Polynomial = + ring { Polynomial(a.coefficients.map { scale(it, value) }) } } - -/** - * 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>: PolynomialSpace { - /** - * 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 - /** - * 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): UInt - /** - * Set of all variables that appear in the polynomial in positive exponents. - */ - public val P.variables: Set get() = degrees.keys - /** - * Count of all variables that appear in the polynomial in positive exponents. - */ - public val P.countOfVariables: Int get() = variables.size -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt index b40aa4775..5eb1af4dc 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt @@ -9,101 +9,6 @@ import space.kscience.kmath.operations.* // TODO: All of this should be moved to algebraic structures' place for utilities -// FIXME: Move receiver to context receiver -/** - * Returns product of [arg] and integer [multiplier]. - * - * @param arg the multiplicand. - * @param multiplier the integer multiplier. - * @return product of the multiplicand [arg] and the multiplier [multiplier]. - * @author Gleb Minaev - */ -internal fun Group.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 GroupOps.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 Group.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 GroupOps.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 Field.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 Field.multiplyExponentiatedBySquaring(base: C, arg: C, exponent: Int): C = - if (exponent >= 0) multiplyExponentiatedBySquaring(base, arg, exponent.toUInt()) - else multiplyExponentiatedBySquaring(base, one / arg, (-exponent).toUInt()) - // FIXME: Move receiver to context receiver /** * Raises [arg] to the integer power [exponent]. diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt deleted file mode 100644 index e95361724..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt +++ /dev/null @@ -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 ListPolynomial(coefficients: List, reverse: Boolean = false): ListPolynomial = - 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 ListPolynomial(vararg coefficients: C, reverse: Boolean = false): ListPolynomial = - ListPolynomial(with(coefficients) { if (reverse) reversed() else toList() }) - -/** - * Represents [this] constant as a [ListPolynomial]. - */ -public fun C.asListPolynomial() : ListPolynomial = 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 ListRationalFunction(numeratorCoefficients: List, denominatorCoefficients: List, reverse: Boolean = false): ListRationalFunction = - ListRationalFunction( - 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 > A.ListRationalFunction(numerator: ListPolynomial): ListRationalFunction = - ListRationalFunction(numerator, ListPolynomial(listOf(one))) -/** - * Constructs [ListRationalFunction] instance with provided [numerator] and unit denominator. - */ -@Suppress("FunctionName") -public fun > ListRationalFunctionSpace.ListRationalFunction(numerator: ListPolynomial): ListRationalFunction = - ListRationalFunction(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 > A.ListRationalFunction(numeratorCoefficients: List, reverse: Boolean = false): ListRationalFunction = - ListRationalFunction( - 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 > ListRationalFunctionSpace.ListRationalFunction(numeratorCoefficients: List, reverse: Boolean = false): ListRationalFunction = - ListRationalFunction( - 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.asListRationalFunction(ring: A) : ListRationalFunction = ring.ListRationalFunction(asListPolynomial()) -///** -// * Represents [this] constant as a rational function. -// */ -//context(A) -//public fun > C.asListRationalFunction() : ListRationalFunction = ListRationalFunction(asListPolynomial()) -///** -// * Represents [this] constant as a rational function. -// */ -//context(ListRationalFunctionSpace) -//public fun > C.asListRationalFunction() : ListRationalFunction = ListRationalFunction(asListPolynomial()) \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt deleted file mode 100644 index 4f3f6d88e..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt +++ /dev/null @@ -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 > A.listPolynomialSpace: ListPolynomialSpace - 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 , R> A.listPolynomialSpace(block: ListPolynomialSpace.() -> R): R { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return ListPolynomialSpace(this).block() -} - -/** - * Creates a [ScalableListPolynomialSpace] over a received scalable ring. - */ -public inline val A.scalableListPolynomialSpace: ScalableListPolynomialSpace where A : Ring, A : ScaleOperations - 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 A.scalableListPolynomialSpace(block: ScalableListPolynomialSpace.() -> R): R where A : Ring, A : ScaleOperations { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return ScalableListPolynomialSpace(this).block() -} - -/** - * Creates a [ListRationalFunctionSpace] over a received ring. - */ -public inline val > A.listRationalFunctionSpace: ListRationalFunctionSpace - 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 , R> A.listRationalFunctionSpace(block: ListRationalFunctionSpace.() -> 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.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 ListPolynomial.substitute(ring: Ring, 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 ListPolynomial.substitute(ring: Ring, arg: ListPolynomial) : ListPolynomial = - ring.listPolynomialSpace { - if (coefficients.isEmpty()) return zero - var result: ListPolynomial = 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 ListPolynomial.substitute(ring: Ring, arg: ListRationalFunction) : ListRationalFunction = - ring.listRationalFunctionSpace { - if (coefficients.isEmpty()) return zero - var result: ListRationalFunction = 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.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 ListRationalFunction.substitute(ring: Field, 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 ListRationalFunction.substitute(ring: Ring, arg: ListPolynomial) : ListRationalFunction = - 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 ListRationalFunction.substitute(ring: Ring, arg: ListRationalFunction) : ListRationalFunction = - ring.listRationalFunctionSpace { - numerator.substitute(ring, arg) / denominator.substitute(ring, arg) - } - -/** - * Represent [this] polynomial as a regular context-less function. - */ -public fun > ListPolynomial.asFunctionOver(ring: A): (C) -> C = { substitute(ring, it) } - -/** - * Represent [this] polynomial as a regular context-less function. - */ -public fun > ListPolynomial.asFunctionOfConstantOver(ring: A): (C) -> C = { substitute(ring, it) } - -/** - * Represent [this] polynomial as a regular context-less function. - */ -public fun > ListPolynomial.asFunctionOfPolynomialOver(ring: A): (ListPolynomial) -> ListPolynomial = { substitute(ring, it) } - -/** - * Represent [this] polynomial as a regular context-less function. - */ -public fun > ListPolynomial.asFunctionOfRationalFunctionOver(ring: A): (ListRationalFunction) -> ListRationalFunction = { substitute(ring, it) } - -/** - * Represent [this] rational function as a regular context-less function. - */ -public fun > ListRationalFunction.asFunctionOver(ring: A): (C) -> C = { substitute(ring, it) } - -/** - * Represent [this] rational function as a regular context-less function. - */ -public fun > ListRationalFunction.asFunctionOfConstantOver(ring: A): (C) -> C = { substitute(ring, it) } - -/** - * Represent [this] rational function as a regular context-less function. - */ -public fun > ListRationalFunction.asFunctionOfPolynomialOver(ring: A): (ListPolynomial) -> ListRationalFunction = { substitute(ring, it) } - -/** - * Represent [this] rational function as a regular context-less function. - */ -public fun > ListRationalFunction.asFunctionOfRationalFunctionOver(ring: A): (ListRationalFunction) -> ListRationalFunction = { substitute(ring, it) } - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun ListPolynomial.derivative( - ring: A, -): ListPolynomial where A : Ring, A : NumericAlgebra = 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 ListPolynomial.nthDerivative( - ring: A, - order: Int, -): ListPolynomial where A : Ring, A : NumericAlgebra = 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 ListPolynomial.antiderivative( - ring: A, -): ListPolynomial where A : Field, A : NumericAlgebra = 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 ListPolynomial.nthAntiderivative( - ring: A, - order: Int, -): ListPolynomial where A : Field, A : NumericAlgebra = 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 > ListPolynomial.integrate( - ring: Field, - range: ClosedRange, -): C = ring { - val antiderivative = antiderivative(ring) - antiderivative.substitute(ring, range.endInclusive) - antiderivative.substitute(ring, range.start) -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt deleted file mode 100644 index 76f1c294e..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt +++ /dev/null @@ -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 \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialConstructors.kt new file mode 100644 index 000000000..ff04607a7 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialConstructors.kt @@ -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 ListPolynomial(coefficients: List, reverse: Boolean = false): Polynomial = + 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 ListPolynomial(vararg coefficients: C, reverse: Boolean = false): Polynomial = + Polynomial(with(coefficients) { if (reverse) reversed() else toList() }) + +/** + * Represents [this] constant as a [Polynomial]. + */ +public fun C.asListPolynomial() : Polynomial = Polynomial(listOf(this)) \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt new file mode 100644 index 000000000..fc3a728df --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt @@ -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 > A.listPolynomialSpace: ListPolynomialSpace + 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 , R> A.listPolynomialSpace(block: ListPolynomialSpace.() -> R): R { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return ListPolynomialSpace(this).block() +} + +/** + * Creates a [ScalableListPolynomialSpace] over a received scalable ring. + */ +public inline val A.scalableListPolynomialSpace: ScalableListPolynomialSpace where A : Ring, A : ScaleOperations + 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 A.scalableListPolynomialSpace(block: ScalableListPolynomialSpace.() -> R): R where A : Ring, A : ScaleOperations { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return ScalableListPolynomialSpace(this).block() +} + + +/** + * Evaluates value of [this] Double polynomial on provided Double argument. + */ +public fun Polynomial.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 Polynomial.substitute(ring: Ring, 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 > Polynomial.asFunctionOver(ring: A): (C) -> C = { substitute(ring, it) } + +/** + * Returns algebraic derivative of received polynomial. + */ +@UnstableKMathAPI +public fun Polynomial.derivative( + ring: A, +): Polynomial where A : Ring, A : NumericAlgebra = 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 Polynomial.antiderivative( + ring: A, +): Polynomial where A : Field, A : NumericAlgebra = 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 > Polynomial.integrate( + ring: Field, + range: ClosedRange, +): C { + val antiderivative = antiderivative(ring) + return ring { antiderivative.substitute(ring, range.endInclusive) - antiderivative.substitute(ring, range.start) } +} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/AlgebraicStubTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/AlgebraicStubTest.kt index 487cd9ee1..5782292b1 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/AlgebraicStubTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/AlgebraicStubTest.kt @@ -26,286 +26,6 @@ object ExprRing : Field { } class AlgebraicStubTest { - @Test - fun test_addMultipliedBySquaring_for_UInt() { - ExprRing { - assertEquals( - "57", - addMultipliedByDoubling(Expr("57"), Expr("179"), 0u).expr, - "tried addMultipliedBySquaring(57, 179, 0u)" - ) - assertEquals( - "(57 + 179)", - addMultipliedByDoubling(Expr("57"), Expr("179"), 1u).expr, - "tried addMultipliedBySquaring(57, 179, 1u)" - ) - assertEquals( - "(57 + (179 + 179))", - addMultipliedByDoubling(Expr("57"), Expr("179"), 2u).expr, - "tried addMultipliedBySquaring(57, 179, 2u)" - ) - assertEquals( - "((57 + 179) + (179 + 179))", - addMultipliedByDoubling(Expr("57"), Expr("179"), 3u).expr, - "tried addMultipliedBySquaring(57, 179, 3u)" - ) - assertEquals( - "(57 + ((179 + 179) + (179 + 179)))", - addMultipliedByDoubling(Expr("57"), Expr("179"), 4u).expr, - "tried addMultipliedBySquaring(57, 179, 4u)" - ) - assertEquals( - "((57 + 179) + ((179 + 179) + (179 + 179)))", - addMultipliedByDoubling(Expr("57"), Expr("179"), 5u).expr, - "tried addMultipliedBySquaring(57, 179, 5u)" - ) - assertEquals( - "((57 + (179 + 179)) + ((179 + 179) + (179 + 179)))", - addMultipliedByDoubling(Expr("57"), Expr("179"), 6u).expr, - "tried addMultipliedBySquaring(57, 179, 6u)" - ) - assertEquals( - "(((57 + 179) + (179 + 179)) + ((179 + 179) + (179 + 179)))", - addMultipliedByDoubling(Expr("57"), Expr("179"), 7u).expr, - "tried addMultipliedBySquaring(57, 179, 7u)" - ) - assertEquals( - "(57 + (((179 + 179) + (179 + 179)) + ((179 + 179) + (179 + 179))))", - addMultipliedByDoubling(Expr("57"), Expr("179"), 8u).expr, - "tried addMultipliedBySquaring(57, 179, 8u)" - ) - } - } - @Test - fun test_multiplyBySquaring_for_UInt() { - ExprRing { - assertEquals( - "0", - multiplyByDoubling(Expr("57"), 0u).expr, - "tried multiplyBySquaring(57, 0u)" - ) - assertEquals( - "57", - multiplyByDoubling(Expr("57"), 1u).expr, - "tried multiplyBySquaring(57, 1u)" - ) - assertEquals( - "(57 + 57)", - multiplyByDoubling(Expr("57"), 2u).expr, - "tried multiplyBySquaring(57, 2u)" - ) - assertEquals( - "(57 + (57 + 57))", - multiplyByDoubling(Expr("57"), 3u).expr, - "tried multiplyBySquaring(57, 3u)" - ) - assertEquals( - "((57 + 57) + (57 + 57))", - multiplyByDoubling(Expr("57"), 4u).expr, - "tried multiplyBySquaring(57, 4u)" - ) - assertEquals( - "(57 + ((57 + 57) + (57 + 57)))", - multiplyByDoubling(Expr("57"), 5u).expr, - "tried multiplyBySquaring(57, 5u)" - ) - assertEquals( - "((57 + 57) + ((57 + 57) + (57 + 57)))", - multiplyByDoubling(Expr("57"), 6u).expr, - "tried multiplyBySquaring(57, 6u)" - ) - assertEquals( - "((57 + (57 + 57)) + ((57 + 57) + (57 + 57)))", - multiplyByDoubling(Expr("57"), 7u).expr, - "tried multiplyBySquaring(57, 7u)" - ) - assertEquals( - "(((57 + 57) + (57 + 57)) + ((57 + 57) + (57 + 57)))", - multiplyByDoubling(Expr("57"), 8u).expr, - "tried multiplyBySquaring(57, 8u)" - ) - } - } - @Test - fun test_addMultipliedBySquaring_for_Int() { - ExprRing { - assertEquals( - "57", - addMultipliedByDoubling(Expr("57"), Expr("179"), 0).expr, - "tried addMultipliedBySquaring(57, 179, 0)" - ) - assertEquals( - "(57 + 179)", - addMultipliedByDoubling(Expr("57"), Expr("179"), 1).expr, - "tried addMultipliedBySquaring(57, 179, 1)" - ) - assertEquals( - "(57 + -179)", - addMultipliedByDoubling(Expr("57"), Expr("179"), -1).expr, - "tried addMultipliedBySquaring(57, 179, -1)" - ) - assertEquals( - "(57 + (179 + 179))", - addMultipliedByDoubling(Expr("57"), Expr("179"), 2).expr, - "tried addMultipliedBySquaring(57, 179, 2)" - ) - assertEquals( - "(57 + (-179 + -179))", - addMultipliedByDoubling(Expr("57"), Expr("179"), -2).expr, - "tried addMultipliedBySquaring(57, 179, -2)" - ) - assertEquals( - "((57 + 179) + (179 + 179))", - addMultipliedByDoubling(Expr("57"), Expr("179"), 3).expr, - "tried addMultipliedBySquaring(57, 179, 3)" - ) - assertEquals( - "((57 + -179) + (-179 + -179))", - addMultipliedByDoubling(Expr("57"), Expr("179"), -3).expr, - "tried addMultipliedBySquaring(57, 179, -3)" - ) - assertEquals( - "(57 + ((179 + 179) + (179 + 179)))", - addMultipliedByDoubling(Expr("57"), Expr("179"), 4).expr, - "tried addMultipliedBySquaring(57, 179, 4)" - ) - assertEquals( - "(57 + ((-179 + -179) + (-179 + -179)))", - addMultipliedByDoubling(Expr("57"), Expr("179"), -4).expr, - "tried addMultipliedBySquaring(57, 179, -4)" - ) - assertEquals( - "((57 + 179) + ((179 + 179) + (179 + 179)))", - addMultipliedByDoubling(Expr("57"), Expr("179"), 5).expr, - "tried addMultipliedBySquaring(57, 179, 5)" - ) - assertEquals( - "((57 + -179) + ((-179 + -179) + (-179 + -179)))", - addMultipliedByDoubling(Expr("57"), Expr("179"), -5).expr, - "tried addMultipliedBySquaring(57, 179, -5)" - ) - assertEquals( - "((57 + (179 + 179)) + ((179 + 179) + (179 + 179)))", - addMultipliedByDoubling(Expr("57"), Expr("179"), 6).expr, - "tried addMultipliedBySquaring(57, 179, 6)" - ) - assertEquals( - "((57 + (-179 + -179)) + ((-179 + -179) + (-179 + -179)))", - addMultipliedByDoubling(Expr("57"), Expr("179"), -6).expr, - "tried addMultipliedBySquaring(57, 179, -6)" - ) - assertEquals( - "(((57 + 179) + (179 + 179)) + ((179 + 179) + (179 + 179)))", - addMultipliedByDoubling(Expr("57"), Expr("179"), 7).expr, - "tried addMultipliedBySquaring(57, 179, 7)" - ) - assertEquals( - "(((57 + -179) + (-179 + -179)) + ((-179 + -179) + (-179 + -179)))", - addMultipliedByDoubling(Expr("57"), Expr("179"), -7).expr, - "tried addMultipliedBySquaring(57, 179, -7)" - ) - assertEquals( - "(57 + (((179 + 179) + (179 + 179)) + ((179 + 179) + (179 + 179))))", - addMultipliedByDoubling(Expr("57"), Expr("179"), 8).expr, - "tried addMultipliedBySquaring(57, 179, 8)" - ) - assertEquals( - "(57 + (((-179 + -179) + (-179 + -179)) + ((-179 + -179) + (-179 + -179))))", - addMultipliedByDoubling(Expr("57"), Expr("179"), -8).expr, - "tried addMultipliedBySquaring(57, 179, -8)" - ) - } - } - @Test - fun test_multiplyBySquaring_for_Int() { - ExprRing { - assertEquals( - "0", - multiplyByDoubling(Expr("57"), 0).expr, - "tried multiplyBySquaring(57, 0)" - ) - assertEquals( - "57", - multiplyByDoubling(Expr("57"), 1).expr, - "tried multiplyBySquaring(57, 1)" - ) - assertEquals( - "-57", - multiplyByDoubling(Expr("57"), -1).expr, - "tried multiplyBySquaring(57, -1)" - ) - assertEquals( - "(57 + 57)", - multiplyByDoubling(Expr("57"), 2).expr, - "tried multiplyBySquaring(57, 2)" - ) - assertEquals( - "(-57 + -57)", - multiplyByDoubling(Expr("57"), -2).expr, - "tried multiplyBySquaring(57, -2)" - ) - assertEquals( - "(57 + (57 + 57))", - multiplyByDoubling(Expr("57"), 3).expr, - "tried multiplyBySquaring(57, 3)" - ) - assertEquals( - "(-57 + (-57 + -57))", - multiplyByDoubling(Expr("57"), -3).expr, - "tried multiplyBySquaring(57, -3)" - ) - assertEquals( - "((57 + 57) + (57 + 57))", - multiplyByDoubling(Expr("57"), 4).expr, - "tried multiplyBySquaring(57, 4)" - ) - assertEquals( - "((-57 + -57) + (-57 + -57))", - multiplyByDoubling(Expr("57"), -4).expr, - "tried multiplyBySquaring(57, -4)" - ) - assertEquals( - "(57 + ((57 + 57) + (57 + 57)))", - multiplyByDoubling(Expr("57"), 5).expr, - "tried multiplyBySquaring(57, 5)" - ) - assertEquals( - "(-57 + ((-57 + -57) + (-57 + -57)))", - multiplyByDoubling(Expr("57"), -5).expr, - "tried multiplyBySquaring(57, -5)" - ) - assertEquals( - "((57 + 57) + ((57 + 57) + (57 + 57)))", - multiplyByDoubling(Expr("57"), 6).expr, - "tried multiplyBySquaring(57, 6)" - ) - assertEquals( - "((-57 + -57) + ((-57 + -57) + (-57 + -57)))", - multiplyByDoubling(Expr("57"), -6).expr, - "tried multiplyBySquaring(57, -6)" - ) - assertEquals( - "((57 + (57 + 57)) + ((57 + 57) + (57 + 57)))", - multiplyByDoubling(Expr("57"), 7).expr, - "tried multiplyBySquaring(57, 7)" - ) - assertEquals( - "((-57 + (-57 + -57)) + ((-57 + -57) + (-57 + -57)))", - multiplyByDoubling(Expr("57"), -7).expr, - "tried multiplyBySquaring(57, -7)" - ) - assertEquals( - "(((57 + 57) + (57 + 57)) + ((57 + 57) + (57 + 57)))", - multiplyByDoubling(Expr("57"), 8).expr, - "tried multiplyBySquaring(57, 8)" - ) - assertEquals( - "(((-57 + -57) + (-57 + -57)) + ((-57 + -57) + (-57 + -57)))", - multiplyByDoubling(Expr("57"), -8).expr, - "tried multiplyBySquaring(57, -8)" - ) - } - } @Test fun test_multiplyExponentiationBySquaring_for_UInt() { ExprRing { @@ -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)" - ) - } - } } \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt index e7d8dfd8c..117ffb579 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt @@ -7,252 +7,11 @@ package space.kscience.kmath.functions -import space.kscience.kmath.functions.testUtils.IntModuloRing -import space.kscience.kmath.functions.testUtils.ListPolynomial -import space.kscience.kmath.functions.testUtils.Rational -import space.kscience.kmath.functions.testUtils.RationalField +import space.kscience.kmath.functions.testUtils.* import kotlin.test.* class ListPolynomialTest { - @Test - fun test_Polynomial_Int_plus() { - RationalField.listPolynomialSpace { - assertEquals( - ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), - ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + -3, - "test 1" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + 2, - "test 2" - ) - assertEquals( - ListPolynomial(Rational(0)), - ListPolynomial(Rational(-2)) + 2, - "test 3" - ) - val polynomial_4 = ListPolynomial() - 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() + 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() - 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() - 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() - assertSame( - polynomial_4, - 0 + polynomial_4, - "test 4" - ) - val polynomial_5 = ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)) - assertSame( - polynomial_5, - 0 + polynomial_5, - "test 5" - ) - assertEquals( - ListPolynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), - 1 + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 6" - ) - assertEquals( - ListPolynomial(Rational(-1)), - 1 + ListPolynomial(Rational(-2)), - "test 7" - ) - assertEquals( - ListPolynomial(Rational(2)), - 2 + ListPolynomial(), - "test 8" - ) - } - } - @Test - fun test_Int_Polynomial_minus() { - RationalField.listPolynomialSpace { - assertEquals( - ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), - 3 - ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), - "test 1" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), - -2 - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 2" - ) - assertEquals( - ListPolynomial(Rational(0)), - -2 - ListPolynomial(Rational(-2)), - "test 3" - ) - assertEquals( - ListPolynomial(Rational(-32, 9), Rational(-8, -9), Rational(8, 7)), - 0 - ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), - "test 4" - ) - assertEquals( - ListPolynomial(), - 0 - ListPolynomial(), - "test 5" - ) - assertEquals( - ListPolynomial(Rational(1), Rational(0), Rational(0), Rational(0)), - -1 - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 6" - ) - assertEquals( - ListPolynomial(Rational(1)), - -1 - ListPolynomial(Rational(-2)), - "test 7" - ) - assertEquals( - ListPolynomial(Rational(-2)), - -2 - ListPolynomial(), - "test 8" - ) - } - } - @Test - fun test_Int_Polynomial_times() { - IntModuloRing(35).listPolynomialSpace { - assertEquals( - ListPolynomial(34, 2, 1, 20, 2), - 27 * ListPolynomial(22, 26, 13, 15, 26), - "test 1" - ) - assertEquals( - ListPolynomial(0, 0, 0, 0, 0), - 15 * ListPolynomial(7, 0, 49, 21, 14), - "test 2" - ) - val polynomial = ListPolynomial(22, 26, 13, 15, 26) - assertSame( - zero, - 0 * polynomial, - "test 3" - ) - assertSame( - polynomial, - 1 * polynomial, - "test 4" - ) - } - } @Test fun test_Polynomial_Constant_plus() { RationalField.listPolynomialSpace { @@ -338,12 +97,12 @@ class ListPolynomialTest { IntModuloRing(35).listPolynomialSpace { assertEquals( ListPolynomial(34, 2, 1, 20, 2), - ListPolynomial(22, 26, 13, 15, 26) * 27.asConstant(), + ListPolynomial(22, 26, 13, 15, 26) * m(27), "test 1" ) assertEquals( ListPolynomial(0, 0, 0, 0, 0), - ListPolynomial(7, 0, 49, 21, 14) * 15.asConstant(), + ListPolynomial(7, 0, 49, 21, 14) * m(15), "test 2" ) } @@ -433,12 +192,12 @@ class ListPolynomialTest { IntModuloRing(35).listPolynomialSpace { assertEquals( ListPolynomial(34, 2, 1, 20, 2), - 27 * ListPolynomial(22, 26, 13, 15, 26), + m(27) * ListPolynomial(22, 26, 13, 15, 26), "test 1" ) assertEquals( ListPolynomial(0, 0, 0, 0, 0), - 15 * ListPolynomial(7, 0, 49, 21, 14), + m(15) * ListPolynomial(7, 0, 49, 21, 14), "test 2" ) } diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt index 339643d02..153b0134b 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt @@ -5,11 +5,9 @@ package space.kscience.kmath.functions -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.functions.testUtils.Rational import space.kscience.kmath.functions.testUtils.RationalField -import space.kscience.kmath.functions.testUtils.assertFailsWithTypeAndMessage -import kotlin.test.Ignore +import space.kscience.kmath.misc.UnstableKMathAPI import kotlin.test.Test import kotlin.test.assertEquals @@ -88,754 +86,6 @@ class ListPolynomialUtilTest { ) } @Test - fun test_Polynomial_substitute_Polynomial() { - assertEquals( - ListPolynomial(Rational(0)), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).substitute(RationalField, ListPolynomial(Rational(1))), - "test 1" - ) - assertEquals( - ListPolynomial(Rational(709, 378), Rational(155, 252), Rational(19, 525), Rational(2, 875)), - ListPolynomial(Rational(1, 7), Rational(9, 4), Rational(1, 3), Rational(2, 7)) - .substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(1, 5))), - "test 2" - ) - assertEquals( - ListPolynomial(Rational(655, 378), Rational(155, 252), Rational(19, 525), Rational(2, 875)), - ListPolynomial(Rational(0), Rational(9, 4), Rational(1, 3), Rational(2, 7)) - .substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(1, 5))), - "test 3" - ) - assertEquals( - ListPolynomial(Rational(677, 378), Rational(97, 180), Rational(1, 75), Rational(0)), - ListPolynomial(Rational(1, 7), Rational(9, 4), Rational(1, 3), Rational(0)) - .substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(1, 5))), - "test 4" - ) - assertEquals( - ListPolynomial(Rational(653, 378), Rational(221, 420), Rational(4, 175), Rational(2, 875)), - ListPolynomial(Rational(1, 7), Rational(9, 4), Rational(0), Rational(2, 7)) - .substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(1, 5))), - "test 5" - ) - assertEquals( - ListPolynomial(Rational(89, 54), Rational(0), Rational(0), Rational(0)), - ListPolynomial(Rational(0), Rational(9, 4), Rational(1, 3), Rational(0)) - .substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(0))), - "test 6" - ) - } - @Test - @Ignore // FIXME: This tests work only for sane realisations of the substitutions. Currently, it is not. - // Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should return denominator r^deg(p), - // not r^(deg(p)(deg(p)+1)/2) as it is now. - fun test_Polynomial_substitute_RationalFunction() { - assertEquals( - ListRationalFunction(ListPolynomial(Rational(0)), ListPolynomial(Rational(1))), - ListPolynomial(Rational(1), Rational(-2), Rational(1)) - .substitute(RationalField, ListRationalFunction(ListPolynomial(Rational(1)), ListPolynomial(Rational(1)))), - "test 1" - ) - assertEquals( - ListRationalFunction( - ListPolynomial( - Rational(66349, 243), - Rational(-17873, 405), - Rational(173533, 3780), - Rational(-91141, 567), - Rational(5773909, 105840), - Rational(-23243, 630), - Rational(1573, 27) - ), - ListPolynomial( - Rational(169, 81), - Rational(-130, 27), - Rational(115, 18), - Rational(-797, 54), - Rational(1985, 144), - Rational(-55, 6), - Rational(121, 9) - ) - ), - ListPolynomial( - Rational(13, 3), - Rational(-9, 5), - Rational(5, 5) - ).substitute(RationalField, - ListRationalFunction( - ListPolynomial( - Rational(15, 1), - Rational(6, 9), - Rational(-3, 7) - ), - ListPolynomial( - Rational(-13, 9), - Rational(10, 6), - Rational(-10, 8), - Rational(11, 3) - ) - ) - ), - "test 2" - ) - assertEquals( - ListRationalFunction( - ListPolynomial( - Rational(0, 1), - Rational(0, 1), - Rational(-14, 9), - Rational(31, 14), - Rational(-5077, 980), - Rational(99, 35) - ), - ListPolynomial( - Rational(0, 1), - Rational(0, 1), - Rational(25, 9), - Rational(-25, 6), - Rational(1985, 144), - Rational(-55, 6), - Rational(121, 9) - ) - ), - ListPolynomial( - Rational(0), - Rational(-9, 5), - Rational(5, 5) - ).substitute(RationalField, - ListRationalFunction( - ListPolynomial( - Rational(0), - Rational(6, 9), - Rational(-3, 7) - ), - ListPolynomial( - Rational(0), - Rational(10, 6), - Rational(-10, 8), - Rational(11, 3) - ) - ) - ), - "test 3" - ) - assertEquals( - ListRationalFunction( - ListPolynomial( - Rational(-898, 27), - Rational(271, 45), - Rational(-65, 12) , - Rational(0), - Rational(0), - Rational(0), - Rational(0) - ), - ListPolynomial( - Rational(-13, 9), - Rational(5, 3), - Rational(-5, 4), - Rational(0), - Rational(0), - Rational(0), - Rational(0) - ) - ), - ListPolynomial( - Rational(13, 3), - Rational(-9, 5), - Rational(0) - ).substitute(RationalField, - ListRationalFunction( - ListPolynomial( - Rational(15, 1), - Rational(6, 9), - Rational(0) - ), - ListPolynomial( - Rational(-13, 9), - Rational(10, 6), - Rational(-10, 8), - Rational(0) - ) - ) - ), - "test 4" - ) - assertEquals( - ListRationalFunction( - ListPolynomial( - Rational(56872, 243), - Rational(0, 1), - Rational(-90, 7), - Rational(-3718, 81), - Rational(9, 49), - Rational(0, 1), - Rational(1573, 27) - ), - ListPolynomial( - Rational(169, 81), - Rational(0, 1), - Rational(0, 1), - Rational(-286, 27), - Rational(0, 1), - Rational(0, 1), - Rational(121, 9) - ) - ), - ListPolynomial( - Rational(13, 3), - Rational(0), - Rational(5, 5) - ).substitute(RationalField, - ListRationalFunction( - ListPolynomial( - Rational(15, 1), - Rational(0), - Rational(-3, 7) - ), - ListPolynomial( - Rational(-13, 9), - Rational(0), - Rational(0), - Rational(11, 3) - ) - ) - ), - "test 5" - ) - } - @Test - fun test_RationalFunction_substitute_Double() { - assertEquals( - 0.0, - ListRationalFunction( - ListPolynomial(1.0, -2.0, 1.0), - ListPolynomial(-6.302012278484357, 5.831971885376948, -9.271604788393432, 5.494387848015814, -3.7187384450880785) - ).substitute(1.0), - 0.001, - "test 1" - ) - assertEquals( - 2.693702616649797, - ListRationalFunction( - ListPolynomial(-5.848840571263625, -1.660411278951134, -3.793740946372443, -9.624569269490076), - ListPolynomial(-2.9680680215311073, -1.862973627119981, 4.776550592888336, -2.7320154512368466) - ).substitute(-7.53452770353279), - 0.001, - "test 2" - ) - assertEquals( - 2.692226268901378, - ListRationalFunction( - ListPolynomial(0.0, -1.660411278951134, -3.793740946372443, -9.624569269490076), - ListPolynomial(0.0, -1.862973627119981, 4.776550592888336, -2.7320154512368466) - ).substitute(-7.53452770353279), - 0.001, - "test 3" - ) - assertEquals( - -0.7394904842099175, - ListRationalFunction( - ListPolynomial(-5.848840571263625, -1.660411278951134, -3.793740946372443, 0.0), - ListPolynomial(-2.9680680215311073, -1.862973627119981, 4.776550592888336, 0.0) - ).substitute(-7.53452770353279), - 0.001, - "test 4" - ) - assertEquals( - 3.526835209398159, - ListRationalFunction( - ListPolynomial(-5.848840571263625, 0.0, 0.0, -9.624569269490076), - ListPolynomial(-2.9680680215311073, 0.0, 0.0, -2.7320154512368466) - ).substitute(-7.53452770353279), - 0.001, - "test 5" - ) - } - @Test - fun test_RationalFunction_substitute_Constant() { - assertEquals( - Rational(0), - ListRationalFunction( - ListPolynomial(Rational(1), Rational(-2), Rational(1)), - ListPolynomial(Rational(1)), - ).substitute(RationalField, Rational(1)), - "test 1" - ) - assertEquals( - Rational(1149615, 61306), - ListRationalFunction( - ListPolynomial(Rational(17, 7), Rational(18, 3), Rational(18, 8), Rational(9, 1)), - ListPolynomial(Rational(11, 9), Rational(-6, 5), Rational(-12, 7), Rational(2, 1)), - ).substitute(RationalField, Rational(-7, 8)), - "test 2" - ) - assertEquals( - Rational(3495, 586), - ListRationalFunction( - ListPolynomial(Rational(0), Rational(18, 3), Rational(18, 8), Rational(9, 1)), - ListPolynomial(Rational(0), Rational(-6, 5), Rational(-12, 7), Rational(2, 1)), - ).substitute(RationalField, Rational(-7, 8)), - "test 3" - ) - assertEquals( - Rational(-88605, 77392), - ListRationalFunction( - ListPolynomial(Rational(17, 7), Rational(18, 3), Rational(18, 8), Rational(0)), - ListPolynomial(Rational(11, 9), Rational(-6, 5), Rational(-12, 7), Rational(0)), - ).substitute(RationalField, Rational(-7, 8)), - "test 4" - ) - assertEquals( - Rational(116145, 3794), - ListRationalFunction( - ListPolynomial(Rational(17, 7), Rational(0), Rational(0), Rational(9, 1)), - ListPolynomial(Rational(11, 9), Rational(0), Rational(0), Rational(2, 1)), - ).substitute(RationalField, Rational(-7, 8)), - "test 5" - ) - } - @Test - fun test_RationalFunction_substitute_Polynomial() { - assertEquals( - ListRationalFunction( - ListPolynomial(Rational(0)), - ListPolynomial(Rational(1)) - ), - ListRationalFunction( - ListPolynomial(Rational(1), Rational(-2), Rational(1)), - ListPolynomial(Rational(1)), - ).substitute(RationalField, ListPolynomial(Rational(1))), - "test 1" - ) - assertEquals( - ListRationalFunction( - ListPolynomial( - Rational(-283303, 36), - Rational(-23593, 24), - Rational(368713, 192), - Rational(1455, 8), - Rational(-272171, 1536), - Rational(-2149, 192), - Rational(469, 64), - Rational(11, 48), - Rational(-11, 96) - ), - ListPolynomial( - Rational(5797, 12), - Rational(595, 16), - Rational(-5285, 72), - Rational(-745, 192), - Rational(1105, 288), - Rational(5, 48), - Rational(-5, 72) - ) - ), - ListRationalFunction( - ListPolynomial( - Rational(2, 9), - Rational(11, 3), - Rational(-9, 4), - Rational(-6, 1), - Rational(-11, 6) - ), - ListPolynomial( - Rational(-2, 3), - Rational(-15, 4), - Rational(5, 9), - Rational(-5, 9) - ) - ).substitute(RationalField, - ListPolynomial( - Rational(-9, 1), - Rational(-1, 4), - Rational(2, 4) - ) - ), - "test 2" - ) - assertEquals( - ListRationalFunction( - ListPolynomial( - Rational(0, 1), - Rational(-11, 12), - Rational(325, 192), - Rational(21, 32), - Rational(-1739, 1536), - Rational(227, 192), - Rational(-59, 64), - Rational(11, 48), - Rational(-11, 96) - ), - ListPolynomial( - Rational(0, 1), - Rational(15, 16), - Rational(-265, 144), - Rational(-25, 192), - Rational(25, 288), - Rational(5, 48), - Rational(-5, 72) - ) - ), - ListRationalFunction( - ListPolynomial( - Rational(0, 9), - Rational(11, 3), - Rational(-9, 4), - Rational(-6, 1), - Rational(-11, 6) - ), - ListPolynomial( - Rational(0, 3), - Rational(-15, 4), - Rational(5, 9), - Rational(-5, 9) - ) - ).substitute(RationalField, - ListPolynomial( - Rational(0, 1), - Rational(-1, 4), - Rational(2, 4) - ) - ), - "test 3" - ) - assertEquals( - ListRationalFunction( - ListPolynomial( - Rational(149723, 36), - Rational(8483, 24), - Rational(639, 64), - Rational(3, 32), - Rational(0), - Rational(0), - Rational(0), - Rational(0), - Rational(0) - ), - ListPolynomial( - Rational(937, 12), - Rational(55, 16), - Rational(5, 144), - Rational(0), - Rational(0), - Rational(0), - Rational(0) - ) - ), - ListRationalFunction( - ListPolynomial( - Rational(2, 9), - Rational(11, 3), - Rational(-9, 4), - Rational(-6, 1), - Rational(0) - ), - ListPolynomial( - Rational(-2, 3), - Rational(-15, 4), - Rational(5, 9), - Rational(0) - ) - ).substitute(RationalField, - ListPolynomial( - Rational(-9, 1), - Rational(-1, 4), - Rational(0) - ) - ), - "test 4" - ) - assertEquals( - ListRationalFunction( - ListPolynomial( - Rational(-216509, 18), - Rational(0, 1), - Rational(2673, 1), - Rational(0, 1), - Rational(-891, 4), - Rational(0, 1), - Rational(33, 4), - Rational(0, 1), - Rational(-11, 96) - ), - ListPolynomial( - Rational(1213, 3), - Rational(0, 1), - Rational(-135, 2), - Rational(0, 1), - Rational(15, 4), - Rational(0, 1), - Rational(-5, 72) - ) - ), - ListRationalFunction( - ListPolynomial( - Rational(2, 9), - Rational(0), - Rational(0), - Rational(0), - Rational(-11, 6) - ), - ListPolynomial( - Rational(-2, 3), - Rational(0), - Rational(0), - Rational(-5, 9) - ) - ).substitute(RationalField, - ListPolynomial( - Rational(-9, 1), - Rational(0), - Rational(2, 4) - ) - ), - "test 5" - ) - } - @Test - @Ignore // FIXME: This tests work only for sane realisations of the substitutions. Currently, it is not. - // Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should return denominator r^deg(p), - // not r^(deg(p)(deg(p)+1)/2) as it is now. - fun test_RationalFunction_substitute_RationalFunction() { - assertEquals( - ListRationalFunction( - ListPolynomial(Rational(0)), - ListPolynomial(Rational(1)) - ), - ListRationalFunction( - ListPolynomial(Rational(1), Rational(-2), Rational(1)), - ListPolynomial(Rational(1)) - ).substitute(RationalField, - ListRationalFunction( - ListPolynomial(Rational(1)), - ListPolynomial(Rational(1)) - ) - ), - "test 1" - ) - assertEquals( - ListRationalFunction( - ListPolynomial( - Rational(130087, 3888), - Rational(-2866333, 65610), - Rational(-5076229, 97200), - Rational(222136997, 3280500), - Rational(754719329, 20995200), - Rational(-12010283, 324000), - Rational(-2011967, 172800), - Rational(18607, 2880), - Rational(4705, 4096) - ), - ListPolynomial( - Rational(-143820355, 3779136), - Rational(73886869, 1574640), - Rational(1440175193, 15746400), - Rational(-5308968857, 52488000), - Rational(-186910083731, 2099520000), - Rational(125043463, 1555200), - Rational(5299123, 388800), - Rational(-213757, 15360), - Rational(1380785, 147456) - ) - ), - ListRationalFunction( - ListPolynomial( - Rational(1, 1), - Rational(-10, 5), - Rational(18, 8), - Rational(-8, 8) - ), - ListPolynomial( - Rational(-14, 8), - Rational(-14, 8), - Rational(-19, 6), - Rational(14, 3), - Rational(8, 9) - ) - ).substitute(RationalField, - ListRationalFunction( - ListPolynomial( - Rational(14, 9), - Rational(-2, 5), - Rational(-14, 7) - ), - ListPolynomial( - Rational(-6, 4), - Rational(5, 9), - Rational(1, 8) - ) - ) - ), - "test 2" - ) - assertEquals( - ListRationalFunction( - ListPolynomial( - Rational(0, 1), - Rational(0, 1), - Rational(0, 1), - Rational(0, 1), - Rational(5173, 18225), - Rational(904291, 364500), - Rational(283127, 43200), - Rational(37189, 5760), - Rational(147, 128) - ), - ListPolynomial( - Rational(0, 1), - Rational(0, 1), - Rational(0, 1), - Rational(0, 1), - Rational(-163589, 911250), - Rational(-881831, 291600), - Rational(-10722229, 777600), - Rational(-640921, 46080), - Rational(86303, 9216) - ) - ), - ListRationalFunction( - ListPolynomial( - Rational(0), - Rational(-10, 5), - Rational(18, 8), - Rational(-8, 8) - ), - ListPolynomial( - Rational(0), - Rational(-14, 8), - Rational(-19, 6), - Rational(14, 3), - Rational(8, 9) - ) - ).substitute(RationalField, - ListRationalFunction( - ListPolynomial( - Rational(0), - Rational(-2, 5), - Rational(-14, 7) - ), - ListPolynomial( - Rational(0), - Rational(5, 9), - Rational(1, 8) - ) - ) - ), - "test 3" - ) - assertEquals( - ListRationalFunction( - ListPolynomial( - Rational(445, 16), - Rational(-2011, 54), - Rational(1359199, 72900), - Rational(-135733, 32805), - Rational(2254, 6561), - Rational(0, 1), - Rational(0, 1), - Rational(0, 1), - Rational(0, 1) - ), - ListPolynomial( - Rational(-2018387, 46656), - Rational(82316437, 1574640), - Rational(-9335047, 393660), - Rational(15765889, 3280500), - Rational(-242089, 656100), - Rational(0, 1), - Rational(0, 1), - Rational(0, 1), - Rational(0, 1) - ) - ), - ListRationalFunction( - ListPolynomial( - Rational(1, 1), - Rational(-10, 5), - Rational(18, 8), - Rational(0) - ), - ListPolynomial( - Rational(-14, 8), - Rational(-14, 8), - Rational(-19, 6), - Rational(14, 3), - Rational(0) - ) - ).substitute(RationalField, - ListRationalFunction( - ListPolynomial( - Rational(14, 9), - Rational(-2, 5), - Rational(0) - ), - ListPolynomial( - Rational(-6, 4), - Rational(5, 9), - Rational(0) - ) - ) - ), - "test 4" - ) - assertEquals( - ListRationalFunction( - ListPolynomial( - Rational(41635, 3888), - Rational(0, 1), - Rational(-279187, 11664), - Rational(0, 1), - Rational(103769, 3456), - Rational(0, 1), - Rational(-11017, 768), - Rational(0, 1), - Rational(4097, 4096) - ), - ListPolynomial( - Rational(-13811791, 3779136), - Rational(0, 1), - Rational(-9999395, 419904), - Rational(0, 1), - Rational(6376601, 124416), - Rational(0, 1), - Rational(-3668315, 82944), - Rational(0, 1), - Rational(2097089, 147456) - ) - ), - ListRationalFunction( - ListPolynomial( - Rational(1, 1), - Rational(0), - Rational(0), - Rational(-8, 8) - ), - ListPolynomial( - Rational(-14, 8), - Rational(0), - Rational(0), - Rational(0), - Rational(8, 9) - ) - ).substitute(RationalField, - ListRationalFunction( - ListPolynomial( - Rational(14, 9), - Rational(0), - Rational(-14, 7) - ), - ListPolynomial( - Rational(-6, 4), - Rational(0), - Rational(1, 8) - ) - ) - ), - "test 5" - ) - } - @Test fun test_Polynomial_derivative() { assertEquals( ListPolynomial(Rational(-2), Rational(2)), @@ -859,55 +109,6 @@ class ListPolynomialUtilTest { ) } @Test - fun test_Polynomial_nthDerivative() { - assertEquals( - ListPolynomial(Rational(-2), Rational(2)), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 1), - "test 1" - ) - assertFailsWithTypeAndMessage( - "Order of derivative must be non-negative", - "test2" - ) { - ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, -1) - } - assertEquals( - ListPolynomial(Rational(1), Rational(-2), Rational(1)), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 0), - "test 3" - ) - assertEquals( - ListPolynomial(Rational(2)), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 2), - "test 4" - ) - assertEquals( - ListPolynomial(), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 3), - "test 5" - ) - assertEquals( - ListPolynomial(), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 4), - "test 6" - ) - assertEquals( - ListPolynomial(Rational(8, 9), Rational(30, 7), Rational(-20, 3)), - ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthDerivative(RationalField, 2), - "test 7" - ) - assertEquals( - ListPolynomial(Rational(8, 9), Rational(30, 7), Rational(-20, 3)), - ListPolynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthDerivative(RationalField, 2), - "test 8" - ) - assertEquals( - ListPolynomial(Rational(8, 9), Rational(30, 7), Rational(0)), - ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).nthDerivative(RationalField, 2), - "test 9" - ) - } - @Test fun test_Polynomial_antiderivative() { assertEquals( ListPolynomial(Rational(0), Rational(1), Rational(-1), Rational(1, 3)), @@ -930,53 +131,4 @@ class ListPolynomialUtilTest { "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( - "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" - ) - } } \ No newline at end of file diff --git a/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt b/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt index 4b65fbea1..997a966a7 100644 --- a/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt +++ b/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt @@ -5,15 +5,14 @@ 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.PolynomialSpaceOverRing -public fun ListPolynomialSpace.ListPolynomial(vararg coefs: Int): ListPolynomial = - ListPolynomial(coefs.map { IntModulo(it, ring.modulus) }) -public fun IntModuloRing.ListPolynomial(vararg coefs: Int): ListPolynomial = - ListPolynomial(coefs.map { IntModulo(it, modulus) }) +public fun ListPolynomialSpace.ListPolynomial(vararg coefs: Int): Polynomial = + Polynomial(coefs.map { IntModulo(it, ring.modulus) }) +public fun IntModuloRing.ListPolynomial(vararg coefs: Int): Polynomial = + Polynomial(coefs.map { IntModulo(it, modulus) }) public fun IntModuloRing.m(arg: Int): IntModulo = IntModulo(arg, modulus) -public fun PolynomialSpaceOverRing.m(arg: Int): IntModulo = IntModulo(arg, ring.modulus) \ No newline at end of file +public fun ListPolynomialSpace.m(arg: Int): IntModulo = IntModulo(arg, ring.modulus) \ No newline at end of file