Feature: Polynomials and rational functions #469
@ -8,23 +8,19 @@ package space.kscience.kmath.functions
|
|||||||
import space.kscience.kmath.operations.Ring
|
import space.kscience.kmath.operations.Ring
|
||||||
import space.kscience.kmath.operations.ScaleOperations
|
import space.kscience.kmath.operations.ScaleOperations
|
||||||
import space.kscience.kmath.operations.invoke
|
import space.kscience.kmath.operations.invoke
|
||||||
import kotlin.contracts.InvocationKind
|
|
||||||
import kotlin.contracts.contract
|
|
||||||
import kotlin.experimental.ExperimentalTypeInference
|
|
||||||
import kotlin.jvm.JvmName
|
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Polynomial model without fixation on specific context they are applied to.
|
* Represents univariate polynomial that stores its coefficients in a [List].
|
||||||
*
|
*
|
||||||
* @param coefficients constant is the leftmost coefficient.
|
* @param coefficients constant is the leftmost coefficient.
|
||||||
*/
|
*/
|
||||||
public data class ListPolynomial<C>(
|
public data class ListPolynomial<C>(
|
||||||
/**
|
/**
|
||||||
* List that collects coefficients of the polynomial. Every monomial `a x^d` is represented as a coefficients
|
* List that contains coefficients of the polynomial. Every monomial `a x^d` is stored as a coefficient `a` placed
|
||||||
* `a` placed into the list with index `d`. For example coefficients of polynomial `5 x^2 - 6` can be represented as
|
* into the list at index `d`. For example, coefficients of a polynomial `5 x^2 - 6` can be represented as
|
||||||
* ```
|
* ```
|
||||||
* listOf(
|
* listOf(
|
||||||
* -6, // -6 +
|
* -6, // -6 +
|
||||||
@ -42,26 +38,28 @@ public data class ListPolynomial<C>(
|
|||||||
* 0, // 0 x^4
|
* 0, // 0 x^4
|
||||||
* )
|
* )
|
||||||
* ```
|
* ```
|
||||||
* It is recommended not to put extra zeros at end of the list (as for `0x^3` and `0x^4` in the example), but is not
|
* 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
|
||||||
* prohibited.
|
* longer the coefficients list the worse performance of arithmetical operations performed on it. Thus, it is
|
||||||
|
* recommended not to put (or even to remove) extra (or useless) coefficients at the end of the coefficients list.
|
||||||
*/
|
*/
|
||||||
public val coefficients: List<C>
|
public val coefficients: List<C>
|
||||||
) : Polynomial<C> {
|
) : Polynomial<C> {
|
||||||
override fun toString(): String = "Polynomial$coefficients"
|
override fun toString(): String = "ListPolynomial$coefficients"
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Space of univariate polynomials constructed over ring.
|
* Arithmetic context for univariate polynomials with coefficients stored as a [List] constructed with the given [ring]
|
||||||
|
* of constants.
|
||||||
*
|
*
|
||||||
* @param C the type of constants. Polynomials have them as a coefficients in their terms.
|
* @param C the type of constants. Polynomials have them a coefficients in their terms.
|
||||||
* @param A type of underlying ring of constants. It's [Ring] of [C].
|
* @param A type of provided underlying ring of constants. It's [Ring] of [C].
|
||||||
* @param ring underlying ring of constants of type [A].
|
* @param ring underlying ring of constants of type [A].
|
||||||
*/
|
*/
|
||||||
public open class ListPolynomialSpace<C, A : Ring<C>>(
|
public open class ListPolynomialSpace<C, A : Ring<C>>(
|
||||||
public override val ring: A,
|
public override val ring: A,
|
||||||
) : PolynomialSpaceOverRing<C, ListPolynomial<C>, A> {
|
) : PolynomialSpaceOverRing<C, ListPolynomial<C>, A> {
|
||||||
/**
|
/**
|
||||||
* Returns sum of the polynomial and the integer represented as polynomial.
|
* 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].
|
* The operation is equivalent to adding [other] copies of unit polynomial to [this].
|
||||||
*/
|
*/
|
||||||
@ -79,7 +77,7 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
/**
|
/**
|
||||||
* Returns difference between the polynomial and the integer represented as polynomial.
|
* 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].
|
* The operation is equivalent to subtraction [other] copies of unit polynomial from [this].
|
||||||
*/
|
*/
|
||||||
@ -97,7 +95,7 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
/**
|
/**
|
||||||
* Returns product of the polynomial and the integer represented as polynomial.
|
* Returns product of the polynomial and the integer represented as a polynomial.
|
||||||
*
|
*
|
||||||
* The operation is equivalent to sum of [other] copies of [this].
|
* The operation is equivalent to sum of [other] copies of [this].
|
||||||
*/
|
*/
|
||||||
@ -112,7 +110,7 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
|
|||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns sum of the integer represented as polynomial and the polynomial.
|
* 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].
|
* The operation is equivalent to adding [this] copies of unit polynomial to [other].
|
||||||
*/
|
*/
|
||||||
@ -130,7 +128,7 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
/**
|
/**
|
||||||
* Returns difference between the integer represented as polynomial and the polynomial.
|
* 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].
|
* The operation is equivalent to subtraction [this] copies of unit polynomial from [other].
|
||||||
*/
|
*/
|
||||||
@ -150,7 +148,7 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
/**
|
/**
|
||||||
* Returns product of the integer represented as polynomial and the polynomial.
|
* Returns product of the integer represented as a polynomial and the polynomial.
|
||||||
*
|
*
|
||||||
* The operation is equivalent to sum of [this] copies of [other].
|
* The operation is equivalent to sum of [this] copies of [other].
|
||||||
*/
|
*/
|
||||||
@ -170,7 +168,7 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
|
|||||||
public override fun number(value: Int): ListPolynomial<C> = number(constantNumber(value))
|
public override fun number(value: Int): ListPolynomial<C> = number(constantNumber(value))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns sum of the constant represented as polynomial and the polynomial.
|
* Returns sum of the constant represented as a polynomial and the polynomial.
|
||||||
*/
|
*/
|
||||||
public override operator fun C.plus(other: ListPolynomial<C>): ListPolynomial<C> =
|
public override operator fun C.plus(other: ListPolynomial<C>): ListPolynomial<C> =
|
||||||
with(other.coefficients) {
|
with(other.coefficients) {
|
||||||
@ -186,7 +184,7 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Returns difference between the constant represented as polynomial and the polynomial.
|
* Returns difference between the constant represented as a polynomial and the polynomial.
|
||||||
*/
|
*/
|
||||||
public override operator fun C.minus(other: ListPolynomial<C>): ListPolynomial<C> =
|
public override operator fun C.minus(other: ListPolynomial<C>): ListPolynomial<C> =
|
||||||
with(other.coefficients) {
|
with(other.coefficients) {
|
||||||
@ -204,7 +202,7 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Returns product of the constant represented as polynomial and the polynomial.
|
* Returns product of the constant represented as a polynomial and the polynomial.
|
||||||
*/
|
*/
|
||||||
public override operator fun C.times(other: ListPolynomial<C>): ListPolynomial<C> =
|
public override operator fun C.times(other: ListPolynomial<C>): ListPolynomial<C> =
|
||||||
ListPolynomial(
|
ListPolynomial(
|
||||||
@ -216,7 +214,7 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
|
|||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns sum of the constant represented as polynomial and the polynomial.
|
* Returns sum of the constant represented as a polynomial and the polynomial.
|
||||||
*/
|
*/
|
||||||
public override operator fun ListPolynomial<C>.plus(other: C): ListPolynomial<C> =
|
public override operator fun ListPolynomial<C>.plus(other: C): ListPolynomial<C> =
|
||||||
with(coefficients) {
|
with(coefficients) {
|
||||||
@ -232,7 +230,7 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Returns difference between the constant represented as polynomial and the polynomial.
|
* Returns difference between the constant represented as a polynomial and the polynomial.
|
||||||
*/
|
*/
|
||||||
public override operator fun ListPolynomial<C>.minus(other: C): ListPolynomial<C> =
|
public override operator fun ListPolynomial<C>.minus(other: C): ListPolynomial<C> =
|
||||||
with(coefficients) {
|
with(coefficients) {
|
||||||
@ -248,7 +246,7 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Returns product of the constant represented as polynomial and the polynomial.
|
* Returns product of the constant represented as a polynomial and the polynomial.
|
||||||
*/
|
*/
|
||||||
public override operator fun ListPolynomial<C>.times(other: C): ListPolynomial<C> =
|
public override operator fun ListPolynomial<C>.times(other: C): ListPolynomial<C> =
|
||||||
ListPolynomial(
|
ListPolynomial(
|
||||||
@ -262,7 +260,7 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
|
|||||||
/**
|
/**
|
||||||
* Converts the constant [value] to polynomial.
|
* Converts the constant [value] to polynomial.
|
||||||
*/
|
*/
|
||||||
public override fun number(value: C): ListPolynomial<C> = ListPolynomial(value)
|
public override fun number(value: C): ListPolynomial<C> = ListPolynomial(listOf(value))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns negation of the polynomial.
|
* Returns negation of the polynomial.
|
||||||
@ -321,9 +319,9 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
|
|||||||
*/
|
*/
|
||||||
override val zero: ListPolynomial<C> = ListPolynomial(emptyList())
|
override val zero: ListPolynomial<C> = ListPolynomial(emptyList())
|
||||||
/**
|
/**
|
||||||
* Instance of unit constant (unit of the underlying ring).
|
* Instance of unit polynomial (unit of the polynomial ring).
|
||||||
*/
|
*/
|
||||||
override val one: ListPolynomial<C> = ListPolynomial(listOf(constantOne))
|
override val one: ListPolynomial<C> by lazy { ListPolynomial(listOf(constantOne)) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is
|
* Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is
|
||||||
@ -331,23 +329,43 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
|
|||||||
*/
|
*/
|
||||||
public override val ListPolynomial<C>.degree: Int get() = coefficients.lastIndex
|
public override val ListPolynomial<C>.degree: Int get() = coefficients.lastIndex
|
||||||
|
|
||||||
|
// TODO: When context receivers will be ready move all of this substitutions and invocations to utilities with
|
||||||
|
// [ListPolynomialSpace] as a context receiver
|
||||||
|
/**
|
||||||
|
* Evaluates value of [this] polynomial on provided argument.
|
||||||
|
*/
|
||||||
@Suppress("NOTHING_TO_INLINE")
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
public inline fun ListPolynomial<C>.substitute(argument: C): C = this.substitute(ring, argument)
|
public inline fun ListPolynomial<C>.substitute(argument: C): C = this.substitute(ring, argument)
|
||||||
|
/**
|
||||||
|
* Substitutes provided polynomial [argument] into [this] polynomial.
|
||||||
|
*/
|
||||||
@Suppress("NOTHING_TO_INLINE")
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
public inline fun ListPolynomial<C>.substitute(argument: ListPolynomial<C>): ListPolynomial<C> = this.substitute(ring, argument)
|
public inline fun ListPolynomial<C>.substitute(argument: ListPolynomial<C>): ListPolynomial<C> = this.substitute(ring, argument)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represent [this] polynomial as a regular context-less function.
|
||||||
|
*/
|
||||||
@Suppress("NOTHING_TO_INLINE")
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
public inline fun ListPolynomial<C>.asFunction(): (C) -> C = { this.substitute(ring, it) }
|
public inline fun ListPolynomial<C>.asFunction(): (C) -> C = { this.substitute(ring, it) }
|
||||||
|
/**
|
||||||
|
* Represent [this] polynomial as a regular context-less function.
|
||||||
|
*/
|
||||||
@Suppress("NOTHING_TO_INLINE")
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
public inline fun ListPolynomial<C>.asFunctionOnConstants(): (C) -> C = { this.substitute(ring, it) }
|
public inline fun ListPolynomial<C>.asFunctionOfConstant(): (C) -> C = { this.substitute(ring, it) }
|
||||||
|
/**
|
||||||
|
* Represent [this] polynomial as a regular context-less function.
|
||||||
|
*/
|
||||||
@Suppress("NOTHING_TO_INLINE")
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
public inline fun ListPolynomial<C>.asFunctionOnPolynomials(): (ListPolynomial<C>) -> ListPolynomial<C> = { this.substitute(ring, it) }
|
public inline fun ListPolynomial<C>.asFunctionOfPolynomial(): (ListPolynomial<C>) -> ListPolynomial<C> = { this.substitute(ring, it) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Evaluates the polynomial for the given value [argument].
|
* Evaluates value of [this] polynomial on provided [argument].
|
||||||
*/
|
*/
|
||||||
@Suppress("NOTHING_TO_INLINE")
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
public inline operator fun ListPolynomial<C>.invoke(argument: C): C = this.substitute(ring, argument)
|
public inline operator fun ListPolynomial<C>.invoke(argument: C): C = this.substitute(ring, argument)
|
||||||
|
/**
|
||||||
|
* Evaluates value of [this] polynomial on provided [argument].
|
||||||
|
*/
|
||||||
@Suppress("NOTHING_TO_INLINE")
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
public inline operator fun ListPolynomial<C>.invoke(argument: ListPolynomial<C>): ListPolynomial<C> = this.substitute(ring, argument)
|
public inline operator fun ListPolynomial<C>.invoke(argument: ListPolynomial<C>): ListPolynomial<C> = this.substitute(ring, argument)
|
||||||
}
|
}
|
||||||
|
@ -8,13 +8,23 @@ package space.kscience.kmath.functions
|
|||||||
import space.kscience.kmath.operations.Ring
|
import space.kscience.kmath.operations.Ring
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents rational function that stores its numerator and denominator as [ListPolynomial]s.
|
||||||
|
*/
|
||||||
public data class ListRationalFunction<C>(
|
public data class ListRationalFunction<C>(
|
||||||
public override val numerator: ListPolynomial<C>,
|
public override val numerator: ListPolynomial<C>,
|
||||||
public override val denominator: ListPolynomial<C>
|
public override val denominator: ListPolynomial<C>
|
||||||
) : RationalFunction<C, ListPolynomial<C>> {
|
) : RationalFunction<C, ListPolynomial<C>> {
|
||||||
override fun toString(): String = "RationalFunction${numerator.coefficients}/${denominator.coefficients}"
|
override fun toString(): String = "ListRationalFunction${numerator.coefficients}/${denominator.coefficients}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Arithmetic context for univariate rational functions with numerator and denominator represented as [ListPolynomial]s.
|
||||||
|
*
|
||||||
|
* @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 class ListRationalFunctionSpace<C, A : Ring<C>> (
|
public class ListRationalFunctionSpace<C, A : Ring<C>> (
|
||||||
public val ring: A,
|
public val ring: A,
|
||||||
) :
|
) :
|
||||||
@ -30,7 +40,13 @@ public class ListRationalFunctionSpace<C, A : Ring<C>> (
|
|||||||
ListRationalFunction<C>,
|
ListRationalFunction<C>,
|
||||||
>() {
|
>() {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Underlying polynomial ring. Its polynomial operations are inherited by local polynomial operations.
|
||||||
|
*/
|
||||||
override val polynomialRing : ListPolynomialSpace<C, A> = ListPolynomialSpace(ring)
|
override val polynomialRing : ListPolynomialSpace<C, A> = ListPolynomialSpace(ring)
|
||||||
|
/**
|
||||||
|
* Constructor of [ListRationalFunction] from numerator and denominator [ListPolynomial].
|
||||||
|
*/
|
||||||
override fun constructRationalFunction(numerator: ListPolynomial<C>, denominator: ListPolynomial<C>): ListRationalFunction<C> =
|
override fun constructRationalFunction(numerator: ListPolynomial<C>, denominator: ListPolynomial<C>): ListRationalFunction<C> =
|
||||||
ListRationalFunction(numerator, denominator)
|
ListRationalFunction(numerator, denominator)
|
||||||
|
|
||||||
@ -43,63 +59,88 @@ public class ListRationalFunctionSpace<C, A : Ring<C>> (
|
|||||||
*/
|
*/
|
||||||
public override val one: ListRationalFunction<C> = ListRationalFunction(polynomialOne, polynomialOne)
|
public override val one: ListRationalFunction<C> = ListRationalFunction(polynomialOne, polynomialOne)
|
||||||
|
|
||||||
// TODO: Разобрать
|
// 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.
|
||||||
|
*/
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
public inline fun ListPolynomial<C>.substitute(argument: C): C = this.substitute(ring, argument)
|
||||||
|
/**
|
||||||
|
* Substitutes provided polynomial [argument] into [this] polynomial.
|
||||||
|
*/
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
public inline fun ListPolynomial<C>.substitute(argument: ListPolynomial<C>): ListPolynomial<C> = this.substitute(ring, argument)
|
||||||
|
/**
|
||||||
|
* Substitutes provided rational function [argument] into [this] polynomial.
|
||||||
|
*/
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
public inline fun ListPolynomial<C>.substitute(argument: ListRationalFunction<C>): ListRationalFunction<C> = this.substitute(ring, argument)
|
||||||
|
/**
|
||||||
|
* Substitutes provided polynomial [argument] into [this] rational function.
|
||||||
|
*/
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
public inline fun ListRationalFunction<C>.substitute(argument: ListPolynomial<C>): ListRationalFunction<C> = this.substitute(ring, argument)
|
||||||
|
/**
|
||||||
|
* Substitutes provided rational function [argument] into [this] rational function.
|
||||||
|
*/
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
public inline fun ListRationalFunction<C>.substitute(argument: ListRationalFunction<C>): ListRationalFunction<C> = this.substitute(ring, argument)
|
||||||
|
|
||||||
// operator fun invoke(arg: UnivariatePolynomial<T>): RationalFunction<T> =
|
/**
|
||||||
// RationalFunction(
|
* Represent [this] polynomial as a regular context-less function.
|
||||||
// numerator(arg),
|
*/
|
||||||
// denominator(arg)
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
// )
|
public inline fun ListPolynomial<C>.asFunction(): (C) -> C = { this.substitute(ring, it) }
|
||||||
//
|
/**
|
||||||
// operator fun invoke(arg: RationalFunction<T>): RationalFunction<T> {
|
* Represent [this] polynomial as a regular context-less function.
|
||||||
// val num = numerator invokeRFTakeNumerator arg
|
*/
|
||||||
// val den = denominator invokeRFTakeNumerator arg
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
// val degreeDif = numeratorDegree - denominatorDegree
|
public inline fun ListPolynomial<C>.asFunctionOfConstant(): (C) -> C = { this.substitute(ring, it) }
|
||||||
// return if (degreeDif > 0)
|
/**
|
||||||
// RationalFunction(
|
* Represent [this] polynomial as a regular context-less function.
|
||||||
// num,
|
*/
|
||||||
// multiplyByPower(den, arg.denominator, degreeDif)
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
// )
|
public inline fun ListPolynomial<C>.asFunctionOfPolynomial(): (ListPolynomial<C>) -> ListPolynomial<C> = { this.substitute(ring, it) }
|
||||||
// else
|
/**
|
||||||
// RationalFunction(
|
* Represent [this] polynomial as a regular context-less function.
|
||||||
// multiplyByPower(num, arg.denominator, -degreeDif),
|
*/
|
||||||
// den
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
// )
|
public inline fun ListPolynomial<C>.asFunctionOfRationalFunction(): (ListRationalFunction<C>) -> ListRationalFunction<C> = { this.substitute(ring, it) }
|
||||||
// }
|
/**
|
||||||
//
|
* Represent [this] rational function as a regular context-less function.
|
||||||
// override fun toString(): String = toString(UnivariatePolynomial.variableName)
|
*/
|
||||||
//
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
// fun toString(withVariableName: String = UnivariatePolynomial.variableName): String =
|
public inline fun ListRationalFunction<C>.asFunctionOfPolynomial(): (ListPolynomial<C>) -> ListRationalFunction<C> = { this.substitute(ring, it) }
|
||||||
// when(true) {
|
/**
|
||||||
// numerator.isZero() -> "0"
|
* Represent [this] rational function as a regular context-less function.
|
||||||
// denominator.isOne() -> numerator.toString(withVariableName)
|
*/
|
||||||
// else -> "${numerator.toStringWithBrackets(withVariableName)}/${denominator.toStringWithBrackets(withVariableName)}"
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
// }
|
public inline fun ListRationalFunction<C>.asFunctionOfRationalFunction(): (ListRationalFunction<C>) -> ListRationalFunction<C> = { this.substitute(ring, it) }
|
||||||
//
|
|
||||||
// fun toStringWithBrackets(withVariableName: String = UnivariatePolynomial.variableName): String =
|
/**
|
||||||
// when(true) {
|
* Evaluates value of [this] polynomial on provided argument.
|
||||||
// numerator.isZero() -> "0"
|
*/
|
||||||
// denominator.isOne() -> numerator.toStringWithBrackets(withVariableName)
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
// else -> "(${numerator.toStringWithBrackets(withVariableName)}/${denominator.toStringWithBrackets(withVariableName)})"
|
public inline operator fun ListPolynomial<C>.invoke(argument: C): C = this.substitute(ring, argument)
|
||||||
// }
|
/**
|
||||||
//
|
* Evaluates value of [this] polynomial on provided argument.
|
||||||
// fun toReversedString(withVariableName: String = UnivariatePolynomial.variableName): String =
|
*/
|
||||||
// when(true) {
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
// numerator.isZero() -> "0"
|
public inline operator fun ListPolynomial<C>.invoke(argument: ListPolynomial<C>): ListPolynomial<C> = this.substitute(ring, argument)
|
||||||
// denominator.isOne() -> numerator.toReversedString(withVariableName)
|
/**
|
||||||
// else -> "${numerator.toReversedStringWithBrackets(withVariableName)}/${denominator.toReversedStringWithBrackets(withVariableName)}"
|
* Evaluates value of [this] polynomial on provided argument.
|
||||||
// }
|
*/
|
||||||
//
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
// fun toReversedStringWithBrackets(withVariableName: String = UnivariatePolynomial.variableName): String =
|
public inline operator fun ListPolynomial<C>.invoke(argument: ListRationalFunction<C>): ListRationalFunction<C> = this.substitute(ring, argument)
|
||||||
// when(true) {
|
/**
|
||||||
// numerator.isZero() -> "0"
|
* Evaluates value of [this] rational function on provided argument.
|
||||||
// denominator.isOne() -> numerator.toReversedStringWithBrackets(withVariableName)
|
*/
|
||||||
// else -> "(${numerator.toReversedStringWithBrackets(withVariableName)}/${denominator.toReversedStringWithBrackets(withVariableName)})"
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
// }
|
public inline operator fun ListRationalFunction<C>.invoke(argument: ListPolynomial<C>): ListRationalFunction<C> = this.substitute(ring, argument)
|
||||||
//
|
/**
|
||||||
// fun removeZeros() =
|
* Evaluates value of [this] rational function on provided argument.
|
||||||
// RationalFunction(
|
*/
|
||||||
// numerator.removeZeros(),
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
// denominator.removeZeros()
|
public inline operator fun ListRationalFunction<C>.invoke(argument: ListRationalFunction<C>): ListRationalFunction<C> = this.substitute(ring, argument)
|
||||||
// )
|
|
||||||
}
|
}
|
@ -435,10 +435,12 @@ public interface MultivariatePolynomialSpace<C, V, P: Polynomial<C>>: Polynomial
|
|||||||
/**
|
/**
|
||||||
* Represents the [variable] as a monic monomial.
|
* Represents the [variable] as a monic monomial.
|
||||||
*/
|
*/
|
||||||
|
@JvmName("numberVariable")
|
||||||
public fun number(variable: V): P = +variable
|
public fun number(variable: V): P = +variable
|
||||||
/**
|
/**
|
||||||
* Represents the variable as a monic monomial.
|
* Represents the variable as a monic monomial.
|
||||||
*/
|
*/
|
||||||
|
@JvmName("asPolynomialVariable")
|
||||||
public fun V.asPolynomial(): P = number(this)
|
public fun V.asPolynomial(): P = number(this)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1060,12 +1060,12 @@ public abstract class PolynomialSpaceOfFractions<
|
|||||||
/**
|
/**
|
||||||
* Instance of zero rational function (zero of the rational functions ring).
|
* Instance of zero rational function (zero of the rational functions ring).
|
||||||
*/
|
*/
|
||||||
public override val zero: R get() = constructRationalFunction(polynomialZero)
|
public override val zero: R by lazy { constructRationalFunction(polynomialZero) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instance of unit polynomial (unit of the rational functions ring).
|
* Instance of unit polynomial (unit of the rational functions ring).
|
||||||
*/
|
*/
|
||||||
public override val one: R get() = constructRationalFunction(polynomialOne)
|
public override val one: R by lazy { constructRationalFunction(polynomialOne) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1177,19 +1177,23 @@ public interface MultivariateRationalFunctionalSpace<
|
|||||||
/**
|
/**
|
||||||
* Represents the [variable] as a monic monomial.
|
* Represents the [variable] as a monic monomial.
|
||||||
*/
|
*/
|
||||||
|
@JvmName("polynomialNumberVariable")
|
||||||
public fun polynomialNumber(variable: V): P = +variable
|
public fun polynomialNumber(variable: V): P = +variable
|
||||||
/**
|
/**
|
||||||
* Represents the variable as a monic monomial.
|
* Represents the variable as a monic monomial.
|
||||||
*/
|
*/
|
||||||
|
@JvmName("asPolynomialVariable")
|
||||||
public fun V.asPolynomial(): P = polynomialNumber(this)
|
public fun V.asPolynomial(): P = polynomialNumber(this)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the [variable] as a rational function.
|
* Represents the [variable] as a rational function.
|
||||||
*/
|
*/
|
||||||
|
@JvmName("numberVariable")
|
||||||
public fun number(variable: V): R = number(polynomialNumber(variable))
|
public fun number(variable: V): R = number(polynomialNumber(variable))
|
||||||
/**
|
/**
|
||||||
* Represents the variable as a rational function.
|
* Represents the variable as a rational function.
|
||||||
*/
|
*/
|
||||||
|
@JvmName("asRationalFunctionVariable")
|
||||||
public fun V.asRationalFunction(): R = number(this)
|
public fun V.asRationalFunction(): R = number(this)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1403,10 +1407,12 @@ public interface MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSp
|
|||||||
/**
|
/**
|
||||||
* Represents the [variable] as a monic monomial.
|
* Represents the [variable] as a monic monomial.
|
||||||
*/
|
*/
|
||||||
|
@JvmName("polynomialNumberVariable")
|
||||||
public override fun polynomialNumber(variable: V): P = polynomialRing { number(variable) }
|
public override fun polynomialNumber(variable: V): P = polynomialRing { number(variable) }
|
||||||
/**
|
/**
|
||||||
* Represents the variable as a monic monomial.
|
* Represents the variable as a monic monomial.
|
||||||
*/
|
*/
|
||||||
|
@JvmName("asPolynomialVariable")
|
||||||
public override fun V.asPolynomial(): P = polynomialRing { this@asPolynomial.asPolynomial() }
|
public override fun V.asPolynomial(): P = polynomialRing { this@asPolynomial.asPolynomial() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,233 +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.min
|
|
||||||
import kotlin.math.pow
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes zeros on the end of the coefficient list of polynomial.
|
|
||||||
*/
|
|
||||||
//context(PolynomialSpace<C, A>)
|
|
||||||
//fun <C, A: Ring<C>> Polynomial<C>.removeZeros() : Polynomial<C> =
|
|
||||||
// if (degree > -1) Polynomial(coefficients.subList(0, degree + 1)) else zero
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a [ListPolynomialSpace] over a received ring.
|
|
||||||
*/
|
|
||||||
public fun <C, A : Ring<C>> A.listPolynomial(): ListPolynomialSpace<C, A> =
|
|
||||||
ListPolynomialSpace(this)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a [ListPolynomialSpace]'s scope over a received ring.
|
|
||||||
*/
|
|
||||||
public inline fun <C, A : Ring<C>, R> A.listPolynomial(block: ListPolynomialSpace<C, A>.() -> R): R {
|
|
||||||
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
|
|
||||||
return ListPolynomialSpace(this).block()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a [ScalableListPolynomialSpace] over a received scalable ring.
|
|
||||||
*/
|
|
||||||
public fun <C, A> A.scalableListPolynomial(): ScalableListPolynomialSpace<C, A> where A : Ring<C>, A : ScaleOperations<C> =
|
|
||||||
ScalableListPolynomialSpace(this)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a [ScalableListPolynomialSpace]'s scope over a received scalable ring.
|
|
||||||
*/
|
|
||||||
public inline fun <C, A, R> A.scalableListPolynomial(block: ScalableListPolynomialSpace<C, A>.() -> R): R where A : Ring<C>, A : ScaleOperations<C> {
|
|
||||||
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
|
|
||||||
return ScalableListPolynomialSpace(this).block()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("NOTHING_TO_INLINE")
|
|
||||||
internal inline fun <C> copyTo(
|
|
||||||
origin: List<C>,
|
|
||||||
originDegree: Int,
|
|
||||||
target: MutableList<C>,
|
|
||||||
) {
|
|
||||||
for (deg in 0 .. originDegree) target[deg] = origin[deg]
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("NOTHING_TO_INLINE")
|
|
||||||
internal inline fun <C> multiplyAddingToUpdater(
|
|
||||||
ring: Ring<C>,
|
|
||||||
multiplicand: MutableList<C>,
|
|
||||||
multiplicandDegree: Int,
|
|
||||||
multiplier: List<C>,
|
|
||||||
multiplierDegree: Int,
|
|
||||||
updater: MutableList<C>,
|
|
||||||
zero: C,
|
|
||||||
) {
|
|
||||||
multiplyAddingTo(
|
|
||||||
ring = ring,
|
|
||||||
multiplicand = multiplicand,
|
|
||||||
multiplicandDegree = multiplicandDegree,
|
|
||||||
multiplier = multiplier,
|
|
||||||
multiplierDegree = multiplierDegree,
|
|
||||||
target = updater
|
|
||||||
)
|
|
||||||
for (updateDeg in 0 .. multiplicandDegree + multiplierDegree) {
|
|
||||||
multiplicand[updateDeg] = updater[updateDeg]
|
|
||||||
updater[updateDeg] = zero
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("NOTHING_TO_INLINE")
|
|
||||||
internal inline fun <C> multiplyAddingTo(
|
|
||||||
ring: Ring<C>,
|
|
||||||
multiplicand: List<C>,
|
|
||||||
multiplicandDegree: Int,
|
|
||||||
multiplier: List<C>,
|
|
||||||
multiplierDegree: Int,
|
|
||||||
target: MutableList<C>
|
|
||||||
) = ring {
|
|
||||||
for (d in 0 .. multiplicandDegree + multiplierDegree)
|
|
||||||
for (k in max(0, d - multiplierDegree)..min(multiplicandDegree, d))
|
|
||||||
target[d] += multiplicand[k] * multiplier[d - k]
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Evaluates the value of the given double polynomial for given double argument.
|
|
||||||
*/
|
|
||||||
public fun ListPolynomial<Double>.substitute(arg: Double): Double =
|
|
||||||
coefficients.reduceIndexedOrNull { index, acc, c ->
|
|
||||||
acc + c * arg.pow(index)
|
|
||||||
} ?: .0
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Evaluates the value of the given polynomial for given argument.
|
|
||||||
*
|
|
||||||
* It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method).
|
|
||||||
*/
|
|
||||||
public fun <C> ListPolynomial<C>.substitute(ring: Ring<C>, arg: C): C = ring {
|
|
||||||
if (coefficients.isEmpty()) return@ring zero
|
|
||||||
var result: C = coefficients.last()
|
|
||||||
for (j in coefficients.size - 2 downTo 0) {
|
|
||||||
result = (arg * result) + coefficients[j]
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
public fun <C> ListPolynomial<C>.substitute(ring: Ring<C>, arg: ListPolynomial<C>) : ListPolynomial<C> = ring {
|
|
||||||
if (coefficients.isEmpty()) return ListPolynomial(emptyList())
|
|
||||||
|
|
||||||
val thisDegree = coefficients.lastIndex
|
|
||||||
if (thisDegree == -1) return ListPolynomial(emptyList())
|
|
||||||
val argDegree = arg.coefficients.lastIndex
|
|
||||||
if (argDegree == -1) return coefficients[0].asListPolynomial()
|
|
||||||
val constantZero = zero
|
|
||||||
val resultCoefs: MutableList<C> = MutableList(thisDegree * argDegree + 1) { constantZero }
|
|
||||||
resultCoefs[0] = coefficients[thisDegree]
|
|
||||||
val resultCoefsUpdate: MutableList<C> = MutableList(thisDegree * argDegree + 1) { constantZero }
|
|
||||||
var resultDegree = 0
|
|
||||||
for (deg in thisDegree - 1 downTo 0) {
|
|
||||||
resultCoefsUpdate[0] = coefficients[deg]
|
|
||||||
multiplyAddingToUpdater(
|
|
||||||
ring = ring,
|
|
||||||
multiplicand = resultCoefs,
|
|
||||||
multiplicandDegree = resultDegree,
|
|
||||||
multiplier = arg.coefficients,
|
|
||||||
multiplierDegree = argDegree,
|
|
||||||
updater = resultCoefsUpdate,
|
|
||||||
zero = constantZero
|
|
||||||
)
|
|
||||||
resultDegree += argDegree
|
|
||||||
}
|
|
||||||
|
|
||||||
return ListPolynomial<C>(resultCoefs)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represent the polynomial as a regular context-less function.
|
|
||||||
*/
|
|
||||||
public fun <C, A : Ring<C>> ListPolynomial<C>.asFunction(ring: A): (C) -> C = { substitute(ring, it) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represent the polynomial as a regular context-less function.
|
|
||||||
*/
|
|
||||||
public fun <C, A : Ring<C>> ListPolynomial<C>.asPolynomialFunctionOver(ring: A): (ListPolynomial<C>) -> ListPolynomial<C> = { substitute(ring, it) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns algebraic derivative of received polynomial.
|
|
||||||
*/
|
|
||||||
@UnstableKMathAPI
|
|
||||||
public fun <C, A> ListPolynomial<C>.derivative(
|
|
||||||
algebra: A,
|
|
||||||
): ListPolynomial<C> where A : Ring<C>, A : NumericAlgebra<C> = algebra {
|
|
||||||
ListPolynomial(
|
|
||||||
buildList(max(0, coefficients.size - 1)) {
|
|
||||||
for (deg in 1 .. coefficients.lastIndex) add(number(deg) * coefficients[deg])
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns algebraic derivative of received polynomial.
|
|
||||||
*/
|
|
||||||
@UnstableKMathAPI
|
|
||||||
public fun <C, A> ListPolynomial<C>.nthDerivative(
|
|
||||||
algebra: A,
|
|
||||||
order: Int,
|
|
||||||
): ListPolynomial<C> where A : Ring<C>, A : NumericAlgebra<C> = algebra {
|
|
||||||
require(order >= 0) { "Order of derivative must be non-negative" }
|
|
||||||
ListPolynomial(
|
|
||||||
buildList(max(0, coefficients.size - order)) {
|
|
||||||
for (deg in order.. coefficients.lastIndex)
|
|
||||||
add((deg - order + 1 .. deg).fold(coefficients[deg]) { acc, d -> acc * number(d) })
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns algebraic antiderivative of received polynomial.
|
|
||||||
*/
|
|
||||||
@UnstableKMathAPI
|
|
||||||
public fun <C, A> ListPolynomial<C>.antiderivative(
|
|
||||||
algebra: A,
|
|
||||||
): ListPolynomial<C> where A : Field<C>, A : NumericAlgebra<C> = algebra {
|
|
||||||
ListPolynomial(
|
|
||||||
buildList(coefficients.size + 1) {
|
|
||||||
add(zero)
|
|
||||||
coefficients.mapIndexedTo(this) { index, t -> t / number(index + 1) }
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns algebraic antiderivative of received polynomial.
|
|
||||||
*/
|
|
||||||
@UnstableKMathAPI
|
|
||||||
public fun <C, A> ListPolynomial<C>.nthAntiderivative(
|
|
||||||
algebra: A,
|
|
||||||
order: Int,
|
|
||||||
): ListPolynomial<C> where A : Field<C>, A : NumericAlgebra<C> = algebra {
|
|
||||||
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) } }
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compute a definite integral of a given polynomial in a [range]
|
|
||||||
*/
|
|
||||||
@UnstableKMathAPI
|
|
||||||
public fun <C : Comparable<C>> ListPolynomial<C>.integrate(
|
|
||||||
algebra: Field<C>,
|
|
||||||
range: ClosedRange<C>,
|
|
||||||
): C = algebra {
|
|
||||||
val integral = antiderivative(algebra)
|
|
||||||
integral.substitute(algebra, range.endInclusive) - integral.substitute(algebra, range.start)
|
|
||||||
}
|
|
@ -0,0 +1,268 @@
|
|||||||
|
/*
|
||||||
|
* 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 fun <C, A : Ring<C>> A.listPolynomialSpace(): ListPolynomialSpace<C, A> =
|
||||||
|
ListPolynomialSpace(this)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a [ListPolynomialSpace]'s scope over a received ring.
|
||||||
|
*/ // TODO: When context will be ready move [ListPolynomialSpace] and add [A] to context receivers of [block]
|
||||||
|
public inline fun <C, A : Ring<C>, R> A.listPolynomialSpace(block: ListPolynomialSpace<C, A>.() -> R): R {
|
||||||
|
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
|
||||||
|
return ListPolynomialSpace(this).block()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a [ScalableListPolynomialSpace] over a received scalable ring.
|
||||||
|
*/
|
||||||
|
public fun <C, A> A.scalableListPolynomialSpace(): ScalableListPolynomialSpace<C, A> where A : Ring<C>, A : ScaleOperations<C> =
|
||||||
|
ScalableListPolynomialSpace(this)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a [ScalableListPolynomialSpace]'s scope over a received scalable ring.
|
||||||
|
*/ // TODO: When context will be ready move [ListPolynomialSpace] and add [A] to context receivers of [block]
|
||||||
|
public inline fun <C, A, R> A.scalableListPolynomialSpace(block: ScalableListPolynomialSpace<C, A>.() -> R): R where A : Ring<C>, A : ScaleOperations<C> {
|
||||||
|
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
|
||||||
|
return ScalableListPolynomialSpace(this).block()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a [ListRationalFunctionSpace] over a received ring.
|
||||||
|
*/
|
||||||
|
public fun <C, A : Ring<C>> A.listRationalFunctionSpace(): ListRationalFunctionSpace<C, A> =
|
||||||
|
ListRationalFunctionSpace(this)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a [ListRationalFunctionSpace]'s scope over a received ring.
|
||||||
|
*/ // TODO: When context will be ready move [ListRationalFunctionSpace] and add [A] to context receivers of [block]
|
||||||
|
public inline fun <C, A : Ring<C>, R> A.listRationalFunctionSpace(block: ListRationalFunctionSpace<C, A>.() -> R): R {
|
||||||
|
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
|
||||||
|
return ListRationalFunctionSpace(this).block()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Evaluates value of [this] Double polynomial on provided Double argument.
|
||||||
|
*/
|
||||||
|
public fun ListPolynomial<Double>.substitute(arg: Double): Double =
|
||||||
|
coefficients.reduceIndexedOrNull { index, acc, c ->
|
||||||
|
acc + c * arg.pow(index)
|
||||||
|
} ?: .0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Evaluates value of [this] polynomial on provided argument.
|
||||||
|
*
|
||||||
|
* It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method).
|
||||||
|
*/
|
||||||
|
public fun <C> ListPolynomial<C>.substitute(ring: Ring<C>, arg: C): C = ring {
|
||||||
|
if (coefficients.isEmpty()) return zero
|
||||||
|
var result: C = coefficients.last()
|
||||||
|
for (j in coefficients.size - 2 downTo 0) {
|
||||||
|
result = (arg * result) + coefficients[j]
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Substitutes provided polynomial [arg] into [this] polynomial.
|
||||||
|
*
|
||||||
|
* It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method).
|
||||||
|
*/ // TODO: To optimize boxing
|
||||||
|
public fun <C> ListPolynomial<C>.substitute(ring: Ring<C>, arg: ListPolynomial<C>) : ListPolynomial<C> =
|
||||||
|
ring.listPolynomialSpace {
|
||||||
|
if (coefficients.isEmpty()) return zero
|
||||||
|
var result: ListPolynomial<C> = coefficients.last().asPolynomial()
|
||||||
|
for (j in coefficients.size - 2 downTo 0) {
|
||||||
|
result = (arg * result) + coefficients[j]
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Substitutes provided rational function [arg] into [this] polynomial.
|
||||||
|
*
|
||||||
|
* It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method).
|
||||||
|
*/ // TODO: To optimize boxing
|
||||||
|
public fun <C> ListPolynomial<C>.substitute(ring: Ring<C>, arg: ListRationalFunction<C>) : ListRationalFunction<C> =
|
||||||
|
ring.listRationalFunctionSpace {
|
||||||
|
if (coefficients.isEmpty()) return zero
|
||||||
|
var result: ListRationalFunction<C> = coefficients.last().asRationalFunction()
|
||||||
|
for (j in coefficients.size - 2 downTo 0) {
|
||||||
|
result = (arg * result) + coefficients[j]
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Evaluates value of [this] Double rational function in provided Double argument.
|
||||||
|
*/
|
||||||
|
public fun ListRationalFunction<Double>.substitute(arg: Double): Double =
|
||||||
|
numerator.substitute(arg) / denominator.substitute(arg)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Evaluates value of [this] polynomial for provided argument.
|
||||||
|
*
|
||||||
|
* It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method).
|
||||||
|
*/
|
||||||
|
public fun <C> ListRationalFunction<C>.substitute(ring: Field<C>, arg: C): C = ring {
|
||||||
|
numerator.substitute(ring, arg) / denominator.substitute(ring, arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Substitutes provided polynomial [arg] into [this] rational function.
|
||||||
|
*/ // TODO: To optimize boxing
|
||||||
|
public fun <C> ListRationalFunction<C>.substitute(ring: Ring<C>, arg: ListPolynomial<C>) : ListRationalFunction<C> =
|
||||||
|
ring.listRationalFunctionSpace {
|
||||||
|
numerator.substitute(ring, arg) / denominator.substitute(ring, arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Substitutes provided rational function [arg] into [this] rational function.
|
||||||
|
*/ // TODO: To optimize boxing
|
||||||
|
public fun <C> ListRationalFunction<C>.substitute(ring: Ring<C>, arg: ListRationalFunction<C>) : ListRationalFunction<C> =
|
||||||
|
ring.listRationalFunctionSpace {
|
||||||
|
numerator.substitute(ring, arg) / denominator.substitute(ring, arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represent [this] polynomial as a regular context-less function.
|
||||||
|
*/
|
||||||
|
public fun <C, A : Ring<C>> ListPolynomial<C>.asFunctionOver(ring: A): (C) -> C = { substitute(ring, it) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represent [this] polynomial as a regular context-less function.
|
||||||
|
*/
|
||||||
|
public fun <C, A : Ring<C>> ListPolynomial<C>.asPolynomialFunctionOver(ring: A): (ListPolynomial<C>) -> ListPolynomial<C> = { substitute(ring, it) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represent [this] polynomial as a regular context-less function.
|
||||||
|
*/
|
||||||
|
public fun <C, A : Ring<C>> ListPolynomial<C>.asFunctionOfRationalFunctionOver(ring: A): (ListPolynomial<C>) -> ListPolynomial<C> = { substitute(ring, it) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represent [this] rational function as a regular context-less function.
|
||||||
|
*/
|
||||||
|
public fun <C, A : Field<C>> ListRationalFunction<C>.asFunctionOver(ring: A): (C) -> C = { substitute(ring, it) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represent [this] rational function as a regular context-less function.
|
||||||
|
*/
|
||||||
|
public fun <C, A : Ring<C>> ListRationalFunction<C>.asPolynomialFunctionOver(ring: A): (ListPolynomial<C>) -> ListRationalFunction<C> = { substitute(ring, it) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represent [this] rational function as a regular context-less function.
|
||||||
|
*/
|
||||||
|
public fun <C, A : Ring<C>> ListRationalFunction<C>.asFunctionOfRationalFunctionOver(ring: A): (ListPolynomial<C>) -> ListRationalFunction<C> = { substitute(ring, it) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns algebraic derivative of received polynomial.
|
||||||
|
*/
|
||||||
|
@UnstableKMathAPI
|
||||||
|
public fun <C, A> ListPolynomial<C>.derivative(
|
||||||
|
ring: A,
|
||||||
|
): ListPolynomial<C> where A : Ring<C>, A : NumericAlgebra<C> = ring {
|
||||||
|
ListPolynomial(
|
||||||
|
buildList(max(0, coefficients.size - 1)) {
|
||||||
|
for (deg in 1 .. coefficients.lastIndex) add(number(deg) * coefficients[deg])
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns algebraic derivative of received polynomial of specified [order]. The [order] should be non-negative integer.
|
||||||
|
*/
|
||||||
|
@UnstableKMathAPI
|
||||||
|
public fun <C, A> ListPolynomial<C>.nthDerivative(
|
||||||
|
ring: A,
|
||||||
|
order: Int,
|
||||||
|
): ListPolynomial<C> where A : Ring<C>, A : NumericAlgebra<C> = ring {
|
||||||
|
require(order >= 0) { "Order of derivative must be non-negative" }
|
||||||
|
ListPolynomial(
|
||||||
|
buildList(max(0, coefficients.size - order)) {
|
||||||
|
for (deg in order.. coefficients.lastIndex)
|
||||||
|
add((deg - order + 1 .. deg).fold(coefficients[deg]) { acc, d -> acc * number(d) })
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns algebraic antiderivative of received polynomial.
|
||||||
|
*/
|
||||||
|
@UnstableKMathAPI
|
||||||
|
public fun <C, A> ListPolynomial<C>.antiderivative(
|
||||||
|
ring: A,
|
||||||
|
): ListPolynomial<C> where A : Field<C>, A : NumericAlgebra<C> = ring {
|
||||||
|
ListPolynomial(
|
||||||
|
buildList(coefficients.size + 1) {
|
||||||
|
add(zero)
|
||||||
|
coefficients.mapIndexedTo(this) { index, t -> t / number(index + 1) }
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns algebraic antiderivative of received polynomial of specified [order]. The [order] should be non-negative integer.
|
||||||
|
*/
|
||||||
|
@UnstableKMathAPI
|
||||||
|
public fun <C, A> ListPolynomial<C>.nthAntiderivative(
|
||||||
|
ring: A,
|
||||||
|
order: Int,
|
||||||
|
): ListPolynomial<C> where A : Field<C>, A : NumericAlgebra<C> = ring {
|
||||||
|
require(order >= 0) { "Order of antiderivative must be non-negative" }
|
||||||
|
ListPolynomial(
|
||||||
|
buildList(coefficients.size + order) {
|
||||||
|
repeat(order) { add(zero) }
|
||||||
|
coefficients.mapIndexedTo(this) { index, c -> (1..order).fold(c) { acc, i -> acc / number(index + i) } }
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes a definite integral of [this] polynomial in the specified [range].
|
||||||
|
*/
|
||||||
|
@UnstableKMathAPI
|
||||||
|
public fun <C : Comparable<C>> ListPolynomial<C>.integrate(
|
||||||
|
ring: Field<C>,
|
||||||
|
range: ClosedRange<C>,
|
||||||
|
): C = ring {
|
||||||
|
val antiderivative = antiderivative(ring)
|
||||||
|
antiderivative.substitute(ring, range.endInclusive) - antiderivative.substitute(ring, range.start)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns algebraic derivative of received rational function.
|
||||||
|
*/
|
||||||
|
@UnstableKMathAPI
|
||||||
|
public fun <C, A> ListRationalFunction<C>.derivative(
|
||||||
|
ring: A,
|
||||||
|
): ListRationalFunction<C> where A : Ring<C>, A : NumericAlgebra<C> = ring.listRationalFunctionSpace {
|
||||||
|
ListRationalFunction(
|
||||||
|
numerator.derivative(ring) * denominator - numerator * denominator.derivative(ring),
|
||||||
|
denominator * denominator
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns algebraic derivative of received rational function of specified [order]. The [order] should be non-negative integer.
|
||||||
|
*/
|
||||||
|
@UnstableKMathAPI
|
||||||
|
public tailrec fun <C, A> ListRationalFunction<C>.nthDerivative(
|
||||||
|
ring: A,
|
||||||
|
order: Int,
|
||||||
|
): ListRationalFunction<C> where A : Ring<C>, A : NumericAlgebra<C> =
|
||||||
|
if (order == 0) this else derivative(ring).nthDerivative(ring, order - 1)
|
@ -5,41 +5,91 @@
|
|||||||
|
|
||||||
package space.kscience.kmath.functions
|
package space.kscience.kmath.functions
|
||||||
|
|
||||||
import space.kscience.kmath.operations.Field
|
|
||||||
import space.kscience.kmath.operations.Ring
|
import space.kscience.kmath.operations.Ring
|
||||||
import space.kscience.kmath.operations.invoke
|
import space.kscience.kmath.operations.invoke
|
||||||
import kotlin.contracts.InvocationKind
|
|
||||||
import kotlin.contracts.contract
|
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
|
import kotlin.math.min
|
||||||
|
|
||||||
|
|
||||||
/**
|
// TODO: Optimized copies of substitution and invocation
|
||||||
* Creates a [ListRationalFunctionSpace] over a received ring.
|
@UnstablePolynomialBoxingOptimization
|
||||||
*/
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
public fun <C, A : Ring<C>> A.listRationalFunction(): ListRationalFunctionSpace<C, A> =
|
internal inline fun <C> copyTo(
|
||||||
ListRationalFunctionSpace(this)
|
origin: List<C>,
|
||||||
|
originDegree: Int,
|
||||||
/**
|
target: MutableList<C>,
|
||||||
* Creates a [ListRationalFunctionSpace]'s scope over a received ring.
|
) {
|
||||||
*/
|
for (deg in 0 .. originDegree) target[deg] = origin[deg]
|
||||||
public inline fun <C, A : Ring<C>, R> A.listRationalFunction(block: ListRationalFunctionSpace<C, A>.() -> R): R {
|
|
||||||
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
|
|
||||||
return ListRationalFunctionSpace(this).block()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@UnstablePolynomialBoxingOptimization
|
||||||
* Evaluates the value of the given double polynomial for given double argument.
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
*/
|
internal inline fun <C> multiplyAddingToUpdater(
|
||||||
public fun ListRationalFunction<Double>.substitute(arg: Double): Double =
|
ring: Ring<C>,
|
||||||
numerator.substitute(arg) / denominator.substitute(arg)
|
multiplicand: MutableList<C>,
|
||||||
|
multiplicandDegree: Int,
|
||||||
|
multiplier: List<C>,
|
||||||
|
multiplierDegree: Int,
|
||||||
|
updater: MutableList<C>,
|
||||||
|
zero: C,
|
||||||
|
) {
|
||||||
|
multiplyAddingTo(
|
||||||
|
ring = ring,
|
||||||
|
multiplicand = multiplicand,
|
||||||
|
multiplicandDegree = multiplicandDegree,
|
||||||
|
multiplier = multiplier,
|
||||||
|
multiplierDegree = multiplierDegree,
|
||||||
|
target = updater
|
||||||
|
)
|
||||||
|
for (updateDeg in 0 .. multiplicandDegree + multiplierDegree) {
|
||||||
|
multiplicand[updateDeg] = updater[updateDeg]
|
||||||
|
updater[updateDeg] = zero
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
@UnstablePolynomialBoxingOptimization
|
||||||
* Evaluates the value of the given polynomial for given argument.
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
*
|
internal inline fun <C> multiplyAddingTo(
|
||||||
* It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method).
|
ring: Ring<C>,
|
||||||
*/
|
multiplicand: List<C>,
|
||||||
public fun <C> ListRationalFunction<C>.substitute(ring: Field<C>, arg: C): C = ring {
|
multiplicandDegree: Int,
|
||||||
numerator.substitute(ring, arg) / denominator.substitute(ring, arg)
|
multiplier: List<C>,
|
||||||
|
multiplierDegree: Int,
|
||||||
|
target: MutableList<C>
|
||||||
|
) = ring {
|
||||||
|
for (d in 0 .. multiplicandDegree + multiplierDegree)
|
||||||
|
for (k in max(0, d - multiplierDegree)..min(multiplicandDegree, d))
|
||||||
|
target[d] += multiplicand[k] * multiplier[d - k]
|
||||||
|
}
|
||||||
|
|
||||||
|
@UnstablePolynomialBoxingOptimization
|
||||||
|
public fun <C> ListPolynomial<C>.substitute2(ring: Ring<C>, arg: ListPolynomial<C>) : ListPolynomial<C> = ring {
|
||||||
|
if (coefficients.isEmpty()) return ListPolynomial(emptyList())
|
||||||
|
|
||||||
|
val thisDegree = coefficients.lastIndex
|
||||||
|
if (thisDegree == -1) return ListPolynomial(emptyList())
|
||||||
|
val argDegree = arg.coefficients.lastIndex
|
||||||
|
if (argDegree == -1) return coefficients[0].asListPolynomial()
|
||||||
|
val constantZero = zero
|
||||||
|
val resultCoefs: MutableList<C> = MutableList(thisDegree * argDegree + 1) { constantZero }
|
||||||
|
resultCoefs[0] = coefficients[thisDegree]
|
||||||
|
val resultCoefsUpdate: MutableList<C> = MutableList(thisDegree * argDegree + 1) { constantZero }
|
||||||
|
var resultDegree = 0
|
||||||
|
for (deg in thisDegree - 1 downTo 0) {
|
||||||
|
resultCoefsUpdate[0] = coefficients[deg]
|
||||||
|
multiplyAddingToUpdater(
|
||||||
|
ring = ring,
|
||||||
|
multiplicand = resultCoefs,
|
||||||
|
multiplicandDegree = resultDegree,
|
||||||
|
multiplier = arg.coefficients,
|
||||||
|
multiplierDegree = argDegree,
|
||||||
|
updater = resultCoefsUpdate,
|
||||||
|
zero = constantZero
|
||||||
|
)
|
||||||
|
resultDegree += argDegree
|
||||||
|
}
|
||||||
|
|
||||||
|
return ListPolynomial<C>(resultCoefs)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -52,6 +102,7 @@ public fun <C> ListRationalFunction<C>.substitute(ring: Field<C>, arg: C): C = r
|
|||||||
*
|
*
|
||||||
* Used in [ListPolynomial.substitute] and [ListRationalFunction.substitute] for performance optimisation.
|
* Used in [ListPolynomial.substitute] and [ListRationalFunction.substitute] for performance optimisation.
|
||||||
*/ // TODO: Дописать
|
*/ // TODO: Дописать
|
||||||
|
@UnstablePolynomialBoxingOptimization
|
||||||
internal fun <C> ListPolynomial<C>.substituteRationalFunctionTakeNumerator(ring: Ring<C>, arg: ListRationalFunction<C>): ListPolynomial<C> = ring {
|
internal fun <C> ListPolynomial<C>.substituteRationalFunctionTakeNumerator(ring: Ring<C>, arg: ListRationalFunction<C>): ListPolynomial<C> = ring {
|
||||||
if (coefficients.isEmpty()) return ListPolynomial(emptyList())
|
if (coefficients.isEmpty()) return ListPolynomial(emptyList())
|
||||||
|
|
||||||
@ -196,26 +247,4 @@ internal fun <C> ListPolynomial<C>.substituteRationalFunctionTakeNumerator(ring:
|
|||||||
end = thisDegree + 1
|
end = thisDegree + 1
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
//operator fun <T: Field<T>> RationalFunction<T>.invoke(arg: T): T = numerator(arg) / denominator(arg)
|
|
||||||
//
|
|
||||||
//fun <T: Field<T>> RationalFunction<T>.reduced(): RationalFunction<T> =
|
|
||||||
// polynomialGCD(numerator, denominator).let {
|
|
||||||
// RationalFunction(
|
|
||||||
// numerator / it,
|
|
||||||
// denominator / it
|
|
||||||
// )
|
|
||||||
// }
|
|
||||||
|
|
||||||
///**
|
|
||||||
// * Returns result of applying formal derivative to the polynomial.
|
|
||||||
// *
|
|
||||||
// * @param T Field where we are working now.
|
|
||||||
// * @return Result of the operator.
|
|
||||||
// */
|
|
||||||
//fun <T: Ring<T>> RationalFunction<T>.derivative() =
|
|
||||||
// RationalFunction(
|
|
||||||
// numerator.derivative() * denominator - denominator.derivative() * numerator,
|
|
||||||
// denominator * denominator
|
|
||||||
// )
|
|
@ -0,0 +1,13 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
|
||||||
|
@RequiresOptIn(
|
||||||
|
message = "It's copy of operation with optimized boxing. It's currently unstable.",
|
||||||
|
level = RequiresOptIn.Level.ERROR
|
||||||
|
)
|
||||||
|
internal annotation class UnstablePolynomialBoxingOptimization
|
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
package space.kscience.kmath.functions
|
package space.kscience.kmath.functions
|
||||||
|
|
||||||
|
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||||
import space.kscience.kmath.test.misc.Rational
|
import space.kscience.kmath.test.misc.Rational
|
||||||
import space.kscience.kmath.test.misc.RationalField
|
import space.kscience.kmath.test.misc.RationalField
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
@ -12,6 +13,7 @@ import kotlin.test.assertEquals
|
|||||||
import kotlin.test.assertFailsWith
|
import kotlin.test.assertFailsWith
|
||||||
|
|
||||||
|
|
||||||
|
@OptIn(UnstableKMathAPI::class)
|
||||||
class ListPolynomialUtilTest {
|
class ListPolynomialUtilTest {
|
||||||
@Test
|
@Test
|
||||||
fun test_substitute_Double() {
|
fun test_substitute_Double() {
|
||||||
|
@ -0,0 +1,135 @@
|
|||||||
|
/*
|
||||||
|
* 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.test.misc
|
||||||
|
|
||||||
|
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||||
|
import space.kscience.kmath.operations.Field
|
||||||
|
import space.kscience.kmath.operations.NumbersAddOps
|
||||||
|
|
||||||
|
class Rational {
|
||||||
|
companion object {
|
||||||
|
val ZERO: Rational = Rational(0L)
|
||||||
|
val ONE: Rational = Rational(1L)
|
||||||
|
}
|
||||||
|
|
||||||
|
val numerator: Long
|
||||||
|
val denominator: Long
|
||||||
|
|
||||||
|
internal constructor(numerator: Long, denominator: Long, toCheckInput: Boolean = true) {
|
||||||
|
if (toCheckInput) {
|
||||||
|
if (denominator == 0L) throw ArithmeticException("/ by zero")
|
||||||
|
|
||||||
|
val greatestCommonDivider = gcd(numerator, denominator).let { if (denominator < 0L) -it else it }
|
||||||
|
|
||||||
|
this.numerator = numerator / greatestCommonDivider
|
||||||
|
this.denominator = denominator / greatestCommonDivider
|
||||||
|
} else {
|
||||||
|
this.numerator = numerator
|
||||||
|
this.denominator = denominator
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(numerator: Int, denominator: Int) : this(numerator.toLong(), denominator.toLong(), true)
|
||||||
|
constructor(numerator: Int, denominator: Long) : this(numerator.toLong(), denominator, true)
|
||||||
|
constructor(numerator: Long, denominator: Int) : this(numerator, denominator.toLong(), true)
|
||||||
|
constructor(numerator: Long, denominator: Long) : this(numerator, denominator, true)
|
||||||
|
constructor(numerator: Int) : this(numerator.toLong(), 1L, false)
|
||||||
|
constructor(numerator: Long) : this(numerator, 1L, false)
|
||||||
|
|
||||||
|
operator fun unaryPlus(): Rational = this
|
||||||
|
operator fun unaryMinus(): Rational = Rational(-this.numerator, this.denominator)
|
||||||
|
operator fun plus(other: Rational): Rational =
|
||||||
|
Rational(
|
||||||
|
numerator * other.denominator + denominator * other.numerator,
|
||||||
|
denominator * other.denominator
|
||||||
|
)
|
||||||
|
operator fun plus(other: Int): Rational =
|
||||||
|
Rational(
|
||||||
|
numerator + denominator * other.toLong(),
|
||||||
|
denominator
|
||||||
|
)
|
||||||
|
operator fun plus(other: Long): Rational =
|
||||||
|
Rational(
|
||||||
|
numerator + denominator * other,
|
||||||
|
denominator
|
||||||
|
)
|
||||||
|
operator fun minus(other: Rational): Rational =
|
||||||
|
Rational(
|
||||||
|
numerator * other.denominator - denominator * other.numerator,
|
||||||
|
denominator * other.denominator
|
||||||
|
)
|
||||||
|
operator fun minus(other: Int): Rational =
|
||||||
|
Rational(
|
||||||
|
numerator - denominator * other.toLong(),
|
||||||
|
denominator
|
||||||
|
)
|
||||||
|
operator fun minus(other: Long): Rational =
|
||||||
|
Rational(
|
||||||
|
numerator - denominator * other,
|
||||||
|
denominator
|
||||||
|
)
|
||||||
|
operator fun times(other: Rational): Rational =
|
||||||
|
Rational(
|
||||||
|
numerator * other.numerator,
|
||||||
|
denominator * other.denominator
|
||||||
|
)
|
||||||
|
operator fun times(other: Int): Rational =
|
||||||
|
Rational(
|
||||||
|
numerator * other.toLong(),
|
||||||
|
denominator
|
||||||
|
)
|
||||||
|
operator fun times(other: Long): Rational =
|
||||||
|
Rational(
|
||||||
|
numerator * other,
|
||||||
|
denominator
|
||||||
|
)
|
||||||
|
operator fun div(other: Rational): Rational =
|
||||||
|
Rational(
|
||||||
|
numerator * other.denominator,
|
||||||
|
denominator * other.numerator
|
||||||
|
)
|
||||||
|
operator fun div(other: Int): Rational =
|
||||||
|
Rational(
|
||||||
|
numerator,
|
||||||
|
denominator * other.toLong()
|
||||||
|
)
|
||||||
|
operator fun div(other: Long): Rational =
|
||||||
|
Rational(
|
||||||
|
numerator,
|
||||||
|
denominator * other
|
||||||
|
)
|
||||||
|
override fun equals(other: Any?): Boolean =
|
||||||
|
when (other) {
|
||||||
|
is Rational -> numerator == other.numerator && denominator == other.denominator
|
||||||
|
is Int -> numerator == other && denominator == 1L
|
||||||
|
is Long -> numerator == other && denominator == 1L
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int = 31 * numerator.hashCode() + denominator.hashCode()
|
||||||
|
|
||||||
|
override fun toString(): String = if (denominator == 1L) "$numerator" else "$numerator/$denominator"
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE")
|
||||||
|
@OptIn(UnstableKMathAPI::class)
|
||||||
|
object RationalField : Field<Rational>, NumbersAddOps<Rational> {
|
||||||
|
override inline val zero: Rational get() = Rational.ZERO
|
||||||
|
override inline val one: Rational get() = Rational.ONE
|
||||||
|
|
||||||
|
override inline fun number(value: Number): Rational = Rational(value.toLong())
|
||||||
|
|
||||||
|
override inline fun add(left: Rational, right: Rational): Rational = left + right
|
||||||
|
override inline fun multiply(left: Rational, right: Rational): Rational = left * right
|
||||||
|
override inline fun divide(left: Rational, right: Rational): Rational = left / right
|
||||||
|
override inline fun scale(a: Rational, value: Double): Rational = a * number(value)
|
||||||
|
|
||||||
|
override inline fun Rational.unaryMinus(): Rational = -this
|
||||||
|
override inline fun Rational.plus(arg: Rational): Rational = this + arg
|
||||||
|
override inline fun Rational.minus(arg: Rational): Rational = this - arg
|
||||||
|
override inline fun Rational.times(arg: Rational): Rational = this * arg
|
||||||
|
override inline fun Rational.div(arg: Rational): Rational = this / arg
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
/*
|
||||||
|
* 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.test.misc
|
||||||
|
|
||||||
|
import kotlin.math.abs
|
||||||
|
|
||||||
|
|
||||||
|
tailrec fun gcd(a: Long, b: Long): Long = if (a == 0L) abs(b) else gcd(b % a, a)
|
Loading…
Reference in New Issue
Block a user