From 24944cdb1639bc6bec924510686052e979bb4561 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Wed, 16 Mar 2022 15:19:27 +0300 Subject: [PATCH] Added support of `power` function to abstract structures. Implemented exponentiation by squaring as default implementation of `power`. Updated docs in algebraicStub.kt and updated realisations in it. --- .../kmath/functions/AbstractPolynomial.kt | 39 ++++-- .../functions/AbstractRationalFunction.kt | 52 ++++++-- .../kscience/kmath/functions/algebraicStub.kt | 124 ++++++++++++++---- .../kmath/functions/labeledPolynomialUtil.kt | 16 +-- .../kmath/functions/numberedPolynomialUtil.kt | 16 +-- .../kmath/functions/polynomialUtil.kt | 2 +- 6 files changed, 181 insertions(+), 68 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt index 8bd8697e3..2d2d22fd3 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt @@ -71,19 +71,19 @@ public interface AbstractPolynomialSpace> : Ring

* * The operation is equivalent to adding [other] copies of unit polynomial to [this]. */ - public operator fun P.plus(other: Int): P = optimizedAddMultiplied(this, one, other) + public operator fun P.plus(other: Int): P = addMultipliedBySquaring(this, one, other) /** * Returns difference between the polynomial and the integer represented as polynomial. * * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. */ - public operator fun P.minus(other: Int): P = optimizedAddMultiplied(this, one, -other) + public operator fun P.minus(other: Int): P = addMultipliedBySquaring(this, one, -other) /** * Returns product of the polynomial and the integer represented as polynomial. * * The operation is equivalent to sum of [other] copies of [this]. */ - public operator fun P.times(other: Int): P = optimizedMultiply(this, other) + public operator fun P.times(other: Int): P = multiplyBySquaring(this, other) // endregion // region Integer-polynomial relation @@ -92,19 +92,19 @@ public interface AbstractPolynomialSpace> : Ring

* * The operation is equivalent to adding [this] copies of unit polynomial to [other]. */ - public operator fun Int.plus(other: P): P = optimizedAddMultiplied(other, one, this) + public operator fun Int.plus(other: P): P = addMultipliedBySquaring(other, one, this) /** * Returns difference between the integer represented as polynomial and the polynomial. * * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. */ - public operator fun Int.minus(other: P): P = optimizedAddMultiplied(-other, one, this) + public operator fun Int.minus(other: P): P = addMultipliedBySquaring(-other, one, this) /** * Returns product of the integer represented as polynomial and the polynomial. * * The operation is equivalent to sum of [this] copies of [other]. */ - public operator fun Int.times(other: P): P = optimizedMultiply(other, this) + public operator fun Int.times(other: P): P = multiplyBySquaring(other, this) // endregion // region Constant-constant relation @@ -138,6 +138,12 @@ public interface AbstractPolynomialSpace> : Ring

