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 bdc725e63..1ac413818 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 @@ -14,7 +14,7 @@ import kotlin.math.min * * @param coefficients constant is the leftmost coefficient. */ -public data class Polynomial(public val coefficients: List) : AbstractPolynomial { +public data class Polynomial(public val coefficients: List) : AbstractPolynomial { override fun toString(): String = "Polynomial$coefficients" } @@ -44,7 +44,7 @@ internal fun polynomialError(message: Any): Nothing = throw PolynomialError(mess * [reverse] parameter is true. */ @Suppress("FunctionName") -public fun Polynomial(coefficients: List, reverse: Boolean = false): Polynomial = +public fun Polynomial(coefficients: List, reverse: Boolean = false): Polynomial = Polynomial(with(coefficients) { if (reverse) reversed() else this }) /** @@ -52,10 +52,10 @@ public fun Polynomial(coefficients: List, reverse: Boolean = false): Poly * [reverse] parameter is true. */ @Suppress("FunctionName") -public fun Polynomial(vararg coefficients: T, reverse: Boolean = false): Polynomial = +public fun Polynomial(vararg coefficients: C, reverse: Boolean = false): Polynomial = Polynomial(with(coefficients) { if (reverse) reversed() else toList() }) -public fun T.asPolynomial() : Polynomial = Polynomial(listOf(this)) +public fun C.asPolynomial() : Polynomial = Polynomial(listOf(this)) // endregion @@ -352,7 +352,7 @@ public open class PolynomialSpace>( Polynomial( (0..(thisDegree + otherDegree)) .map { d -> - (max(0, d - otherDegree)..(min(thisDegree, d))) + (max(0, d - otherDegree)..min(thisDegree, d)) .map { coefficients[it] * other.coefficients[d - it] } .reduce { acc, rational -> acc + rational } } @@ -370,16 +370,14 @@ public open class PolynomialSpace>( */ public override fun Polynomial.isOne(): Boolean = with(coefficients) { - isNotEmpty() && - asSequence().withIndex().any { (index, c) -> if (index == 0) c.isOne() else c.isZero() } // TODO: It's better to write new methods like `anyIndexed`. But what's better way to do it? + isNotEmpty() && withIndex().any { (index, c) -> if (index == 0) c.isOne() else c.isZero() } } /** * Check if the instant is minus unit polynomial. */ public override fun Polynomial.isMinusOne(): Boolean = with(coefficients) { - isNotEmpty() && - asSequence().withIndex().any { (index, c) -> if (index == 0) c.isMinusOne() else c.isZero() } // TODO: It's better to write new methods like `anyIndexed`. But what's better way to do it? + isNotEmpty() && withIndex().any { (index, c) -> if (index == 0) c.isMinusOne() else c.isZero() } } /** 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 7e40b6246..a41a6cbd6 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 @@ -9,7 +9,8 @@ import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.* import kotlin.contracts.InvocationKind import kotlin.contracts.contract -import kotlin.jvm.JvmName +import kotlin.math.max +import kotlin.math.min import kotlin.math.pow @@ -77,15 +78,32 @@ public fun Polynomial.substitute(ring: Ring, arg: C): C = ring { return result } -// TODO: (Waiting for hero) Replace with optimisation: the [result] may be unboxed, and all operations may be performed -// as soon as possible on it public fun Polynomial.substitute(ring: Ring, arg: Polynomial) : Polynomial = ring.polynomial { if (coefficients.isEmpty()) return zero - var result: Polynomial = coefficients.last().asPolynomial() - for (j in coefficients.size - 2 downTo 0) { - result = (arg * result) + coefficients[j] + + val thisDegree = degree + if (thisDegree == -1) return zero + val argDegree = arg.degree + if (argDegree == -1) return coefficients[0].asPolynomial() + val constantZero = constantZero + val resultCoefs: MutableList = MutableList(thisDegree + argDegree + 1) { constantZero } + val resultCoefsUpdate: MutableList = MutableList(thisDegree + argDegree + 1) { constantZero } + var resultDegree = 0 + for (deg in thisDegree downTo 0) { + resultCoefsUpdate[0] = coefficients[deg] + for (updateDeg in 0 .. resultDegree + argDegree) { + var newC = resultCoefsUpdate[updateDeg] + for (deg1 in max(0, updateDeg - argDegree)..min(resultDegree, updateDeg)) + newC += resultCoefs[deg1] * arg.coefficients[updateDeg - deg1] + resultCoefsUpdate[updateDeg] = newC + } + resultDegree += argDegree + for (updateDeg in 0 .. resultDegree + argDegree) { + resultCoefs[updateDeg] = resultCoefsUpdate[updateDeg] + resultCoefsUpdate[updateDeg] = constantZero + } } - return result + return Polynomial(resultCoefs) } /** @@ -109,7 +127,7 @@ public fun > Polynomial.asPolynomialFunctionOver(ring: A): (Po public fun Polynomial.derivative( algebra: A, ): Polynomial where A : Ring, A : NumericAlgebra = algebra { - Polynomial(coefficients.drop(1).mapIndexed { index, c -> number(index) * c }) + Polynomial(coefficients.drop(1).mapIndexed { index, c -> number(index + 1) * c }) } /** @@ -120,8 +138,7 @@ public fun Polynomial.nthDerivative( algebra: A, order: UInt, ): Polynomial where A : Ring, A : NumericAlgebra = algebra { - TODO() - Polynomial(coefficients.drop(order.toInt()).mapIndexed { index, c -> number(index) * c }) + Polynomial(coefficients.drop(order.toInt()).mapIndexed { index, c -> (1..order.toInt()).fold(c) { acc, i -> acc * number(index + i) } }) } /** @@ -133,7 +150,7 @@ public fun Polynomial.antiderivative( ): Polynomial where A : Field, A : NumericAlgebra = algebra { val integratedCoefficients = buildList(coefficients.size + 1) { add(zero) - coefficients.forEachIndexed{ index, t -> add(t / number(index + 1)) } + coefficients.mapIndexedTo(this) { index, t -> t / number(index + 1) } } Polynomial(integratedCoefficients) } @@ -146,12 +163,11 @@ public fun Polynomial.nthAntiderivative( algebra: A, order: UInt, ): Polynomial where A : Field, A : NumericAlgebra = algebra { - TODO() - val integratedCoefficients = buildList(coefficients.size + 1) { - add(zero) - coefficients.forEachIndexed{ index, t -> add(t / number(index + 1)) } + val newCoefficients = buildList(coefficients.size + order.toInt()) { + repeat(order.toInt()) { add(zero) } + coefficients.mapIndexedTo(this) { index, c -> (1..order.toInt()).fold(c) { acc, i -> acc / number(index + i) } } } - Polynomial(integratedCoefficients) + return Polynomial(newCoefficients) } /**