@JvmName("constantTimes") @JsName("constantTimes") public operator fun C.times(other: C): C + /** + * Raises [arg] to the integer power [exponent]. + */ + @JvmName("constantPower") + @JsName("constantPower") + public fun power(arg: C, exponent: UInt) : C /** * Check if the instant is zero constant. @@ -225,6 +231,10 @@ public interface AbstractPolynomialSpace> : Ring

* Returns product of the polynomials. */ public override operator fun P.times(other: P): P + /** + * Raises [arg] to the integer power [exponent]. + */ + public override fun power(arg: P, exponent: UInt) : P = exponentiationBySquaring(arg, exponent) /** * Check if the instant is zero polynomial. @@ -331,19 +341,19 @@ public interface AbstractPolynomialSpaceOverRing, A: * * 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 { optimizedAddMultiplied(this@plus, one, other) } + public override operator fun C.plus(other: Int): C = ring { addMultipliedBySquaring(this@plus, one, other) } /** * Returns difference between the constant and the integer represented as constant (member of underlying ring). * * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. */ - public override operator fun C.minus(other: Int): C = ring { optimizedAddMultiplied(this@minus, one, -other) } + public override operator fun C.minus(other: Int): C = ring { addMultipliedBySquaring(this@minus, one, -other) } /** * Returns product of the constant and the integer represented as constant (member of underlying ring). * * The operation is equivalent to sum of [other] copies of [this]. */ - public override operator fun C.times(other: Int): C = ring { optimizedMultiply(this@times, other) } + public override operator fun C.times(other: Int): C = ring { multiplyBySquaring(this@times, other) } // endregion // region Integer-constant relation @@ -352,19 +362,19 @@ public interface AbstractPolynomialSpaceOverRing, A: * * 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 { optimizedAddMultiplied(other, one, this@plus) } + public override operator fun Int.plus(other: C): C = ring { addMultipliedBySquaring(other, one, this@plus) } /** * Returns difference between the integer represented as constant (member of underlying ring) and the constant. * * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. */ - public override operator fun Int.minus(other: C): C = ring { optimizedAddMultiplied(-other, one, this@minus) } + public override operator fun Int.minus(other: C): C = ring { addMultipliedBySquaring(-other, one, this@minus) } /** * Returns product of the integer represented as constant (member of underlying ring) and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ - public override operator fun Int.times(other: C): C = ring { optimizedMultiply(other, this@times) } + public override operator fun Int.times(other: C): C = ring { multiplyBySquaring(other, this@times) } // endregion // region Constant-constant relation @@ -388,6 +398,11 @@ public interface AbstractPolynomialSpaceOverRing, A: */ @JvmName("constantTimes") public override operator fun C.times(other: C): C = ring { this@times * other } + /** + * Raises [arg] to the integer power [exponent]. + */ + @JvmName("constantPower") + override fun power(arg: C, exponent: UInt): C = ring { power(arg, exponent) } /** * Instance of zero constant (zero of the underlying ring). diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt index 685cf4ca3..c6f1d7a7a 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt @@ -120,19 +120,19 @@ public interface AbstractRationalFunctionalSpace, R: * * The operation is equivalent to adding [other] copies of unit polynomial to [this]. */ - public operator fun R.plus(other: Int): R = optimizedAddMultiplied(this, one, other) + public operator fun R.plus(other: Int): R = addMultipliedBySquaring(this, one, other) /** * Returns difference between the rational function and the integer represented as rational function. * * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. */ - public operator fun R.minus(other: Int): R = optimizedAddMultiplied(this, one, -other) + public operator fun R.minus(other: Int): R = addMultipliedBySquaring(this, one, -other) /** * Returns product of the rational function and the integer represented as rational function. * * The operation is equivalent to sum of [other] copies of [this]. */ - public operator fun R.times(other: Int): R = optimizedMultiply(this, other) + public operator fun R.times(other: Int): R = multiplyBySquaring(this, other) // endregion // region Integer-Rational relation @@ -141,19 +141,19 @@ public interface AbstractRationalFunctionalSpace, R: * * The operation is equivalent to adding [this] copies of unit polynomial to [other]. */ - public operator fun Int.plus(other: R): R = optimizedAddMultiplied(other, one, this) + public operator fun Int.plus(other: R): R = addMultipliedBySquaring(other, one, this) /** * Returns difference between the integer represented as rational function and the rational function. * * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. */ - public operator fun Int.minus(other: R): R = optimizedAddMultiplied(-other, one, this) + public operator fun Int.minus(other: R): R = addMultipliedBySquaring(-other, one, this) /** * Returns product of the integer represented as rational function and the rational function. * * The operation is equivalent to sum of [this] copies of [other]. */ - public operator fun Int.times(other: R): R = optimizedMultiply(other, this) + public operator fun Int.times(other: R): R = multiplyBySquaring(other, this) // endregion // region Constant-constant relation @@ -187,6 +187,12 @@ public interface AbstractRationalFunctionalSpace, R: @JvmName("constantTimes") @JsName("constantTimes") public operator fun C.times(other: C): C + /** + * Raises [arg] to the integer power [exponent]. + */ + @JvmName("constantPower") + @JsName("constantPower") + public fun power(arg: C, exponent: UInt) : C /** * Check if the instant is zero constant. @@ -274,6 +280,10 @@ public interface AbstractRationalFunctionalSpace, R: * Returns product of the polynomials. */ public operator fun P.times(other: P): P + /** + * Raises [arg] to the integer power [exponent]. + */ + public fun power(arg: P, exponent: UInt) : P /** * Check if the instant is zero polynomial. @@ -400,6 +410,10 @@ public interface AbstractRationalFunctionalSpace, R: * Returns product of the rational functions. */ public override operator fun R.times(other: R): R + /** + * Raises [arg] to the integer power [exponent]. + */ + public override fun power(arg: R, exponent: UInt) : R = exponentiationBySquaring(arg, exponent) /** * Check if the instant is zero rational function. @@ -536,19 +550,19 @@ public interface AbstractRationalFunctionalSpaceOverRing Group.optimizedMultiply(arg: C, other: Int): C = - if (other >= 0) optimizedMultiply(arg, other.toUInt()) - else optimizedMultiply(arg, (-other).toUInt()) +internal fun Group.multiplyBySquaring(arg: C, multiplier: Int): C = + if (multiplier >= 0) multiplyBySquaring(arg, multiplier.toUInt()) + else multiplyBySquaring(-arg, (-multiplier).toUInt()) // TODO: Move receiver to context receiver /** * Adds product of [arg] and [multiplier] to [base]. * - * @receiver the algebra to provide multiplication. * @param base the augend. * @param arg the multiplicand. - * @param multiplier the multiplier. + * @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 Group.optimizedAddMultiplied(base: C, arg: C, multiplier: Int): C = - if (multiplier >= 0) optimizedAddMultiplied(base, arg, multiplier.toUInt()) - else optimizedAddMultiplied(base, arg, (-multiplier).toUInt()) +internal fun GroupOps.addMultipliedBySquaring(base: C, arg: C, multiplier: Int): C = + if (multiplier >= 0) addMultipliedBySquaring(base, arg, multiplier.toUInt()) + else addMultipliedBySquaring(base, -arg, (-multiplier).toUInt()) // TODO: Move receiver to context receiver /** - * Multiplication of element and integer. + * Returns product of [arg] and integer [multiplier]. * - * @receiver the multiplicand. - * @param other the multiplier. - * @return the difference. + * 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.optimizedMultiply(arg: C, other: UInt): C = +internal tailrec fun Group.multiplyBySquaring(arg: C, multiplier: UInt): C = when { - other == 0u -> zero - other == 1u -> arg - other % 2u == 0u -> optimizedMultiply(arg + arg, other / 2u) - other % 2u == 1u -> optimizedAddMultiplied(arg, arg + arg, other / 2u) + multiplier == 0u -> zero + multiplier == 1u -> arg + multiplier and 1u == 0u -> multiplyBySquaring(arg + arg, multiplier shr 1) + multiplier and 1u == 1u -> addMultipliedBySquaring(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") } @@ -59,18 +60,87 @@ internal tailrec fun Group.optimizedMultiply(arg: C, other: UInt): C = /** * Adds product of [arg] and [multiplier] to [base]. * - * @receiver the algebra to provide multiplication. + * 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 multiplier. + * @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 Group.optimizedAddMultiplied(base: C, arg: C, multiplier: UInt): C = +internal tailrec fun GroupOps.addMultipliedBySquaring(base: C, arg: C, multiplier: UInt): C = when { multiplier == 0u -> base multiplier == 1u -> base + arg - multiplier % 2u == 0u -> optimizedAddMultiplied(base, arg + arg, multiplier / 2u) - multiplier % 2u == 1u -> optimizedAddMultiplied(base + arg, arg + arg, multiplier / 2u) + multiplier and 1u == 0u -> addMultipliedBySquaring(base, arg + arg, multiplier shr 1) + multiplier and 1u == 1u -> addMultipliedBySquaring(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") + } + +// TODO: 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.exponentiationBySquaring(arg: C, exponent: Int): C = + if (exponent >= 0) exponentiationBySquaring(arg, exponent.toUInt()) + else exponentiationBySquaring(one / arg, (-exponent).toUInt()) + +// TODO: 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.multiplyExponentiationBySquaring(base: C, arg: C, exponent: Int): C = + if (exponent >= 0) multiplyExponentiationBySquaring(base, arg, exponent.toUInt()) + else multiplyExponentiationBySquaring(base, one / arg, (-exponent).toUInt()) + +// TODO: Move receiver to context receiver +/** + * Raises [arg] to the integer power [exponent]. + * + * This is implementation of variation of [exponentiation by squaring](https://en.wikipedia.org/wiki/Exponentiation_by_squaring) + * + * @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 tailrec fun Ring.exponentiationBySquaring(arg: C, exponent: UInt): C = + when { + exponent == 0u -> zero + exponent == 1u -> arg + exponent and 1u == 0u -> exponentiationBySquaring(arg * arg, exponent shr 1) + exponent and 1u == 1u -> multiplyExponentiationBySquaring(arg, arg * arg, exponent shr 1) + else -> error("Error in multiplication group instant by unsigned integer: got reminder by division by 2 different from 0 and 1") + } + +// TODO: Move receiver to context receiver +/** + * Multiplies [base] and [arg] raised to the integer power [exponent]. + * + * This is implementation of variation of [exponentiation by squaring](https://en.wikipedia.org/wiki/Exponentiation_by_squaring) + * + * @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 tailrec fun RingOps.multiplyExponentiationBySquaring(base: C, arg: C, exponent: UInt): C = + when { + exponent == 0u -> base + exponent == 1u -> base + arg + exponent and 1u == 0u -> multiplyExponentiationBySquaring(base, arg * arg, exponent shr 1) + exponent and 1u == 1u -> multiplyExponentiationBySquaring(base * arg, arg * arg, exponent shr 1) else -> error("Error in multiplication group instant by unsigned integer: got reminder by division by 2 different from 0 and 1") } \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt index 9408a09f2..516e76b8f 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt @@ -351,7 +351,7 @@ public fun > LabeledPolynomial.derivativeWithRespectTo( } } }, - optimizedMultiply(c, degs[variable]!!) + multiplyBySquaring(c, degs[variable]!!) ) } } @@ -382,7 +382,7 @@ public fun > LabeledPolynomial.derivativeWithRespectTo( } } }, - cleanedVariables.fold(c) { acc, variable -> optimizedMultiply(acc, degs[variable]!!) } + cleanedVariables.fold(c) { acc, variable -> multiplyBySquaring(acc, degs[variable]!!) } ) } } @@ -415,7 +415,7 @@ public fun > LabeledPolynomial.nthDerivativeWithRespectTo( }, degs[variable]!!.let { deg -> (deg downTo deg - order + 1u) - .fold(c) { acc, ord -> optimizedMultiply(acc, ord) } + .fold(c) { acc, ord -> multiplyBySquaring(acc, ord) } } ) } @@ -451,7 +451,7 @@ public fun > LabeledPolynomial.nthDerivativeWithRespectTo( filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> degs[index]!!.let { deg -> (deg downTo deg - order + 1u) - .fold(acc1) { acc2, ord -> optimizedMultiply(acc2, ord) } + .fold(acc1) { acc2, ord -> multiplyBySquaring(acc2, ord) } } } ) @@ -478,7 +478,7 @@ public fun > LabeledPolynomial.antiderivativeWithRespectTo( } put( newDegs, - c / optimizedMultiply(one, newDegs[variable]!!) + c / multiplyBySquaring(one, newDegs[variable]!!) ) } } @@ -505,7 +505,7 @@ public fun > LabeledPolynomial.antiderivativeWithRespectTo( } put( newDegs, - cleanedVariables.fold(c) { acc, variable -> acc / optimizedMultiply(one, newDegs[variable]!!) } + cleanedVariables.fold(c) { acc, variable -> acc / multiplyBySquaring(one, newDegs[variable]!!) } ) } } @@ -534,7 +534,7 @@ public fun > LabeledPolynomial.nthAntiderivativeWithRespectTo newDegs, newDegs[variable]!!.let { deg -> (deg downTo deg - order + 1u) - .fold(c) { acc, ord -> acc / optimizedMultiply(one, ord) } + .fold(c) { acc, ord -> acc / multiplyBySquaring(one, ord) } } ) } @@ -565,7 +565,7 @@ public fun > LabeledPolynomial.nthAntiderivativeWithRespectTo filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> newDegs[index]!!.let { deg -> (deg downTo deg - order + 1u) - .fold(acc1) { acc2, ord -> acc2 / optimizedMultiply(one, ord) } + .fold(acc1) { acc2, ord -> acc2 / multiplyBySquaring(one, ord) } } } ) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt index 47644b26a..ac411fc28 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt @@ -393,7 +393,7 @@ public fun > NumberedPolynomial.derivativeWithRespectTo( else -> return@forEach } }.cleanUp(), - optimizedMultiply(c, degs[variable]) + multiplyBySquaring(c, degs[variable]) ) } } @@ -424,7 +424,7 @@ public fun > NumberedPolynomial.derivativeWithRespectTo( else -> return@forEach } }.cleanUp(), - cleanedVariables.fold(c) { acc, variable -> optimizedMultiply(acc, degs[variable]) } + cleanedVariables.fold(c) { acc, variable -> multiplyBySquaring(acc, degs[variable]) } ) } } @@ -456,7 +456,7 @@ public fun > NumberedPolynomial.nthDerivativeWithRespectTo( }.cleanUp(), degs[variable].let { deg -> (deg downTo deg - order + 1u) - .fold(c) { acc, ord -> optimizedMultiply(acc, ord) } + .fold(c) { acc, ord -> multiplyBySquaring(acc, ord) } } ) } @@ -489,7 +489,7 @@ public fun > NumberedPolynomial.nthDerivativeWithRespectTo( filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> degs[index].let { deg -> (deg downTo deg - order + 1u) - .fold(acc1) { acc2, ord -> optimizedMultiply(acc2, ord) } + .fold(acc1) { acc2, ord -> multiplyBySquaring(acc2, ord) } } } ) @@ -512,7 +512,7 @@ public fun > NumberedPolynomial.antiderivativeWithRespectTo( .forEach { (degs, c) -> put( List(max(variable + 1, degs.size)) { if (it != variable) degs[it] else degs[it] + 1u }, - c / optimizedMultiply(one, degs[variable]) + c / multiplyBySquaring(one, degs[variable]) ) } } @@ -536,7 +536,7 @@ public fun > NumberedPolynomial.antiderivativeWithRespectTo( .forEach { (degs, c) -> put( List(max(maxRespectedVariable + 1, degs.size)) { if (it !in variables) degs[it] else degs[it] + 1u }, - cleanedVariables.fold(c) { acc, variable -> acc / optimizedMultiply(one, degs[variable]) } + cleanedVariables.fold(c) { acc, variable -> acc / multiplyBySquaring(one, degs[variable]) } ) } } @@ -561,7 +561,7 @@ public fun > NumberedPolynomial.nthAntiderivativeWithRespectT List(max(variable + 1, degs.size)) { if (it != variable) degs[it] else degs[it] + order }, degs[variable].let { deg -> (deg downTo deg - order + 1u) - .fold(c) { acc, ord -> acc / optimizedMultiply(one, ord) } + .fold(c) { acc, ord -> acc / multiplyBySquaring(one, ord) } } ) } @@ -589,7 +589,7 @@ public fun > NumberedPolynomial.nthAntiderivativeWithRespectT filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> degs[index].let { deg -> (deg downTo deg - order + 1u) - .fold(acc1) { acc2, ord -> acc2 / optimizedMultiply(one, ord) } + .fold(acc1) { acc2, ord -> acc2 / multiplyBySquaring(one, ord) } } } ) 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 index 9c8cc0090..2d0377d2c 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt @@ -137,7 +137,7 @@ public fun Polynomial.derivative( public fun Polynomial.nthDerivative( algebra: A, order: UInt, -): Polynomial where A : Ring, A : NumericAlgebra = algebra { +): Polynomial where A : Ring, A : NumericAlgebra = algebra { Polynomial(coefficients.drop(order.toInt()).mapIndexed { index, c -> (index + 1..index + order.toInt()).fold(c) { acc, i -> acc * number(i) } }) }